1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00
Files
postgres/src/backend/parser/parse_relation.c
Tom Lane 7f76eab140 Rewrite parser's handling of INSERT ... SELECT so that processing
of the SELECT part of the statement is just like a plain SELECT.  All
INSERT-specific processing happens after the SELECT parsing is done.
This eliminates many problems, e.g. INSERT ... SELECT ... GROUP BY using
the wrong column labels.  Ensure that DEFAULT clauses are coerced to
the target column type, whether or not stored clause produces the right
type.  Substantial cleanup of parser's array support.
1999-07-19 00:26:20 +00:00

368 lines
7.7 KiB
C

/*-------------------------------------------------------------------------
*
* parse_relation.c
* parser support routines dealing with relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.26 1999/07/19 00:26:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "parser/parse_coerce.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
static struct
{
char *field;
int code;
} special_attr[] =
{
{
"ctid", SelfItemPointerAttributeNumber
},
{
"oid", ObjectIdAttributeNumber
},
{
"xmin", MinTransactionIdAttributeNumber
},
{
"cmin", MinCommandIdAttributeNumber
},
{
"xmax", MaxTransactionIdAttributeNumber
},
{
"cmax", MaxCommandIdAttributeNumber
},
};
#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
static char *attnum_type[SPECIALS] = {
"tid",
"oid",
"xid",
"cid",
"xid",
"cid",
};
/* given refname, return a pointer to the range table entry */
RangeTblEntry *
refnameRangeTableEntry(ParseState *pstate, char *refname)
{
List *temp;
while (pstate != NULL)
{
foreach(temp, pstate->p_rtable)
{
RangeTblEntry *rte = lfirst(temp);
if (!strcmp(rte->refname, refname))
return rte;
}
/* only allow correlated columns in WHERE clause */
if (pstate->p_in_where_clause)
pstate = pstate->parentParseState;
else
break;
}
return NULL;
}
/* given refname, return id of variable; position starts with 1 */
int
refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up)
{
int index;
List *temp;
if (sublevels_up)
*sublevels_up = 0;
while (pstate != NULL)
{
index = 1;
foreach(temp, pstate->p_rtable)
{
RangeTblEntry *rte = lfirst(temp);
if (!strcmp(rte->refname, refname))
return index;
index++;
}
/* only allow correlated columns in WHERE clause */
if (pstate->p_in_where_clause)
{
pstate = pstate->parentParseState;
if (sublevels_up)
(*sublevels_up)++;
}
else
break;
}
return 0;
}
/*
* returns range entry if found, else NULL
*/
RangeTblEntry *
colnameRangeTableEntry(ParseState *pstate, char *colname)
{
List *et;
List *rtable;
RangeTblEntry *rte_result;
rte_result = NULL;
while (pstate != NULL)
{
if (pstate->p_is_rule)
rtable = lnext(lnext(pstate->p_rtable));
else
rtable = pstate->p_rtable;
foreach(et, rtable)
{
RangeTblEntry *rte = lfirst(et);
/* only entries on outer(non-function?) scope */
if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
continue;
if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
{
if (rte_result != NULL)
{
if (!pstate->p_is_insert ||
rte != pstate->p_target_rangetblentry)
elog(ERROR, "Column '%s' is ambiguous", colname);
}
else
rte_result = rte;
}
}
/* only allow correlated columns in WHERE clause */
if (pstate->p_in_where_clause && rte_result == NULL)
pstate = pstate->parentParseState;
else
break;
}
return rte_result;
}
/*
* put new entry in pstate p_rtable structure, or return pointer
* if pstate null
*/
RangeTblEntry *
addRangeTableEntry(ParseState *pstate,
char *relname,
char *refname,
bool inh,
bool inFromCl)
{
Relation relation;
RangeTblEntry *rte = makeNode(RangeTblEntry);
int sublevels_up;
if (pstate != NULL)
{
if (refnameRangeTablePosn(pstate, refname, &sublevels_up) != 0 &&
(!inFromCl || sublevels_up == 0))
{
if (!strcmp(refname, "*CURRENT*") || !strcmp(refname, "*NEW*"))
{
int rt_index = refnameRangeTablePosn(pstate, refname, &sublevels_up);
return (RangeTblEntry *) nth(rt_index - 1, pstate->p_rtable);
}
elog(ERROR, "Table name '%s' specified more than once", refname);
}
}
rte->relname = pstrdup(relname);
rte->refname = pstrdup(refname);
relation = heap_openr(relname);
if (relation == NULL)
elog(ERROR, "%s: %s",
relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
rte->relid = RelationGetRelid(relation);
heap_close(relation);
/*
* Flags - zero or more from inheritance,union,version or recursive
* (transitive closure) [we don't support them all -- ay 9/94 ]
*/
rte->inh = inh;
/* RelOID */
rte->inFromCl = inFromCl;
/*
* close the relation we're done with it for now.
*/
if (pstate != NULL)
pstate->p_rtable = lappend(pstate->p_rtable, rte);
return rte;
}
/*
* expandAll -
* makes a list of attributes
*/
List *
expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
{
List *te_list = NIL;
RangeTblEntry *rte;
Relation rel;
int varattno,
maxattrs;
rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL)
rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE);
rel = heap_open(rte->relid);
if (rel == NULL)
elog(ERROR, "Unable to expand all -- heap_open failed on %s",
rte->refname);
maxattrs = RelationGetNumberOfAttributes(rel);
for (varattno = 0; varattno < maxattrs; varattno++)
{
char *attrname;
Var *varnode;
TargetEntry *te = makeNode(TargetEntry);
attrname = pstrdup(rel->rd_att->attrs[varattno]->attname.data);
varnode = make_var(pstate, rte->relid, refname, attrname);
/*
* Even if the elements making up a set are complex, the set
* itself is not.
*/
te->resdom = makeResdom((AttrNumber) (*this_resno)++,
varnode->vartype,
varnode->vartypmod,
attrname,
(Index) 0,
(Oid) 0,
false);
te->expr = (Node *) varnode;
te_list = lappend(te_list, te);
}
heap_close(rel);
return te_list;
}
/*
* given relation and att name, return id of variable
*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version get_attnum()
* for access to non-opened relations.
*/
int
attnameAttNum(Relation rd, char *a)
{
int i;
for (i = 0; i < rd->rd_rel->relnatts; i++)
if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
return i + 1;
for (i = 0; i < SPECIALS; i++)
if (!strcmp(special_attr[i].field, a))
return special_attr[i].code;
/* on failure */
elog(ERROR, "Relation '%s' does not have attribute '%s'",
RelationGetRelationName(rd), a);
return 0; /* lint */
}
/*
* Given range variable, return whether attribute of this name
* is a set.
* NOTE the ASSUMPTION here that no system attributes are, or ever
* will be, sets.
*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version get_attisset()
* for access to non-opened relations.
*/
bool
attnameIsSet(Relation rd, char *name)
{
int i;
/* First check if this is a system attribute */
for (i = 0; i < SPECIALS; i++)
{
if (!strcmp(special_attr[i].field, name))
{
return false; /* no sys attr is a set */
}
}
return get_attisset(RelationGetRelid(rd), name);
}
/*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version
* for access to non-opened relations.
*/
int
attnumAttNelems(Relation rd, int attid)
{
return rd->rd_att->attrs[attid - 1]->attnelems;
}
/* given attribute id, return type of that attribute */
/*
* This should only be used if the relation is already
* heap_open()'ed. Use the cache version get_atttype()
* for access to non-opened relations.
*/
Oid
attnumTypeId(Relation rd, int attid)
{
if (attid < 0)
return typeTypeId(typenameType(attnum_type[-attid - 1]));
/*
* -1 because varattno (where attid comes from) returns one more than
* index
*/
return rd->rd_att->attrs[attid - 1]->atttypid;
}