Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit fb5d058

Browse files
committed
Implement parser hooks for processing ColumnRef and ParamRef nodes, as per my
recent proposal. As proof of concept, remove knowledge of Params from the core parser, arranging for them to be handled entirely by parser hook functions. It turns out we need an additional hook for that --- I had forgotten about the code that handles inferring a parameter's type from context. This is a preliminary step towards letting plpgsql handle its variables through parser hooks. Additional work remains to be done to expose the facility through SPI, but I think this is all the changes needed in the core parser.
1 parent 8442317 commit fb5d058

15 files changed

+938
-514
lines changed

src/backend/catalog/namespace.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.119 2009/10/08 02:39:17 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.120 2009/10/31 01:41:31 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -2289,6 +2289,38 @@ DeconstructQualifiedName(List *names,
22892289
*objname_p = objname;
22902290
}
22912291

2292+
/*
2293+
* LookupNamespaceNoError
2294+
* Look up a schema name.
2295+
*
2296+
* Returns the namespace OID, or InvalidOid if not found.
2297+
*
2298+
* Note this does NOT perform any permissions check --- callers are
2299+
* responsible for being sure that an appropriate check is made.
2300+
* In the majority of cases LookupExplicitNamespace is preferable.
2301+
*/
2302+
Oid
2303+
LookupNamespaceNoError(const char *nspname)
2304+
{
2305+
/* check for pg_temp alias */
2306+
if (strcmp(nspname, "pg_temp") == 0)
2307+
{
2308+
if (OidIsValid(myTempNamespace))
2309+
return myTempNamespace;
2310+
2311+
/*
2312+
* Since this is used only for looking up existing objects, there is
2313+
* no point in trying to initialize the temp namespace here; and doing
2314+
* so might create problems for some callers. Just report "not found".
2315+
*/
2316+
return InvalidOid;
2317+
}
2318+
2319+
return GetSysCacheOid(NAMESPACENAME,
2320+
CStringGetDatum(nspname),
2321+
0, 0, 0);
2322+
}
2323+
22922324
/*
22932325
* LookupExplicitNamespace
22942326
* Process an explicitly-specified schema name: look up the schema
@@ -2336,8 +2368,8 @@ LookupExplicitNamespace(const char *nspname)
23362368
* LookupCreationNamespace
23372369
* Look up the schema and verify we have CREATE rights on it.
23382370
*
2339-
* This is just like LookupExplicitNamespace except for the permission check,
2340-
* and that we are willing to create pg_temp if needed.
2371+
* This is just like LookupExplicitNamespace except for the different
2372+
* permission check, and that we are willing to create pg_temp if needed.
23412373
*
23422374
* Note: calling this may result in a CommandCounterIncrement operation,
23432375
* if we have to create or clean out the temp namespace.

src/backend/parser/Makefile

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# Makefile for parser
44
#
5-
# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.51 2009/08/28 20:26:19 petere Exp $
5+
# $PostgreSQL: pgsql/src/backend/parser/Makefile,v 1.52 2009/10/31 01:41:31 tgl Exp $
66
#
77
#-------------------------------------------------------------------------
88

@@ -12,9 +12,10 @@ include $(top_builddir)/src/Makefile.global
1212

1313
override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
1414

15-
OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_cte.o parse_clause.o \
16-
parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \
17-
parse_type.o parse_coerce.o parse_target.o parse_utilcmd.o scansup.o kwlookup.o
15+
OBJS= analyze.o gram.o keywords.o kwlookup.o parser.o \
16+
parse_agg.o parse_clause.o parse_coerce.o parse_cte.o parse_expr.o \
17+
parse_func.o parse_node.o parse_oper.o parse_param.o parse_relation.o \
18+
parse_target.o parse_type.o parse_utilcmd.o scansup.o
1819

1920
FLEXFLAGS = -CF
2021

src/backend/parser/README

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
$PostgreSQL: pgsql/src/backend/parser/README,v 1.10 2008/04/09 01:00:46 momjian Exp $
1+
$PostgreSQL: pgsql/src/backend/parser/README,v 1.11 2009/10/31 01:41:31 tgl Exp $
22

33
Parser
44
======
@@ -10,17 +10,20 @@ to the optimizer and then executor.
1010
parser.c things start here
1111
scan.l break query into tokens
1212
scansup.c handle escapes in input strings
13-
keywords.c turn keywords into specific tokens
14-
gram.y parse the tokens and fill query-type-specific structures
13+
kwlookup.c turn keywords into specific tokens
14+
keywords.c table of standard keywords (passed to kwlookup.c)
15+
gram.y parse the tokens and produce a "raw" parse tree
1516
analyze.c top level of parse analysis for optimizable queries
17+
parse_agg.c handle aggregates, like SUM(col1), AVG(col2), ...
1618
parse_clause.c handle clauses like WHERE, ORDER BY, GROUP BY, ...
1719
parse_coerce.c handle coercing expressions to different data types
20+
parse_cte.c handle Common Table Expressions (WITH clauses)
1821
parse_expr.c handle expressions like col, col + 3, x = 3 or x = 4
19-
parse_oper.c handle operators in expressions
20-
parse_agg.c handle aggregates, like SUM(col1), AVG(col2), ...
2122
parse_func.c handle functions, table.column and column identifiers
2223
parse_node.c create nodes for various structures
23-
parse_target.c handle the result list of the query
24+
parse_oper.c handle operators in expressions
25+
parse_param.c handle Params (for the cases used in the core backend)
2426
parse_relation.c support routines for tables and column handling
27+
parse_target.c handle the result list of the query
2528
parse_type.c support routines for data type handling
2629
parse_utilcmd.c parse analysis for utility commands (done at execution time)

src/backend/parser/analyze.c

Lines changed: 10 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
1818
* Portions Copyright (c) 1994, Regents of the University of California
1919
*
20-
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.395 2009/10/28 14:55:43 tgl Exp $
20+
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.396 2009/10/31 01:41:31 tgl Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -35,6 +35,7 @@
3535
#include "parser/parse_coerce.h"
3636
#include "parser/parse_cte.h"
3737
#include "parser/parse_oper.h"
38+
#include "parser/parse_param.h"
3839
#include "parser/parse_relation.h"
3940
#include "parser/parse_target.h"
4041
#include "parser/parsetree.h"
@@ -62,7 +63,6 @@ static Query *transformExplainStmt(ParseState *pstate,
6263
ExplainStmt *stmt);
6364
static void transformLockingClause(ParseState *pstate, Query *qry,
6465
LockingClause *lc, bool pushedDown);
65-
static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
6666

6767

6868
/*
@@ -86,9 +86,9 @@ parse_analyze(Node *parseTree, const char *sourceText,
8686
Assert(sourceText != NULL); /* required as of 8.4 */
8787

