]> granicus.if.org Git - postgresql/commitdiff
Infrastructure for deducing Param types from context, in the same way
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Apr 2003 22:13:11 +0000 (22:13 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 29 Apr 2003 22:13:11 +0000 (22:13 +0000)
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.

29 files changed:
src/backend/catalog/heap.c
src/backend/commands/schemacmds.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/executor/spi.c
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/parser/analyze.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_node.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/parser/parse_type.c
src/backend/parser/parser.c
src/backend/rewrite/rewriteHandler.c
src/backend/tcop/postgres.c
src/include/parser/analyze.h
src/include/parser/gramparse.h
src/include/parser/parse_coerce.h
src/include/parser/parse_func.h
src/include/parser/parse_node.h
src/include/parser/parse_oper.h
src/include/parser/parser.h
src/include/tcop/tcopprot.h

index 802f5932f7375b6ea907af719ea7372f50c7783d..5a6ec98e1b8a02207f9688893529a06d70b5c0f0 100644 (file)
@@ -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)
index ba37c24987315b541e3d09402a5f6289f23ef800..4e2224e189bb6d9de2f0ef3c00f0cb6651ed7b17 100644 (file)
@@ -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)
                {
index b4576893c660626757bdaf5528152761dc97da69..5f60ab9cf016d9daefa63b412d6eab0773eb3d88 100644 (file)
@@ -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.
index 3cc11ed81a5970e91343e043ec9664cfe8f4d311..0523878f2a717578f31a955b614d37a5e08544e6 100644 (file)
@@ -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
index 218b56a601315088f8d339fa44118c5fedca6f15..aca27d0aebf3597900e057dbe046e6be9c53777c 100644 (file)
@@ -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);
 
index 15d16d002211746f4867a4338693514533ece315..4be69d77cfdf95d7e663cd17e59fdef2e5fa5fec 100644 (file)
@@ -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),
index fb7bf9e70700ad084a93eb474bb524271d290095..d2b91c2ec6d23510c92c9e6c6fca594ad830e57b 100644 (file)
@@ -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;
index 778fc3a2bb9054c679bdb3eefdd96f83ba01ec20..c0ffd939cbe520f9a50e0f9b7c93c5b857df3a7b 100644 (file)
@@ -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;
index 5dc3d82bea8f695dfb01818356f02d0355854024..c2159a70e0e78f1e550030cc239f2f7c215e1cde 100644 (file)
@@ -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);
index 2fd5811000a07ac0bf1152936ab848ae7b4932a3..1c8cb8bc0e3721603011004c87aa0714b5ff8607 100644 (file)
@@ -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;
 }
index a4b739b0f7e8a77db2ac1da07fd6982d30832742..9dc0c7f1c19ba4f0b66a952676e09ed567dd0dde 100644 (file)
@@ -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",
index 10702e9a2693d924957a0497d2039fc64397bebe..429a9ac8c8a3dffe1b5c8771163008b22848972c 100644 (file)
@@ -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);
index 7cbef96536989aac2b059e30d4d174479417cef8..058b9aad73dc8524b162955dfcf601a3b8031ddb 100644 (file)
@@ -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,
index 700c4b158de9ff82070e7a6294f8deb3da1381c1..2f5775212cb2bee967283b89d15fe08180ac41f0 100644 (file)
@@ -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);
index 3be29e64defb749739098b7184a38e5ee7298aca..6238258ed2f6448eea2e8dfa84e32b205460d541 100644 (file)
@@ -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);
index 4ae3bf23153229616db8ae6e7debafe33508ae32..41fd98fc0713f0c109aef4b3208758a0259eb456 100644 (file)
@@ -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,
index e1be47b3ec56a6a674ee783a6d8b12848e6745c9..dc8f241d45ea6e03450f4ace313a3c997a8b11ca 100644 (file)
@@ -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);
index 85aeafacc59befaf6dacdce87d341b27a19f733e..d1a324dbf0afbab819f7271785158ccc1a200ac3 100644 (file)
@@ -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;
index 16745f7b3708249ab8a405cee8362a472e178c16..37436d30079c92e51125b1d16cfe85b64e9d0c52 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 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).
  *
index e39ee0efbe7498b6d843c2bd91df5b9021cc78fe..8ca7fb954f098817f29d1f3a35bcfd2b355a9018 100644 (file)
@@ -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);
index dca6455b0d0642d0634c39e70d18658b5b77913f..bc98d1d91ecd17f0a93d91d6b7ae883846799daa 100644 (file)
@@ -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");
        }
 
        /*
index f780ec4d294a1e5fe271c7d04649ae66ee81564c..b7d6a7d66581404a953b63d31bacfb4f912a1db1 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 #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);
index 97108f2b1c959a22c4f10d8c375c2388a79ddb02..f9a03959116f153f404abc89230cf205ac9542cc 100644 (file)
@@ -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 */
index b21a83601bf602a1f5c8aad98ed4cc04cd13586f..de2ea95db8547f1d35724aa7ce9f69cffee6d829 100644 (file)
@@ -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,
index 3bd369e3c7041fe2a3772aa0fcba332839ae6b36..2b1a1fad4b9734f74ff9008efbc89c74a63e53cd 100644 (file)
@@ -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);
 
index 12dcaccbefd90d8f2634ab70b96414981b6d2558..1f52963e5c018b654dd19bbe3885b51ce35cec7d 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
  * 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;
index 2cde7189ddafea945b2537912631d39a69068580..6d2268bf5573529840c8a13d77f5009841039343 100644 (file)
@@ -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 */
index 42d82869f081c78a52fcfc7033bad26e0f0056b4..e5e5bddfafcbf569f819b82ccc96c06c047c2c6b 100644 (file)
@@ -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 */
index 4235d6d257f4273adead6cec18215b97fa7c8c0f..b81df05320cd106a6f423a908b4ced14a4876033 100644 (file)
@@ -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 */