mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
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.
This commit is contained in:
parent
19141f5584
commit
aa282d4446
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
ParseState *pstate = make_parsestate(parentParseState);
|
||||
|
||||
/* 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);
|
||||
queries = parse_analyze((Node *) stmt->query, argtoids, nargs);
|
||||
|
||||
stmt->query = transformStmt(pstate, (Node *) stmt->query,
|
||||
&extras_before, &extras_after);
|
||||
|
||||
/* Shouldn't get any extras, since grammar only allows OptimizableStmt */
|
||||
if (extras_before || extras_after)
|
||||
/*
|
||||
* 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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,16 +194,61 @@ coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
|
||||
cformat);
|
||||
|
||||
ReleaseSysCache(targetType);
|
||||
|
||||
return result;
|
||||
}
|
||||
else if (targetTypeId == ANYOID ||
|
||||
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,
|
||||
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,
|
||||
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;
|
||||
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",
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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).
|
||||
*
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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,21 +39,25 @@ 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,
|
||||
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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user