mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
From: Dan McGuirk <mcguirk@indirect.com>
Subject: [HACKERS] equal column and table name patch This fixes a bug where selects fail when there is a column with the same name as the table it's a part of.
This commit is contained in:
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.22 1997/03/02 01:02:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.23 1997/03/12 20:51:33 scrappy Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -52,7 +52,10 @@ static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
|
|||||||
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
|
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
|
||||||
static Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
|
static Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
|
||||||
|
|
||||||
static Node *transformExpr(ParseState *pstate, Node *expr);
|
#define EXPR_COLUMN_FIRST 1
|
||||||
|
#define EXPR_RELATION_FIRST 2
|
||||||
|
static Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
|
||||||
|
static Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
|
||||||
|
|
||||||
static void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
|
static void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
|
||||||
static List *expandAllTables(ParseState *pstate);
|
static List *expandAllTables(ParseState *pstate);
|
||||||
@ -534,7 +537,7 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
|
|||||||
* here.
|
* here.
|
||||||
*/
|
*/
|
||||||
static Node *
|
static Node *
|
||||||
transformExpr(ParseState *pstate, Node *expr)
|
transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||||
{
|
{
|
||||||
Node *result = NULL;
|
Node *result = NULL;
|
||||||
|
|
||||||
@ -553,11 +556,11 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
while(idx!=NIL) {
|
while(idx!=NIL) {
|
||||||
A_Indices *ai = (A_Indices *)lfirst(idx);
|
A_Indices *ai = (A_Indices *)lfirst(idx);
|
||||||
Node *lexpr=NULL, *uexpr;
|
Node *lexpr=NULL, *uexpr;
|
||||||
uexpr = transformExpr(pstate, ai->uidx); /* must exists */
|
uexpr = transformExpr(pstate, ai->uidx, precedence); /* must exists */
|
||||||
if (exprType(uexpr) != INT4OID)
|
if (exprType(uexpr) != INT4OID)
|
||||||
elog(WARN, "array index expressions must be int4's");
|
elog(WARN, "array index expressions must be int4's");
|
||||||
if (ai->lidx != NULL) {
|
if (ai->lidx != NULL) {
|
||||||
lexpr = transformExpr(pstate, ai->lidx);
|
lexpr = transformExpr(pstate, ai->lidx, precedence);
|
||||||
if (exprType(lexpr) != INT4OID)
|
if (exprType(lexpr) != INT4OID)
|
||||||
elog(WARN, "array index expressions must be int4's");
|
elog(WARN, "array index expressions must be int4's");
|
||||||
}
|
}
|
||||||
@ -615,14 +618,14 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
switch(a->oper) {
|
switch(a->oper) {
|
||||||
case OP:
|
case OP:
|
||||||
{
|
{
|
||||||
Node *lexpr = transformExpr(pstate, a->lexpr);
|
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||||
Node *rexpr = transformExpr(pstate, a->rexpr);
|
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
|
||||||
result = (Node *)make_op(a->opname, lexpr, rexpr);
|
result = (Node *)make_op(a->opname, lexpr, rexpr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ISNULL:
|
case ISNULL:
|
||||||
{
|
{
|
||||||
Node *lexpr = transformExpr(pstate, a->lexpr);
|
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||||
result = ParseFunc(pstate,
|
result = ParseFunc(pstate,
|
||||||
"NullValue", lcons(lexpr, NIL),
|
"NullValue", lcons(lexpr, NIL),
|
||||||
&pstate->p_last_resno);
|
&pstate->p_last_resno);
|
||||||
@ -630,7 +633,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
break;
|
break;
|
||||||
case NOTNULL:
|
case NOTNULL:
|
||||||
{
|
{
|
||||||
Node *lexpr = transformExpr(pstate, a->lexpr);
|
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||||
result = ParseFunc(pstate,
|
result = ParseFunc(pstate,
|
||||||
"NonNullValue", lcons(lexpr, NIL),
|
"NonNullValue", lcons(lexpr, NIL),
|
||||||
&pstate->p_last_resno);
|
&pstate->p_last_resno);
|
||||||
@ -639,8 +642,8 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
case AND:
|
case AND:
|
||||||
{
|
{
|
||||||
Expr *expr = makeNode(Expr);
|
Expr *expr = makeNode(Expr);
|
||||||
Node *lexpr = transformExpr(pstate, a->lexpr);
|
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||||
Node *rexpr = transformExpr(pstate, a->rexpr);
|
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
|
||||||
if (exprType(lexpr) != BOOLOID)
|
if (exprType(lexpr) != BOOLOID)
|
||||||
elog(WARN,
|
elog(WARN,
|
||||||
"left-hand side of AND is type '%s', not bool",
|
"left-hand side of AND is type '%s', not bool",
|
||||||
@ -658,8 +661,8 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
case OR:
|
case OR:
|
||||||
{
|
{
|
||||||
Expr *expr = makeNode(Expr);
|
Expr *expr = makeNode(Expr);
|
||||||
Node *lexpr = transformExpr(pstate, a->lexpr);
|
Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
|
||||||
Node *rexpr = transformExpr(pstate, a->rexpr);
|
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
|
||||||
if (exprType(lexpr) != BOOLOID)
|
if (exprType(lexpr) != BOOLOID)
|
||||||
elog(WARN,
|
elog(WARN,
|
||||||
"left-hand side of OR is type '%s', not bool",
|
"left-hand side of OR is type '%s', not bool",
|
||||||
@ -677,7 +680,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
case NOT:
|
case NOT:
|
||||||
{
|
{
|
||||||
Expr *expr = makeNode(Expr);
|
Expr *expr = makeNode(Expr);
|
||||||
Node *rexpr = transformExpr(pstate, a->rexpr);
|
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
|
||||||
if (exprType(rexpr) != BOOLOID)
|
if (exprType(rexpr) != BOOLOID)
|
||||||
elog(WARN,
|
elog(WARN,
|
||||||
"argument to NOT is type '%s', not bool",
|
"argument to NOT is type '%s', not bool",
|
||||||
@ -692,24 +695,8 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_Ident: {
|
case T_Ident: {
|
||||||
Ident *ident = (Ident*)expr;
|
/* look for a column name or a relation name (the default behavior) */
|
||||||
RangeTblEntry *rte;
|
result = transformIdent(pstate, expr, precedence);
|
||||||
|
|
||||||
/* could be a column name or a relation_name */
|
|
||||||
if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL) {
|
|
||||||
ident->isRel = TRUE;
|
|
||||||
result = (Node*)ident;
|
|
||||||
}
|
|
||||||
else if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
|
|
||||||
{
|
|
||||||
Attr *att = makeNode(Attr);
|
|
||||||
|
|
||||||
att->relname = rte->refname;
|
|
||||||
att->attrs = lcons(makeString(ident->name), NIL);
|
|
||||||
result =
|
|
||||||
(Node*)handleNestedDots(pstate, att, &pstate->p_last_resno);
|
|
||||||
} else
|
|
||||||
elog(WARN, "attribute \"%s\" not found", ident->name);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case T_FuncCall: {
|
case T_FuncCall: {
|
||||||
@ -718,7 +705,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
|
|
||||||
/* transform the list of arguments */
|
/* transform the list of arguments */
|
||||||
foreach(args, fn->args)
|
foreach(args, fn->args)
|
||||||
lfirst(args) = transformExpr(pstate, (Node*)lfirst(args));
|
lfirst(args) = transformExpr(pstate, (Node*)lfirst(args), precedence);
|
||||||
result = ParseFunc(pstate,
|
result = ParseFunc(pstate,
|
||||||
fn->funcname, fn->args, &pstate->p_last_resno);
|
fn->funcname, fn->args, &pstate->p_last_resno);
|
||||||
break;
|
break;
|
||||||
@ -733,6 +720,49 @@ transformExpr(ParseState *pstate, Node *expr)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Node *
|
||||||
|
transformIdent(ParseState *pstate, Node *expr, int precedence)
|
||||||
|
{
|
||||||
|
Ident *ident = (Ident*)expr;
|
||||||
|
RangeTblEntry *rte;
|
||||||
|
Node *column_result, *relation_result, *result;
|
||||||
|
|
||||||
|
column_result = relation_result = result = 0;
|
||||||
|
/* try to find the ident as a column */
|
||||||
|
if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL) {
|
||||||
|
Attr *att = makeNode(Attr);
|
||||||
|
|
||||||
|
att->relname = rte->refname;
|
||||||
|
att->attrs = lcons(makeString(ident->name), NIL);
|
||||||
|
column_result =
|
||||||
|
(Node*)handleNestedDots(pstate, att, &pstate->p_last_resno);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to find the ident as a relation */
|
||||||
|
if (refnameRangeTableEntry(pstate->p_rtable, 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)
|
||||||
|
elog(WARN, "attribute \"%s\" not found", ident->name);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* From Clause
|
* From Clause
|
||||||
@ -1011,7 +1041,11 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
|
|
||||||
identname = ((Ident*)res->val)->name;
|
identname = ((Ident*)res->val)->name;
|
||||||
handleTargetColname(pstate, &res->name, NULL, res->name);
|
handleTargetColname(pstate, &res->name, NULL, res->name);
|
||||||
expr = transformExpr(pstate, (Node*)res->val);
|
|
||||||
|
/* here we want to look for column names only, not relation */
|
||||||
|
/* names (even though they can be stored in Ident nodes, */
|
||||||
|
/* too) */
|
||||||
|
expr = transformIdent(pstate, (Node*)res->val, EXPR_COLUMN_FIRST);
|
||||||
type_id = exprType(expr);
|
type_id = exprType(expr);
|
||||||
type_len = tlen(get_id_type(type_id));
|
type_len = tlen(get_id_type(type_id));
|
||||||
resname = (res->name) ? res->name : identname;
|
resname = (res->name) ? res->name : identname;
|
||||||
@ -1030,7 +1064,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
case T_FuncCall:
|
case T_FuncCall:
|
||||||
case T_A_Const:
|
case T_A_Const:
|
||||||
case T_A_Expr: {
|
case T_A_Expr: {
|
||||||
Node *expr = transformExpr(pstate, (Node *)res->val);
|
Node *expr = transformExpr(pstate, (Node *)res->val, EXPR_COLUMN_FIRST);
|
||||||
|
|
||||||
handleTargetColname(pstate, &res->name, NULL, NULL);
|
handleTargetColname(pstate, &res->name, NULL, NULL);
|
||||||
/* note indirection has not been transformed */
|
/* note indirection has not been transformed */
|
||||||
@ -1054,13 +1088,13 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
str = save_str = (char*)palloc(strlen(val) + MAXDIM * 25 + 2);
|
str = save_str = (char*)palloc(strlen(val) + MAXDIM * 25 + 2);
|
||||||
foreach(elt, res->indirection) {
|
foreach(elt, res->indirection) {
|
||||||
A_Indices *aind = (A_Indices *)lfirst(elt);
|
A_Indices *aind = (A_Indices *)lfirst(elt);
|
||||||
aind->uidx = transformExpr(pstate, aind->uidx);
|
aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
|
||||||
if (!IsA(aind->uidx,Const))
|
if (!IsA(aind->uidx,Const))
|
||||||
elog(WARN,
|
elog(WARN,
|
||||||
"Array Index for Append should be a constant");
|
"Array Index for Append should be a constant");
|
||||||
uindx[i] = ((Const *)aind->uidx)->constvalue;
|
uindx[i] = ((Const *)aind->uidx)->constvalue;
|
||||||
if (aind->lidx!=NULL) {
|
if (aind->lidx!=NULL) {
|
||||||
aind->lidx = transformExpr(pstate, aind->lidx);
|
aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
|
||||||
if (!IsA(aind->lidx,Const))
|
if (!IsA(aind->lidx,Const))
|
||||||
elog(WARN,
|
elog(WARN,
|
||||||
"Array Index for Append should be a constant");
|
"Array Index for Append should be a constant");
|
||||||
@ -1101,8 +1135,8 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
List *ilist = res->indirection;
|
List *ilist = res->indirection;
|
||||||
while (ilist!=NIL) {
|
while (ilist!=NIL) {
|
||||||
A_Indices *ind = lfirst(ilist);
|
A_Indices *ind = lfirst(ilist);
|
||||||
ind->lidx = transformExpr(pstate, ind->lidx);
|
ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
|
||||||
ind->uidx = transformExpr(pstate, ind->uidx);
|
ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
|
||||||
ilist = lnext(ilist);
|
ilist = lnext(ilist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1178,8 +1212,8 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
|||||||
List *ilist = att->indirection;
|
List *ilist = att->indirection;
|
||||||
while (ilist!=NIL) {
|
while (ilist!=NIL) {
|
||||||
A_Indices *ind = lfirst(ilist);
|
A_Indices *ind = lfirst(ilist);
|
||||||
ind->lidx = transformExpr(pstate, ind->lidx);
|
ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
|
||||||
ind->uidx = transformExpr(pstate, ind->uidx);
|
ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
|
||||||
ilist = lnext(ilist);
|
ilist = lnext(ilist);
|
||||||
}
|
}
|
||||||
result = (Node*)make_array_ref(result, att->indirection);
|
result = (Node*)make_array_ref(result, att->indirection);
|
||||||
@ -1390,7 +1424,7 @@ make_targetlist_expr(ParseState *pstate,
|
|||||||
tent->expr = expr;
|
tent->expr = expr;
|
||||||
|
|
||||||
return tent;
|
return tent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -1412,7 +1446,7 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
|
|||||||
if (a_expr == NULL)
|
if (a_expr == NULL)
|
||||||
return (Node *)NULL; /* no qualifiers */
|
return (Node *)NULL; /* no qualifiers */
|
||||||
|
|
||||||
qual = transformExpr(pstate, a_expr);
|
qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
|
||||||
if (exprType(qual) != BOOLOID) {
|
if (exprType(qual) != BOOLOID) {
|
||||||
elog(WARN,
|
elog(WARN,
|
||||||
"where clause must return type bool, not %s",
|
"where clause must return type bool, not %s",
|
||||||
@ -1633,7 +1667,7 @@ handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno)
|
|||||||
Node *retval = NULL;
|
Node *retval = NULL;
|
||||||
|
|
||||||
if (attr->paramNo != NULL) {
|
if (attr->paramNo != NULL) {
|
||||||
Param *param = (Param *)transformExpr(pstate, (Node*)attr->paramNo);
|
Param *param = (Param *)transformExpr(pstate, (Node*)attr->paramNo, EXPR_RELATION_FIRST);
|
||||||
|
|
||||||
retval =
|
retval =
|
||||||
ParseFunc(pstate, strVal(lfirst(attr->attrs)),
|
ParseFunc(pstate, strVal(lfirst(attr->attrs)),
|
||||||
|
Reference in New Issue
Block a user