aboutsummaryrefslogtreecommitdiff
path: root/src/include/nodes/parsenodes.h
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-01-14 16:02:35 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2017-01-14 16:02:35 -0500
commitab1f0c8225714aaa18d2f9ca4f80cd009f145421 (patch)
tree76cddd3b6b74474384d799fd61a4f211094ea55b /src/include/nodes/parsenodes.h
parent75abb955dfef064f2fbc5c043f37fff8d0262ffe (diff)
downloadpostgresql-ab1f0c8225714aaa18d2f9ca4f80cd009f145421.tar.gz
postgresql-ab1f0c8225714aaa18d2f9ca4f80cd009f145421.zip
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
Diffstat (limited to 'src/include/nodes/parsenodes.h')
-rw-r--r--src/include/nodes/parsenodes.h65
1 files changed, 50 insertions, 15 deletions
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 7ceaa22c33b..edb5cd21521 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,9 @@
* This is a byte (not character) offset in the original source text, to be
* used for positioning an error cursor when there is an error related to
* the node. Access to the original source text is needed to make use of
- * the location.
+ * the location. At the topmost (statement) level, we also provide a
+ * statement length, likewise measured in bytes, for convenience in
+ * identifying statement boundaries in multi-statement source strings.
*
*
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
@@ -89,9 +91,7 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */
* for further processing by the rewriter and planner.
*
* Utility statements (i.e. non-optimizable statements) have the
- * utilityStmt field set, and the Query itself is mostly dummy.
- * DECLARE CURSOR is a special case: it is represented like a SELECT,
- * but the original DeclareCursorStmt is stored in utilityStmt.
+ * utilityStmt field set, and the rest of the Query is mostly dummy.
*
* Planning converts a Query tree into a Plan tree headed by a PlannedStmt
* node --- the Query structure is not used by the executor.
@@ -108,8 +108,7 @@ typedef struct Query
bool canSetTag; /* do I set the command result tag? */
- Node *utilityStmt; /* non-null if this is DECLARE CURSOR or a
- * non-optimizable statement */
+ Node *utilityStmt; /* non-null if commandType == CMD_UTILITY */
int resultRelation; /* rtable index of target relation for
* INSERT/UPDATE/DELETE; 0 for SELECT */
@@ -162,6 +161,15 @@ typedef struct Query
* are only added during rewrite and
* therefore are not written out as
* part of Query. */
+
+ /*
+ * The following two fields identify the portion of the source text string
+ * containing this query. They are typically only populated in top-level
+ * Queries, not in sub-queries. When not set, they might both be zero, or
+ * both be -1 meaning "unknown".
+ */
+ int stmt_location; /* start location, or -1 if unknown */
+ int stmt_len; /* length in bytes; 0 means "rest of string" */
} Query;
@@ -1308,6 +1316,30 @@ typedef struct TriggerTransition
} TriggerTransition;
/*****************************************************************************
+ * Raw Grammar Output Statements
+ *****************************************************************************/
+
+/*
+ * RawStmt --- container for any one statement's raw parse tree
+ *
+ * Parse analysis converts a raw parse tree headed by a RawStmt node into
+ * an analyzed statement headed by a Query node. For optimizable statements,
+ * the conversion is complex. For utility statements, the parser usually just
+ * transfers the raw parse tree (sans RawStmt) into the utilityStmt field of
+ * the Query node, and all the useful work happens at execution time.
+ *
+ * stmt_location/stmt_len identify the portion of the source text string
+ * containing this raw statement (useful for multi-statement strings).
+ */
+typedef struct RawStmt
+{
+ NodeTag type;
+ Node *stmt; /* raw parse tree */
+ int stmt_location; /* start location, or -1 if unknown */
+ int stmt_len; /* length in bytes; 0 means "rest of string" */
+} RawStmt;
+
+/*****************************************************************************
* Optimizable Statements
*****************************************************************************/
@@ -1474,6 +1506,9 @@ typedef struct SetOperationStmt
* statements do need attention from parse analysis, and this is
* done by routines in parser/parse_utilcmd.c after ProcessUtility
* receives the command for execution.
+ * DECLARE CURSOR, EXPLAIN, and CREATE TABLE AS are special cases:
+ * they contain optimizable statements, which get processed normally
+ * by parser/analyze.c.
*****************************************************************************/
/*
@@ -1794,7 +1829,7 @@ typedef struct CopyStmt
NodeTag type;
RangeVar *relation; /* the relation to copy */
Node *query; /* the query (SELECT or DML statement with
- * RETURNING) to copy */
+ * RETURNING) to copy, as a raw parse tree */
List *attlist; /* List of column names (as Strings), or NIL
* for all columns */
bool is_from; /* TO or FROM */
@@ -2472,9 +2507,9 @@ typedef struct SecLabelStmt
/* ----------------------
* Declare Cursor Statement
*
- * Note: the "query" field of DeclareCursorStmt is only used in the raw grammar
- * output. After parse analysis it's set to null, and the Query points to the
- * DeclareCursorStmt, not vice versa.
+ * The "query" field is initially a raw parse tree, and is converted to a
+ * Query node during parse analysis. Note that rewriting and planning
+ * of the query are always postponed until execution.
* ----------------------
*/
#define CURSOR_OPT_BINARY 0x0001 /* BINARY */
@@ -2493,7 +2528,7 @@ typedef struct DeclareCursorStmt
NodeTag type;
char *portalname; /* name of the portal (cursor) */
int options; /* bitmask of options (see above) */
- Node *query; /* the raw SELECT query */
+ Node *query; /* the query (see comments above) */
} DeclareCursorStmt;
/* ----------------------
@@ -2841,7 +2876,7 @@ typedef struct ViewStmt
NodeTag type;
RangeVar *view; /* the view to be created */
List *aliases; /* target column names */
- Node *query; /* the SELECT query */
+ Node *query; /* the SELECT query (as a raw parse tree) */
bool replace; /* replace an existing view? */
List *options; /* options from WITH clause */
ViewCheckOption withCheckOption; /* WITH CHECK OPTION */
@@ -2950,9 +2985,9 @@ typedef struct VacuumStmt
/* ----------------------
* Explain Statement
*
- * The "query" field is either a raw parse tree (SelectStmt, InsertStmt, etc)
- * or a Query node if parse analysis has been done. Note that rewriting and
- * planning of the query are always postponed until execution of EXPLAIN.
+ * The "query" field is initially a raw parse tree, and is converted to a
+ * Query node during parse analysis. Note that rewriting and planning
+ * of the query are always postponed until execution.
* ----------------------
*/
typedef struct ExplainStmt