LCOV - differential code coverage report
Current view: top level - src/backend/commands - createas.c (source / functions) Coverage Total Hit UBC GBC CBC
Current: Differential Code Coverage 16@8cea358b128 vs 17@8cea358b128 Lines: 98.2 % 169 166 3 3 163
Current Date: 2024-04-14 14:21:10 Functions: 100.0 % 10 10 1 9
Baseline: 16@8cea358b128 Branches: 72.3 % 94 68 26 68
Baseline Date: 2024-04-14 14:21:09 Line coverage date bins:
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed [..60] days: 100.0 % 1 1 1
(240..) days: 98.2 % 168 165 3 3 162
Function coverage date bins:
(240..) days: 100.0 % 10 10 1 9
Branch coverage date bins:
(240..) days: 72.3 % 94 68 26 68

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * createas.c
                                  4                 :                :  *    Execution of CREATE TABLE ... AS, a/k/a SELECT INTO.
                                  5                 :                :  *    Since CREATE MATERIALIZED VIEW shares syntax and most behaviors,
                                  6                 :                :  *    we implement that here, too.
                                  7                 :                :  *
                                  8                 :                :  * We implement this by diverting the query's normal output to a
                                  9                 :                :  * specialized DestReceiver type.
                                 10                 :                :  *
                                 11                 :                :  * Formerly, CTAS was implemented as a variant of SELECT, which led
                                 12                 :                :  * to assorted legacy behaviors that we still try to preserve, notably that
                                 13                 :                :  * we must return a tuples-processed count in the QueryCompletion.  (We no
                                 14                 :                :  * longer do that for CTAS ... WITH NO DATA, however.)
                                 15                 :                :  *
                                 16                 :                :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
                                 17                 :                :  * Portions Copyright (c) 1994, Regents of the University of California
                                 18                 :                :  *
                                 19                 :                :  *
                                 20                 :                :  * IDENTIFICATION
                                 21                 :                :  *    src/backend/commands/createas.c
                                 22                 :                :  *
                                 23                 :                :  *-------------------------------------------------------------------------
                                 24                 :                :  */
                                 25                 :                : #include "postgres.h"
                                 26                 :                : 
                                 27                 :                : #include "access/heapam.h"
                                 28                 :                : #include "access/reloptions.h"
                                 29                 :                : #include "access/tableam.h"
                                 30                 :                : #include "access/xact.h"
                                 31                 :                : #include "catalog/namespace.h"
                                 32                 :                : #include "catalog/toasting.h"
                                 33                 :                : #include "commands/createas.h"
                                 34                 :                : #include "commands/matview.h"
                                 35                 :                : #include "commands/prepare.h"
                                 36                 :                : #include "commands/tablecmds.h"
                                 37                 :                : #include "commands/view.h"
                                 38                 :                : #include "miscadmin.h"
                                 39                 :                : #include "nodes/makefuncs.h"
                                 40                 :                : #include "nodes/nodeFuncs.h"
                                 41                 :                : #include "rewrite/rewriteHandler.h"
                                 42                 :                : #include "tcop/tcopprot.h"
                                 43                 :                : #include "utils/builtins.h"
                                 44                 :                : #include "utils/lsyscache.h"
                                 45                 :                : #include "utils/rel.h"
                                 46                 :                : #include "utils/rls.h"
                                 47                 :                : #include "utils/snapmgr.h"
                                 48                 :                : 
                                 49                 :                : typedef struct
                                 50                 :                : {
                                 51                 :                :     DestReceiver pub;           /* publicly-known function pointers */
                                 52                 :                :     IntoClause *into;           /* target relation specification */
                                 53                 :                :     /* These fields are filled by intorel_startup: */
                                 54                 :                :     Relation    rel;            /* relation to write to */
                                 55                 :                :     ObjectAddress reladdr;      /* address of rel, for ExecCreateTableAs */
                                 56                 :                :     CommandId   output_cid;     /* cmin to insert in output tuples */
                                 57                 :                :     int         ti_options;     /* table_tuple_insert performance options */
                                 58                 :                :     BulkInsertState bistate;    /* bulk insert state */
                                 59                 :                : } DR_intorel;
                                 60                 :                : 
                                 61                 :                : /* utility functions for CTAS definition creation */
                                 62                 :                : static ObjectAddress create_ctas_internal(List *attrList, IntoClause *into);
                                 63                 :                : static ObjectAddress create_ctas_nodata(List *tlist, IntoClause *into);
                                 64                 :                : 
                                 65                 :                : /* DestReceiver routines for collecting data */
                                 66                 :                : static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo);
                                 67                 :                : static bool intorel_receive(TupleTableSlot *slot, DestReceiver *self);
                                 68                 :                : static void intorel_shutdown(DestReceiver *self);
                                 69                 :                : static void intorel_destroy(DestReceiver *self);
                                 70                 :                : 
                                 71                 :                : 
                                 72                 :                : /*
                                 73                 :                :  * create_ctas_internal
                                 74                 :                :  *
                                 75                 :                :  * Internal utility used for the creation of the definition of a relation
                                 76                 :                :  * created via CREATE TABLE AS or a materialized view.  Caller needs to
                                 77                 :                :  * provide a list of attributes (ColumnDef nodes).
                                 78                 :                :  */
                                 79                 :                : static ObjectAddress
 2848 tgl@sss.pgh.pa.us          80                 :CBC         800 : create_ctas_internal(List *attrList, IntoClause *into)
                                 81                 :                : {
                                 82                 :            800 :     CreateStmt *create = makeNode(CreateStmt);
                                 83                 :                :     bool        is_matview;
                                 84                 :                :     char        relkind;
                                 85                 :                :     Datum       toast_options;
                                 86                 :                :     static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
                                 87                 :                :     ObjectAddress intoRelationAddr;
                                 88                 :                : 
                                 89                 :                :     /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
                                 90                 :            800 :     is_matview = (into->viewQuery != NULL);
                                 91         [ +  + ]:            800 :     relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION;
                                 92                 :                : 
                                 93                 :                :     /*
                                 94                 :                :      * Create the target relation by faking up a CREATE TABLE parsetree and
                                 95                 :                :      * passing it to DefineRelation.
                                 96                 :                :      */
                                 97                 :            800 :     create->relation = into->rel;
                                 98                 :            800 :     create->tableElts = attrList;
                                 99                 :            800 :     create->inhRelations = NIL;
                                100                 :            800 :     create->ofTypename = NULL;
                                101                 :            800 :     create->constraints = NIL;
                                102                 :            800 :     create->options = into->options;
                                103                 :            800 :     create->oncommit = into->onCommit;
                                104                 :            800 :     create->tablespacename = into->tableSpaceName;
                                105                 :            800 :     create->if_not_exists = false;
 1866 andres@anarazel.de        106                 :            800 :     create->accessMethod = into->accessMethod;
                                107                 :                : 
                                108                 :                :     /*
                                109                 :                :      * Create the relation.  (This will error out if there's an existing view,
                                110                 :                :      * so we don't need more code to complain if "replace" is false.)
                                111                 :                :      */
 2685 rhaas@postgresql.org      112                 :            800 :     intoRelationAddr = DefineRelation(create, relkind, InvalidOid, NULL, NULL);
                                113                 :                : 
                                114                 :                :     /*
                                115                 :                :      * If necessary, create a TOAST table for the target table.  Note that
                                116                 :                :      * NewRelationCreateToastTable ends with CommandCounterIncrement(), so
                                117                 :                :      * that the TOAST table will be visible for insertion.
                                118                 :                :      */
 2848 tgl@sss.pgh.pa.us         119                 :            791 :     CommandCounterIncrement();
                                120                 :                : 
                                121                 :                :     /* parse and validate reloptions for the toast table */
                                122                 :            791 :     toast_options = transformRelOptions((Datum) 0,
                                123                 :                :                                         create->options,
                                124                 :                :                                         "toast",
                                125                 :                :                                         validnsps,
                                126                 :                :                                         true, false);
                                127                 :                : 
    3 akorotkov@postgresql      128                 :            791 :     (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true);
                                129                 :                : 
 2848 tgl@sss.pgh.pa.us         130                 :            791 :     NewRelationCreateToastTable(intoRelationAddr.objectId, toast_options);
                                131                 :                : 
                                132                 :                :     /* Create the "view" part of a materialized view. */
                                133         [ +  + ]:            791 :     if (is_matview)
                                134                 :                :     {
                                135                 :                :         /* StoreViewQuery scribbles on tree, so make a copy */
                                136                 :            219 :         Query      *query = (Query *) copyObject(into->viewQuery);
                                137                 :                : 
                                138                 :            219 :         StoreViewQuery(intoRelationAddr.objectId, query, false);
                                139                 :            219 :         CommandCounterIncrement();
                                140                 :                :     }
                                141                 :                : 
                                142                 :            791 :     return intoRelationAddr;
                                143                 :                : }
                                144                 :                : 
                                145                 :                : 
                                146                 :                : /*
                                147                 :                :  * create_ctas_nodata
                                148                 :                :  *
                                149                 :                :  * Create CTAS or materialized view when WITH NO DATA is used, starting from
                                150                 :                :  * the targetlist of the SELECT or view definition.
                                151                 :                :  */
                                152                 :                : static ObjectAddress
                                153                 :             54 : create_ctas_nodata(List *tlist, IntoClause *into)
                                154                 :                : {
                                155                 :                :     List       *attrList;
                                156                 :                :     ListCell   *t,
                                157                 :                :                *lc;
                                158                 :                : 
                                159                 :                :     /*
                                160                 :                :      * Build list of ColumnDefs from non-junk elements of the tlist.  If a
                                161                 :                :      * column name list was specified in CREATE TABLE AS, override the column
                                162                 :                :      * names in the query.  (Too few column names are OK, too many are not.)
                                163                 :                :      */
                                164                 :             54 :     attrList = NIL;
                                165                 :             54 :     lc = list_head(into->colNames);
                                166   [ +  -  +  +  :            174 :     foreach(t, tlist)
                                              +  + ]
                                167                 :                :     {
                                168                 :            120 :         TargetEntry *tle = (TargetEntry *) lfirst(t);
                                169                 :                : 
                                170         [ +  - ]:            120 :         if (!tle->resjunk)
                                171                 :                :         {
                                172                 :                :             ColumnDef  *col;
                                173                 :                :             char       *colname;
                                174                 :                : 
                                175         [ +  + ]:            120 :             if (lc)
                                176                 :                :             {
                                177                 :             38 :                 colname = strVal(lfirst(lc));
 1735                           178                 :             38 :                 lc = lnext(into->colNames, lc);
                                179                 :                :             }
                                180                 :                :             else
 2848                           181                 :             82 :                 colname = tle->resname;
                                182                 :                : 
                                183                 :            120 :             col = makeColumnDef(colname,
                                184                 :            120 :                                 exprType((Node *) tle->expr),
                                185                 :            120 :                                 exprTypmod((Node *) tle->expr),
                                186                 :            120 :                                 exprCollation((Node *) tle->expr));
                                187                 :                : 
                                188                 :                :             /*
                                189                 :                :              * It's possible that the column is of a collatable type but the
                                190                 :                :              * collation could not be resolved, so double-check.  (We must
                                191                 :                :              * check this here because DefineRelation would adopt the type's
                                192                 :                :              * default collation rather than complaining.)
                                193                 :                :              */
                                194   [ +  +  -  + ]:            230 :             if (!OidIsValid(col->collOid) &&
                                195                 :            110 :                 type_is_collatable(col->typeName->typeOid))
 2848 tgl@sss.pgh.pa.us         196         [ #  # ]:UBC           0 :                 ereport(ERROR,
                                197                 :                :                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
                                198                 :                :                          errmsg("no collation was derived for column \"%s\" with collatable type %s",
                                199                 :                :                                 col->colname,
                                200                 :                :                                 format_type_be(col->typeName->typeOid)),
                                201                 :                :                          errhint("Use the COLLATE clause to set the collation explicitly.")));
                                202                 :                : 
 2848 tgl@sss.pgh.pa.us         203                 :CBC         120 :             attrList = lappend(attrList, col);
                                204                 :                :         }
                                205                 :                :     }
                                206                 :                : 
                                207         [ +  + ]:             54 :     if (lc != NULL)
                                208         [ +  - ]:              6 :         ereport(ERROR,
                                209                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                210                 :                :                  errmsg("too many column names were specified")));
                                211                 :                : 
                                212                 :                :     /* Create the relation definition using the ColumnDef list */
                                213                 :             48 :     return create_ctas_internal(attrList, into);
                                214                 :                : }
                                215                 :                : 
                                216                 :                : 
                                217                 :                : /*
                                218                 :                :  * ExecCreateTableAs -- execute a CREATE TABLE AS command
                                219                 :                :  */
                                220                 :                : ObjectAddress
 1562 peter@eisentraut.org      221                 :            840 : ExecCreateTableAs(ParseState *pstate, CreateTableAsStmt *stmt,
                                222                 :                :                   ParamListInfo params, QueryEnvironment *queryEnv,
                                223                 :                :                   QueryCompletion *qc)
                                224                 :                : {
 2635 andres@anarazel.de        225                 :            840 :     Query      *query = castNode(Query, stmt->query);
 4409 tgl@sss.pgh.pa.us         226                 :            840 :     IntoClause *into = stmt->into;
 3929 noah@leadboat.com         227                 :            840 :     bool        is_matview = (into->viewQuery != NULL);
                                228                 :                :     DestReceiver *dest;
                                229                 :            840 :     Oid         save_userid = InvalidOid;
                                230                 :            840 :     int         save_sec_context = 0;
                                231                 :            840 :     int         save_nestlevel = 0;
                                232                 :                :     ObjectAddress address;
                                233                 :                :     List       *rewritten;
                                234                 :                :     PlannedStmt *plan;
                                235                 :                :     QueryDesc  *queryDesc;
                                236                 :                : 
                                237                 :                :     /* Check if the relation exists or not */
 1201 michael@paquier.xyz       238         [ +  + ]:            840 :     if (CreateTableAsRelExists(stmt))
                                239                 :             23 :         return InvalidObjectAddress;
                                240                 :                : 
                                241                 :                :     /*
                                242                 :                :      * Create the tuple receiver object and insert info it will need
                                243                 :                :      */
 4409 tgl@sss.pgh.pa.us         244                 :            794 :     dest = CreateIntoRelDestReceiver(into);
                                245                 :                : 
                                246                 :                :     /*
                                247                 :                :      * The contained Query could be a SELECT, or an EXECUTE utility command.
                                248                 :                :      * If the latter, we just pass it off to ExecuteQuery.
                                249                 :                :      */
                                250         [ +  + ]:            794 :     if (query->commandType == CMD_UTILITY &&
                                251         [ +  - ]:             21 :         IsA(query->utilityStmt, ExecuteStmt))
                                252                 :                :     {
 2635 andres@anarazel.de        253                 :             21 :         ExecuteStmt *estmt = castNode(ExecuteStmt, query->utilityStmt);
                                254                 :                : 
 3929 noah@leadboat.com         255         [ -  + ]:             21 :         Assert(!is_matview);    /* excluded by syntax */
 1504 alvherre@alvh.no-ip.      256                 :             21 :         ExecuteQuery(pstate, estmt, into, params, dest, qc);
                                257                 :                : 
                                258                 :                :         /* get object address that intorel_startup saved for us */
 2848 tgl@sss.pgh.pa.us         259                 :             21 :         address = ((DR_intorel *) dest)->reladdr;
                                260                 :                : 
 3330 alvherre@alvh.no-ip.      261                 :             21 :         return address;
                                262                 :                :     }
 4020 tgl@sss.pgh.pa.us         263         [ -  + ]:            773 :     Assert(query->commandType == CMD_SELECT);
                                264                 :                : 
                                265                 :                :     /*
                                266                 :                :      * For materialized views, lock down security-restricted operations and
                                267                 :                :      * arrange to make GUC variable changes local to this command.  This is
                                268                 :                :      * not necessary for security, but this keeps the behavior similar to
                                269                 :                :      * REFRESH MATERIALIZED VIEW.  Otherwise, one could create a materialized
                                270                 :                :      * view not possible to refresh.
                                271                 :                :      */
 3929 noah@leadboat.com         272         [ +  + ]:            773 :     if (is_matview)
                                273                 :                :     {
                                274                 :            222 :         GetUserIdAndSecContext(&save_userid, &save_sec_context);
                                275                 :            222 :         SetUserIdAndSecContext(save_userid,
                                276                 :                :                                save_sec_context | SECURITY_RESTRICTED_OPERATION);
                                277                 :            222 :         save_nestlevel = NewGUCNestLevel();
                                278                 :                :     }
                                279                 :                : 
 2848 tgl@sss.pgh.pa.us         280         [ +  + ]:            773 :     if (into->skipData)
                                281                 :                :     {
                                282                 :                :         /*
                                283                 :                :          * If WITH NO DATA was specified, do not go through the rewriter,
                                284                 :                :          * planner and executor.  Just define the relation using a code path
                                285                 :                :          * similar to CREATE VIEW.  This avoids dump/restore problems stemming
                                286                 :                :          * from running the planner before all dependencies are set up.
                                287                 :                :          */
                                288                 :             54 :         address = create_ctas_nodata(query->targetList, into);
                                289                 :                :     }
                                290                 :                :     else
                                291                 :                :     {
                                292                 :                :         /*
                                293                 :                :          * Parse analysis was done already, but we still have to run the rule
                                294                 :                :          * rewriter.  We do not do AcquireRewriteLocks: we assume the query
                                295                 :                :          * either came straight from the parser, or suitable locks were
                                296                 :                :          * acquired by plancache.c.
                                297                 :                :          */
 1031                           298                 :            719 :         rewritten = QueryRewrite(query);
                                299                 :                : 
                                300                 :                :         /* SELECT should never rewrite to more or less than one SELECT query */
 2848                           301         [ -  + ]:            719 :         if (list_length(rewritten) != 1)
 2848 tgl@sss.pgh.pa.us         302   [ #  #  #  # ]:UBC           0 :             elog(ERROR, "unexpected rewrite result for %s",
                                303                 :                :                  is_matview ? "CREATE MATERIALIZED VIEW" :
                                304                 :                :                  "CREATE TABLE AS SELECT");
 2561 tgl@sss.pgh.pa.us         305                 :CBC         719 :         query = linitial_node(Query, rewritten);
 2848                           306         [ -  + ]:            719 :         Assert(query->commandType == CMD_SELECT);
                                307                 :                : 
                                308                 :                :         /* plan the query */
 1476 fujii@postgresql.org      309                 :            719 :         plan = pg_plan_query(query, pstate->p_sourcetext,
                                310                 :                :                              CURSOR_OPT_PARALLEL_OK, params);
                                311                 :                : 
                                312                 :                :         /*
                                313                 :                :          * Use a snapshot with an updated command ID to ensure this query sees
                                314                 :                :          * results of any previously executed queries.  (This could only
                                315                 :                :          * matter if the planner executed an allegedly-stable function that
                                316                 :                :          * changed the database contents, but let's do it anyway to be
                                317                 :                :          * parallel to the EXPLAIN code path.)
                                318                 :                :          */
 2848 tgl@sss.pgh.pa.us         319                 :            716 :         PushCopiedSnapshot(GetActiveSnapshot());
                                320                 :            716 :         UpdateActiveSnapshotCommandId();
                                321                 :                : 
                                322                 :                :         /* Create a QueryDesc, redirecting output to our tuple receiver */
 1562 peter@eisentraut.org      323                 :            716 :         queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext,
                                324                 :                :                                     GetActiveSnapshot(), InvalidSnapshot,
                                325                 :                :                                     dest, params, queryEnv, 0);
                                326                 :                : 
                                327                 :                :         /* call ExecutorStart to prepare the plan for execution */
 2848 tgl@sss.pgh.pa.us         328                 :            716 :         ExecutorStart(queryDesc, GetIntoRelEFlags(into));
                                329                 :                : 
                                330                 :                :         /* run the plan to completion */
  382 peter@eisentraut.org      331                 :            716 :         ExecutorRun(queryDesc, ForwardScanDirection, 0, true);
                                332                 :                : 
                                333                 :                :         /* save the rowcount if we're given a qc to fill */
 1504 alvherre@alvh.no-ip.      334         [ +  + ]:            695 :         if (qc)
                                335                 :            685 :             SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed);
                                336                 :                : 
                                337                 :                :         /* get object address that intorel_startup saved for us */
 2848 tgl@sss.pgh.pa.us         338                 :            695 :         address = ((DR_intorel *) dest)->reladdr;
                                339                 :                : 
                                340                 :                :         /* and clean up */
                                341                 :            695 :         ExecutorFinish(queryDesc);
                                342                 :            695 :         ExecutorEnd(queryDesc);
                                343                 :                : 
                                344                 :            695 :         FreeQueryDesc(queryDesc);
                                345                 :                : 
                                346                 :            695 :         PopActiveSnapshot();
                                347                 :                :     }
                                348                 :                : 
 3929 noah@leadboat.com         349         [ +  + ]:            743 :     if (is_matview)
                                350                 :                :     {
                                351                 :                :         /* Roll back any GUC changes */
                                352                 :            213 :         AtEOXact_GUC(false, save_nestlevel);
                                353                 :                : 
                                354                 :                :         /* Restore userid and security context */
                                355                 :            213 :         SetUserIdAndSecContext(save_userid, save_sec_context);
                                356                 :                :     }
                                357                 :                : 
 3330 alvherre@alvh.no-ip.      358                 :            743 :     return address;
                                359                 :                : }
                                360                 :                : 
                                361                 :                : /*
                                362                 :                :  * GetIntoRelEFlags --- compute executor flags needed for CREATE TABLE AS
                                363                 :                :  *
                                364                 :                :  * This is exported because EXPLAIN and PREPARE need it too.  (Note: those
                                365                 :                :  * callers still need to deal explicitly with the skipData flag; since they
                                366                 :                :  * use different methods for suppressing execution, it doesn't seem worth
                                367                 :                :  * trying to encapsulate that part.)
                                368                 :                :  */
                                369                 :                : int
 4409 tgl@sss.pgh.pa.us         370                 :            785 : GetIntoRelEFlags(IntoClause *intoClause)
                                371                 :                : {
 1972 andres@anarazel.de        372                 :            785 :     int         flags = 0;
                                373                 :                : 
 4060 kgrittn@postgresql.o      374         [ +  + ]:            785 :     if (intoClause->skipData)
                                375                 :             21 :         flags |= EXEC_FLAG_WITH_NO_DATA;
                                376                 :                : 
                                377                 :            785 :     return flags;
                                378                 :                : }
                                379                 :                : 
                                380                 :                : /*
                                381                 :                :  * CreateTableAsRelExists --- check existence of relation for CreateTableAsStmt
                                382                 :                :  *
                                383                 :                :  * Utility wrapper checking if the relation pending for creation in this
                                384                 :                :  * CreateTableAsStmt query already exists or not.  Returns true if the
                                385                 :                :  * relation exists, otherwise false.
                                386                 :                :  */
                                387                 :                : bool
 1201 michael@paquier.xyz       388                 :            918 : CreateTableAsRelExists(CreateTableAsStmt *ctas)
                                389                 :                : {
                                390                 :                :     Oid         nspid;
                                391                 :                :     Oid         oldrelid;
                                392                 :                :     ObjectAddress address;
                                393                 :            918 :     IntoClause *into = ctas->into;
                                394                 :                : 
                                395                 :            918 :     nspid = RangeVarGetCreationNamespace(into->rel);
                                396                 :                : 
  615 tgl@sss.pgh.pa.us         397                 :            918 :     oldrelid = get_relname_relid(into->rel->relname, nspid);
                                398         [ +  + ]:            918 :     if (OidIsValid(oldrelid))
                                399                 :                :     {
 1201 michael@paquier.xyz       400         [ +  + ]:             76 :         if (!ctas->if_not_exists)
                                401         [ +  - ]:             36 :             ereport(ERROR,
                                402                 :                :                     (errcode(ERRCODE_DUPLICATE_TABLE),
                                403                 :                :                      errmsg("relation \"%s\" already exists",
                                404                 :                :                             into->rel->relname)));
                                405                 :                : 
                                406                 :                :         /*
                                407                 :                :          * The relation exists and IF NOT EXISTS has been specified.
                                408                 :                :          *
                                409                 :                :          * If we are in an extension script, insist that the pre-existing
                                410                 :                :          * object be a member of the extension, to avoid security risks.
                                411                 :                :          */
  615 tgl@sss.pgh.pa.us         412                 :             40 :         ObjectAddressSet(address, RelationRelationId, oldrelid);
                                413                 :             40 :         checkMembershipInCurrentExtension(&address);
                                414                 :                : 
                                415                 :                :         /* OK to skip */
 1201 michael@paquier.xyz       416         [ +  + ]:             38 :         ereport(NOTICE,
                                417                 :                :                 (errcode(ERRCODE_DUPLICATE_TABLE),
                                418                 :                :                  errmsg("relation \"%s\" already exists, skipping",
                                419                 :                :                         into->rel->relname)));
                                420                 :             38 :         return true;
                                421                 :                :     }
                                422                 :                : 
                                423                 :                :     /* Relation does not exist, it can be created */
                                424                 :            842 :     return false;
                                425                 :                : }
                                426                 :                : 
                                427                 :                : /*
                                428                 :                :  * CreateIntoRelDestReceiver -- create a suitable DestReceiver object
                                429                 :                :  *
                                430                 :                :  * intoClause will be NULL if called from CreateDestReceiver(), in which
                                431                 :                :  * case it has to be provided later.  However, it is convenient to allow
                                432                 :                :  * self->into to be filled in immediately for other callers.
                                433                 :                :  */
                                434                 :                : DestReceiver *
 4409 tgl@sss.pgh.pa.us         435                 :            842 : CreateIntoRelDestReceiver(IntoClause *intoClause)
                                436                 :                : {
                                437                 :            842 :     DR_intorel *self = (DR_intorel *) palloc0(sizeof(DR_intorel));
                                438                 :                : 
                                439                 :            842 :     self->pub.receiveSlot = intorel_receive;
                                440                 :            842 :     self->pub.rStartup = intorel_startup;
                                441                 :            842 :     self->pub.rShutdown = intorel_shutdown;
                                442                 :            842 :     self->pub.rDestroy = intorel_destroy;
                                443                 :            842 :     self->pub.mydest = DestIntoRel;
                                444                 :            842 :     self->into = intoClause;
                                445                 :                :     /* other private fields will be set during intorel_startup */
                                446                 :                : 
                                447                 :            842 :     return (DestReceiver *) self;
                                448                 :                : }
                                449                 :                : 
                                450                 :                : /*
                                451                 :                :  * intorel_startup --- executor startup
                                452                 :                :  */
                                453                 :                : static void
                                454                 :            764 : intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
                                455                 :                : {
                                456                 :            764 :     DR_intorel *myState = (DR_intorel *) self;
                                457                 :            764 :     IntoClause *into = myState->into;
                                458                 :                :     bool        is_matview;
                                459                 :                :     List       *attrList;
                                460                 :                :     ObjectAddress intoRelationAddr;
                                461                 :                :     Relation    intoRelationDesc;
                                462                 :                :     ListCell   *lc;
                                463                 :                :     int         attnum;
                                464                 :                : 
                                465         [ -  + ]:            764 :     Assert(into != NULL);       /* else somebody forgot to set it */
                                466                 :                : 
                                467                 :                :     /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */
 4020                           468                 :            764 :     is_matview = (into->viewQuery != NULL);
                                469                 :                : 
                                470                 :                :     /*
                                471                 :                :      * Build column definitions using "pre-cooked" type and collation info. If
                                472                 :                :      * a column name list was specified in CREATE TABLE AS, override the
                                473                 :                :      * column names derived from the query.  (Too few column names are OK, too
                                474                 :                :      * many are not.)
                                475                 :                :      */
 2848                           476                 :            764 :     attrList = NIL;
 4409                           477                 :            764 :     lc = list_head(into->colNames);
                                478         [ +  + ]:           2964 :     for (attnum = 0; attnum < typeinfo->natts; attnum++)
                                479                 :                :     {
 2429 andres@anarazel.de        480                 :           2206 :         Form_pg_attribute attribute = TupleDescAttr(typeinfo, attnum);
                                481                 :                :         ColumnDef  *col;
                                482                 :                :         char       *colname;
                                483                 :                : 
 4409 tgl@sss.pgh.pa.us         484         [ +  + ]:           2206 :         if (lc)
                                485                 :                :         {
 2848                           486                 :            133 :             colname = strVal(lfirst(lc));
 1735                           487                 :            133 :             lc = lnext(into->colNames, lc);
                                488                 :                :         }
                                489                 :                :         else
 2848                           490                 :           2073 :             colname = NameStr(attribute->attname);
                                491                 :                : 
                                492                 :           2206 :         col = makeColumnDef(colname,
                                493                 :                :                             attribute->atttypid,
                                494                 :                :                             attribute->atttypmod,
                                495                 :                :                             attribute->attcollation);
                                496                 :                : 
                                497                 :                :         /*
                                498                 :                :          * It's possible that the column is of a collatable type but the
                                499                 :                :          * collation could not be resolved, so double-check.  (We must check
                                500                 :                :          * this here because DefineRelation would adopt the type's default
                                501                 :                :          * collation rather than complaining.)
                                502                 :                :          */
 4409                           503   [ +  +  +  + ]:           4069 :         if (!OidIsValid(col->collOid) &&
 2848                           504                 :           1863 :             type_is_collatable(col->typeName->typeOid))
 4409                           505         [ +  - ]:              6 :             ereport(ERROR,
                                506                 :                :                     (errcode(ERRCODE_INDETERMINATE_COLLATION),
                                507                 :                :                      errmsg("no collation was derived for column \"%s\" with collatable type %s",
                                508                 :                :                             col->colname,
                                509                 :                :                             format_type_be(col->typeName->typeOid)),
                                510                 :                :                      errhint("Use the COLLATE clause to set the collation explicitly.")));
                                511                 :                : 
 2848                           512                 :           2200 :         attrList = lappend(attrList, col);
                                513                 :                :     }
                                514                 :                : 
 4409                           515         [ +  + ]:            758 :     if (lc != NULL)
                                516         [ +  - ]:              6 :         ereport(ERROR,
                                517                 :                :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                518                 :                :                  errmsg("too many column names were specified")));
                                519                 :                : 
                                520                 :                :     /*
                                521                 :                :      * Actually create the target table
                                522                 :                :      */
 2848                           523                 :            752 :     intoRelationAddr = create_ctas_internal(attrList, into);
                                524                 :                : 
                                525                 :                :     /*
                                526                 :                :      * Finally we can open the target table
                                527                 :                :      */
 1910 andres@anarazel.de        528                 :            743 :     intoRelationDesc = table_open(intoRelationAddr.objectId, AccessExclusiveLock);
                                529                 :                : 
                                530                 :                :     /*
                                531                 :                :      * Make sure the constructed table does not have RLS enabled.
                                532                 :                :      *
                                533                 :                :      * check_enable_rls() will ereport(ERROR) itself if the user has requested
                                534                 :                :      * something invalid, and otherwise will return RLS_ENABLED if RLS should
                                535                 :                :      * be enabled here.  We don't actually support that currently, so throw
                                536                 :                :      * our own ereport(ERROR) if that happens.
                                537                 :                :      */
 3330 alvherre@alvh.no-ip.      538         [ -  + ]:            743 :     if (check_enable_rls(intoRelationAddr.objectId, InvalidOid, false) == RLS_ENABLED)
 3495 sfrost@snowman.net        539         [ #  # ]:UBC           0 :         ereport(ERROR,
                                540                 :                :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                541                 :                :                  errmsg("policies not yet implemented for this command")));
                                542                 :                : 
                                543                 :                :     /*
                                544                 :                :      * Tentatively mark the target as populated, if it's a matview and we're
                                545                 :                :      * going to fill it; otherwise, no change needed.
                                546                 :                :      */
 3996 tgl@sss.pgh.pa.us         547   [ +  +  +  + ]:CBC         743 :     if (is_matview && !into->skipData)
                                548                 :            178 :         SetMatViewPopulatedState(intoRelationDesc, true);
                                549                 :                : 
                                550                 :                :     /*
                                551                 :                :      * Fill private fields of myState for use by later routines
                                552                 :                :      */
 4409                           553                 :            743 :     myState->rel = intoRelationDesc;
 2848                           554                 :            743 :     myState->reladdr = intoRelationAddr;
 4409                           555                 :            743 :     myState->output_cid = GetCurrentCommandId(true);
 1471 noah@leadboat.com         556                 :            743 :     myState->ti_options = TABLE_INSERT_SKIP_FSM;
                                557                 :                : 
                                558                 :                :     /*
                                559                 :                :      * If WITH NO DATA is specified, there is no need to set up the state for
                                560                 :                :      * bulk inserts as there are no tuples to insert.
                                561                 :                :      */
 1245 michael@paquier.xyz       562         [ +  + ]:            743 :     if (!into->skipData)
                                563                 :            725 :         myState->bistate = GetBulkInsertState();
                                564                 :                :     else
                                565                 :             18 :         myState->bistate = NULL;
                                566                 :                : 
                                567                 :                :     /*
                                568                 :                :      * Valid smgr_targblock implies something already wrote to the relation.
                                569                 :                :      * This may be harmless, but this function hasn't planned for it.
                                570                 :                :      */
 4409 tgl@sss.pgh.pa.us         571   [ -  +  -  - ]:            743 :     Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber);
                                572                 :            743 : }
                                573                 :                : 
                                574                 :                : /*
                                575                 :                :  * intorel_receive --- receive one tuple
                                576                 :                :  */
                                577                 :                : static bool
                                578                 :        1061874 : intorel_receive(TupleTableSlot *slot, DestReceiver *self)
                                579                 :                : {
                                580                 :        1061874 :     DR_intorel *myState = (DR_intorel *) self;
                                581                 :                : 
                                582                 :                :     /* Nothing to insert if WITH NO DATA is specified. */
 1245 michael@paquier.xyz       583         [ +  - ]:        1061874 :     if (!myState->into->skipData)
                                584                 :                :     {
                                585                 :                :         /*
                                586                 :                :          * Note that the input slot might not be of the type of the target
                                587                 :                :          * relation. That's supported by table_tuple_insert(), but slightly
                                588                 :                :          * less efficient than inserting with the right slot - but the
                                589                 :                :          * alternative would be to copy into a slot of the right type, which
                                590                 :                :          * would not be cheap either. This also doesn't allow accessing per-AM
                                591                 :                :          * data (say a tuple's xmin), but since we don't do that here...
                                592                 :                :          */
                                593                 :        1061874 :         table_tuple_insert(myState->rel,
                                594                 :                :                            slot,
                                595                 :                :                            myState->output_cid,
                                596                 :                :                            myState->ti_options,
                                597                 :                :                            myState->bistate);
                                598                 :                :     }
                                599                 :                : 
                                600                 :                :     /* We know this is a newly created relation, so there are no indexes */
                                601                 :                : 
 2869 rhaas@postgresql.org      602                 :        1061874 :     return true;
                                603                 :                : }
                                604                 :                : 
                                605                 :                : /*
                                606                 :                :  * intorel_shutdown --- executor end
                                607                 :                :  */
                                608                 :                : static void
 4409 tgl@sss.pgh.pa.us         609                 :            743 : intorel_shutdown(DestReceiver *self)
                                610                 :                : {
                                611                 :            743 :     DR_intorel *myState = (DR_intorel *) self;
 1245 michael@paquier.xyz       612                 :            743 :     IntoClause *into = myState->into;
                                613                 :                : 
                                614         [ +  + ]:            743 :     if (!into->skipData)
                                615                 :                :     {
                                616                 :            725 :         FreeBulkInsertState(myState->bistate);
                                617                 :            725 :         table_finish_bulk_insert(myState->rel, myState->ti_options);
                                618                 :                :     }
                                619                 :                : 
                                620                 :                :     /* close rel, but keep lock until commit */
 1910 andres@anarazel.de        621                 :            743 :     table_close(myState->rel, NoLock);
 4409 tgl@sss.pgh.pa.us         622                 :            743 :     myState->rel = NULL;
                                623                 :            743 : }
                                624                 :                : 
                                625                 :                : /*
                                626                 :                :  * intorel_destroy --- release DestReceiver object
                                627                 :                :  */
                                628                 :                : static void
 4409 tgl@sss.pgh.pa.us         629                 :GBC          48 : intorel_destroy(DestReceiver *self)
                                630                 :                : {
                                631                 :             48 :     pfree(self);
                                632                 :             48 : }
        

Generated by: LCOV version 2.1-beta2-3-g6141622