Support subscripts on bare column names.
This commit is contained in:
parent
f9e2c7fae8
commit
36ce6d439f
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.52 1999/07/16 04:59:32 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.53 1999/07/16 22:32:25 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -30,7 +30,10 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
|
||||||
static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
|
static Node *parser_typecast(Value *expr, TypeName *typename, int32 atttypmod);
|
||||||
static Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
|
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
|
||||||
|
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
|
||||||
|
static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
||||||
|
List *indirection, int precedence);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transformExpr -
|
* transformExpr -
|
||||||
@ -51,45 +54,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
{
|
{
|
||||||
case T_Attr:
|
case T_Attr:
|
||||||
{
|
{
|
||||||
Attr *att = (Attr *) expr;
|
result = transformAttr(pstate, (Attr *) expr, precedence);
|
||||||
Node *temp;
|
|
||||||
|
|
||||||
/* what if att.attrs == "*"? */
|
|
||||||
temp = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno,
|
|
||||||
precedence);
|
|
||||||
if (att->indirection != NIL)
|
|
||||||
{
|
|
||||||
List *idx = att->indirection;
|
|
||||||
|
|
||||||
while (idx != NIL)
|
|
||||||
{
|
|
||||||
A_Indices *ai = (A_Indices *) lfirst(idx);
|
|
||||||
Node *lexpr = NULL,
|
|
||||||
*uexpr;
|
|
||||||
|
|
||||||
uexpr = transformExpr(pstate, ai->uidx, precedence); /* must exists */
|
|
||||||
if (exprType(uexpr) != INT4OID)
|
|
||||||
elog(ERROR, "array index expressions must be int4's");
|
|
||||||
if (ai->lidx != NULL)
|
|
||||||
{
|
|
||||||
lexpr = transformExpr(pstate, ai->lidx, precedence);
|
|
||||||
if (exprType(lexpr) != INT4OID)
|
|
||||||
elog(ERROR, "array index expressions must be int4's");
|
|
||||||
}
|
|
||||||
ai->lidx = lexpr;
|
|
||||||
ai->uidx = uexpr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* note we reuse the list of indices, make sure we
|
|
||||||
* don't free them! Otherwise, make a new list
|
|
||||||
* here
|
|
||||||
*/
|
|
||||||
idx = lnext(idx);
|
|
||||||
}
|
|
||||||
result = (Node *) make_array_ref(temp, att->indirection);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = temp;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_A_Const:
|
case T_A_Const:
|
||||||
@ -106,12 +71,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
case T_ParamNo:
|
case T_ParamNo:
|
||||||
{
|
{
|
||||||
ParamNo *pno = (ParamNo *) expr;
|
ParamNo *pno = (ParamNo *) expr;
|
||||||
Oid toid;
|
int paramno = pno->number;
|
||||||
int paramno;
|
Oid toid = param_type(paramno);
|
||||||
Param *param;
|
Param *param;
|
||||||
|
|
||||||
paramno = pno->number;
|
|
||||||
toid = param_type(paramno);
|
|
||||||
if (!OidIsValid(toid))
|
if (!OidIsValid(toid))
|
||||||
elog(ERROR, "Parameter '$%d' is out of range", paramno);
|
elog(ERROR, "Parameter '$%d' is out of range", paramno);
|
||||||
param = makeNode(Param);
|
param = makeNode(Param);
|
||||||
@ -120,40 +83,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
param->paramname = "<unnamed>";
|
param->paramname = "<unnamed>";
|
||||||
param->paramtype = (Oid) toid;
|
param->paramtype = (Oid) toid;
|
||||||
param->param_tlist = (List *) NULL;
|
param->param_tlist = (List *) NULL;
|
||||||
|
result = transformIndirection(pstate, (Node *) param,
|
||||||
if (pno->indirection != NIL)
|
pno->indirection, precedence);
|
||||||
{
|
|
||||||
List *idx = pno->indirection;
|
|
||||||
|
|
||||||
while (idx != NIL)
|
|
||||||
{
|
|
||||||
A_Indices *ai = (A_Indices *) lfirst(idx);
|
|
||||||
Node *lexpr = NULL,
|
|
||||||
*uexpr;
|
|
||||||
|
|
||||||
uexpr = transformExpr(pstate, ai->uidx, precedence); /* must exists */
|
|
||||||
if (exprType(uexpr) != INT4OID)
|
|
||||||
elog(ERROR, "array index expressions must be int4's");
|
|
||||||
if (ai->lidx != NULL)
|
|
||||||
{
|
|
||||||
lexpr = transformExpr(pstate, ai->lidx, precedence);
|
|
||||||
if (exprType(lexpr) != INT4OID)
|
|
||||||
elog(ERROR, "array index expressions must be int4's");
|
|
||||||
}
|
|
||||||
ai->lidx = lexpr;
|
|
||||||
ai->uidx = uexpr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* note we reuse the list of indices, make sure we
|
|
||||||
* don't free them! Otherwise, make a new list
|
|
||||||
* here
|
|
||||||
*/
|
|
||||||
idx = lnext(idx);
|
|
||||||
}
|
|
||||||
result = (Node *) make_array_ref((Node *) param, pno->indirection);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = (Node *) param;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_A_Expr:
|
case T_A_Expr:
|
||||||
@ -247,12 +178,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
}
|
}
|
||||||
case T_Ident:
|
case T_Ident:
|
||||||
{
|
{
|
||||||
|
result = transformIdent(pstate, (Ident *) expr, precedence);
|
||||||
/*
|
|
||||||
* look for a column name or a relation name (the default
|
|
||||||
* behavior)
|
|
||||||
*/
|
|
||||||
result = transformIdent(pstate, expr, precedence);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_FuncCall:
|
case T_FuncCall:
|
||||||
@ -544,48 +470,79 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Node *
|
static Node *
|
||||||
transformIdent(ParseState *pstate, Node *expr, int precedence)
|
transformIndirection(ParseState *pstate, Node *basenode,
|
||||||
|
List *indirection, int precedence)
|
||||||
{
|
{
|
||||||
Ident *ident = (Ident *) expr;
|
List *idx;
|
||||||
RangeTblEntry *rte;
|
|
||||||
Node *column_result,
|
|
||||||
*relation_result,
|
|
||||||
*result;
|
|
||||||
|
|
||||||
column_result = relation_result = result = 0;
|
if (indirection == NIL)
|
||||||
|
return basenode;
|
||||||
|
foreach (idx, indirection)
|
||||||
|
{
|
||||||
|
A_Indices *ai = (A_Indices *) lfirst(idx);
|
||||||
|
Node *lexpr = NULL,
|
||||||
|
*uexpr;
|
||||||
|
|
||||||
|
/* uidx is always present, but lidx might be null */
|
||||||
|
if (ai->lidx != NULL)
|
||||||
|
{
|
||||||
|
lexpr = transformExpr(pstate, ai->lidx, precedence);
|
||||||
|
if (exprType(lexpr) != INT4OID)
|
||||||
|
elog(ERROR, "array index expressions must be int4's");
|
||||||
|
}
|
||||||
|
uexpr = transformExpr(pstate, ai->uidx, precedence);
|
||||||
|
if (exprType(uexpr) != INT4OID)
|
||||||
|
elog(ERROR, "array index expressions must be int4's");
|
||||||
|
ai->lidx = lexpr;
|
||||||
|
ai->uidx = uexpr;
|
||||||
|
/*
|
||||||
|
* note we reuse the list of A_Indices nodes, make sure
|
||||||
|
* we don't free them! Otherwise, make a new list here
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
return (Node *) make_array_ref(basenode, indirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
transformAttr(ParseState *pstate, Attr *att, int precedence)
|
||||||
|
{
|
||||||
|
Node *basenode;
|
||||||
|
|
||||||
|
/* what if att->attrs == "*"? */
|
||||||
|
basenode = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno,
|
||||||
|
precedence);
|
||||||
|
return transformIndirection(pstate, basenode,
|
||||||
|
att->indirection, precedence);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
transformIdent(ParseState *pstate, Ident *ident, int precedence)
|
||||||
|
{
|
||||||
|
Node *result = NULL;
|
||||||
|
RangeTblEntry *rte;
|
||||||
|
|
||||||
|
/* try to find the ident as a relation ... but not if subscripts appear */
|
||||||
|
if (ident->indirection == NIL &&
|
||||||
|
refnameRangeTableEntry(pstate, ident->name) != NULL)
|
||||||
|
{
|
||||||
|
ident->isRel = TRUE;
|
||||||
|
result = (Node *) ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == NULL || precedence == EXPR_COLUMN_FIRST)
|
||||||
|
{
|
||||||
/* try to find the ident as a column */
|
/* try to find the ident as a column */
|
||||||
if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
|
if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
|
||||||
{
|
{
|
||||||
|
/* Convert it to a fully qualified Attr, and transform that */
|
||||||
Attr *att = makeNode(Attr);
|
Attr *att = makeNode(Attr);
|
||||||
|
|
||||||
/* we add the relation name for them */
|
|
||||||
att->relname = rte->refname;
|
att->relname = rte->refname;
|
||||||
|
att->paramNo = NULL;
|
||||||
att->attrs = lcons(makeString(ident->name), NIL);
|
att->attrs = lcons(makeString(ident->name), NIL);
|
||||||
column_result = (Node *) ParseNestedFuncOrColumn(pstate, att,
|
att->indirection = ident->indirection;
|
||||||
&pstate->p_last_resno, precedence);
|
return transformAttr(pstate, att, precedence);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to find the ident as a relation */
|
|
||||||
if (refnameRangeTableEntry(pstate, ident->name) != NULL)
|
|
||||||
{
|
|
||||||
ident->isRel = TRUE;
|
|
||||||
relation_result = (Node *) ident;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* choose the right result based on the precedence */
|
|
||||||
if (precedence == EXPR_COLUMN_FIRST)
|
|
||||||
{
|
|
||||||
if (column_result)
|
|
||||||
result = column_result;
|
|
||||||
else
|
|
||||||
result = relation_result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (relation_result)
|
|
||||||
result = relation_result;
|
|
||||||
else
|
|
||||||
result = column_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user