8888
pstate->p_sourcetext = sourceText;
89-
pstate->p_paramtypes = paramTypes;
90-
pstate->p_numparams = numParams;
91-
pstate->p_variableparams = false;
89+
90+
if (numParams > 0)
91+
parse_fixed_parameters(pstate, paramTypes, numParams);
9292

9393
query = transformStmt(pstate, parseTree);
9494

@@ -114,18 +114,13 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
114114
Assert(sourceText != NULL); /* required as of 8.4 */
115115

116116
pstate->p_sourcetext = sourceText;
117-
pstate->p_paramtypes = *paramTypes;
118-
pstate->p_numparams = *numParams;
119-
pstate->p_variableparams = true;
117+
118+
parse_variable_parameters(pstate, paramTypes, numParams);
120119

121120
query = transformStmt(pstate, parseTree);
122121

123122
/* make sure all is well with parameter types */
124-
if (pstate->p_numparams > 0)
125-
check_parameter_resolution_walker((Node *) query, pstate);
126-
127-
*paramTypes = pstate->p_paramtypes;
128-
*numParams = pstate->p_numparams;
123+
check_variable_parameters(pstate, query);
129124

130125
free_parsestate(pstate);
131126

@@ -1982,7 +1977,7 @@ transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
19821977
*
19831978
* EXPLAIN is just like other utility statements in that we emit it as a
19841979
* CMD_UTILITY Query node with no transformation of the raw parse tree.
1985-
* However, if p_variableparams is set, it could be that the client is
1980+
* However, if p_coerce_param_hook is set, it could be that the client is
19861981
* expecting us to resolve parameter types in something like
19871982
* EXPLAIN SELECT * FROM tab WHERE col = $1
19881983
* To deal with such cases, we run parse analysis and throw away the result;
@@ -1996,7 +1991,7 @@ transformExplainStmt(ParseState *pstate, ExplainStmt *stmt)
19961991
{
19971992
Query *result;
19981993

1999-
if (pstate->p_variableparams)
1994+
if (pstate->p_coerce_param_hook != NULL)
20001995
{
20011996
/* Since parse analysis scribbles on its input, copy the tree first! */
20021997
(void) transformStmt(pstate, copyObject(stmt->query));
@@ -2239,50 +2234,3 @@ applyLockingClause(Query *qry, Index rtindex,
22392234
rc->pushedDown = pushedDown;
22402235
qry->rowMarks = lappend(qry->rowMarks, rc);
22412236
}
2242-
2243-
2244-
/*
2245-
* Traverse a fully-analyzed tree to verify that parameter symbols
2246-
* match their types. We need this because some Params might still
2247-
* be UNKNOWN, if there wasn't anything to force their coercion,
2248-
* and yet other instances seen later might have gotten coerced.
2249-
*/
2250-
static bool
2251-
check_parameter_resolution_walker(Node *node, ParseState *pstate)
2252-
{
2253-
if (node == NULL)
2254-
return false;
2255-
if (IsA(node, Param))
2256-
{
2257-
Param *param = (Param *) node;
2258-
2259-
if (param->paramkind == PARAM_EXTERN)
2260-
{
2261-
int paramno = param->paramid;
2262-
2263-
if (paramno <= 0 || /* shouldn't happen, but... */
2264-
paramno > pstate->p_numparams)
2265-
ereport(ERROR,
2266-
(errcode(ERRCODE_UNDEFINED_PARAMETER),
2267-
errmsg("there is no parameter $%d", paramno),
2268-
parser_errposition(pstate, param->location)));
2269-
2270-
if (param->paramtype != pstate->p_paramtypes[paramno - 1])
2271-
ereport(ERROR,
2272-
(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
2273-
errmsg("could not determine data type of parameter $%d",
2274-
paramno),
2275-
parser_errposition(pstate, param->location)));
2276-
}
2277-
return false;
2278-
}
2279-
if (IsA(node, Query))
2280-
{
2281-
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
2282-
return query_tree_walker((Query *) node,
2283-
check_parameter_resolution_walker,
2284-
(void *) pstate, 0);
2285-
}
2286-
return expression_tree_walker(node, check_parameter_resolution_walker,
2287-
(void *) pstate);
2288-
}

src/backend/parser/parse_coerce.c

Lines changed: 13 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.177 2009/06/11 14:49:00 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.178 2009/10/31 01:41:31 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -259,69 +259,21 @@ coerce_type(ParseState *pstate, Node *node,
259259

260260
return result;
261261
}
262-
if (inputTypeId == UNKNOWNOID && IsA(node, Param) &&
263-
((Param *) node)->paramkind == PARAM_EXTERN &&
264-
pstate != NULL && pstate->p_variableparams)
262+
if (IsA(node, Param) &&
263+
pstate != NULL && pstate->p_coerce_param_hook != NULL)
265264
{
266265
/*
267-
* Input is a Param of previously undetermined type, and we want to
268-
* update our knowledge of the Param's type. Find the topmost
269-
* ParseState and update the state.
266+
* Allow the CoerceParamHook to decide what happens. It can return
267+
* a transformed node (very possibly the same Param node), or return
268+
* NULL to indicate we should proceed with normal coercion.
270269
*/
271-
Param *param = (Param *) node;
272-
int paramno = param->paramid;
273-
ParseState *toppstate;
274-
275-
toppstate = pstate;
276-
while (toppstate->parentParseState != NULL)
277-
toppstate = toppstate->parentParseState;
278-
279-
if (paramno <= 0 || /* shouldn't happen, but... */
280-
paramno > toppstate->p_numparams)
281-
ereport(ERROR,
282-
(errcode(ERRCODE_UNDEFINED_PARAMETER),
283-
errmsg("there is no parameter $%d", paramno),
284-
parser_errposition(pstate, param->location)));
285-
286-
if (toppstate->p_paramtypes[paramno - 1] == UNKNOWNOID)
287-
{
288-
/* We've successfully resolved the type */
289-
toppstate->p_paramtypes[paramno - 1] = targetTypeId;
290-
}
291-
else if (toppstate->p_paramtypes[paramno - 1] == targetTypeId)
292-
{
293-
/* We previously resolved the type, and it matches */
294-
}
295-
else
296-
{
297-
/* Ooops */
298-
ereport(ERROR,
299-
(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
300-
errmsg("inconsistent types deduced for parameter $%d",
301-
paramno),
302-
errdetail("%s versus %s",
303-
format_type_be(toppstate->p_paramtypes[paramno - 1]),
304-
format_type_be(targetTypeId)),
305-
parser_errposition(pstate, param->location)));
306-
}
307-
308-
param->paramtype = targetTypeId;
309-
310-
/*
311-
* Note: it is tempting here to set the Param's paramtypmod to
312-
* targetTypeMod, but that is probably unwise because we have no
313-
* infrastructure that enforces that the value delivered for a Param
314-
* will match any particular typmod. Leaving it -1 ensures that a
315-
* run-time length check/coercion will occur if needed.
316-
*/
317-
param->paramtypmod = -1;
318-
319-
/* Use the leftmost of the param's and coercion's locations */
320-
if (location >= 0 &&
321-
(param->location < 0 || location < param->location))
322-
param->location = location;
323-
324-
return (Node *) param;
270+
result = (*pstate->p_coerce_param_hook) (pstate,
271+
(Param *) node,
272+
targetTypeId,
273+
targetTypeMod,
274+
location);
275+
if (result)
276+
return result;
325277
}
326278
pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
327279
&funcId);

0 commit comments

Comments
 (0)