summaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_relation.c
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>1997-11-25 22:07:18 +0000
committerBruce Momjian <bruce@momjian.us>1997-11-25 22:07:18 +0000
commit4a5b781d71b61887fd312112d75979f250bf723f (patch)
tree315803e512d9e978301311a92866a8b6f17a592d /src/backend/parser/parse_relation.c
parent3aff4011c735faa747ce94d20da6fd9f85144955 (diff)
downloadpostgresql-4a5b781d71b61887fd312112d75979f250bf723f.tar.gz
Break parser functions into smaller files, group together.
Diffstat (limited to 'src/backend/parser/parse_relation.c')
-rw-r--r--src/backend/parser/parse_relation.c480
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 0000000000..dd3fa2787a
--- /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);
+}