aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c140
-rw-r--r--src/backend/parser/gram.y109
-rw-r--r--src/backend/parser/keywords.c4
-rw-r--r--src/backend/parser/parser.c37
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