8000 Change representation of statement lists, and add statement location … · postgrespro/postgres@ab1f0c8 · GitHub
[go: up one dir, main page]

Skip to content

Commit ab1f0c8

Browse files
committed
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of representation of lists of statements. It's always been the case that the output of parse analysis is a list of Query nodes, whatever the types of the individual statements in the list. This patch brings similar consistency to the outputs of raw parsing and planning steps: * The output of raw parsing is now always a list of RawStmt nodes; the statement-type-dependent nodes are one level down from that. * The output of pg_plan_queries() is now always a list of PlannedStmt nodes, even for utility statements. In the case of a utility statement, "planning" just consists of wrapping a CMD_UTILITY PlannedStmt around the utility node. This list representation is now used in Portal and CachedPlan plan lists, replacing the former convention of intermixing PlannedStmts with bare utility-statement nodes. Now, every list of statements has a consistent head-node type depending on how far along it is in processing. This allows changing many places that formerly used generic "Node *" pointers to use a more specific pointer type, thus reducing the number of IsA() tests and casts needed, as well as improving code clarity. Also, the post-parse-analysis representation of DECLARE CURSOR is changed so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained SELECT remains a child of the DeclareCursorStmt rather than getting flipped around to be the other way. It's now true for both Query and PlannedStmt that utilityStmt is non-null if and only if commandType is CMD_UTILITY. That allows simplifying a lot of places that were testing both fields. (I think some of those were just defensive programming, but in many places, it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.) Because PlannedStmt carries a canSetTag field, we're also able to get rid of some ad-hoc rules about how to reconstruct canSetTag for a bare utility statement; specifically, the assumption that a utility is canSetTag if and only if it's the only one in its list. While I see no near-term need for relaxing that restriction, it's nice to get rid of the ad-hocery. The API of ProcessUtility() is changed so that what it's passed is the wrapper PlannedStmt not just the bare utility statement. This will affect all users of ProcessUtility_hook, but the changes are pretty trivial; see the affected contrib modules for examples of the minimum change needed. (Most compilers should give pointer-type-mismatch warnings for uncorrected code.) There's also a change in the API of ExplainOneQuery_hook, to pass through cursorOptions instead of expecting hook functions to know what to pick. This is needed because of the DECLARE CURSOR changes, but really should have been done in 9.6; it's unlikely that any extant hook functions know about using CURSOR_OPT_PARALLEL_OK. Finally, teach gram.y to save statement boundary locations in RawStmt nodes, and pass those through to Query and PlannedStmt nodes. This allows more intelligent handling of cases where a source query string contains multiple statements. This patch doesn't actually do anything with the information, but a follow-on patch will. (Passing this information through cleanly is the true motivation for these changes; while I think this is all good cleanup, it's unlikely we'd have bothered without this end goal.) catversion bump because addition of location fields to struct Query affects stored rules. This patch is by me, but it owes a good deal to Fabien Coelho who did a lot of preliminary work on the problem, and also reviewed the patch. Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
1 parent 75abb95 commit ab1f0c8

File tree

53 files changed

