Yes. I'll try to put together a patch and submit it to the next CF.Here it is. I'll add this to the next CF.
Oops... better without a stupid overflow. Shame on me! -- Fabien.
diff --git a/contrib/pg_stat_statements/expected/pg_stat_statements.out b/contrib/pg_stat_statements/expected/pg_stat_statements.out index 3573c19..5a1b227 100644 --- a/contrib/pg_stat_statements/expected/pg_stat_statements.out +++ b/contrib/pg_stat_statements/expected/pg_stat_statements.out @@ -1,21 +1,346 @@ CREATE EXTENSION pg_stat_statements; -CREATE TABLE test (a int, b char(20)); --- test the basic functionality of pg_stat_statements +-- +-- +-- simple and compound statements +-- +SET pg_stat_statements.track_utility = FALSE; SELECT pg_stat_statements_reset(); pg_stat_statements_reset -------------------------- (1 row) +SELECT 1 AS "int"; + int +----- + 1 +(1 row) + +SELECT 'hello' + -- multiline + AS "text"; + text +------- + hello +(1 row) + +SELECT 'world' AS "text"; + text +------- + world +(1 row) + +-- transaction +BEGIN; +SELECT 1 AS "int"; + int +----- + 1 +(1 row) + +SELECT 'hello' AS "text"; + text +------- + hello +(1 row) + +COMMIT; +-- compound transaction +BEGIN \; +SELECT 2.0 AS "float" \; +SELECT 'world' AS "text" \; +COMMIT; +-- compound with empty statements and spurious leading spacing +\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;; + ?column? +---------- + 5 +(1 row) + +-- non ;-terminated statements +SELECT 1 + 1 + 1 AS "add" \gset +SELECT :add + 1 + 1 AS "add" \; +SELECT :add + 1 + 1 AS "add" \gset +-- set operator +SELECT 1 AS i UNION SELECT 2 ORDER BY i; + i +--- + 1 + 2 +(2 rows) + +-- cte +WITH t(f) AS ( + VALUES (1.0), (2.0) +) + SELECT f FROM t ORDER BY f; + f +----- + 1.0 + 2.0 +(2 rows) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + query | calls | rows +-----------------------------------------+-------+------ + SELECT ? || ? | 1 | 1 + SELECT ? AS "float" | 1 | 1 + SELECT pg_stat_statements_reset() | 1 | 1 + SELECT ? + ? | 2 | 2 + SELECT ? AS "int" | 2 | 2 + SELECT ? AS i UNION SELECT ? ORDER BY i | 1 | 2 + WITH t(f) AS ( +| 1 | 2 + VALUES (?), (?) +| | + ) +| | + SELECT f FROM t ORDER BY f | | + SELECT ? + ? + ? AS "add" | 3 | 3 + SELECT ? +| 4 | 4 + +| | + AS "text" | | +(9 rows) + +-- +-- +-- CRUD: INSERT SELECT UPDATE DELETE on test table +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +-- utility "create table" must not show +CREATE TABLE test (a int, b char(20)); INSERT INTO test VALUES(generate_series(1, 10), 'aaa'); -UPDATE test SET b = 'bbb' WHERE a > 5; -SELECT query, calls, rows from pg_stat_statements ORDER BY rows; - query | calls | rows -----------------------------------------------------+-------+------ - SELECT pg_stat_statements_reset(); | 1 | 1 - UPDATE test SET b = ? WHERE a > ?; | 1 | 5 - INSERT INTO test VALUES(generate_series(?, ?), ?); | 1 | 10 +UPDATE test SET b = 'bbb' WHERE a > 7; +DELETE FROM test WHERE a > 9; +-- explicit transaction +BEGIN; +UPDATE test SET b = '111' WHERE a = 1 ; +COMMIT; +BEGIN \; +UPDATE test SET b = '222' WHERE a = 2 \; +COMMIT ; +UPDATE test SET b = '333' WHERE a = 3 \; +UPDATE test SET b = '444' WHERE a = 4 ; +BEGIN \; +UPDATE test SET b = '555' WHERE a = 5 \; +UPDATE test SET b = '666' WHERE a = 6 \; +COMMIT ; +-- SELECT with constants +SELECT * FROM test WHERE a > 5 ORDER BY a ; + a | b +---+---------------------- + 6 | 666 + 7 | aaa + 8 | bbb + 9 | bbb +(4 rows) + +SELECT * + FROM test + WHERE a > 9 + ORDER BY a ; + a | b +---+--- +(0 rows) + +-- SELECT without constants +SELECT * FROM test ORDER BY a; + a | b +---+---------------------- + 1 | 111 + 2 | 222 + 3 | 333 + 4 | 444 + 5 | 555 + 6 | 666 + 7 | aaa + 8 | bbb + 9 | bbb +(9 rows) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + query | calls | rows +---------------------------------------------------+-------+------ + DELETE FROM test WHERE a > ? | 1 | 1 + SELECT pg_stat_statements_reset() | 1 | 1 + UPDATE test SET b = ? WHERE a > ? | 1 | 3 + SELECT * FROM test WHERE a > ? ORDER BY a | 2 | 4 + UPDATE test SET b = ? WHERE a = ? | 6 | 6 + SELECT * FROM test ORDER BY a | 1 | 9 + INSERT INTO test VALUES(generate_series(?, ?), ?) | 1 | 10 +(7 rows) + +-- +-- +-- pg_stat_statements.track = none +-- +SET pg_stat_statements.track = 'none'; +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SELECT 1 AS "one"; + one +----- + 1 +(1 row) + +SELECT 1 + 1 AS "two"; + two +----- + 2 +(1 row) + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + query | calls | rows +-------+-------+------ +(0 rows) + +-- +-- +-- pg_stat_statements.track = top +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SET pg_stat_statements.track = 'top'; +DO LANGUAGE plpgsql $$ +BEGIN + -- this is a SELECT + PERFORM 'hello world'::TEXT; +END; +$$; +-- PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; +SELECT PLUS_TWO(3); + plus_two +---------- + 5 +(1 row) + +SELECT PLUS_TWO(7); + plus_two +---------- + 9 +(1 row) + +-- SQL function +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL; +SELECT PLUS_ONE(8); + plus_one +---------- + 9 +(1 row) + +SELECT PLUS_ONE(10); + plus_one +---------- + 11 +(1 row) + +DROP FUNCTION PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + query | calls | rows +--------------------+-------+------ + SELECT ?::TEXT | 1 | 1 + SELECT PLUS_ONE(?) | 2 | 2 + SELECT PLUS_TWO(?) | 2 | 2 (3 rows) +-- +-- +-- pg_stat_statements.track = all +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SET pg_stat_statements.track = 'all'; +-- recreate PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; +SELECT PLUS_TWO(-1); + plus_two +---------- + 1 +(1 row) + +SELECT PLUS_TWO(2); + plus_two +---------- + 4 +(1 row) + +-- SQL function nesting +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL; +SELECT PLUS_ONE(3); + plus_one +---------- + 4 +(1 row) + +SELECT PLUS_ONE(1); + plus_one +---------- + 2 +(1 row) + +-- bug? PLUS_ONE expansion is missing +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + query | calls | rows +-----------------------------------+-------+------ + SELECT pg_stat_statements_reset() | 1 | 1 + SELECT (i + ? + ?)::INTEGER | 2 | 2 + SELECT PLUS_ONE(?) | 2 | 2 + SELECT PLUS_TWO(?) | 2 | 2 +(4 rows) + +-- +-- +-- utility commands +-- +SELECT pg_stat_statements_reset(); + pg_stat_statements_reset +-------------------------- + +(1 row) + +SET pg_stat_statements.track_utility = TRUE; +CREATE INDEX test_b ON test(b); DROP TABLE test; +DROP FUNCTION PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + query | calls | rows +-----------------------------------+-------+------ + CREATE INDEX test_b ON test(b) | 1 | 0 + DROP FUNCTION PLUS_ONE(INTEGER) | 1 | 0 + DROP FUNCTION PLUS_TWO(INTEGER) | 1 | 0 + DROP TABLE test | 1 | 0 + SELECT pg_stat_statements_reset() | 1 | 1 +(5 rows) + DROP EXTENSION pg_stat_statements; diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c index 8ce24e0..d265de9 100644 --- a/contrib/pg_stat_statements/pg_stat_statements.c +++ b/contrib/pg_stat_statements/pg_stat_statements.c @@ -298,10 +298,9 @@ static void pgss_ProcessUtility(Node *parsetree, const char *queryString, static uint32 pgss_hash_fn(const void *key, Size keysize); static int pgss_match_fn(const void *key1, const void *key2, Size keysize); static uint32 pgss_hash_string(const char *str); -static void pgss_store(const char *query, uint32 queryId, - double total_time, uint64 rows, - const BufferUsage *bufusage, - pgssJumbleState *jstate); +static void pgss_store(const char *query, int query_loc, int query_len, + uint32 queryId, double total_time, uint64 rows, + const BufferUsage *bufusage, pgssJumbleState *jstate); static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext); @@ -324,7 +323,7 @@ static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable); static void JumbleExpr(pgssJumbleState *jstate, Node *node); static void RecordConstLocation(pgssJumbleState *jstate, int location); static char *generate_normalized_query(pgssJumbleState *jstate, const char *query, - int *query_len_p, int encoding); + int query_len, int *query_len_p, int encoding); static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query); static int comp_location(const void *a, const void *b); @@ -820,7 +819,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) * there's no need for an early entry. */ if (jstate.clocations_count > 0) - pgss_store(pstate->p_sourcetext, + pgss_store(pstate->p_sourcetext, query->qlocation, query->qlength, query->queryId, 0, 0, @@ -925,6 +924,8 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) InstrEndLoop(queryDesc->totaltime); pgss_store(queryDesc->sourceText, + queryDesc->plannedstmt->qlocation, + queryDesc->plannedstmt->qlength, queryId, queryDesc->totaltime->total * 1000.0, /* convert to msec */ queryDesc->estate->es_processed, @@ -971,6 +972,9 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString, BufferUsage bufusage_start, bufusage; uint32 queryId; + ParseNode *parsenode = (ParseNode *) parsetree; + + Assert(isParseNode(node)); bufusage_start = pgBufferUsage; INSTR_TIME_SET_CURRENT(start); @@ -1034,7 +1038,7 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString, /* For utility statements, we just hash the query string directly */ queryId = pgss_hash_string(queryString); - pgss_store(queryString, + pgss_store(queryString, parsenode->qlocation, parsenode->qlength, queryId, INSTR_TIME_GET_MILLISEC(duration), rows, @@ -1103,7 +1107,7 @@ pgss_hash_string(const char *str) * query string. total_time, rows, bufusage are ignored in this case. */ static void -pgss_store(const char *query, uint32 queryId, +pgss_store(const char *query, int query_loc, int query_len, uint32 queryId, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate) @@ -1112,15 +1116,15 @@ pgss_store(const char *query, uint32 queryId, pgssEntry *entry; char *norm_query = NULL; int encoding = GetDatabaseEncoding(); - int query_len; - Assert(query != NULL); + Assert(query != NULL && query_loc >= 0 && query_len >= 0); /* Safety check... */ if (!pgss || !pgss_hash) return; - query_len = strlen(query); + if (query_len == 0) + query_len = strlen(query); /* Set up key for hashtable search */ key.userid = GetUserId(); @@ -1140,6 +1144,11 @@ pgss_store(const char *query, uint32 queryId, bool stored; bool do_gc; + /* skip leading spaces */ + while (isspace(query[query_loc])) + query_loc++, query_len--; + /* should skip trailing spaces? encoding dependence? */ + /* * Create a new, normalized query string if caller asked. We don't * need to hold the lock while doing this work. (Note: in any case, @@ -1150,11 +1159,17 @@ pgss_store(const char *query, uint32 queryId, if (jstate) { LWLockRelease(pgss->lock); - norm_query = generate_normalized_query(jstate, query, + norm_query = generate_normalized_query(jstate, query, query_loc, &query_len, encoding); LWLockAcquire(pgss->lock, LW_SHARED); } + else if (strlen(query) != query_len) + { + norm_query = palloc(query_len + 1); + memcpy(norm_query, query + query_loc, query_len); + norm_query[query_len] = '\0'; + } /* Append new query text to file with only shared lock held */ stored = qtext_store(norm_query ? norm_query : query, query_len, @@ -2882,15 +2897,15 @@ RecordConstLocation(pgssJumbleState *jstate, int location) */ static char * generate_normalized_query(pgssJumbleState *jstate, const char *query, - int *query_len_p, int encoding) + int query_loc, int *query_len_p, int encoding) { char *norm_query; int query_len = *query_len_p; int i, len_to_wrt, /* Length (in bytes) to write */ - quer_loc = 0, /* Source query byte location */ + quer_loc = query_loc, /* Source query byte location */ n_quer_loc = 0, /* Normalized query byte location */ - last_off = 0, /* Offset from start for previous tok */ + last_off = query_loc, /* Offset from start for previous tok */ last_tok_len = 0; /* Length (in bytes) of that tok */ /* @@ -2933,7 +2948,7 @@ generate_normalized_query(pgssJumbleState *jstate, const char *query, * We've copied up until the last ignorable constant. Copy over the * remaining bytes of the original query string. */ - len_to_wrt = query_len - quer_loc; + len_to_wrt = query_loc + query_len - quer_loc; Assert(len_to_wrt >= 0); memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt); diff --git a/contrib/pg_stat_statements/sql/pg_stat_statements.sql b/contrib/pg_stat_statements/sql/pg_stat_statements.sql index 7e2b263..5a30436 100644 --- a/contrib/pg_stat_statements/sql/pg_stat_statements.sql +++ b/contrib/pg_stat_statements/sql/pg_stat_statements.sql @@ -1,15 +1,183 @@ CREATE EXTENSION pg_stat_statements; -CREATE TABLE test (a int, b char(20)); +-- +-- +-- simple and compound statements +-- +SET pg_stat_statements.track_utility = FALSE; +SELECT pg_stat_statements_reset(); + +SELECT 1 AS "int"; + + +SELECT 'hello' + -- multiline + AS "text"; +SELECT 'world' AS "text"; + +-- transaction +BEGIN; +SELECT 1 AS "int"; +SELECT 'hello' AS "text"; +COMMIT; + +-- compound transaction +BEGIN \; +SELECT 2.0 AS "float" \; +SELECT 'world' AS "text" \; +COMMIT; + +-- compound with empty statements and spurious leading spacing +\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;; + +-- non ;-terminated statements +SELECT 1 + 1 + 1 AS "add" \gset +SELECT :add + 1 + 1 AS "add" \; +SELECT :add + 1 + 1 AS "add" \gset + +-- set operator +SELECT 1 AS i UNION SELECT 2 ORDER BY i; + +-- cte +WITH t(f) AS ( + VALUES (1.0), (2.0) +) + SELECT f FROM t ORDER BY f; --- test the basic functionality of pg_stat_statements +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + +-- +-- +-- CRUD: INSERT SELECT UPDATE DELETE on test table +-- SELECT pg_stat_statements_reset(); +-- utility "create table" must not show +CREATE TABLE test (a int, b char(20)); + INSERT INTO test VALUES(generate_series(1, 10), 'aaa'); -UPDATE test SET b = 'bbb' WHERE a > 5; +UPDATE test SET b = 'bbb' WHERE a > 7; +DELETE FROM test WHERE a > 9; + +-- explicit transaction +BEGIN; +UPDATE test SET b = '111' WHERE a = 1 ; +COMMIT; + +BEGIN \; +UPDATE test SET b = '222' WHERE a = 2 \; +COMMIT ; + +UPDATE test SET b = '333' WHERE a = 3 \; +UPDATE test SET b = '444' WHERE a = 4 ; + +BEGIN \; +UPDATE test SET b = '555' WHERE a = 5 \; +UPDATE test SET b = '666' WHERE a = 6 \; +COMMIT ; + +-- SELECT with constants +SELECT * FROM test WHERE a > 5 ORDER BY a ; +SELECT * + FROM test + WHERE a > 9 + ORDER BY a ; + +-- SELECT without constants +SELECT * FROM test ORDER BY a; + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; -SELECT query, calls, rows from pg_stat_statements ORDER BY rows; +-- +-- +-- pg_stat_statements.track = none +-- +SET pg_stat_statements.track = 'none'; +SELECT pg_stat_statements_reset(); +SELECT 1 AS "one"; +SELECT 1 + 1 AS "two"; +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + +-- +-- +-- pg_stat_statements.track = top +-- +SELECT pg_stat_statements_reset(); +SET pg_stat_statements.track = 'top'; + +DO LANGUAGE plpgsql $$ +BEGIN + -- this is a SELECT + PERFORM 'hello world'::TEXT; +END; +$$; + +-- PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; + +SELECT PLUS_TWO(3); +SELECT PLUS_TWO(7); +-- SQL function +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL; + +SELECT PLUS_ONE(8); +SELECT PLUS_ONE(10); + +DROP FUNCTION PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + +-- +-- +-- pg_stat_statements.track = all +-- +SELECT pg_stat_statements_reset(); +SET pg_stat_statements.track = 'all'; + +-- recreate PL/pgSQL function +CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ +DECLARE + r INTEGER; +BEGIN + SELECT (i + 1 + 1.0)::INTEGER INTO r; + RETURN r; +END; $$ LANGUAGE plpgsql; + +SELECT PLUS_TWO(-1); +SELECT PLUS_TWO(2); + +-- SQL function nesting +CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +$$ SELECT (i + 1.0)::INTEGER $$ LANGUAGE SQL; + +SELECT PLUS_ONE(3); +SELECT PLUS_ONE(1); + +-- bug? PLUS_ONE expansion is missing +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + +-- +-- +-- utility commands +-- +SELECT pg_stat_statements_reset(); +SET pg_stat_statements.track_utility = TRUE; + +CREATE INDEX test_b ON test(b); DROP TABLE test; +DROP FUNCTION PLUS_ONE(INTEGER); +DROP FUNCTION PLUS_TWO(INTEGER); + +SELECT query, calls, rows FROM pg_stat_statements ORDER BY rows, query; + DROP EXTENSION pg_stat_statements; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 41dde50..e652feb 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -177,6 +177,11 @@ planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result = (*planner_hook) (parse, cursorOptions, boundParams); else result = standard_planner(parse, cursorOptions, boundParams); + + /* copy query location to planned statement */ + result->qlocation = parse->qlocation; + result->qlength = parse->qlength; + return result; } diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index a558083..bdff79c 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -307,6 +307,11 @@ transformStmt(ParseState *pstate, Node *parseTree) result->querySource = QSRC_ORIGINAL; result->canSetTag = true; + /* keep track of location & length */ + Assert(isParseNode(parseTree)); + result->qlocation = ((ParseNode*) parseTree)->qlocation; + result->qlength = ((ParseNode*) parseTree)->qlength; + return result; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 834a009..b0657f4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -178,6 +178,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); +static void setQueryLocation(Node *node, core_yyscan_t yyscanner, int start); %} @@ -761,14 +762,20 @@ stmtblock: stmtmulti stmtmulti: stmtmulti ';' stmt { if ($3 != NULL) + { + setQueryLocation($3, yyscanner, @2+1); $$ = lappend($1, $3); + } else $$ = $1; } | stmt { if ($1 != NULL) + { + setQueryLocation($1, yyscanner, 0); $$ = list_make1($1); + } else $$ = NIL; } @@ -15283,6 +15290,23 @@ makeRecursiveViewSelect(char *relname, List *aliases, Node *query) return (Node *) s; } +/* set qlocation & qlength for statements starting at "start" */ +static void +setQueryLocation(Node *node, core_yyscan_t yyscanner, int start) +{ + base_yy_extra_type *extra = pg_yyget_extra(yyscanner); + ParseNode *pn = (ParseNode *) node; + Assert(isParseNode(node)); + + pn->qlocation = start; + if (extra->last_semicolon == -1 || start == (extra->last_semicolon + 1)) + /* reduction triggered by end of input */ + pn->qlength = strlen(extra->core_yy_extra.scanbuf) - start; + else + /* reduction triggered by ';' */ + pn->qlength = extra->last_semicolon - start; +} + /* parser_init() * Initialize to parse one query string */ @@ -15290,4 +15314,5 @@ void parser_init(base_yy_extra_type *yyext) { yyext->parsetree = NIL; /* in case grammar forgets to set it */ + yyext->last_semicolon = -1; } diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l index acd9269..470a697 100644 --- a/src/backend/parser/scan.l +++ b/src/backend/parser/scan.l @@ -351,7 +351,8 @@ not_equals "!=" * If you change either set, adjust the character lists appearing in the * rule for "operator"! */ -self [,()\[\].;\:\+\-\*\/\%\^\<\>\=] +semicolon ; +self [,()\[\].\:\+\-\*\/\%\^\<\>\=] op_chars [\~\!\@\#\^\&\|\`\?\+\-\*\/\%\<\>\=] operator {op_chars}+ @@ -845,7 +846,11 @@ other . SET_YYLLOC(); return NOT_EQUALS; } - +{semicolon} { + SET_YYLLOC(); + pg_yyget_extra(yyscanner)->last_semicolon = *yylloc; + return yytext[0]; + } {self} { SET_YYLLOC(); return yytext[0]; diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index c514d3f..1a5e68d 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -308,7 +308,6 @@ typedef enum NodeTag T_UpdateStmt, T_SelectStmt, T_AlterTableStmt, - T_AlterTableCmd, T_AlterDomainStmt, T_SetOperationStmt, T_GrantStmt, @@ -406,7 +405,6 @@ typedef enum NodeTag T_AlterPolicyStmt, T_CreateTransformStmt, T_CreateAmStmt, - T_PartitionCmd, /* * TAGS FOR PARSE TREE NODES (parsenodes.h) @@ -459,6 +457,8 @@ typedef enum NodeTag T_PartitionSpec, T_PartitionBoundSpec, T_PartitionRangeDatum, + T_AlterTableCmd, + T_PartitionCmd, /* * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index fc532fb..704694c 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -78,6 +78,24 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */ /* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */ #define ACL_SELECT_FOR_UPDATE ACL_UPDATE +/* + * A ParseNode is a Node with additional location information. + * Zero qlengh means not set. + * If non-zero, then qlocation is within to the initial query string. + */ +typedef struct ParseNode +{ + NodeTag type; + int qlocation; + int qlength; +} ParseNode; + +/* + * All high-level statements coming out of the parser are ParseNode, + * plus Query & PlannedStmt. + */ +#define isParseNodeTag(tag) ((T_Query <= (tag)) && ((tag) < T_A_Expr)) +#define isParseNode(nodeptr) isParseNodeTag(nodeTag(nodeptr)) /***************************************************************************** * Query Tree @@ -99,6 +117,8 @@ typedef uint32 AclMode; /* a bitmask of privilege bits */ typedef struct Query { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ CmdType commandType; /* select|insert|update|delete|utility */ @@ -1322,6 +1342,8 @@ typedef struct TriggerTransition typedef struct InsertStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* relation to insert into */ List *cols; /* optional: names of the target columns */ Node *selectStmt; /* the source SELECT/VALUES, or NULL */ @@ -1337,6 +1359,8 @@ typedef struct InsertStmt typedef struct DeleteStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* relation to delete from */ List *usingClause; /* optional using clause for more tables */ Node *whereClause; /* qualifications */ @@ -1351,6 +1375,8 @@ typedef struct DeleteStmt typedef struct UpdateStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* relation to update */ List *targetList; /* the target list (of ResTarget) */ Node *whereClause; /* qualifications */ @@ -1383,6 +1409,8 @@ typedef enum SetOperation typedef struct SelectStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ /* * These fields are used only in "leaf" SelectStmts. @@ -1450,6 +1478,8 @@ typedef struct SelectStmt typedef struct SetOperationStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ SetOperation op; /* type of set op */ bool all; /* ALL specified? */ Node *larg; /* left child */ @@ -1541,6 +1571,8 @@ typedef enum ObjectType typedef struct CreateSchemaStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *schemaname; /* the name of the schema to create */ Node *authrole; /* the owner of the created schema */ List *schemaElts; /* schema components (list of parsenodes) */ @@ -1560,6 +1592,8 @@ typedef enum DropBehavior typedef struct AlterTableStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* table to work on */ List *cmds; /* list of subcommands */ ObjectType relkind; /* type of object */ @@ -1637,6 +1671,8 @@ typedef enum AlterTableType typedef struct ReplicaIdentityStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char identity_type; char *name; } ReplicaIdentityStmt; @@ -1665,6 +1701,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ typedef struct AlterDomainStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char subtype; /*------------ * T = alter column default * N = alter column drop not null @@ -1712,6 +1750,8 @@ typedef enum GrantObjectType typedef struct GrantStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ bool is_grant; /* true = GRANT, false = REVOKE */ GrantTargetType targtype; /* type of the grant target */ GrantObjectType objtype; /* kind of object being operated on */ @@ -1762,6 +1802,8 @@ typedef struct AccessPriv typedef struct GrantRoleStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *granted_roles; /* list of roles to be granted/revoked */ List *grantee_roles; /* list of member roles to add/delete */ bool is_grant; /* true = GRANT, false = REVOKE */ @@ -1777,6 +1819,8 @@ typedef struct GrantRoleStmt typedef struct AlterDefaultPrivilegesStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *options; /* list of DefElem */ GrantStmt *action; /* GRANT/REVOKE action (with objects=NIL) */ } AlterDefaultPrivilegesStmt; @@ -1792,6 +1836,8 @@ typedef struct AlterDefaultPrivilegesStmt typedef struct CopyStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* the relation to copy */ Node *query; /* the query (SELECT or DML statement with * RETURNING) to copy */ @@ -1823,6 +1869,8 @@ typedef enum typedef struct VariableSetStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ VariableSetKind kind; char *name; /* variable to be set */ List *args; /* List of A_Const nodes */ @@ -1836,6 +1884,8 @@ typedef struct VariableSetStmt typedef struct VariableShowStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *name; } VariableShowStmt; @@ -1853,6 +1903,8 @@ typedef struct VariableShowStmt typedef struct CreateStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* relation to create */ List *tableElts; /* column definitions (list of ColumnDef) */ List *inhRelations; /* relations to inherit from (list of @@ -1980,6 +2032,8 @@ typedef struct Constraint typedef struct CreateTableSpaceStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *tablespacename; Node *owner; char *location; @@ -1989,6 +2043,8 @@ typedef struct CreateTableSpaceStmt typedef struct DropTableSpaceStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *tablespacename; bool missing_ok; /* skip error if missing? */ } DropTableSpaceStmt; @@ -1996,6 +2052,8 @@ typedef struct DropTableSpaceStmt typedef struct AlterTableSpaceOptionsStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *tablespacename; List *options; bool isReset; @@ -2004,6 +2062,8 @@ typedef struct AlterTableSpaceOptionsStmt typedef struct AlterTableMoveAllStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *orig_tablespacename; ObjectType objtype; /* Object type to move */ List *roles; /* List of roles to move objects of */ @@ -2019,6 +2079,8 @@ typedef struct AlterTableMoveAllStmt typedef struct CreateExtensionStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *extname; bool if_not_exists; /* just do nothing if it already exists? */ List *options; /* List of DefElem nodes */ @@ -2028,6 +2090,8 @@ typedef struct CreateExtensionStmt typedef struct AlterExtensionStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *extname; List *options; /* List of DefElem nodes */ } AlterExtensionStmt; @@ -2035,6 +2099,8 @@ typedef struct AlterExtensionStmt typedef struct AlterExtensionContentsStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *extname; /* Extension's name */ int action; /* +1 = add object, -1 = drop object */ ObjectType objtype; /* Object's type */ @@ -2050,6 +2116,8 @@ typedef struct AlterExtensionContentsStmt typedef struct CreateFdwStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *fdwname; /* foreign-data wrapper name */ List *func_options; /* HANDLER/VALIDATOR options */ List *options; /* generic options to FDW */ @@ -2058,6 +2126,8 @@ typedef struct CreateFdwStmt typedef struct AlterFdwStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *fdwname; /* foreign-data wrapper name */ List *func_options; /* HANDLER/VALIDATOR options */ List *options; /* generic options to FDW */ @@ -2071,6 +2141,8 @@ typedef struct AlterFdwStmt typedef struct CreateForeignServerStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *servername; /* server name */ char *servertype; /* optional server type */ char *version; /* optional server version */ @@ -2081,6 +2153,8 @@ typedef struct CreateForeignServerStmt typedef struct AlterForeignServerStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *servername; /* server name */ char *version; /* optional server version */ List *options; /* generic options to server */ @@ -2094,7 +2168,7 @@ typedef struct AlterForeignServerStmt typedef struct CreateForeignTableStmt { - CreateStmt base; + CreateStmt base; /* is a ParseNode */ char *servername; List *options; } CreateForeignTableStmt; @@ -2107,6 +2181,8 @@ typedef struct CreateForeignTableStmt typedef struct CreateUserMappingStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *user; /* user role */ char *servername; /* server name */ List *options; /* generic options to server */ @@ -2115,6 +2191,8 @@ typedef struct CreateUserMappingStmt typedef struct AlterUserMappingStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *user; /* user role */ char *servername; /* server name */ List *options; /* generic options to server */ @@ -2123,6 +2201,8 @@ typedef struct AlterUserMappingStmt typedef struct DropUserMappingStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *user; /* user role */ char *servername; /* server name */ bool missing_ok; /* ignore missing mappings */ @@ -2143,6 +2223,8 @@ typedef enum ImportForeignSchemaType typedef struct ImportForeignSchemaStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *server_name; /* FDW server name */ char *remote_schema; /* remote schema name to query */ char *local_schema; /* local schema to create objects in */ @@ -2158,6 +2240,8 @@ typedef struct ImportForeignSchemaStmt typedef struct CreatePolicyStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *policy_name; /* Policy's name */ RangeVar *table; /* the table name the policy applies to */ char *cmd_name; /* the command name the policy applies to */ @@ -2174,6 +2258,8 @@ typedef struct CreatePolicyStmt typedef struct AlterPolicyStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *policy_name; /* Policy's name */ RangeVar *table; /* the table name the policy applies to */ List *roles; /* the roles associated with the policy */ @@ -2188,6 +2274,8 @@ typedef struct AlterPolicyStmt typedef struct CreateAmStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *amname; /* access method name */ List *handler_name; /* handler function name */ char amtype; /* type of access method */ @@ -2200,6 +2288,8 @@ typedef struct CreateAmStmt typedef struct CreateTrigStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *trigname; /* TRIGGER's name */ RangeVar *relation; /* relation trigger is on */ List *funcname; /* qual. name of function to call */ @@ -2227,6 +2317,8 @@ typedef struct CreateTrigStmt typedef struct CreateEventTrigStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *trigname; /* TRIGGER's name */ char *eventname; /* event's identifier */ List *whenclause; /* list of DefElems indicating filtering */ @@ -2240,6 +2332,8 @@ typedef struct CreateEventTrigStmt typedef struct AlterEventTrigStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *trigname; /* TRIGGER's name */ char tgenabled; /* trigger's firing configuration WRT * session_replication_role */ @@ -2253,6 +2347,8 @@ typedef struct AlterEventTrigStmt typedef struct CreatePLangStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ bool replace; /* T => replace if already exists */ char *plname; /* PL name */ List *plhandler; /* PL call handler function (qual. name) */ @@ -2280,6 +2376,8 @@ typedef enum RoleStmtType typedef struct CreateRoleStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RoleStmtType stmt_type; /* ROLE/USER/GROUP */ char *role; /* role name */ List *options; /* List of DefElem nodes */ @@ -2288,6 +2386,8 @@ typedef struct CreateRoleStmt typedef struct AlterRoleStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *role; /* role */ List *options; /* List of DefElem nodes */ int action; /* +1 = add members, -1 = drop members */ @@ -2296,6 +2396,8 @@ typedef struct AlterRoleStmt typedef struct AlterRoleSetStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *role; /* role */ char *database; /* database name, or NULL */ VariableSetStmt *setstmt; /* SET or RESET subcommand */ @@ -2304,6 +2406,8 @@ typedef struct AlterRoleSetStmt typedef struct DropRoleStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *roles; /* List of roles to remove */ bool missing_ok; /* skip error if a role is missing? */ } DropRoleStmt; @@ -2316,6 +2420,8 @@ typedef struct DropRoleStmt typedef struct CreateSeqStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *sequence; /* the sequence to create */ List *options; Oid ownerId; /* ID of owner, or InvalidOid for default */ @@ -2325,6 +2431,8 @@ typedef struct CreateSeqStmt typedef struct AlterSeqStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *sequence; /* the sequence to alter */ List *options; bool missing_ok; /* skip error if a role is missing? */ @@ -2337,6 +2445,8 @@ typedef struct AlterSeqStmt typedef struct DefineStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType kind; /* aggregate, operator, type */ bool oldstyle; /* hack to signal old CREATE AGG syntax */ List *defnames; /* qualified name (list of Value strings) */ @@ -2351,6 +2461,8 @@ typedef struct DefineStmt typedef struct CreateDomainStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *domainname; /* qualified name (list of Value strings) */ TypeName *typeName; /* the base type */ CollateClause *collClause; /* untransformed COLLATE spec, if any */ @@ -2364,6 +2476,8 @@ typedef struct CreateDomainStmt typedef struct CreateOpClassStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *opclassname; /* qualified name (list of Value strings) */ List *opfamilyname; /* qualified name (ditto); NIL if omitted */ char *amname; /* name of index AM opclass is for */ @@ -2397,6 +2511,8 @@ typedef struct CreateOpClassItem typedef struct CreateOpFamilyStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *opfamilyname; /* qualified name (list of Value strings) */ char *amname; /* name of index AM opfamily is for */ } CreateOpFamilyStmt; @@ -2408,6 +2524,8 @@ typedef struct CreateOpFamilyStmt typedef struct AlterOpFamilyStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *opfamilyname; /* qualified name (list of Value strings) */ char *amname; /* name of index AM opfamily is for */ bool isDrop; /* ADD or DROP the items? */ @@ -2422,6 +2540,8 @@ typedef struct AlterOpFamilyStmt typedef struct DropStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *objects; /* list of sublists of names (as Values) */ List *arguments; /* list of sublists of arguments (as Values) */ ObjectType removeType; /* object type */ @@ -2437,6 +2557,8 @@ typedef struct DropStmt typedef struct TruncateStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *relations; /* relations (RangeVars) to be truncated */ bool restart_seqs; /* restart owned sequences? */ DropBehavior behavior; /* RESTRICT or CASCADE behavior */ @@ -2449,6 +2571,8 @@ typedef struct TruncateStmt typedef struct CommentStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType objtype; /* Object's type */ List *objname; /* Qualified name of the object */ List *objargs; /* Arguments if needed (eg, for functions) */ @@ -2462,6 +2586,8 @@ typedef struct CommentStmt typedef struct SecLabelStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType objtype; /* Object's type */ List *objname; /* Qualified name of the object */ List *objargs; /* Arguments if needed (eg, for functions) */ @@ -2491,6 +2617,8 @@ typedef struct SecLabelStmt typedef struct DeclareCursorStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *portalname; /* name of the portal (cursor) */ int options; /* bitmask of options (see above) */ Node *query; /* the raw SELECT query */ @@ -2503,6 +2631,8 @@ typedef struct DeclareCursorStmt typedef struct ClosePortalStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *portalname; /* name of the portal (cursor) */ /* NULL means CLOSE ALL */ } ClosePortalStmt; @@ -2526,6 +2656,8 @@ typedef enum FetchDirection typedef struct FetchStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ FetchDirection direction; /* see above */ long howMany; /* number of rows, or position argument */ char *portalname; /* name of portal (cursor) */ @@ -2546,6 +2678,8 @@ typedef struct FetchStmt typedef struct IndexStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *idxname; /* name of new index, or NULL for default */ RangeVar *relation; /* relation to build index on */ char *accessMethod; /* name of access method (eg. btree) */ @@ -2574,6 +2708,8 @@ typedef struct IndexStmt typedef struct CreateFunctionStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ bool replace; /* T => replace if already exists */ List *funcname; /* qualified name of function to create */ List *parameters; /* a list of FunctionParameter */ @@ -2604,6 +2740,8 @@ typedef struct FunctionParameter typedef struct AlterFunctionStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ FuncWithArgs *func; /* name and args of function */ List *actions; /* list of DefElem */ } AlterFunctionStmt; @@ -2617,6 +2755,8 @@ typedef struct AlterFunctionStmt typedef struct DoStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *args; /* List of DefElem nodes */ } DoStmt; @@ -2635,6 +2775,8 @@ typedef struct InlineCodeBlock typedef struct RenameStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType renameType; /* OBJECT_TABLE, OBJECT_COLUMN, etc */ ObjectType relationType; /* if column name, associated relation type */ RangeVar *relation; /* in case it's a table */ @@ -2654,6 +2796,8 @@ typedef struct RenameStmt typedef struct AlterObjectDependsStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType objectType; /* OBJECT_FUNCTION, OBJECT_TRIGGER, etc */ RangeVar *relation; /* in case a table is involved */ List *objname; /* name of the object */ @@ -2668,6 +2812,8 @@ typedef struct AlterObjectDependsStmt typedef struct AlterObjectSchemaStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ RangeVar *relation; /* in case it's a table */ List *object; /* in case it's some other object */ @@ -2683,6 +2829,8 @@ typedef struct AlterObjectSchemaStmt typedef struct AlterOwnerStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ObjectType objectType; /* OBJECT_TABLE, OBJECT_TYPE, etc */ RangeVar *relation; /* in case it's a table */ List *object; /* in case it's some other object */ @@ -2698,6 +2846,8 @@ typedef struct AlterOwnerStmt typedef struct AlterOperatorStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *opername; /* operator name */ List *operargs; /* operator's argument TypeNames */ List *options; /* List of DefElem nodes */ @@ -2711,6 +2861,8 @@ typedef struct AlterOperatorStmt typedef struct RuleStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* relation the rule is for */ char *rulename; /* name of the rule */ Node *whereClause; /* qualifications */ @@ -2727,6 +2879,8 @@ typedef struct RuleStmt typedef struct NotifyStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *conditionname; /* condition name to notify */ char *payload; /* the payload string, or NULL if none */ } NotifyStmt; @@ -2738,6 +2892,8 @@ typedef struct NotifyStmt typedef struct ListenStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *conditionname; /* condition name to listen on */ } ListenStmt; @@ -2748,6 +2904,8 @@ typedef struct ListenStmt typedef struct UnlistenStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *conditionname; /* name to unlisten on, or NULL for all */ } UnlistenStmt; @@ -2772,6 +2930,8 @@ typedef enum TransactionStmtKind typedef struct TransactionStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ TransactionStmtKind kind; /* see above */ List *options; /* for BEGIN/START and savepoint commands */ char *gid; /* for two-phase-commit related commands */ @@ -2784,6 +2944,8 @@ typedef struct TransactionStmt typedef struct CompositeTypeStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *typevar; /* the composite type to be created */ List *coldeflist; /* list of ColumnDef nodes */ } CompositeTypeStmt; @@ -2795,6 +2957,8 @@ typedef struct CompositeTypeStmt typedef struct CreateEnumStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *typeName; /* qualified name (list of Value strings) */ List *vals; /* enum values (list of Value strings) */ } CreateEnumStmt; @@ -2806,6 +2970,8 @@ typedef struct CreateEnumStmt typedef struct CreateRangeStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *typeName; /* qualified name (list of Value strings) */ List *params; /* range parameters (list of DefElem) */ } CreateRangeStmt; @@ -2817,6 +2983,8 @@ typedef struct CreateRangeStmt typedef struct AlterEnumStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *typeName; /* qualified name (list of Value strings) */ char *oldVal; /* old enum value's name, if renaming */ char *newVal; /* new enum value's name */ @@ -2839,6 +3007,8 @@ typedef enum ViewCheckOption typedef struct ViewStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *view; /* the view to be created */ List *aliases; /* target column names */ Node *query; /* the SELECT query */ @@ -2854,6 +3024,8 @@ typedef struct ViewStmt typedef struct LoadStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *filename; /* file to load */ } LoadStmt; @@ -2864,6 +3036,8 @@ typedef struct LoadStmt typedef struct CreatedbStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *dbname; /* name of database to create */ List *options; /* List of DefElem nodes */ } CreatedbStmt; @@ -2875,6 +3049,8 @@ typedef struct CreatedbStmt typedef struct AlterDatabaseStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *dbname; /* name of database to alter */ List *options; /* List of DefElem nodes */ } AlterDatabaseStmt; @@ -2882,6 +3058,8 @@ typedef struct AlterDatabaseStmt typedef struct AlterDatabaseSetStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *dbname; /* database name */ VariableSetStmt *setstmt; /* SET or RESET subcommand */ } AlterDatabaseSetStmt; @@ -2893,6 +3071,8 @@ typedef struct AlterDatabaseSetStmt typedef struct DropdbStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *dbname; /* database to drop */ bool missing_ok; /* skip error if db is missing? */ } DropdbStmt; @@ -2904,6 +3084,8 @@ typedef struct DropdbStmt typedef struct AlterSystemStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ VariableSetStmt *setstmt; /* SET subcommand */ } AlterSystemStmt; @@ -2914,6 +3096,8 @@ typedef struct AlterSystemStmt typedef struct ClusterStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ RangeVar *relation; /* relation being indexed, or NULL if all */ char *indexname; /* original index defined */ bool verbose; /* print progress info */ @@ -2942,6 +3126,8 @@ typedef enum VacuumOption typedef struct VacuumStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ int options; /* OR of VacuumOption flags */ RangeVar *relation; /* single table to process, or NULL */ List *va_cols; /* list of column names, or NIL for all */ @@ -2958,6 +3144,8 @@ typedef struct VacuumStmt typedef struct ExplainStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *query; /* the query (see comments above) */ List *options; /* list of DefElem nodes */ } ExplainStmt; @@ -2978,6 +3166,8 @@ typedef struct ExplainStmt typedef struct CreateTableAsStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ Node *query; /* the query (see comments above) */ IntoClause *into; /* destination table */ ObjectType relkind; /* OBJECT_TABLE or OBJECT_MATVIEW */ @@ -2992,6 +3182,8 @@ typedef struct CreateTableAsStmt typedef struct RefreshMatViewStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ bool concurrent; /* allow concurrent access? */ bool skipData; /* true for WITH NO DATA */ RangeVar *relation; /* relation to insert into */ @@ -3004,6 +3196,8 @@ typedef struct RefreshMatViewStmt typedef struct CheckPointStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ } CheckPointStmt; /* ---------------------- @@ -3022,6 +3216,8 @@ typedef enum DiscardMode typedef struct DiscardStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ DiscardMode target; } DiscardStmt; @@ -3032,6 +3228,8 @@ typedef struct DiscardStmt typedef struct LockStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *relations; /* relations to lock */ int mode; /* lock mode */ bool nowait; /* no wait mode */ @@ -3044,6 +3242,8 @@ typedef struct LockStmt typedef struct ConstraintsSetStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *constraints; /* List of names as RangeVars */ bool deferred; } ConstraintsSetStmt; @@ -3068,6 +3268,8 @@ typedef enum ReindexObjectType typedef struct ReindexStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ ReindexObjectType kind; /* REINDEX_OBJECT_INDEX, REINDEX_OBJECT_TABLE, * etc. */ RangeVar *relation; /* Table or index to reindex */ @@ -3082,6 +3284,8 @@ typedef struct ReindexStmt typedef struct CreateConversionStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *conversion_name; /* Name of the conversion */ char *for_encoding_name; /* source encoding name */ char *to_encoding_name; /* destination encoding name */ @@ -3096,6 +3300,8 @@ typedef struct CreateConversionStmt typedef struct CreateCastStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ TypeName *sourcetype; TypeName *targettype; FuncWithArgs *func; @@ -3110,6 +3316,8 @@ typedef struct CreateCastStmt typedef struct CreateTransformStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ bool replace; TypeName *type_name; char *lang; @@ -3124,6 +3332,8 @@ typedef struct CreateTransformStmt typedef struct PrepareStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *name; /* Name of plan, arbitrary */ List *argtypes; /* Types of parameters (List of TypeName) */ Node *query; /* The query itself (as a raw parsetree) */ @@ -3138,6 +3348,8 @@ typedef struct PrepareStmt typedef struct ExecuteStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *name; /* The name of the plan to execute */ List *params; /* Values to assign to parameters */ } ExecuteStmt; @@ -3150,6 +3362,8 @@ typedef struct ExecuteStmt typedef struct DeallocateStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ char *name; /* The name of the plan to remove */ /* NULL means DEALLOCATE ALL */ } DeallocateStmt; @@ -3160,6 +3374,8 @@ typedef struct DeallocateStmt typedef struct DropOwnedStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *roles; DropBehavior behavior; } DropOwnedStmt; @@ -3170,6 +3386,8 @@ typedef struct DropOwnedStmt typedef struct ReassignOwnedStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *roles; Node *newrole; } ReassignOwnedStmt; @@ -3180,6 +3398,8 @@ typedef struct ReassignOwnedStmt typedef struct AlterTSDictionaryStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ List *dictname; /* qualified name (list of Value strings) */ List *options; /* List of DefElem nodes */ } AlterTSDictionaryStmt; @@ -3199,6 +3419,8 @@ typedef enum AlterTSConfigType typedef struct AlterTSConfigurationStmt { NodeTag type; + int qlocation; /* query location */ + int qlength; /* query length, 0 if unset */ AlterTSConfigType kind; /* ALTER_TSCONFIG_ADD_MAPPING, etc */ List *cfgname; /* qualified name (list of Value strings) */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index e2fbc7d..bf9cae4 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -36,6 +36,8 @@ typedef struct PlannedStmt { NodeTag type; + int qlocation; /* query location, or -1 if unknown */ + int qlength; /* query length, 0 if unknown */ CmdType commandType; /* select|insert|update|delete */ diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h index 6d8e493..e373ab2 100644 --- a/src/include/parser/gramparse.h +++ b/src/include/parser/gramparse.h @@ -49,6 +49,8 @@ typedef struct base_yy_extra_type char *lookahead_end; /* end of current token */ char lookahead_hold_char; /* to be put back at *lookahead_end */ + int last_semicolon; /* for query length computation */ + /* * State variables that belong to the grammar. */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers