From aa282d44464df0fbfa0672dc353d36734ec1092e Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Tue, 29 Apr 2003 22:13:11 +0000 Subject: [PATCH] Infrastructure for deducing Param types from context, in the same way that the types of untyped string-literal constants are deduced (ie, when coerce_type is applied to 'em, that's what the type must be). Remove the ancient hack of storing the input Param-types array as a global variable, and put the info into ParseState instead. This touches a lot of files because of adjustment of routine parameter lists, but it's really not a large patch. Note: PREPARE statement still insists on exact specification of parameter types, but that could easily be relaxed now, if we wanted to do so. --- src/backend/catalog/heap.c | 6 +- src/backend/commands/schemacmds.c | 4 +- src/backend/commands/tablecmds.c | 4 +- src/backend/commands/typecmds.c | 4 +- src/backend/executor/spi.c | 6 +- src/backend/optimizer/plan/subselect.c | 9 +- src/backend/optimizer/prep/prepunion.c | 5 +- src/backend/optimizer/util/clauses.c | 14 +-- src/backend/parser/analyze.c | 163 ++++++++++++++++++------- src/backend/parser/parse_clause.c | 22 ++-- src/backend/parser/parse_coerce.c | 116 +++++++++++++----- src/backend/parser/parse_expr.c | 102 ++++++++++++---- src/backend/parser/parse_func.c | 16 ++- src/backend/parser/parse_node.c | 18 ++- src/backend/parser/parse_oper.c | 17 ++- src/backend/parser/parse_relation.c | 4 +- src/backend/parser/parse_target.c | 7 +- src/backend/parser/parse_type.c | 4 +- src/backend/parser/parser.c | 44 +------ src/backend/rewrite/rewriteHandler.c | 5 +- src/backend/tcop/postgres.c | 33 ++--- src/include/parser/analyze.h | 8 +- src/include/parser/gramparse.h | 5 +- src/include/parser/parse_coerce.h | 17 ++- src/include/parser/parse_func.h | 6 +- src/include/parser/parse_node.h | 17 ++- src/include/parser/parse_oper.h | 11 +- src/include/parser/parser.h | 8 +- src/include/tcop/tcopprot.h | 12 +- 29 files changed, 441 insertions(+), 246 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 802f5932f73..5a6ec98e1b8 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.241 2003/03/23 05:14:36 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.242 2003/04/29 22:13:08 tgl Exp $ * * * INTERFACE ROUTINES @@ -1592,7 +1592,7 @@ AddRelationRawConstraints(Relation rel, /* * Make sure it yields a boolean result. */ - expr = coerce_to_boolean(expr, "CHECK"); + expr = coerce_to_boolean(pstate, expr, "CHECK"); /* * Make sure no outside relations are referred to. @@ -1743,7 +1743,7 @@ cookDefault(ParseState *pstate, { Oid type_id = exprType(expr); - if (coerce_to_target_type(expr, type_id, + if (coerce_to_target_type(pstate, expr, type_id, atttypid, atttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST) == NULL) diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index ba37c249873..4e2224e189b 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.7 2002/12/05 04:04:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.8 2003/04/29 22:13:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -124,7 +124,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt) List *querytree_list, *querytree_item; - querytree_list = parse_analyze(parsetree, NULL); + querytree_list = parse_analyze(parsetree, NULL, 0); foreach(querytree_item, querytree_list) { diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b4576893c66..5f60ab9cf01 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.71 2003/04/21 15:19:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.72 2003/04/29 22:13:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2852,7 +2852,7 @@ AlterTableAddCheckConstraint(Relation rel, Constraint *constr) /* * Make sure it yields a boolean result. */ - expr = coerce_to_boolean(expr, "CHECK"); + expr = coerce_to_boolean(pstate, expr, "CHECK"); /* * Make sure no outside relations are referred to. diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 3cc11ed81a5..0523878f2a7 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.33 2003/04/08 16:57:45 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.34 2003/04/29 22:13:08 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -1601,7 +1601,7 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid, /* * Make sure it yields a boolean result. */ - expr = coerce_to_boolean(expr, "CHECK"); + expr = coerce_to_boolean(pstate, expr, "CHECK"); /* * Make sure no outside relations are diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 218b56a6013..aca27d0aebf 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.92 2003/04/29 03:21:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.93 2003/04/29 22:13:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -993,7 +993,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) /* * Parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(src, argtypes, nargs); + raw_parsetree_list = pg_parse_query(src); /* * Do parse analysis and rule rewrite for each raw parsetree. @@ -1036,7 +1036,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan) if (plan) plan->origCmdType = origCmdType; - query_list = pg_analyze_and_rewrite(parsetree); + query_list = pg_analyze_and_rewrite(parsetree, argtypes, nargs); query_list_list = lappend(query_list_list, query_list); diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 15d16d00221..4be69d77cfd 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.74 2003/04/08 23:20:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.75 2003/04/29 22:13:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -495,10 +495,13 @@ convert_sublink_opers(List *lefthand, List *operOids, * Make the expression node. * * Note: we use make_op_expr in case runtime type conversion - * function calls must be inserted for this operator! + * function calls must be inserted for this operator! (But we + * are not expecting to have to resolve unknown Params, so + * it's okay to pass a null pstate.) */ result = lappend(result, - make_op_expr(tup, + make_op_expr(NULL, + tup, leftop, rightop, exprType(leftop), diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index fb7bf9e7070..d2b91c2ec6d 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.93 2003/04/24 23:43:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.94 2003/04/29 22:13:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -418,7 +418,8 @@ generate_setop_tlist(List *colTypes, int flag, } else { - expr = coerce_to_common_type(expr, + expr = coerce_to_common_type(NULL, /* no UNKNOWNs here */ + expr, colType, "UNION/INTERSECT/EXCEPT"); colTypmod = -1; diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 778fc3a2bb9..c0ffd939cbe 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.135 2003/04/27 20:09:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.136 2003/04/29 22:13:09 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1747,17 +1747,17 @@ inline_function(Oid funcid, Oid result_type, List *args, /* * We just do parsing and parse analysis, not rewriting, because - * rewriting will not affect SELECT-only queries, which is all that - * we care about. Also, we can punt as soon as we detect more than + * rewriting will not affect table-free-SELECT-only queries, which is all + * that we care about. Also, we can punt as soon as we detect more than * one command in the function body. */ - raw_parsetree_list = pg_parse_query(src, - funcform->proargtypes, - funcform->pronargs); + raw_parsetree_list = pg_parse_query(src); if (length(raw_parsetree_list) != 1) goto fail; - querytree_list = parse_analyze(lfirst(raw_parsetree_list), NULL); + querytree_list = parse_analyze(lfirst(raw_parsetree_list), + funcform->proargtypes, + funcform->pronargs); if (length(querytree_list) != 1) goto fail; diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 5dc3d82bea8..c2159a70e0e 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.267 2003/04/29 03:21:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.268 2003/04/29 22:13:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -84,6 +84,7 @@ typedef struct } CreateStmtContext; +static List *do_parse_analyze(Node *parseTree, ParseState *pstate); static Query *transformStmt(ParseState *pstate, Node *stmt, List **extras_before, List **extras_after); static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt); @@ -125,10 +126,12 @@ static void release_pstate_resources(ParseState *pstate); static FromExpr *makeFromExpr(List *fromlist, Node *quals); - /* - * parse_analyze - - * analyze a raw parse tree and transform it to Query form. + * parse_analyze + * Analyze a raw parse tree and transform it to Query form. + * + * Optionally, information about $n parameter types can be supplied. + * References to $n indexes not defined by paramTypes[] are disallowed. * * The result is a List of Query nodes (we need a list since some commands * produce multiple Queries). Optimizable statements require considerable @@ -136,11 +139,74 @@ static FromExpr *makeFromExpr(List *fromlist, Node *quals); * a dummy CMD_UTILITY Query node. */ List * -parse_analyze(Node *parseTree, ParseState *parentParseState) +parse_analyze(Node *parseTree, Oid *paramTypes, int numParams) +{ + ParseState *pstate = make_parsestate(NULL); + List *result; + + pstate->p_paramtypes = paramTypes; + pstate->p_numparams = numParams; + pstate->p_variableparams = false; + + result = do_parse_analyze(parseTree, pstate); + + pfree(pstate); + + return result; +} + +/* + * parse_analyze_varparams + * + * This variant is used when it's okay to deduce information about $n + * symbol datatypes from context. The passed-in paramTypes[] array can + * be modified or enlarged (via repalloc). + */ +List * +parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams) +{ + ParseState *pstate = make_parsestate(NULL); + List *result; + + pstate->p_paramtypes = *paramTypes; + pstate->p_numparams = *numParams; + pstate->p_variableparams = true; + + result = do_parse_analyze(parseTree, pstate); + + *paramTypes = pstate->p_paramtypes; + *numParams = pstate->p_numparams; + + pfree(pstate); + + return result; +} + +/* + * parse_sub_analyze + * Entry point for recursively analyzing a sub-statement. + */ +List * +parse_sub_analyze(Node *parseTree, ParseState *parentParseState) { - List *result = NIL; ParseState *pstate = make_parsestate(parentParseState); + List *result; + + result = do_parse_analyze(parseTree, pstate); + + pfree(pstate); + return result; +} + +/* + * do_parse_analyze + * Workhorse code shared by the above variants of parse_analyze. + */ +static List * +do_parse_analyze(Node *parseTree, ParseState *pstate) +{ + List *result = NIL; /* Lists to return extra commands from transformation */ List *extras_before = NIL; List *extras_after = NIL; @@ -148,11 +214,14 @@ parse_analyze(Node *parseTree, ParseState *parentParseState) List *listscan; query = transformStmt(pstate, parseTree, &extras_before, &extras_after); + + /* don't need to access result relation any more */ release_pstate_resources(pstate); while (extras_before != NIL) { - result = nconc(result, parse_analyze(lfirst(extras_before), pstate)); + result = nconc(result, + parse_sub_analyze(lfirst(extras_before), pstate)); extras_before = lnext(extras_before); } @@ -160,13 +229,14 @@ parse_analyze(Node *parseTree, ParseState *parentParseState) while (extras_after != NIL) { - result = nconc(result, parse_analyze(lfirst(extras_after), pstate)); + result = nconc(result, + parse_sub_analyze(lfirst(extras_after), pstate)); extras_after = lnext(extras_after); } /* * Make sure that only the original query is marked original. We have - * to do this explicitly since recursive calls of parse_analyze will + * to do this explicitly since recursive calls of do_parse_analyze will * have marked some of the added-on queries as "original". */ foreach(listscan, result) @@ -176,8 +246,6 @@ parse_analyze(Node *parseTree, ParseState *parentParseState) q->querySource = (q == query ? QSRC_ORIGINAL : QSRC_PARSER); } - pfree(pstate); - return result; } @@ -423,7 +491,14 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, */ if (stmt->selectStmt) { - ParseState *sub_pstate = make_parsestate(pstate->parentParseState); + /* + * We make the sub-pstate a child of the outer pstate so that it + * can see any Param definitions supplied from above. Since the + * outer pstate's rtable and namespace are presently empty, there + * are no side-effects of exposing names the sub-SELECT shouldn't + * be able to see. + */ + ParseState *sub_pstate = make_parsestate(pstate); Query *selectQuery; RangeTblEntry *rte; RangeTblRef *rtr; @@ -475,12 +550,12 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, * separate from the subquery's tlist because we may add columns, * insert datatype coercions, etc.) * - * HACK: constants in the INSERT's targetlist are copied up as-is - * rather than being referenced as subquery outputs. This is - * mainly to ensure that when we try to coerce them to the target - * column's datatype, the right things happen for UNKNOWN - * constants. Otherwise this fails: INSERT INTO foo SELECT 'bar', - * ... FROM baz + * HACK: unknown-type constants and params in the INSERT's targetlist + * are copied up as-is rather than being referenced as subquery + * outputs. This is to ensure that when we try to coerce them + * to the target column's datatype, the right things happen (see + * special cases in coerce_type). Otherwise, this fails: + * INSERT INTO foo SELECT 'bar', ... FROM baz */ qry->targetList = NIL; foreach(tl, selectQuery->targetList) @@ -491,7 +566,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, if (resnode->resjunk) continue; - if (tle->expr && IsA(tle->expr, Const)) + if (tle->expr && + (IsA(tle->expr, Const) || IsA(tle->expr, Param)) && + exprType((Node *) tle->expr) == UNKNOWNOID) expr = tle->expr; else expr = (Expr *) makeVar(rtr->rtindex, @@ -500,7 +577,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, resnode->restypmod, 0); resnode = copyObject(resnode); - resnode->resno = (AttrNumber) pstate->p_last_resno++; + resnode->resno = (AttrNumber) pstate->p_next_resno++; qry->targetList = lappend(qry->targetList, makeTargetEntry(resnode, expr)); } @@ -520,8 +597,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, */ /* Prepare to assign non-conflicting resnos to resjunk attributes */ - if (pstate->p_last_resno <= pstate->p_target_relation->rd_rel->relnatts) - pstate->p_last_resno = pstate->p_target_relation->rd_rel->relnatts + 1; + if (pstate->p_next_resno <= pstate->p_target_relation->rd_rel->relnatts) + pstate->p_next_resno = pstate->p_target_relation->rd_rel->relnatts + 1; /* Validate stmt->cols list, or build default list if no list given */ icolumns = checkInsertTargets(pstate, stmt->cols, &attrnos); @@ -1484,7 +1561,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, List *newactions = NIL; /* - * transform each statement, like parse_analyze() + * transform each statement, like parse_sub_analyze() */ foreach(oldactions, stmt->actions) { @@ -1789,7 +1866,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt) Resdom *resdom; Expr *expr; - resdom = makeResdom((AttrNumber) pstate->p_last_resno++, + resdom = makeResdom((AttrNumber) pstate->p_next_resno++, colType, -1, colName, @@ -1938,7 +2015,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt) * of this sub-query, because they are not in the toplevel * pstate's namespace list. */ - selectList = parse_analyze((Node *) stmt, pstate); + selectList = parse_sub_analyze((Node *) stmt, pstate); Assert(length(selectList) == 1); selectQuery = (Query *) lfirst(selectList); @@ -2132,8 +2209,8 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) */ /* Prepare to assign non-conflicting resnos to resjunk attributes */ - if (pstate->p_last_resno <= pstate->p_target_relation->rd_rel->relnatts) - pstate->p_last_resno = pstate->p_target_relation->rd_rel->relnatts + 1; + if (pstate->p_next_resno <= pstate->p_target_relation->rd_rel->relnatts) + pstate->p_next_resno = pstate->p_target_relation->rd_rel->relnatts + 1; /* Prepare non-junk columns for assignment to target table */ origTargetList = stmt->targetList; @@ -2151,7 +2228,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) * columns; else rewriter or planner might get confused. */ resnode->resname = "?resjunk?"; - resnode->resno = (AttrNumber) pstate->p_last_resno++; + resnode->resno = (AttrNumber) pstate->p_next_resno++; continue; } if (origTargetList == NIL) @@ -2316,11 +2393,10 @@ 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 */ + Oid *argtoids = NULL; /* and as an array */ int nargs; + List *queries; result->commandType = CMD_UTILITY; result->utilityStmt = (Node *) stmt; @@ -2348,24 +2424,19 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt) 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. + * Analyze the statement using these parameter types (any parameters + * passed in from above us will not be visible to it). */ - parser_param_set(argtoids, nargs); - - stmt->query = transformStmt(pstate, (Node *) stmt->query, - &extras_before, &extras_after); + queries = parse_analyze((Node *) stmt->query, argtoids, nargs); - /* Shouldn't get any extras, since grammar only allows OptimizableStmt */ - if (extras_before || extras_after) + /* + * Shouldn't get any extra statements, since grammar only allows + * OptimizableStmt + */ + if (length(queries) != 1) elog(ERROR, "transformPrepareStmt: internal error"); - /* Remove links to our local parameters */ - parser_param_set(NULL, 0); + stmt->query = lfirst(queries); return result; } @@ -2409,7 +2480,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt) given_type_id = exprType(expr); expected_type_id = lfirsto(paramtypes); - expr = coerce_to_target_type(expr, given_type_id, + expr = coerce_to_target_type(pstate, expr, given_type_id, expected_type_id, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 2fd5811000a..1c8cb8bc0e3 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.112 2003/03/22 01:49:38 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.113 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -54,7 +54,7 @@ static RangeTblRef *transformRangeFunction(ParseState *pstate, RangeFunction *r); static Node *transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels); -static Node *buildMergedJoinVar(JoinType jointype, +static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, Var *l_colvar, Var *r_colvar); static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause); @@ -284,7 +284,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) */ result = transformExpr(pstate, result); - result = coerce_to_boolean(result, "JOIN/USING"); + result = coerce_to_boolean(pstate, result, "JOIN/USING"); return result; } /* transformJoinUsingClause() */ @@ -318,7 +318,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, /* This part is just like transformWhereClause() */ result = transformExpr(pstate, j->quals); - result = coerce_to_boolean(result, "JOIN/ON"); + result = coerce_to_boolean(pstate, result, "JOIN/ON"); pstate->p_namespace = save_namespace; @@ -398,7 +398,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r) /* * Analyze and transform the subquery. */ - parsetrees = parse_analyze(r->subquery, pstate); + parsetrees = parse_sub_analyze(r->subquery, pstate); /* * Check that we got something reasonable. Some of these conditions @@ -759,7 +759,8 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels) res_colnames = lappend(res_colnames, lfirst(ucol)); res_colvars = lappend(res_colvars, - buildMergedJoinVar(j->jointype, + buildMergedJoinVar(pstate, + j->jointype, l_colvar, r_colvar)); } @@ -836,7 +837,8 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels) * generate a suitable replacement expression for a merged join column */ static Node * -buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar) +buildMergedJoinVar(ParseState *pstate, JoinType jointype, + Var *l_colvar, Var *r_colvar) { Oid outcoltype; int32 outcoltypmod; @@ -869,7 +871,7 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar) * typmod is not same as input. */ if (l_colvar->vartype != outcoltype) - l_node = coerce_type((Node *) l_colvar, l_colvar->vartype, + l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype, outcoltype, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else if (l_colvar->vartypmod != outcoltypmod) @@ -880,7 +882,7 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar) l_node = (Node *) l_colvar; if (r_colvar->vartype != outcoltype) - r_node = coerce_type((Node *) r_colvar, r_colvar->vartype, + r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype, outcoltype, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else if (r_colvar->vartypmod != outcoltypmod) @@ -953,7 +955,7 @@ transformWhereClause(ParseState *pstate, Node *clause) qual = transformExpr(pstate, clause); - qual = coerce_to_boolean(qual, "WHERE"); + qual = coerce_to_boolean(pstate, qual, "WHERE"); return qual; } diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index a4b739b0f7e..9dc0c7f1c19 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.95 2003/04/10 02:47:46 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.96 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "catalog/pg_cast.h" #include "catalog/pg_proc.h" #include "nodes/makefuncs.h" +#include "nodes/params.h" #include "optimizer/clauses.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" @@ -49,6 +50,7 @@ static Node *build_func_call(Oid funcid, Oid rettype, List *args, * conversion is not possible. (We do this, rather than elog'ing directly, * so that callers can generate custom error messages indicating context.) * + * pstate - parse state (can be NULL, see coerce_type) * expr - input expression tree (already transformed by transformExpr) * exprtype - result type of expr * targettype - desired result type @@ -56,13 +58,13 @@ static Node *build_func_call(Oid funcid, Oid rettype, List *args, * ccontext, cformat - context indicators to control coercions */ Node * -coerce_to_target_type(Node *expr, Oid exprtype, +coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat) { if (can_coerce_type(1, &exprtype, &targettype, ccontext)) - expr = coerce_type(expr, exprtype, targettype, + expr = coerce_type(pstate, expr, exprtype, targettype, ccontext, cformat); /* * String hacks to get transparent conversions for char and varchar: @@ -79,7 +81,7 @@ coerce_to_target_type(Node *expr, Oid exprtype, if (can_coerce_type(1, &exprtype, &text_id, ccontext)) { - expr = coerce_type(expr, exprtype, text_id, + expr = coerce_type(pstate, expr, exprtype, text_id, ccontext, cformat); /* Need a RelabelType if no typmod coercion is performed */ if (targettypmod < 0) @@ -117,9 +119,14 @@ coerce_to_target_type(Node *expr, Oid exprtype, * call coerce_type_typmod as well, if a typmod constraint is wanted. * (But if the target type is a domain, it may internally contain a * typmod constraint, which will be applied inside coerce_to_domain.) + * + * pstate is only used in the case that we are able to resolve the type of + * a previously UNKNOWN Param. It is okay to pass pstate = NULL if the + * caller does not want type information updated for Params. */ Node * -coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, +coerce_type(ParseState *pstate, Node *node, + Oid inputTypeId, Oid targetTypeId, CoercionContext ccontext, CoercionForm cformat) { Node *result; @@ -129,9 +136,9 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, node == NULL) { /* no conversion needed */ - result = node; + return node; } - else if (inputTypeId == UNKNOWNOID && IsA(node, Const)) + if (inputTypeId == UNKNOWNOID && IsA(node, Const)) { /* * Input is a string constant with previously undetermined type. @@ -187,17 +194,62 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, cformat); ReleaseSysCache(targetType); + + return result; } - else if (targetTypeId == ANYOID || - targetTypeId == ANYARRAYOID || - targetTypeId == ANYELEMENTOID) + if (inputTypeId == UNKNOWNOID && IsA(node, Param) && + ((Param *) node)->paramkind == PARAM_NUM && + pstate != NULL && pstate->p_variableparams) + { + /* + * Input is a Param of previously undetermined type, and we want + * to update our knowledge of the Param's type. Find the topmost + * ParseState and update the state. + */ + Param *param = (Param *) node; + int paramno = param->paramid; + ParseState *toppstate; + + toppstate = pstate; + while (toppstate->parentParseState != NULL) + toppstate = toppstate->parentParseState; + + if (paramno <= 0 || /* shouldn't happen, but... */ + paramno > toppstate->p_numparams) + elog(ERROR, "Parameter '$%d' is out of range", paramno); + + if (toppstate->p_paramtypes[paramno-1] == UNKNOWNOID) + { + /* We've successfully resolved the type */ + toppstate->p_paramtypes[paramno-1] = targetTypeId; + } + else if (toppstate->p_paramtypes[paramno-1] == targetTypeId) + { + /* We previously resolved the type, and it matches */ + } + else + { + /* Ooops */ + elog(ERROR, "Inconsistent types deduced for parameter '$%d'" + "\n\tCould be either %s or %s", + paramno, + format_type_be(toppstate->p_paramtypes[paramno-1]), + format_type_be(targetTypeId)); + } + + param->paramtype = targetTypeId; + return (Node *) param; + } + if (targetTypeId == ANYOID || + targetTypeId == ANYARRAYOID || + targetTypeId == ANYELEMENTOID) { /* assume can_coerce_type verified that implicit coercion is okay */ /* NB: we do NOT want a RelabelType here */ - result = node; + return node; } - else if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext, - &funcId)) + if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext, + &funcId)) { if (OidIsValid(funcId)) { @@ -247,27 +299,23 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, cformat); } } + return result; } - else if (typeInheritsFrom(inputTypeId, targetTypeId)) + if (typeInheritsFrom(inputTypeId, targetTypeId)) { /* * Input class type is a subclass of target, so nothing to do --- * except relabel the type. This is binary compatibility for * complex types. */ - result = (Node *) makeRelabelType((Expr *) node, - targetTypeId, -1, - cformat); + return (Node *) makeRelabelType((Expr *) node, + targetTypeId, -1, + cformat); } - else - { - /* If we get here, caller blew it */ - elog(ERROR, "coerce_type: no conversion function from %s to %s", - format_type_be(inputTypeId), format_type_be(targetTypeId)); - result = NULL; /* keep compiler quiet */ - } - - return result; + /* If we get here, caller blew it */ + elog(ERROR, "coerce_type: no conversion function from %s to %s", + format_type_be(inputTypeId), format_type_be(targetTypeId)); + return NULL; /* keep compiler quiet */ } @@ -484,15 +532,19 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod, * (AND, OR, NOT, etc). Also check that input is not a set. * * Returns the possibly-transformed node tree. + * + * As with coerce_type, pstate may be NULL if no special unknown-Param + * processing is wanted. */ Node * -coerce_to_boolean(Node *node, const char *constructName) +coerce_to_boolean(ParseState *pstate, Node *node, + const char *constructName) { Oid inputTypeId = exprType(node); if (inputTypeId != BOOLOID) { - node = coerce_to_target_type(node, inputTypeId, + node = coerce_to_target_type(pstate, node, inputTypeId, BOOLOID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); @@ -594,16 +646,20 @@ select_common_type(List *typeids, const char *context) * This is used following select_common_type() to coerce the individual * expressions to the desired type. 'context' is a phrase to use in the * error message if we fail to coerce. + * + * As with coerce_type, pstate may be NULL if no special unknown-Param + * processing is wanted. */ Node * -coerce_to_common_type(Node *node, Oid targetTypeId, const char *context) +coerce_to_common_type(ParseState *pstate, Node *node, + Oid targetTypeId, const char *context) { Oid inputTypeId = exprType(node); if (inputTypeId == targetTypeId) return node; /* no work */ if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT)) - node = coerce_type(node, inputTypeId, targetTypeId, + node = coerce_type(pstate, node, inputTypeId, targetTypeId, COERCION_IMPLICIT, COERCE_IMPLICIT_CAST); else elog(ERROR, "%s unable to convert to type %s", diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 10702e9a269..429a9ac8c8a 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.147 2003/04/08 23:20:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.148 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,7 +39,8 @@ static int expr_depth_counter = 0; bool Transform_null_equals = false; -static Node *typecast_expression(Node *expr, TypeName *typename); +static Node *typecast_expression(ParseState *pstate, Node *expr, + TypeName *typename); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); @@ -112,17 +113,54 @@ transformExpr(ParseState *pstate, Node *expr) { ParamRef *pref = (ParamRef *) expr; int paramno = pref->number; - Oid paramtyp = param_type(paramno); + ParseState *toppstate; Param *param; List *fields; - if (!OidIsValid(paramtyp)) - elog(ERROR, "Parameter '$%d' is out of range", paramno); + /* + * Find topmost ParseState, which is where paramtype info + * lives. + */ + toppstate = pstate; + while (toppstate->parentParseState != NULL) + toppstate = toppstate->parentParseState; + + /* Check parameter number is in range */ + if (paramno <= 0) /* probably can't happen? */ + elog(ERROR, "Parameter '$%d' is out of range", + paramno); + if (paramno > toppstate->p_numparams) + { + if (!toppstate->p_variableparams) + elog(ERROR, "Parameter '$%d' is out of range", + paramno); + /* Okay to enlarge param array */ + if (toppstate->p_paramtypes) + toppstate->p_paramtypes = + (Oid *) repalloc(toppstate->p_paramtypes, + paramno * sizeof(Oid)); + else + toppstate->p_paramtypes = + (Oid *) palloc(paramno * sizeof(Oid)); + /* Zero out the previously-unreferenced slots */ + MemSet(toppstate->p_paramtypes + toppstate->p_numparams, + 0, + (paramno - toppstate->p_numparams) * sizeof(Oid)); + toppstate->p_numparams = paramno; + } + if (toppstate->p_variableparams) + { + /* If not seen before, initialize to UNKNOWN type */ + if (toppstate->p_paramtypes[paramno-1] == InvalidOid) + toppstate->p_paramtypes[paramno-1] = UNKNOWNOID; + } + param = makeNode(Param); param->paramkind = PARAM_NUM; param->paramid = (AttrNumber) paramno; - param->paramtype = paramtyp; + param->paramtype = toppstate->p_paramtypes[paramno-1]; result = (Node *) param; + /* handle qualification, if any */ foreach(fields, pref->fields) { @@ -143,7 +181,8 @@ transformExpr(ParseState *pstate, Node *expr) result = (Node *) make_const(val); if (con->typename != NULL) - result = typecast_expression(result, con->typename); + result = typecast_expression(pstate, result, + con->typename); break; } case T_ExprFieldSelect: @@ -170,7 +209,7 @@ transformExpr(ParseState *pstate, Node *expr) TypeCast *tc = (TypeCast *) expr; Node *arg = transformExpr(pstate, tc->arg); - result = typecast_expression(arg, tc->typename); + result = typecast_expression(pstate, arg, tc->typename); break; } case T_A_Expr: @@ -212,7 +251,8 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - result = (Node *) make_op(a->name, + result = (Node *) make_op(pstate, + a->name, lexpr, rexpr); } @@ -225,8 +265,8 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - lexpr = coerce_to_boolean(lexpr, "AND"); - rexpr = coerce_to_boolean(rexpr, "AND"); + lexpr = coerce_to_boolean(pstate, lexpr, "AND"); + rexpr = coerce_to_boolean(pstate, rexpr, "AND"); result = (Node *) makeBoolExpr(AND_EXPR, makeList2(lexpr, @@ -240,8 +280,8 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - lexpr = coerce_to_boolean(lexpr, "OR"); - rexpr = coerce_to_boolean(rexpr, "OR"); + lexpr = coerce_to_boolean(pstate, lexpr, "OR"); + rexpr = coerce_to_boolean(pstate, rexpr, "OR"); result = (Node *) makeBoolExpr(OR_EXPR, makeList2(lexpr, @@ -253,7 +293,7 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - rexpr = coerce_to_boolean(rexpr, "NOT"); + rexpr = coerce_to_boolean(pstate, rexpr, "NOT"); result = (Node *) makeBoolExpr(NOT_EXPR, makeList1(rexpr)); @@ -266,7 +306,8 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - result = (Node *) make_op(a->name, + result = (Node *) make_op(pstate, + a->name, lexpr, rexpr); if (((OpExpr *) result)->opresulttype != BOOLOID) @@ -284,7 +325,8 @@ transformExpr(ParseState *pstate, Node *expr) Node *rexpr = transformExpr(pstate, a->rexpr); - result = (Node *) make_op(a->name, + result = (Node *) make_op(pstate, + a->name, lexpr, rexpr); if (((OpExpr *) result)->opresulttype != BOOLOID) @@ -375,7 +417,7 @@ transformExpr(ParseState *pstate, Node *expr) break; } pstate->p_hasSubLinks = true; - qtrees = parse_analyze(sublink->subselect, pstate); + qtrees = parse_sub_analyze(sublink->subselect, pstate); if (length(qtrees) != 1) elog(ERROR, "Bad query in subselect"); qtree = (Query *) lfirst(qtrees); @@ -523,7 +565,7 @@ transformExpr(ParseState *pstate, Node *expr) if (needNot) { - expr = coerce_to_boolean(expr, "NOT"); + expr = coerce_to_boolean(pstate, expr, "NOT"); expr = (Node *) makeBoolExpr(NOT_EXPR, makeList1(expr)); } @@ -561,7 +603,8 @@ transformExpr(ParseState *pstate, Node *expr) } neww->expr = (Expr *) transformExpr(pstate, warg); - neww->expr = (Expr *) coerce_to_boolean((Node *) neww->expr, + neww->expr = (Expr *) coerce_to_boolean(pstate, + (Node *) neww->expr, "CASE/WHEN"); /* @@ -615,7 +658,8 @@ transformExpr(ParseState *pstate, Node *expr) /* Convert default result clause, if necessary */ newc->defresult = (Expr *) - coerce_to_common_type((Node *) newc->defresult, + coerce_to_common_type(pstate, + (Node *) newc->defresult, ptype, "CASE/ELSE"); @@ -625,7 +669,8 @@ transformExpr(ParseState *pstate, Node *expr) CaseWhen *w = (CaseWhen *) lfirst(args); w->result = (Expr *) - coerce_to_common_type((Node *) w->result, + coerce_to_common_type(pstate, + (Node *) w->result, ptype, "CASE/WHEN"); } @@ -666,7 +711,9 @@ transformExpr(ParseState *pstate, Node *expr) Node *e = (Node *) lfirst(element); Node *newe; - newe = coerce_to_common_type(e, element_type, "ARRAY"); + newe = coerce_to_common_type(pstate, e, + element_type, + "ARRAY"); newcoercedelems = lappend(newcoercedelems, newe); } @@ -753,7 +800,8 @@ transformExpr(ParseState *pstate, Node *expr) Node *e = (Node *) lfirst(args); Node *newe; - newe = coerce_to_common_type(e, newc->coalescetype, + newe = coerce_to_common_type(pstate, e, + newc->coalescetype, "COALESCE"); newcoercedargs = lappend(newcoercedargs, newe); } @@ -806,7 +854,9 @@ transformExpr(ParseState *pstate, Node *expr) b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg); - b->arg = (Expr *) coerce_to_boolean((Node *) b->arg, clausename); + b->arg = (Expr *) coerce_to_boolean(pstate, + (Node *) b->arg, + clausename); result = expr; break; @@ -1404,7 +1454,7 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod) * the type name and then apply any necessary coercion function(s). */ static Node * -typecast_expression(Node *expr, TypeName *typename) +typecast_expression(ParseState *pstate, Node *expr, TypeName *typename) { Oid inputType = exprType(expr); Oid targetType; @@ -1414,7 +1464,7 @@ typecast_expression(Node *expr, TypeName *typename) if (inputType == InvalidOid) return expr; /* do nothing if NULL input */ - expr = coerce_to_target_type(expr, inputType, + expr = coerce_to_target_type(pstate, expr, inputType, targetType, typename->typmod, COERCION_EXPLICIT, COERCE_EXPLICIT_CAST); diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 7cbef965369..058b9aad73d 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.146 2003/04/24 21:16:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.147 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -253,7 +253,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, * We can do it as a trivial coercion. coerce_type can handle * these cases, so why duplicate code... */ - return coerce_type(lfirst(fargs), actual_arg_types[0], rettype, + return coerce_type(pstate, lfirst(fargs), actual_arg_types[0], + rettype, COERCION_EXPLICIT, COERCE_EXPLICIT_CALL); } else if (fdresult == FUNCDETAIL_NORMAL) @@ -316,7 +317,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, rettype); /* perform the necessary typecasting of arguments */ - make_fn_arguments(fargs, actual_arg_types, declared_arg_types); + make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types); /* build the appropriate output structure */ if (fdresult == FUNCDETAIL_NORMAL) @@ -1145,9 +1146,13 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId) * allowed. * * Caution: given argument list is modified in-place. + * + * As with coerce_type, pstate may be NULL if no special unknown-Param + * processing is wanted. */ void -make_fn_arguments(List *fargs, +make_fn_arguments(ParseState *pstate, + List *fargs, Oid *actual_arg_types, Oid *declared_arg_types) { @@ -1159,7 +1164,8 @@ make_fn_arguments(List *fargs, /* types don't match? then force coercion using a function call... */ if (actual_arg_types[i] != declared_arg_types[i]) { - lfirst(current_fargs) = coerce_type(lfirst(current_fargs), + lfirst(current_fargs) = coerce_type(pstate, + lfirst(current_fargs), actual_arg_types[i], declared_arg_types[i], COERCION_IMPLICIT, diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 700c4b158de..2f5775212cb 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.77 2003/04/08 23:20:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.78 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -39,7 +39,12 @@ make_parsestate(ParseState *parentParseState) pstate = palloc0(sizeof(ParseState)); pstate->parentParseState = parentParseState; - pstate->p_last_resno = 1; + + /* Fill in fields that don't start at null/false/zero */ + pstate->p_next_resno = 1; + + if (parentParseState) + pstate->p_variableparams = parentParseState->p_variableparams; return pstate; } @@ -166,7 +171,8 @@ transformArraySubscripts(ParseState *pstate, { subexpr = transformExpr(pstate, ai->lidx); /* If it's not int4 already, try to coerce */ - subexpr = coerce_to_target_type(subexpr, exprType(subexpr), + subexpr = coerce_to_target_type(pstate, + subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); @@ -186,7 +192,8 @@ transformArraySubscripts(ParseState *pstate, } subexpr = transformExpr(pstate, ai->uidx); /* If it's not int4 already, try to coerce */ - subexpr = coerce_to_target_type(subexpr, exprType(subexpr), + subexpr = coerce_to_target_type(pstate, + subexpr, exprType(subexpr), INT4OID, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); @@ -205,7 +212,8 @@ transformArraySubscripts(ParseState *pstate, if (typesource != InvalidOid) { - assignFrom = coerce_to_target_type(assignFrom, typesource, + assignFrom = coerce_to_target_type(pstate, + assignFrom, typesource, typeneeded, arrayTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index 3be29e64def..6238258ed2f 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.62 2003/04/08 23:20:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.63 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1019,9 +1019,12 @@ unary_op_error(List *op, Oid arg, bool is_left_op) * * Transform operator expression ensuring type compatibility. * This is where some type conversion happens. + * + * As with coerce_type, pstate may be NULL if no special unknown-Param + * processing is wanted. */ Expr * -make_op(List *opname, Node *ltree, Node *rtree) +make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree) { Oid ltypeId, rtypeId; @@ -1052,7 +1055,7 @@ make_op(List *opname, Node *ltree, Node *rtree) } /* Do typecasting and build the expression tree */ - result = make_op_expr(tup, ltree, rtree, ltypeId, rtypeId); + result = make_op_expr(pstate, tup, ltree, rtree, ltypeId, rtypeId); ReleaseSysCache(tup); @@ -1063,9 +1066,13 @@ make_op(List *opname, Node *ltree, Node *rtree) /* * make_op_expr() * Build operator expression using an already-looked-up operator. + * + * As with coerce_type, pstate may be NULL if no special unknown-Param + * processing is wanted. */ Expr * -make_op_expr(Operator op, Node *ltree, Node *rtree, +make_op_expr(ParseState *pstate, Operator op, + Node *ltree, Node *rtree, Oid ltypeId, Oid rtypeId) { Form_pg_operator opform = (Form_pg_operator) GETSTRUCT(op); @@ -1114,7 +1121,7 @@ make_op_expr(Operator op, Node *ltree, Node *rtree, opform->oprresult); /* perform the necessary typecasting of arguments */ - make_fn_arguments(args, actual_arg_types, declared_arg_types); + make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); /* and build the expression node */ result = makeNode(OpExpr); diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 4ae3bf23153..41fd98fc071 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.80 2002/12/12 15:49:39 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.81 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1447,7 +1447,7 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte) Node *varnode = (Node *) lfirst(vars); TargetEntry *te = makeNode(TargetEntry); - te->resdom = makeResdom((AttrNumber) (pstate->p_last_resno)++, + te->resdom = makeResdom((AttrNumber) pstate->p_next_resno++, exprType(varnode), exprTypmod(varnode), label, diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index e1be47b3ec5..dc8f241d45e 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.99 2003/04/08 23:20:02 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.100 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -73,7 +73,7 @@ transformTargetEntry(ParseState *pstate, colname = FigureColname(node); } - resnode = makeResdom((AttrNumber) pstate->p_last_resno++, + resnode = makeResdom((AttrNumber) pstate->p_next_resno++, type_id, type_mod, colname, @@ -290,7 +290,8 @@ updateTargetListEntry(ParseState *pstate, if (type_id != InvalidOid) { tle->expr = (Expr *) - coerce_to_target_type((Node *) tle->expr, type_id, + coerce_to_target_type(pstate, + (Node *) tle->expr, type_id, attrtype, attrtypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 85aeafacc59..d1a324dbf0a 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.56 2003/04/27 20:09:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.57 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -437,7 +437,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod) initStringInfo(&buf); appendStringInfo(&buf, "SELECT (NULL::%s)", str); - raw_parsetree_list = parser(buf.data, NULL, 0); + raw_parsetree_list = raw_parser(buf.data); /* * Make sure we got back exactly what we expected and no more; diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index 16745f7b370..37436d30079 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.56 2003/04/27 20:09:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.57 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -30,32 +30,27 @@ 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? */ /* - * parser - * Given a query in string form, and optionally info about - * parameter types, do lexical and syntactic analysis. + * raw_parser + * Given a query in string form, do lexical and grammatical analysis. * * Returns a list of raw (un-analyzed) parse trees. */ List * -parser(const char *str, Oid *typev, int nargs) +raw_parser(const char *str) { int yyresult; - parsetree = NIL; /* in case parser forgets to set it */ + parsetree = NIL; /* in case grammar forgets to set it */ have_lookahead = false; scanner_init(str); parser_init(); parse_expr_init(); - parser_param_set(typev, nargs); yyresult = yyparse(); @@ -69,35 +64,6 @@ parser(const char *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). * diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e39ee0efbe7..8ca7fb954f0 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.118 2003/02/25 23:47:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.119 2003/04/29 22:13:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -498,7 +498,8 @@ build_column_default(Relation rel, int attrno) */ exprtype = exprType(expr); - expr = coerce_to_target_type(expr, exprtype, + expr = coerce_to_target_type(NULL, /* no UNKNOWN params here */ + expr, exprtype, atttype, atttypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index dca6455b0d0..bc98d1d91ec 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.325 2003/04/27 20:09:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.326 2003/04/29 22:13:11 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -339,8 +339,8 @@ ReadCommand(StringInfo inBuf) */ List * pg_parse_and_rewrite(const char *query_string, /* string to execute */ - Oid *typev, /* parameter types */ - int nargs) /* number of parameters */ + Oid *paramTypes, /* parameter types */ + int numParams) /* number of parameters */ { List *raw_parsetree_list; List *querytree_list; @@ -349,7 +349,7 @@ pg_parse_and_rewrite(const char *query_string, /* string to execute */ /* * (1) parse the request string into a list of raw parse trees. */ - raw_parsetree_list = pg_parse_query(query_string, typev, nargs); + raw_parsetree_list = pg_parse_query(query_string); /* * (2) Do parse analysis and rule rewrite. @@ -360,7 +360,9 @@ pg_parse_and_rewrite(const char *query_string, /* string to execute */ Node *parsetree = (Node *) lfirst(list_item); querytree_list = nconc(querytree_list, - pg_analyze_and_rewrite(parsetree)); + pg_analyze_and_rewrite(parsetree, + paramTypes, + numParams)); } return querytree_list; @@ -380,7 +382,7 @@ pg_parse_and_rewrite(const char *query_string, /* string to execute */ * commands are not processed any further than the raw parse stage. */ List * -pg_parse_query(const char *query_string, Oid *typev, int nargs) +pg_parse_query(const char *query_string) { List *raw_parsetree_list; @@ -390,7 +392,7 @@ pg_parse_query(const char *query_string, Oid *typev, int nargs) if (log_parser_stats) ResetUsage(); - raw_parsetree_list = parser(query_string, typev, nargs); + raw_parsetree_list = raw_parser(query_string); if (log_parser_stats) ShowUsage("PARSER STATISTICS"); @@ -399,8 +401,8 @@ pg_parse_query(const char *query_string, Oid *typev, int nargs) } /* - * Given a raw parsetree (gram.y output), perform parse analysis and - * rule rewriting. + * Given a raw parsetree (gram.y output), and optionally information about + * types of parameter symbols ($n), perform parse analysis and rule rewriting. * * A list of Query nodes is returned, since either the analyzer or the * rewriter might expand one query to several. @@ -408,7 +410,7 @@ pg_parse_query(const char *query_string, Oid *typev, int nargs) * NOTE: for reasons mentioned above, this must be separate from raw parsing. */ List * -pg_analyze_and_rewrite(Node *parsetree) +pg_analyze_and_rewrite(Node *parsetree, Oid *paramTypes, int numParams) { List *querytree_list; List *list_item; @@ -421,7 +423,7 @@ pg_analyze_and_rewrite(Node *parsetree) if (log_parser_stats) ResetUsage(); - querytree_list = parse_analyze(parsetree, NULL); + querytree_list = parse_analyze(parsetree, paramTypes, numParams); if (log_parser_stats) { @@ -562,8 +564,7 @@ pg_plan_query(Query *querytree) * * ---------------------------------------------------------------- */ - -void +static void pg_exec_query_string(const char *query_string, /* string to execute */ CommandDest dest, /* where results should go */ MemoryContext parse_context) /* context for @@ -614,7 +615,7 @@ pg_exec_query_string(const char *query_string, /* string to execute */ * Do basic parsing of the query or queries (this should be safe even * if we are in aborted transaction state!) */ - parsetree_list = pg_parse_query(query_string, NULL, 0); + parsetree_list = pg_parse_query(query_string); /* * Switch back to execution context to enter the loop. @@ -710,7 +711,7 @@ pg_exec_query_string(const char *query_string, /* string to execute */ */ oldcontext = MemoryContextSwitchTo(parse_context); - querytree_list = pg_analyze_and_rewrite(parsetree); + querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0); /* * Switch back to execution context for planning and execution. @@ -1826,7 +1827,7 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.325 $ $Date: 2003/04/27 20:09:44 $\n"); + puts("$Revision: 1.326 $ $Date: 2003/04/29 22:13:11 $\n"); } /* diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index f780ec4d294..b7d6a7d6658 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: analyze.h,v 1.20 2002/06/20 20:29:51 momjian Exp $ + * $Id: analyze.h,v 1.21 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -15,7 +15,11 @@ #include "parser/parse_node.h" -extern List *parse_analyze(Node *parseTree, ParseState *parentParseState); + +extern List *parse_analyze(Node *parseTree, Oid *paramTypes, int numParams); +extern List *parse_analyze_varparams(Node *parseTree, Oid **paramTypes, + int *numParams); +extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState); extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt); extern void CheckSelectForUpdate(Query *qry); diff --git a/src/include/parser/gramparse.h b/src/include/parser/gramparse.h index 97108f2b1c9..f9a03959116 100644 --- a/src/include/parser/gramparse.h +++ b/src/include/parser/gramparse.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: gramparse.h,v 1.26 2003/04/27 20:09:44 tgl Exp $ + * $Id: gramparse.h,v 1.27 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,9 +17,8 @@ #include "nodes/parsenodes.h" + /* from parser.c */ -extern void parser_param_set(Oid *typev, int nargs); -extern Oid param_type(int t); extern int yylex(void); /* from scan.l */ diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h index b21a83601bf..de2ea95db85 100644 --- a/src/include/parser/parse_coerce.h +++ b/src/include/parser/parse_coerce.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_coerce.h,v 1.50 2003/04/08 23:20:04 tgl Exp $ + * $Id: parse_coerce.h,v 1.51 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "catalog/pg_type.h" #include "parser/parse_node.h" + typedef enum CATEGORY { INVALID_TYPE, @@ -38,22 +39,26 @@ extern bool IsBinaryCoercible(Oid srctype, Oid targettype); extern bool IsPreferredType(CATEGORY category, Oid type); extern CATEGORY TypeCategory(Oid type); -extern Node *coerce_to_target_type(Node *expr, Oid exprtype, +extern Node *coerce_to_target_type(ParseState *pstate, + Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat); extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids, CoercionContext ccontext); -extern Node *coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId, +extern Node *coerce_type(ParseState *pstate, Node *node, + Oid inputTypeId, Oid targetTypeId, CoercionContext ccontext, CoercionForm cformat); extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId, CoercionForm cformat); -extern Node *coerce_to_boolean(Node *node, const char *constructName); +extern Node *coerce_to_boolean(ParseState *pstate, Node *node, + const char *constructName); extern Oid select_common_type(List *typeids, const char *context); -extern Node *coerce_to_common_type(Node *node, Oid targetTypeId, - const char *context); +extern Node *coerce_to_common_type(ParseState *pstate, Node *node, + Oid targetTypeId, + const char *context); extern bool check_generic_type_consistency(Oid *actual_arg_types, Oid *declared_arg_types, diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h index 3bd369e3c70..2b1a1fad4b9 100644 --- a/src/include/parser/parse_func.h +++ b/src/include/parser/parse_func.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_func.h,v 1.44 2003/04/08 23:20:04 tgl Exp $ + * $Id: parse_func.h,v 1.45 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "parser/parse_node.h" + /* * This structure is used to explore the inheritance hierarchy above * nodes in the type tree in order to disambiguate among polymorphic @@ -49,7 +50,8 @@ extern FuncDetailCode func_get_detail(List *funcname, List *fargs, extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId); -extern void make_fn_arguments(List *fargs, +extern void make_fn_arguments(ParseState *pstate, + List *fargs, Oid *actual_arg_types, Oid *declared_arg_types); diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index 12dcaccbefd..1f52963e5c0 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -1,12 +1,13 @@ /*------------------------------------------------------------------------- * * parse_node.h + * Internal definitions for parser * * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_node.h,v 1.34 2003/04/08 23:20:04 tgl Exp $ + * $Id: parse_node.h,v 1.35 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,6 +33,15 @@ * joinlist. Note that an RTE that is present in p_namespace, but does not * have its inFromCl flag set, is accessible only with an explicit qualifier; * lookups of unqualified column names should ignore it. + * + * p_paramtypes: an array of p_numparams type OIDs for $n parameter symbols + * (zeroth entry in array corresponds to $1). If p_variableparams is true, the + * set of param types is not predetermined; in that case, a zero array entry + * means that parameter number hasn't been seen, and UNKNOWNOID means the + * parameter has been used but its type is not yet known. NOTE: in a stack + * of ParseStates, only the topmost ParseState contains paramtype info; but + * we copy the p_variableparams flag down to the child nodes for speed in + * coerce_type. */ typedef struct ParseState { @@ -40,9 +50,12 @@ typedef struct ParseState List *p_joinlist; /* join items so far (will become FromExpr * node's fromlist) */ List *p_namespace; /* current lookup namespace (join items) */ - int p_last_resno; /* last targetlist resno assigned */ + Oid *p_paramtypes; /* OIDs of types for $n parameter symbols */ + int p_numparams; /* allocated size of p_paramtypes[] */ + int p_next_resno; /* next targetlist resno to assign */ List *p_forUpdate; /* FOR UPDATE clause, if any (see gram.y) */ Node *p_value_substitute; /* what to replace VALUE with, if any */ + bool p_variableparams; bool p_hasAggs; bool p_hasSubLinks; bool p_is_insert; diff --git a/src/include/parser/parse_oper.h b/src/include/parser/parse_oper.h index 2cde7189dda..6d2268bf557 100644 --- a/src/include/parser/parse_oper.h +++ b/src/include/parser/parse_oper.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_oper.h,v 1.24 2003/04/08 23:20:04 tgl Exp $ + * $Id: parse_oper.h,v 1.25 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -15,7 +15,8 @@ #define PARSE_OPER_H #include "access/htup.h" -#include "nodes/parsenodes.h" +#include "parser/parse_node.h" + typedef HeapTuple Operator; @@ -50,8 +51,10 @@ extern Oid oprid(Operator op); extern Oid oprfuncid(Operator op); /* Build expression tree for an operator invocation */ -extern Expr *make_op(List *opname, Node *ltree, Node *rtree); -extern Expr *make_op_expr(Operator op, Node *ltree, Node *rtree, +extern Expr *make_op(ParseState *pstate, List *opname, + Node *ltree, Node *rtree); +extern Expr *make_op_expr(ParseState *pstate, Operator op, + Node *ltree, Node *rtree, Oid ltypeId, Oid rtypeId); #endif /* PARSE_OPER_H */ diff --git a/src/include/parser/parser.h b/src/include/parser/parser.h index 42d82869f08..e5e5bddfafc 100644 --- a/src/include/parser/parser.h +++ b/src/include/parser/parser.h @@ -1,21 +1,19 @@ /*------------------------------------------------------------------------- * * parser.h - * + * Definitions for the "raw" parser (lex and yacc phases only) * * * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parser.h,v 1.14 2003/04/27 20:09:44 tgl Exp $ + * $Id: parser.h,v 1.15 2003/04/29 22:13:11 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef PARSER_H #define PARSER_H -#include "parser/parse_node.h" - -extern List *parser(const char *str, Oid *typev, int nargs); +extern List *raw_parser(const char *str); #endif /* PARSER_H */ diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 4235d6d257f..b81df05320c 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: tcopprot.h,v 1.54 2003/04/27 20:09:44 tgl Exp $ + * $Id: tcopprot.h,v 1.55 2003/04/29 22:13:11 tgl Exp $ * * OLD COMMENTS * This file was created so that other c files could get the two @@ -35,14 +35,12 @@ extern DLLIMPORT const char *debug_query_string; #ifndef BOOTSTRAP_INCLUDE -extern List *pg_parse_query(const char *query_string, Oid *typev, int nargs); -extern List *pg_analyze_and_rewrite(Node *parsetree); +extern List *pg_parse_query(const char *query_string); +extern List *pg_analyze_and_rewrite(Node *parsetree, + Oid *paramTypes, int numParams); extern List *pg_parse_and_rewrite(const char *query_string, - Oid *typev, int nargs); + Oid *paramTypes, int numParams); extern Plan *pg_plan_query(Query *querytree); -extern void pg_exec_query_string(const char *query_string, - CommandDest dest, - MemoryContext parse_context); #endif /* BOOTSTRAP_INCLUDE */ -- GitLab