+788
-547
lines changed
  • optimizer
  • parser
  • rewrite
  • tcop
  • utils
  • include
  • pl/plpgsql/src
  • Some content is hidden

    Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

    53 files changed

    +788
    -547
    lines changed

    contrib/pg_stat_statements/pg_stat_statements.c

    Lines changed: 8 additions & 6 deletions
    Original file line numberDiff line numberDiff line change
    @@ -292,7 +292,7 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc,
    292292
    uint64 count);
    293293
    static void pgss_ExecutorFinish(QueryDesc *queryDesc);
    294294
    static void pgss_ExecutorEnd(QueryDesc *queryDesc);
    295-
    static void pgss_ProcessUtility(Node *parsetree, const char *queryString,
    295+
    static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
    296296
    ProcessUtilityContext context, ParamListInfo params,
    297297
    DestReceiver *dest, char *completionTag);
    298298
    static uint32 pgss_hash_fn(const void *key, Size keysize);
    @@ -942,10 +942,12 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
    942942
    * ProcessUtility hook
    943943
    */
    944944
    static void
    945-
    pgss_ProcessUtility(Node *parsetree, const char *queryString,
    945+
    pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
    946946
    ProcessUtilityContext context, ParamListInfo params,
    947947
    DestReceiver *dest, char *completionTag)
    948948
    {
    949+
    Node *parsetree = pstmt->utilityStmt;
    950+
    949951
    /*
    950952
    * If it's an EXECUTE statement, we don't track it and don't increment the
    951953
    * nesting level. This allows the cycles to be charged to the underlying
    @@ -979,11 +981,11 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString,
    979981
    PG_TRY();
    980982
    {
    981983
    if (prev_ProcessUtility)
    982-
    prev_ProcessUtility(parsetree, queryString,
    984+
    prev_ProcessUtility(pstmt, queryString,
    983985
    context, params,
    984986
    dest, completionTag);
    985987
    else
    986-
    standard_ProcessUtility(parsetree, queryString,
    988+
    standard_ProcessUtility(pstmt, queryString,
    987989
    context, params,
    988990
    dest, completionTag);
    989991
    nested_level--;
    @@ -1044,11 +1046,11 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString,
    10441046
    else
    10451047
    {
    10461048
    if (prev_ProcessUtility)
    1047-
    prev_ProcessUtility(parsetree, queryString,
    1049+
    prev_ProcessUtility(pstmt, queryString,
    10481050
    context, params,
    10491051
    dest, completionTag);
    10501052
    else
    1051-
    standard_ProcessUtility(parsetree, queryString,
    1053+
    standard_ProcessUtility(pstmt, queryString,
    10521054
    context, params,
    10531055
    dest, completionTag);
    10541056
    }

    contrib/sepgsql/hooks.c

    Lines changed: 4 additions & 3 deletions
    Original file line numberDiff line numberDiff line change
    @@ -297,13 +297,14 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
    297297
    * break whole of the things if nefarious user would use.
    298298
    */
    299299
    static void
    300-
    sepgsql_utility_command(Node *parsetree,
    300+
    sepgsql_utility_command(PlannedStmt *pstmt,
    301301
    const char *queryString,
    302302
    ProcessUtilityContext context,
    303303
    ParamListInfo params,
    304304
    DestReceiver *dest,
    305305
    char *completionTag)
    306306
    {
    307+
    Node *parsetree = pstmt->utilityStmt;
    307308
    sepgsql_context_info_t saved_context_info = sepgsql_context_info;
    308309
    ListCell *cell;
    309310

    @@ -362,11 +363,11 @@ sepgsql_utility_command(Node *parsetree,
    362363
    }
    363364

    364365
    if (next_ProcessUtility_hook)
    365-
    (*next_ProcessUtility_hook) (parsetree, queryString,
    366+
    (*next_ProcessUtility_hook) (pstmt, queryString,
    366367
    context, params,
    367368
    dest, completionTag);
    368369
    else
    369-
    standard_ProcessUtility(parsetree, queryString,
    370+
    standard_ProcessUtility(pstmt, queryString,
    370371
    context, params,
    371372
    dest, completionTag);
    372373
    }

    src/backend/catalog/pg_proc.c

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -934,7 +934,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
    934934
    querytree_list = NIL;
    935935
    foreach(lc, raw_parsetree_list)
    936936
    {
    937-
    Node *parsetree = (Node *) lfirst(lc);
    937+
    RawStmt *parsetree = (RawStmt *) lfirst(lc);
    938938
    List *querytree_sublist;
    939939

    940940
    querytree_sublist = pg_analyze_and_rewrite_params(parsetree,

    src/backend/commands/copy.c

    Lines changed: 23 additions & 16 deletions
    Original file line numberDiff line numberDiff line change
    @@ -287,13 +287,13 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
    287287

    288288

    289289
    /* non-export function prototypes */
    290-
    static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, Node *raw_query,
    291-
    const Oid queryRelId, List *attnamelist,
    290+
    static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
    291+
    RawStmt *raw_query, Oid queryRelId, List *attnamelist,
    292292
    List *options);
    293293
    static void EndCopy(CopyState cstate);
    294294
    static void ClosePipeToProgram(CopyState cstate);
    295-
    static CopyState BeginCopyTo(ParseState *pstate, Relation rel, Node *query,
    296-
    const Oid queryRelId, const char *filename, bool is_program,
    295+
    static CopyState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *query,
    296+
    Oid queryRelId, const char *filename, bool is_program,
    297297
    List *attnamelist, List *options);
    298298
    static void EndCopyTo(CopyState cstate);
    299299
    static uint64 DoCopyTo(CopyState cstate);
    @@ -770,15 +770,17 @@ CopyLoadRawBuf(CopyState cstate)
    770770
    * Do not allow the copy if user doesn't have proper permission to access
    771771
    * the table or the specifically requested columns.
    772772
    */
    773-
    Oid
    774-
    DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed)
    773+
    void
    774+
    DoCopy(ParseState *pstate, const CopyStmt *stmt,
    775+
    int stmt_location, int stmt_len,
    776+
    uint64 *processed)
    775777
    {
    776778
    CopyState cstate;
    777779
    bool is_from = stmt->is_from;
    778780
    bool pipe = (stmt->filename == NULL);
    779781
    Relation rel;
    780782
    Oid relid;
    781-
    Node *query = NULL;
    783+
    RawStmt *query = NULL;
    782784
    List *range_table = NIL;
    783785

    784786
    /* Disallow COPY to/from file or program except to superusers. */
    @@ -929,7 +931,10 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed)
    929931
    select->targetList = targetList;
    930932
    select->fromClause = list_make1(from);
    931933

    932-
    query = (Node *) select;
    934+
    query = makeNode(RawStmt);
    935+
    query->stmt = (Node *) select;
    936+
    query->stmt_location = stmt_location;
    937+
    query->stmt_len = stmt_len;
    933938

    934939
    /*
    935940
    * Close the relation for now, but keep the lock on it to prevent
    @@ -945,7 +950,11 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed)
    945950
    {
    946951
    Assert(stmt->query);
    947952

    948-
    query = stmt->query;
    953+
    query = makeNode(RawStmt);
    954+
    query->stmt = stmt->query;
    955+
    query->stmt_location = stmt_location;
    956+
    query->stmt_len = stmt_len;
    957+
    949958
    relid = InvalidOid;
    950959
    rel = NULL;
    951960
    }
    @@ -981,8 +990,6 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed)
    981990
    */
    982991
    if (rel != NULL)
    983992
    heap_close(rel, (is_from ? NoLock : AccessShareLock));
    984-
    985-
    return relid;
    986993
    }
    987994

    988995
    /*
    @@ -1364,8 +1371,8 @@ static CopyState
    13641371
    BeginCopy(ParseState *pstate,
    13651372
    bool is_from,
    13661373
    Relation rel,
    1367-
    Node *raw_query,
    1368-
    const Oid queryRelId,
    1374+
    RawStmt *raw_query,
    1375+
    Oid queryRelId,
    13691376
    List *attnamelist,
    13701377
    List *options)
    13711378
    {
    @@ -1456,7 +1463,7 @@ BeginCopy(ParseState *pstate,
    14561463
    * function and is executed repeatedly. (See also the same hack in
    14571464
    * DECLARE CURSOR and PREPARE.) XXX FIXME someday.
    14581465
    */
    1459-
    rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query),
    1466+
    rewritten = pg_analyze_and_rewrite((RawStmt *) copyObject(raw_query),
    14601467
    pstate->p_sourcetext, NULL, 0);
    14611468

    14621469
    /* check that we got back something we can work with */
    @@ -1747,8 +1754,8 @@ EndCopy(CopyState cstate)
    17471754
    static CopyState
    17481755
    BeginCopyTo(ParseState *pstate,
    17491756
    Relation rel,
    1750-
    Node *query,
    1751-
    const Oid queryRelId,
    1757+
    RawStmt *query,
    1758+
    Oid queryRelId,
    17521759
    const char *filename,
    17531760
    bool is_program,
    17541761
    List *attnamelist,

    src/backend/commands/createas.c

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -326,7 +326,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
    326326
    query = (Query *) linitial(rewritten);
    327327
    Assert(query->commandType == CMD_SELECT);
    328328

    329-
    /* plan the query */
    329+
    /* plan the query --- note we disallow parallelism */
    330330
    plan = pg_plan_query(query, 0, params);
    331331

    332332
    /*

    src/backend/commands/explain.c

    Lines changed: 35 additions & 11 deletions
    Original file line numberDiff line numberDiff line change
    @@ -53,7 +53,8 @@ explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
    5353
    #define X_CLOSE_IMMEDIATE 2
    5454
    #define X_NOWHITESPACE 4
    5555

    56-
    static void ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
    56+
    static void ExplainOneQuery(Query *query, int cursorOptions,
    57+
    IntoClause *into, ExplainState *es,
    5758
    const char *queryString, ParamListInfo params);
    5859
    static void report_triggers(ResultRelInfo *rInfo, bool show_relname,
    5960
    ExplainState *es);
    @@ -245,7 +246,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
    245246
    /* Explain every plan */
    246247
    foreach(l, rewritten)
    247248
    {
    248-
    ExplainOneQuery((Query *) lfirst(l), NULL, es,
    249+
    ExplainOneQuery((Query *) lfirst(l),
    250+
    CURSOR_OPT_PARALLEL_OK, NULL, es,
    249251
    queryString, params);
    250252

    251253
    /* Separate plans with an appropriate separator */
    @@ -329,7 +331,8 @@ ExplainResultDesc(ExplainStmt *stmt)
    329331
    * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt.
    330332
    */
    331333
    static void
    332-
    ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
    334+
    ExplainOneQuery(Query *query, int cursorOptions,
    335+
    IntoClause *into, ExplainState *es,
    333336
    const char *queryString, ParamListInfo params)
    334337
    {
    335338
    /* planner will not cope with utility statements */
    @@ -341,7 +344,8 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
    341344

    342345
    /* if an advisor plugin is present, let it manage things */
    343346
    if (ExplainOneQuery_hook)
    344-
    (*ExplainOneQuery_hook) (query, into, es, queryString, params);
    347+
    (*ExplainOneQuery_hook) (query, cursorOptions, into, es,
    348+
    queryString, params);
    345349
    else
    346350
    {
    347351
    PlannedStmt *plan;
    @@ -351,7 +355,7 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
    351355
    INSTR_TIME_SET_CURRENT(planstart);
    352356

    353357
    /* plan the query */
    354-
    plan = pg_plan_query(query, into ? 0 : CURSOR_OPT_PARALLEL_OK, params);
    358+
    plan = pg_plan_query(query, cursorOptions, params);
    355359

    356360
    INSTR_TIME_SET_CURRENT(planduration);
    357361
    INSTR_TIME_SUBTRACT(planduration, planstart);
    @@ -385,14 +389,37 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
    385389
    * We have to rewrite the contained SELECT and then pass it back to
    386390
    * ExplainOneQuery. It's probably not really necessary to copy the
    387391
    * contained parsetree another time, but let's be safe.
    392+
    *
    393+
    * Like ExecCreateTableAs, disallow parallelism in the plan.
    388394
    */
    389395
    CreateTableAsStmt *ctas = (CreateTableAsStmt *) utilityStmt;
    390396
    List *rewritten;
    391397

    392398
    Assert(IsA(ctas->query, Query));
    393399
    rewritten = QueryRewrite((Query *) copyObject(ctas->query));
    394400
    Assert(list_length(rewritten) == 1);
    395-
    ExplainOneQuery((Query *) linitial(rewritten), ctas->into, es,
    401+
    ExplainOneQuery((Query *) linitial(rewritten),
    402+
    0, ctas->into, es,
    403+
    queryString, params);
    404+
    }
    405+
    else if (IsA(utilityStmt, DeclareCursorStmt))
    406+
    {
    407+
    /*
    408+
    * Likewise for DECLARE CURSOR.
    409+
    *
    410+
    * Notice that if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll
    411+
    * actually run the query. This is different from pre-8.3 behavior
    412+
    * but seems more useful than not running the query. No cursor will
    413+
    * be created, however.
    414+
    */
    415+
    DeclareCursorStmt *dcs = (DeclareCursorStmt *) utilityStmt;
    416+
    List *rewritten;
    417+
    418+
    Assert(IsA(dcs->query, Query));
    419+
    rewritten = QueryRewrite((Query *) copyObject(dcs->query));
    420+
    Assert(list_length(rewritten) == 1);
    421+
    ExplainOneQuery((Query *) linitial(rewritten),
    422+
    dcs->options, NULL, es,
    396423
    queryString, params);
    397424
    }
    398425
    else if (IsA(utilityStmt, ExecuteStmt))
    @@ -423,11 +450,6 @@ ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es,
    423450
    * "into" is NULL unless we are explaining the contents of a CreateTableAsStmt,
    424451
    * in which case executing the query should result in creating that table.
    425452
    *
    426-
    * Since we ignore any DeclareCursorStmt that might be attached to the query,
    427-
    * if you say EXPLAIN ANALYZE DECLARE CURSOR then we'll actually run the
    428-
    * query. This is different from pre-8.3 behavior but seems more useful than
    429-
    * not running the query. No cursor will be created, however.
    430-
    *
    431453
    * This is exported because it's called back from prepare.c in the
    432454
    * EXPLAIN EXECUTE case, and because an index advisor plugin would need
    433455
    * to call it.
    @@ -444,6 +466,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
    444466
    int eflags;
    445467
    int instrument_option = 0;
    446468

    469+
    Assert(plannedstmt->commandType != CMD_UTILITY);
    470+
    447471
    if (es->analyze && es->timing)
    448472
    instrument_option |= INSTRUMENT_TIMER;
    449473
    else if (es->analyze)

    src/backend/commands/extension.c

    Lines changed: 11 additions & 11 deletions
    < 17AE td data-grid-cell-id="diff-f8bf486566de0369065b520e001b0434577000d53dacd135f733931adabc0883-744-738-2" data-line-anchor="diff-f8bf486566de0369065b520e001b0434577000d53dacd135f733931adabc0883R738" data-selected="false" role="gridcell" style="background-color:var(--bgColor-default);padding-right:24px" tabindex="-1" valign="top" class="focusable-grid-cell diff-text-cell right-side-diff-cell left-side">
    sql,
    Original file line numberDiff line numberDiff line change
    @@ -712,7 +712,7 @@ execute_sql_string(const char *sql, const char *filename)
    712712
    */
    713713
    foreach(lc1, raw_parsetree_list)
    714714
    {
    715-
    Node *parsetree = (Node *) lfirst(lc1);
    715+
    RawStmt *parsetree = (RawStmt *) lfirst(lc1);
    716716
    List *stmt_list;
    717717
    ListCell *lc2;
    718718

    @@ -724,23 +724,17 @@ execute_sql_string(const char *sql, const char *filename)
    724724

    725725
    foreach(lc2, stmt_list)
    726726
    {
    727-
    Node *stmt = (Node *) lfirst(lc2);
    728-
    729-
    if (IsA(stmt, TransactionStmt))
    730-
    ereport(ERROR,
    731-
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    732-
    errmsg("transaction control statements are not allowed within an extension script")));
    727+
    PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2);
    733728

    734729
    CommandCounterIncrement();
    735730

    736731
    PushActiveSnapshot(GetTransactionSnapshot());
    737732

    738-
    if (IsA(stmt, PlannedStmt) &&
    739-
    ((PlannedStmt *) stmt)->utilityStmt == NULL)
    733+
    if (stmt->utilityStmt == NULL)
    740734
    {
    741735
    QueryDesc *qdesc;
    742736

    743-
    qdesc = CreateQueryDesc((PlannedStmt *) stmt,
    737+
    qdesc = CreateQueryDesc(stmt,
    744738
    745739
    GetActiveSnapshot(), NULL,
    746740
    dest, NULL, 0);
    @@ -754,6 +748,11 @@ execute_sql_string(const char *sql, const char *filename)
    754748
    }
    755749
    else
    756750
    {
    751+
    if (IsA(stmt->utilityStmt, TransactionStmt))
    752+
    ereport(ERROR,
    753+
    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    754+
    errmsg("transaction control statements are not allowed within an extension script")));
    755+
    757756
    ProcessUtility(stmt,
    758757
    sql,
    759758
    PROCESS_UTILITY_QUERY,
    @@ -1434,7 +1433,8 @@ CreateExtensionInternal(char *extensionName,
    14341433
    csstmt->authrole = NULL; /* will be created by current user */
    14351434
    csstmt->schemaElts = NIL;
    14361435
    csstmt->if_not_exists = false;
    1437-
    CreateSchemaCommand(csstmt, NULL);
    1436+
    CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
    1437+
    -1, -1);
    14381438

    14391439
    /*
    14401440
    * CreateSchemaCommand includes CommandCounterIncrement, so new

    src/backend/commands/foreigncmds.c

    Lines changed: 12 additions & 2 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1572,7 +1572,9 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt)
    15721572
    */
    15731573
    foreach(lc2, raw_parsetree_list)
    15741574
    {
    1575-
    CreateForeignTableStmt *cstmt = lfirst(lc2);
    1575+
    RawStmt *rs = (RawStmt *) lfirst(lc2);
    1576+
    CreateForeignTableStmt *cstmt = (CreateForeignTableStmt *) rs->stmt;
    1577+
    PlannedStmt *pstmt;
    15761578

    15771579
    /*
    15781580
    * Because we only allow CreateForeignTableStmt, we can skip parse
    @@ -1593,8 +1595,16 @@ ImportForeignSchema(ImportForeignSchemaStmt *stmt)
    15931595
    /* Ensure creation schema is the one given in IMPORT statement */
    15941596
    cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
    15951597

    1598+
    /* No planning needed, just make a wrapper PlannedStmt */
    1599+
    pstmt = makeNode(PlannedStmt);
    1600+
    pstmt->commandType = CMD_UTILITY;
    1601+
    pstmt->canSetTag = false;
    1602+
    pstmt->utilityStmt = (Node *) cstmt;
    1603+
    pstmt->stmt_location = rs->stmt_location;
    1604+
    pstmt->stmt_len = rs->stmt_len;
    1605+
    15961606
    /* Execute statement */
    1597-
    ProcessUtility((Node *) cstmt,
    1607+
    ProcessUtility(pstmt,
    15981608
    cmd,
    15991609
    PROCESS_UTILITY_SUBCOMMAND, NULL,
    16001610
    None_Receiver, NULL);

    0 commit comments

    Comments
     (0)
    0