diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/tablecmds.c | 2 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 52 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 22 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 5 | ||||
-rw-r--r-- | src/backend/parser/parse_type.c | 64 | ||||
-rw-r--r-- | src/backend/parser/parser.c | 27 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 2 |
7 files changed, 100 insertions, 74 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 11dae782fd2..993da56d437 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -12095,7 +12095,7 @@ ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, * parse_analyze() or the rewriter, but instead we need to pass them * through parse_utilcmd.c to make them ready for execution. */ - raw_parsetree_list = raw_parser(cmd); + raw_parsetree_list = raw_parser(cmd, RAW_PARSE_DEFAULT); querytree_list = NIL; foreach(list_item, raw_parsetree_list) { diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 8368ead1ef6..6c0593686a9 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -508,6 +508,7 @@ SPI_execute(const char *src, bool read_only, long tcount) memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; _SPI_prepare_oneshot_plan(src, &plan); @@ -681,6 +682,7 @@ SPI_execute_with_args(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; plan.nargs = nargs; plan.argtypes = argtypes; @@ -726,6 +728,7 @@ SPI_execute_with_receiver(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = CURSOR_OPT_PARALLEL_OK; if (params) { @@ -768,6 +771,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; @@ -785,6 +789,42 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, } SPIPlanPtr +SPI_prepare_extended(const char *src, + const SPIPrepareOptions *options) +{ + _SPI_plan plan; + SPIPlanPtr result; + + if (src == NULL || options == NULL) + { + SPI_result = SPI_ERROR_ARGUMENT; + return NULL; + } + + SPI_result = _SPI_begin_call(true); + if (SPI_result < 0) + return NULL; + + memset(&plan, 0, sizeof(_SPI_plan)); + plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = options->parseMode; + plan.cursor_options = options->cursorOptions; + plan.nargs = 0; + plan.argtypes = NULL; + plan.parserSetup = options->parserSetup; + plan.parserSetupArg = options->parserSetupArg; + + _SPI_prepare_plan(src, &plan); + + /* copy plan to procedure context */ + result = _SPI_make_plan_non_temp(&plan); + + _SPI_end_call(true); + + return result; +} + +SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, @@ -805,6 +845,7 @@ SPI_prepare_params(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = 0; plan.argtypes = NULL; @@ -1340,6 +1381,7 @@ SPI_cursor_open_with_args(const char *name, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; plan.nargs = nargs; plan.argtypes = argtypes; @@ -1400,6 +1442,7 @@ SPI_cursor_parse_open_with_paramlist(const char *name, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; + plan.parse_mode = RAW_PARSE_DEFAULT; plan.cursor_options = cursorOptions; if (params) { @@ -2036,7 +2079,8 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) * Parse and analyze a querystring. * * At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup - * and plan->parserSetupArg) must be valid, as must plan->cursor_options. + * and plan->parserSetupArg) must be valid, as must plan->parse_mode and + * plan->cursor_options. * * Results are stored into *plan (specifically, plan->plancache_list). * Note that the result data is all in CurrentMemoryContext or child contexts @@ -2063,7 +2107,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = raw_parser(src, plan->parse_mode); /* * Do parse analysis and rule rewrite for each raw parsetree, storing the @@ -2168,7 +2212,7 @@ _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src); + raw_parsetree_list = raw_parser(src, plan->parse_mode); /* * Construct plancache entries, but don't do parse analysis yet. @@ -2866,6 +2910,7 @@ _SPI_make_plan_non_temp(SPIPlanPtr plan) newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->plancxt = plancxt; + newplan->parse_mode = plan->parse_mode; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) @@ -2930,6 +2975,7 @@ _SPI_save_plan(SPIPlanPtr plan) newplan = (SPIPlanPtr) palloc0(sizeof(_SPI_plan)); newplan->magic = _SPI_PLAN_MAGIC; newplan->plancxt = plancxt; + newplan->parse_mode = plan->parse_mode; newplan->cursor_options = plan->cursor_options; newplan->nargs = plan->nargs; if (plan->nargs > 0) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 18e181d5005..fb025f08a4e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -384,7 +384,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); %type <node> vacuum_relation %type <selectlimit> opt_select_limit select_limit limit_clause -%type <list> stmtblock stmtmulti +%type <list> parse_toplevel stmtmulti OptTableElementList TableElementList OptInherit definition OptTypedTableElementList TypedTableElementList reloptions opt_reloptions @@ -723,6 +723,15 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); */ %token NOT_LA NULLS_LA WITH_LA +/* + * The grammar likewise thinks these tokens are keywords, but they are never + * generated by the scanner. Rather, they can be injected by parser.c as + * the initial token of the string (using the lookahead-token mechanism + * implemented there). This provides a way to tell the grammar to parse + * something other than the usual list of SQL commands. + */ +%token MODE_TYPE_NAME + /* Precedence: lowest to highest */ %nonassoc SET /* see relation_expr_opt_alias */ @@ -787,11 +796,20 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); /* * The target production for the whole parse. + * + * Ordinarily we parse a list of statements, but if we see one of the + * special MODE_XXX symbols as first token, we parse something else. + * The options here correspond to enum RawParseMode, which see for details. */ -stmtblock: stmtmulti +parse_toplevel: + stmtmulti { pg_yyget_extra(yyscanner)->parsetree = $1; } + | MODE_TYPE_NAME Typename + { + pg_yyget_extra(yyscanner)->parsetree = list_make1($2); + } ; /* diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 8d01fca6d21..74eb39c0e4d 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -1541,7 +1541,7 @@ select_common_typmod(ParseState *pstate, List *exprs, Oid common_type) foreach(lc, exprs) { - Node *expr = (Node *) lfirst(lc); + Node *expr = (Node *) lfirst(lc); /* Types must match */ if (exprType(expr) != common_type) @@ -2380,7 +2380,8 @@ enforce_generic_type_consistency(const Oid *actual_arg_types, if (!OidIsValid(elem_typeid)) { /* - * if we don't have an element type yet, use the one we just got + * if we don't have an element type yet, use the one we just + * got */ elem_typeid = range_typelem; } diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 717125ad873..abe131ebebf 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -719,13 +719,6 @@ pts_error_callback(void *arg) const char *str = (const char *) arg; errcontext("invalid type name \"%s\"", str); - - /* - * Currently we just suppress any syntax error position report, rather - * than transforming to an "internal query" error. It's unlikely that a - * type name is complex enough to need positioning. - */ - errposition(0); } /* @@ -737,11 +730,7 @@ pts_error_callback(void *arg) TypeName * typeStringToTypeName(const char *str) { - StringInfoData buf; List *raw_parsetree_list; - SelectStmt *stmt; - ResTarget *restarget; - TypeCast *typecast; TypeName *typeName; ErrorContextCallback ptserrcontext; @@ -749,9 +738,6 @@ typeStringToTypeName(const char *str) if (strspn(str, " \t\n\r\f") == strlen(str)) goto fail; - initStringInfo(&buf); - appendStringInfo(&buf, "SELECT NULL::%s", str); - /* * Setup error traceback support in case of ereport() during parse */ @@ -760,58 +746,18 @@ typeStringToTypeName(const char *str) ptserrcontext.previous = error_context_stack; error_context_stack = &ptserrcontext; - raw_parsetree_list = raw_parser(buf.data); + raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME); error_context_stack = ptserrcontext.previous; - /* - * Make sure we got back exactly what we expected and no more; paranoia is - * justified since the string might contain anything. - */ - if (list_length(raw_parsetree_list) != 1) - goto fail; - stmt = (SelectStmt *) linitial_node(RawStmt, raw_parsetree_list)->stmt; - if (stmt == NULL || - !IsA(stmt, SelectStmt) || - stmt->distinctClause != NIL || - stmt->intoClause != NULL || - stmt->fromClause != NIL || - stmt->whereClause != NULL || - stmt->groupClause != NIL || - stmt->havingClause != NULL || - stmt->windowClause != NIL || - stmt->valuesLists != NIL || - stmt->sortClause != NIL || - stmt->limitOffset != NULL || - stmt->limitCount != NULL || - stmt->lockingClause != NIL || - stmt->withClause != NULL || - stmt->op != SETOP_NONE) - goto fail; - if (list_length(stmt->targetList) != 1) - goto fail; - restarget = (ResTarget *) linitial(stmt->targetList); - if (restarget == NULL || - !IsA(restarget, ResTarget) || - restarget->name != NULL || - restarget->indirection != NIL) - goto fail; - typecast = (TypeCast *) restarget->val; - if (typecast == NULL || - !IsA(typecast, TypeCast) || - typecast->arg == NULL || - !IsA(typecast->arg, A_Const)) - goto fail; + /* We should get back exactly one TypeName node. */ + Assert(list_length(raw_parsetree_list) == 1); + typeName = linitial_node(TypeName, raw_parsetree_list); - typeName = typecast->typeName; - if (typeName == NULL || - !IsA(typeName, TypeName)) - goto fail; + /* The grammar allows SETOF in TypeName, but we don't want that here. */ if (typeName->setof) goto fail; - pfree(buf.data); - return typeName; fail: diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index b897a5160a2..8eb8feb372e 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -35,11 +35,11 @@ static char *str_udeescape(const char *str, char escape, * raw_parser * Given a query in string form, do lexical and grammatical analysis. * - * Returns a list of raw (un-analyzed) parse trees. The immediate elements - * of the list are always RawStmt nodes. + * Returns a list of raw (un-analyzed) parse trees. The contents of the + * list have the form required by the specified RawParseMode. */ List * -raw_parser(const char *str) +raw_parser(const char *str, RawParseMode mode) { core_yyscan_t yyscanner; base_yy_extra_type yyextra; @@ -49,8 +49,22 @@ raw_parser(const char *str) yyscanner = scanner_init(str, &yyextra.core_yy_extra, &ScanKeywords, ScanKeywordTokens); - /* base_yylex() only needs this much initialization */ - yyextra.have_lookahead = false; + /* base_yylex() only needs us to initialize the lookahead token, if any */ + if (mode == RAW_PARSE_DEFAULT) + yyextra.have_lookahead = false; + else + { + /* this array is indexed by RawParseMode enum */ + static const int mode_token[] = { + 0, /* RAW_PARSE_DEFAULT */ + MODE_TYPE_NAME /* RAW_PARSE_TYPE_NAME */ + }; + + yyextra.have_lookahead = true; + yyextra.lookahead_token = mode_token[mode]; + yyextra.lookahead_yylloc = 0; + yyextra.lookahead_end = NULL; + } /* initialize the bison parser */ parser_init(&yyextra); @@ -104,7 +118,8 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner) cur_token = yyextra->lookahead_token; lvalp->core_yystype = yyextra->lookahead_yylval; *llocp = yyextra->lookahead_yylloc; - *(yyextra->lookahead_end) = yyextra->lookahead_hold_char; + if (yyextra->lookahead_end) + *(yyextra->lookahead_end) = yyextra->lookahead_hold_char; yyextra->have_lookahead = false; } else diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index dfa0d685a83..f5c14249d13 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -635,7 +635,7 @@ pg_parse_query(const char *query_string) if (log_parser_stats) ResetUsage(); - raw_parsetree_list = raw_parser(query_string); + raw_parsetree_list = raw_parser(query_string, RAW_PARSE_DEFAULT); if (log_parser_stats) ShowUsage("PARSER STATISTICS"); |