diff options
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r-- | src/backend/parser/parse_relation.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c new file mode 100644 index 00000000000..dd3fa2787a1 --- /dev/null +++ b/src/backend/parser/parse_relation.c @@ -0,0 +1,480 @@ +/*------------------------------------------------------------------------- + * + * 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.1 1997/11/25 22:05:45 momjian Exp $ + * + *------------------------------------------------------------------------- + */ +#include <ctype.h> +#include <string.h> + +#include "postgres.h" +#include "access/heapam.h" +#include <access/htup.h> +#include <catalog/pg_type.h> +#include "nodes/makefuncs.h" +#include <parser/parse_relation.h> +#include <utils/acl.h> +#include "utils/builtins.h" +#include <utils/lsyscache.h> + +#ifdef 0 +#include "fmgr.h" +#include "access/tupmacs.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */ + +#include "utils/syscache.h" +#include "catalog/pg_operator.h" + +#include "nodes/pg_list.h" +#include "nodes/primnodes.h" +#include "nodes/parsenodes.h" +#endif + +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(List *rtable, char *refname) +{ + List *temp; + + foreach(temp, rtable) + { + RangeTblEntry *rte = lfirst(temp); + + if (!strcmp(rte->refname, refname)) + return rte; + } + return NULL; +} + +/* given refname, return id of variable; position starts with 1 */ +int +refnameRangeTablePosn(List *rtable, char *refname) +{ + int index; + List *temp; + + index = 1; + foreach(temp, rtable) + { + RangeTblEntry *rte = lfirst(temp); + + if (!strcmp(rte->refname, refname)) + return index; + index++; + } + return (0); +} + +/* + * returns range entry if found, else NULL + */ +RangeTblEntry * +colnameRangeTableEntry(ParseState *pstate, char *colname) +{ + List *et; + List *rtable; + RangeTblEntry *rte_result; + + if (pstate->p_is_rule) + rtable = lnext(lnext(pstate->p_rtable)); + else + rtable = pstate->p_rtable; + + rte_result = NULL; + 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(WARN, "Column %s is ambiguous", colname); + } + else + rte_result = rte; + } + } + 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); + + if (pstate != NULL && + refnameRangeTableEntry(pstate->p_rtable, refname) != NULL) + elog(WARN, "Table name %s specified more than once", refname); + + rte->relname = pstrdup(relname); + rte->refname = pstrdup(refname); + + relation = heap_openr(relname); + if (relation == NULL) + { + elog(WARN, "%s: %s", + relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]); + } + + /* + * 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->relid = RelationGetRelationId(relation); + + rte->inFromCl = inFromCl; + + /* + * close the relation we're done with it for now. + */ + if (pstate != NULL) + pstate->p_rtable = lappend(pstate->p_rtable, rte); + + heap_close(relation); + + return rte; +} + +/* + * expandAll - + * makes a list of attributes + * assumes reldesc caching works + */ +List * +expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno) +{ + Relation rdesc; + List *te_tail = NIL, + *te_head = NIL; + Var *varnode; + int varattno, + maxattrs; + Oid type_id; + int type_len; + RangeTblEntry *rte; + + rte = refnameRangeTableEntry(pstate->p_rtable, refname); + if (rte == NULL) + rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE); + + rdesc = heap_open(rte->relid); + + if (rdesc == NULL) + { + elog(WARN, "Unable to expand all -- heap_open failed on %s", + rte->refname); + return NIL; + } + maxattrs = RelationGetNumberOfAttributes(rdesc); + + for (varattno = 0; varattno <= maxattrs - 1; varattno++) + { + char *attrname; + char *resname = NULL; + TargetEntry *te = makeNode(TargetEntry); + + attrname = pstrdup((rdesc->rd_att->attrs[varattno]->attname).data); + varnode = (Var *) make_var(pstate, refname, attrname, &type_id); + type_len = (int) typeLen(typeidType(type_id)); + + handleTargetColname(pstate, &resname, refname, attrname); + if (resname != NULL) + attrname = resname; + + /* + * Even if the elements making up a set are complex, the set + * itself is not. + */ + + te->resdom = makeResdom((AttrNumber) (*this_resno)++, + type_id, + (Size) type_len, + attrname, + (Index) 0, + (Oid) 0, + 0); + te->expr = (Node *) varnode; + if (te_head == NIL) + te_head = te_tail = lcons(te, NIL); + else + te_tail = lappend(te_tail, te); + } + + heap_close(rdesc); + return (te_head); +} + +/* given relation and att name, return id of variable */ +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(WARN, "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. + */ +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(rd->rd_id, name)); +} + +/*------------- + * given an attribute number and a relation, return its relation name + */ +char * +attnumAttName(Relation rd, int attrno) +{ + char *name; + int i; + + if (attrno < 0) + { + for (i = 0; i < SPECIALS; i++) + { + if (special_attr[i].code == attrno) + { + name = special_attr[i].field; + return (name); + } + } + elog(WARN, "Illegal attr no %d for relation %s", + attrno, RelationGetRelationName(rd)); + } + else if (attrno >= 1 && attrno <= RelationGetNumberOfAttributes(rd)) + { + name = (rd->rd_att->attrs[attrno - 1]->attname).data; + return (name); + } + else + { + elog(WARN, "Illegal attr no %d for relation %s", + attrno, RelationGetRelationName(rd)); + } + + /* + * Shouldn't get here, but we want lint to be happy... + */ + + return (NULL); +} + +int +attnumAttNelems(Relation rd, int attid) +{ + return (rd->rd_att->attrs[attid - 1]->attnelems); +} + +Oid +attnameTypeId(Oid relid, char *attrname) +{ + int attid; + Oid vartype; + Relation rd; + + rd = heap_open(relid); + if (!RelationIsValid(rd)) + { + rd = heap_openr(typeidTypeName(relid)); + if (!RelationIsValid(rd)) + elog(WARN, "cannot compute type of att %s for relid %d", + attrname, relid); + } + + attid = attnameAttNum(rd, attrname); /* could elog(WARN) and never return */ + + vartype = attnumTypeId(rd, attid); + + /* + * close relation we're done with it now + */ + heap_close(rd); + + return (vartype); +} + +/* given attribute id, return type of that attribute */ +/* XXX Special case for pseudo-attributes is a hack */ +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); +} + +/* + * handleTargetColname - + * use column names from insert + */ +void +handleTargetColname(ParseState *pstate, char **resname, + char *refname, char *colname) +{ + if (pstate->p_is_insert) + { + if (pstate->p_insert_columns != NIL) + { + Ident *id = lfirst(pstate->p_insert_columns); + + *resname = id->name; + pstate->p_insert_columns = lnext(pstate->p_insert_columns); + } + else + elog(WARN, "insert: more expressions than target columns"); + } + if (pstate->p_is_insert || pstate->p_is_update) + checkTargetTypes(pstate, *resname, refname, colname); +} + +/* + * checkTargetTypes - + * checks value and target column types + */ +void +checkTargetTypes(ParseState *pstate, char *target_colname, + char *refname, char *colname) +{ + Oid attrtype_id, + attrtype_target; + int resdomno_id, + resdomno_target; + Relation rd; + RangeTblEntry *rte; + + if (target_colname == NULL || colname == NULL) + return; + + if (refname != NULL) + rte = refnameRangeTableEntry(pstate->p_rtable, refname); + else + { + rte = colnameRangeTableEntry(pstate, colname); + if (rte == (RangeTblEntry *) NULL) + elog(WARN, "attribute %s not found", colname); + refname = rte->refname; + } + +/* + if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry) + elog(WARN, "%s not available in this context", colname); +*/ + rd = heap_open(rte->relid); + + resdomno_id = attnameAttNum(rd, colname); + attrtype_id = attnumTypeId(rd, resdomno_id); + + resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname); + attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target); + + if (attrtype_id != attrtype_target) + elog(WARN, "Type of %s does not match target column %s", + colname, target_colname); + + if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) && + rd->rd_att->attrs[resdomno_id - 1]->attlen != + pstate->p_target_relation->rd_att->attrs[resdomno_target - 1]->attlen) + elog(WARN, "Length of %s does not match length of target column %s", + colname, target_colname); + + heap_close(rd); +} |