diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 140 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 109 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 4 | ||||
-rw-r--r-- | src/backend/parser/parser.c | 37 |
4 files changed, 261 insertions, 29 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 01e6d867ce4..ffa371d9260 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.243 2002/08/27 03:56:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.244 2002/08/27 04:55:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,7 +20,10 @@ #include "catalog/namespace.h" #include "catalog/pg_index.h" #include "catalog/pg_type.h" +#include "commands/prepare.h" #include "nodes/makefuncs.h" +#include "optimizer/clauses.h" +#include "optimizer/planmain.h" #include "parser/analyze.h" #include "parser/gramparse.h" #include "parser/parsetree.h" @@ -94,6 +97,8 @@ static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt); static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt); static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt); static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt); +static Query *transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt); +static Query *transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt); static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt, List **extras_before, List **extras_after); static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt, @@ -277,6 +282,14 @@ transformStmt(ParseState *pstate, Node *parseTree, extras_before, extras_after); break; + case T_PrepareStmt: + result = transformPrepareStmt(pstate, (PrepareStmt *) parseTree); + break; + + case T_ExecuteStmt: + result = transformExecuteStmt(pstate, (ExecuteStmt *) parseTree); + break; + /* * Optimizable statements */ @@ -2454,6 +2467,131 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt, return qry; } +static Query * +transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt) +{ + Query *result = makeNode(Query); + List *extras_before = NIL, + *extras_after = NIL; + List *argtype_oids = NIL; /* argtype OIDs in a list */ + Oid *argtoids = NULL; /* as an array for parser_param_set */ + int nargs; + + result->commandType = CMD_UTILITY; + result->utilityStmt = (Node *) stmt; + + /* Transform list of TypeNames to list (and array) of type OIDs */ + nargs = length(stmt->argtypes); + + if (nargs) + { + List *l; + int i = 0; + + argtoids = (Oid *) palloc(nargs * sizeof(Oid)); + + foreach (l, stmt->argtypes) + { + TypeName *tn = lfirst(l); + Oid toid = typenameTypeId(tn); + + argtype_oids = lappendi(argtype_oids, toid); + argtoids[i++] = toid; + } + } + + stmt->argtype_oids = argtype_oids; + + /* + * We need to adjust the parameters expected by the + * rest of the system, so that $1, ... $n are parsed properly. + * + * This is somewhat of a hack; however, the main parser interface + * only allows parameters to be specified when working with a + * raw query string, which is not helpful here. + */ + parser_param_set(argtoids, nargs); + + stmt->query = transformStmt(pstate, (Node *) stmt->query, + &extras_before, &extras_after); + + /* Shouldn't get any extras, since grammar only allows OptimizableStmt */ + if (extras_before || extras_after) + elog(ERROR, "transformPrepareStmt: internal error"); + + /* Remove links to our local parameters */ + parser_param_set(NULL, 0); + + return result; +} + +static Query * +transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt) +{ + Query *result = makeNode(Query); + List *paramtypes; + + result->commandType = CMD_UTILITY; + result->utilityStmt = (Node *) stmt; + + paramtypes = FetchQueryParams(stmt->name); + + if (stmt->params || paramtypes) + { + int nparams = length(stmt->params); + int nexpected = length(paramtypes); + List *l; + int i = 1; + + if (nparams != nexpected) + elog(ERROR, "Wrong number of parameters, expected %d but got %d", + nexpected, nparams); + + foreach (l, stmt->params) + { + Node *expr = lfirst(l); + Oid expected_type_id, + given_type_id; + + expr = transformExpr(pstate, expr); + + /* Cannot contain subselects or aggregates */ + if (contain_subplans(expr)) + elog(ERROR, "Cannot use subselects in EXECUTE parameters"); + if (contain_agg_clause(expr)) + elog(ERROR, "Cannot use aggregates in EXECUTE parameters"); + + given_type_id = exprType(expr); + expected_type_id = (Oid) lfirsti(paramtypes); + + if (given_type_id != expected_type_id) + { + expr = CoerceTargetExpr(pstate, + expr, + given_type_id, + expected_type_id, + -1, + false); + + if (!expr) + elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s" + "\n\tYou will need to rewrite or cast the expression", + i, + format_type_be(given_type_id), + format_type_be(expected_type_id)); + } + + fix_opids(expr); + lfirst(l) = expr; + + paramtypes = lnext(paramtypes); + i++; + } + } + + return result; +} + /* exported so planner can check again after rewriting, query pullup, etc */ void CheckSelectForUpdate(Query *qry) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 80aa372f9c5..0f512c7d31b 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.360 2002/08/19 15:08:47 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.361 2002/08/27 04:55:08 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -68,8 +68,6 @@ extern List *parsetree; /* final parse result is delivered here */ static bool QueryIsRule = FALSE; -static Oid *param_type_info; -static int pfunc_num_args; /* * If you need access to certain yacc-generated variables and find that @@ -149,7 +147,8 @@ static void doNegateFloat(Value *v); SelectStmt, TransactionStmt, TruncateStmt, UnlistenStmt, UpdateStmt, VacuumStmt, VariableResetStmt, VariableSetStmt, VariableShowStmt, - ViewStmt, CheckPointStmt, CreateConversionStmt + ViewStmt, CheckPointStmt, CreateConversionStmt, + DeallocateStmt, PrepareStmt, ExecuteStmt %type <node> select_no_parens, select_with_parens, select_clause, simple_select @@ -218,7 +217,8 @@ static void doNegateFloat(Value *v); group_clause, TriggerFuncArgs, select_limit, opt_select_limit, opclass_item_list, trans_options, TableFuncElementList, OptTableFuncElementList, - convert_args + convert_args, prep_type_clause, prep_type_list, + execute_param_clause, execute_param_list %type <range> into_clause, OptTempTableName @@ -335,7 +335,7 @@ static void doNegateFloat(Value *v); CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE, - DATABASE, DAY_P, DEC, DECIMAL, DECLARE, DEFAULT, + DATABASE, DAY_P, DEALLOCATE, DEC, DECIMAL, DECLARE, DEFAULT, DEFERRABLE, DEFERRED, DEFINER, DELETE_P, DELIMITER, DELIMITERS, DESC, DISTINCT, DO, DOMAIN_P, DOUBLE, DROP, @@ -371,7 +371,7 @@ static void doNegateFloat(Value *v); ORDER, OUT_P, OUTER_P, OVERLAPS, OVERLAY, OWNER, PARTIAL, PASSWORD, PATH_P, PENDANT, PLACING, POSITION, - PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, + PRECISION, PREPARE, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE, PROCEDURAL, READ, REAL, RECHECK, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE, @@ -490,6 +490,7 @@ stmt : | CreateTrigStmt | CreateUserStmt | ClusterStmt + | DeallocateStmt | DefineStmt | DropStmt | TruncateStmt @@ -502,6 +503,7 @@ stmt : | DropTrigStmt | DropRuleStmt | DropUserStmt + | ExecuteStmt | ExplainStmt | FetchStmt | GrantStmt @@ -510,6 +512,7 @@ stmt : | UnlistenStmt | LockStmt | NotifyStmt + | PrepareStmt | ReindexStmt | RemoveAggrStmt | RemoveOperStmt @@ -3875,6 +3878,77 @@ ExplainStmt: } ; +/***************************************************************************** + * + * QUERY: + * PREPARE <plan_name> [(args, ...)] AS <query> + * + *****************************************************************************/ + +PrepareStmt: PREPARE name prep_type_clause AS OptimizableStmt + { + PrepareStmt *n = makeNode(PrepareStmt); + n->name = $2; + n->argtypes = $3; + n->query = (Query *) $5; + $$ = (Node *) n; + } + ; + +prep_type_clause: '(' prep_type_list ')' { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; + +prep_type_list: Typename { $$ = makeList1($1); } + | prep_type_list ',' Typename + { $$ = lappend($1, $3); } + ; + +/***************************************************************************** + * + * QUERY: + * EXECUTE <plan_name> [(params, ...)] [INTO ...] + * + *****************************************************************************/ + +ExecuteStmt: EXECUTE name execute_param_clause into_clause + { + ExecuteStmt *n = makeNode(ExecuteStmt); + n->name = $2; + n->params = $3; + n->into = $4; + $$ = (Node *) n; + } + ; + +execute_param_clause: '(' execute_param_list ')' { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; + +execute_param_list: a_expr { $$ = makeList1($1); } + | execute_param_list ',' a_expr { $$ = lappend($1, $3); } + ; + +/***************************************************************************** + * + * QUERY: + * DEALLOCATE [PREPARE] <plan_name> + * + *****************************************************************************/ + +DeallocateStmt: DEALLOCATE name + { + DeallocateStmt *n = makeNode(DeallocateStmt); + n->name = $2; + $$ = (Node *) n; + } + | DEALLOCATE PREPARE name + { + DeallocateStmt *n = makeNode(DeallocateStmt); + n->name = $3; + $$ = (Node *) n; + } + ; /***************************************************************************** * * @@ -6947,6 +7021,7 @@ unreserved_keyword: | CYCLE | DATABASE | DAY_P + | DEALLOCATE | DECLARE | DEFERRED | DEFINER @@ -7019,6 +7094,7 @@ unreserved_keyword: | PATH_P | PENDANT | PRECISION + | PREPARE | PRIOR | PRIVILEGES | PROCEDURAL @@ -7589,26 +7665,9 @@ SystemTypeName(char *name) * Initialize to parse one query string */ void -parser_init(Oid *typev, int nargs) +parser_init(void) { QueryIsRule = FALSE; - /* - * Keep enough information around to fill out the type of param nodes - * used in postquel functions - */ - param_type_info = typev; - pfunc_num_args = nargs; -} - -/* param_type() - * Fetch a parameter type previously passed to parser_init - */ -Oid -param_type(int t) -{ - if ((t > pfunc_num_args) || (t <= 0)) - return InvalidOid; - return param_type_info[t - 1]; } /* exprIsNullConstant() diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 2bb6772054a..9a3064ad661 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.125 2002/08/18 09:36:25 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.126 2002/08/27 04:55:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -96,6 +96,7 @@ static const ScanKeyword ScanKeywords[] = { {"cycle", CYCLE}, {"database", DATABASE}, {"day", DAY_P}, + {"deallocate", DEALLOCATE}, {"dec", DEC}, {"decimal", DECIMAL}, {"declare", DECLARE}, @@ -229,6 +230,7 @@ static const ScanKeyword ScanKeywords[] = { {"placing", PLACING}, {"position", POSITION}, {"precision", PRECISION}, + {"prepare", PREPARE}, {"primary", PRIMARY}, {"prior", PRIOR}, {"privileges", PRIVILEGES}, diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index f4cd24e0c4f..8c129cb9161 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -14,7 +14,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.53 2002/06/20 20:29:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.54 2002/08/27 04:55:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,6 +30,9 @@ List *parsetree; /* result of parsing is left here */ +static Oid *param_type_info; /* state for param_type() */ +static int param_count; + static int lookahead_token; /* one-token lookahead */ static bool have_lookahead; /* lookahead_token set? */ @@ -50,8 +53,9 @@ parser(StringInfo str, Oid *typev, int nargs) have_lookahead = false; scanner_init(str); - parser_init(typev, nargs); + parser_init(); parse_expr_init(); + parser_param_set(typev, nargs); yyresult = yyparse(); @@ -66,6 +70,35 @@ parser(StringInfo str, Oid *typev, int nargs) /* + * Save information needed to fill out the type of Param references ($n) + * + * This is used for SQL functions, PREPARE statements, etc. It's split + * out from parser() setup because PREPARE needs to change the info after + * the grammar runs and before parse analysis is done on the preparable + * query. + */ +void +parser_param_set(Oid *typev, int nargs) +{ + param_type_info = typev; + param_count = nargs; +} + +/* + * param_type() + * + * Fetch a parameter type previously passed to parser_param_set + */ +Oid +param_type(int t) +{ + if (t > param_count || t <= 0) + return InvalidOid; + return param_type_info[t - 1]; +} + + +/* * Intermediate filter between parser and base lexer (base_yylex in scan.l). * * The filter is needed because in some cases SQL92 requires more than one |