aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_node.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_node.c')
-rw-r--r--src/backend/parser/parse_node.c513
1 files changed, 513 insertions, 0 deletions
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
new file mode 100644
index 00000000000..c06e00888b9
--- /dev/null
+++ b/src/backend/parser/parse_node.c
@@ -0,0 +1,513 @@
+/*-------------------------------------------------------------------------
+ *
+ * parse_node.c--
+ * various routines that make nodes for query plans
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.1 1997/11/25 22:05:42 momjian Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <ctype.h>
+#include <string.h>
+
+#include "postgres.h"
+#include "fmgr.h"
+#include "access/heapam.h"
+#include "catalog/pg_operator.h"
+#include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_oper.h"
+#include "parser/parse_node.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_type.h"
+#include "utils/builtins.h"
+#include "utils/syscache.h"
+
+#ifdef 0
+#include "access/tupmacs.h"
+#include "utils/elog.h"
+#include "utils/palloc.h"
+#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */
+#include "utils/rel.h" /* Relation stuff */
+
+#include "utils/syscache.h"
+
+#include "nodes/pg_list.h"
+#include "nodes/primnodes.h"
+#include "nodes/parsenodes.h"
+#endif
+
+/*
+ * make_parsestate() --
+ * allocate and initialize a new ParseState.
+ * the CALLERS is responsible for freeing the ParseState* returned
+ *
+ */
+
+ParseState *
+make_parsestate(void)
+{
+ ParseState *pstate;
+
+ pstate = malloc(sizeof(ParseState));
+ pstate->p_last_resno = 1;
+ pstate->p_rtable = NIL;
+ pstate->p_numAgg = 0;
+ pstate->p_aggs = NIL;
+ pstate->p_is_insert = false;
+ pstate->p_insert_columns = NIL;
+ pstate->p_is_update = false;
+ pstate->p_is_rule = false;
+ pstate->p_in_where_clause = false;
+ pstate->p_target_relation = NULL;
+ pstate->p_target_rangetblentry = NULL;
+
+ return (pstate);
+}
+
+Node *
+make_operand(char *opname,
+ Node *tree,
+ Oid orig_typeId,
+ Oid true_typeId)
+{
+ Node *result;
+ Type true_type;
+ Datum val;
+ Oid infunc;
+
+ if (tree != NULL)
+ {
+ result = tree;
+ true_type = typeidType(true_typeId);
+ disallow_setop(opname, true_type, result);
+ if (true_typeId != orig_typeId)
+ { /* must coerce */
+ Const *con = (Const *) result;
+
+ Assert(nodeTag(result) == T_Const);
+ val = (Datum) textout((struct varlena *)
+ con->constvalue);
+ infunc = typeidRetinfunc(true_typeId);
+ con = makeNode(Const);
+ con->consttype = true_typeId;
+ con->constlen = typeLen(true_type);
+ con->constvalue = (Datum) fmgr(infunc,
+ val,
+ typeidTypElem(true_typeId),
+ -1 /* for varchar() type */ );
+ con->constisnull = false;
+ con->constbyval = true;
+ con->constisset = false;
+ result = (Node *) con;
+ }
+ }
+ else
+ {
+ Const *con = makeNode(Const);
+
+ con->consttype = true_typeId;
+ con->constlen = 0;
+ con->constvalue = (Datum) (struct varlena *) NULL;
+ con->constisnull = true;
+ con->constbyval = true;
+ con->constisset = false;
+ result = (Node *) con;
+ }
+
+ return result;
+}
+
+
+void
+disallow_setop(char *op, Type optype, Node *operand)
+{
+ if (operand == NULL)
+ return;
+
+ if (nodeTag(operand) == T_Iter)
+ {
+ elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
+ op, typeTypeName(optype));
+ elog(WARN, "but '%s' takes single values, not sets.",
+ op);
+ }
+}
+
+Expr *
+make_op(char *opname, Node *ltree, Node *rtree)
+{
+ Oid ltypeId,
+ rtypeId;
+ Operator temp;
+ OperatorTupleForm opform;
+ Oper *newop;
+ Node *left,
+ *right;
+ Expr *result;
+
+ if (rtree == NULL)
+ {
+
+ /* right operator */
+ ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
+ temp = right_oper(opname, ltypeId);
+ opform = (OperatorTupleForm) GETSTRUCT(temp);
+ left = make_operand(opname, ltree, ltypeId, opform->oprleft);
+ right = NULL;
+
+ }
+ else if (ltree == NULL)
+ {
+
+ /* left operator */
+ rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
+ temp = left_oper(opname, rtypeId);
+ opform = (OperatorTupleForm) GETSTRUCT(temp);
+ right = make_operand(opname, rtree, rtypeId, opform->oprright);
+ left = NULL;
+
+ }
+ else
+ {
+ char *outstr;
+ Oid infunc,
+ outfunc;
+ Type newtype;
+
+#define CONVERTABLE_TYPE(t) ( (t) == INT2OID || \
+ (t) == INT4OID || \
+ (t) == OIDOID || \
+ (t) == FLOAT4OID || \
+ (t) == FLOAT8OID || \
+ (t) == CASHOID)
+
+ /* binary operator */
+ ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
+ rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
+
+ /*
+ * convert constant when using a const of a numeric type and a
+ * non-const of another numeric type
+ */
+ if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
+ CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
+ !((Const *) rtree)->constiscast)
+ {
+ outfunc = typeidRetoutfunc(rtypeId);
+ infunc = typeidRetinfunc(ltypeId);
+ outstr = (char *) fmgr(outfunc, ((Const *) rtree)->constvalue);
+ ((Const *) rtree)->constvalue = (Datum) fmgr(infunc, outstr);
+ pfree(outstr);
+ ((Const *) rtree)->consttype = rtypeId = ltypeId;
+ newtype = typeidType(rtypeId);
+ ((Const *) rtree)->constlen = typeLen(newtype);
+ ((Const *) rtree)->constbyval = typeByVal(newtype);
+ }
+
+ if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
+ CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
+ !((Const *) ltree)->constiscast)
+ {
+ outfunc = typeidRetoutfunc(ltypeId);
+ infunc = typeidRetinfunc(rtypeId);
+ outstr = (char *) fmgr(outfunc, ((Const *) ltree)->constvalue);
+ ((Const *) ltree)->constvalue = (Datum) fmgr(infunc, outstr);
+ pfree(outstr);
+ ((Const *) ltree)->consttype = ltypeId = rtypeId;
+ newtype = typeidType(ltypeId);
+ ((Const *) ltree)->constlen = typeLen(newtype);
+ ((Const *) ltree)->constbyval = typeByVal(newtype);
+ }
+
+ temp = oper(opname, ltypeId, rtypeId, false);
+ opform = (OperatorTupleForm) GETSTRUCT(temp);
+ left = make_operand(opname, ltree, ltypeId, opform->oprleft);
+ right = make_operand(opname, rtree, rtypeId, opform->oprright);
+ }
+
+ newop = makeOper(oprid(temp), /* opno */
+ InvalidOid,/* opid */
+ opform->oprresult, /* operator result type */
+ 0,
+ NULL);
+
+ result = makeNode(Expr);
+ result->typeOid = opform->oprresult;
+ result->opType = OP_EXPR;
+ result->oper = (Node *) newop;
+
+ if (!left)
+ {
+ result->args = lcons(right, NIL);
+ }
+ else if (!right)
+ {
+ result->args = lcons(left, NIL);
+ }
+ else
+ {
+ result->args = lcons(left, lcons(right, NIL));
+ }
+
+ return result;
+}
+
+Var *
+make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
+{
+ Var *varnode;
+ int vnum,
+ attid;
+ Oid vartypeid;
+ Relation rd;
+ RangeTblEntry *rte;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE);
+
+ vnum = refnameRangeTablePosn(pstate->p_rtable, refname);
+
+ rd = heap_open(rte->relid);
+
+ attid = attnameAttNum(rd, attrname); /* could elog(WARN) */
+ vartypeid = attnumTypeId(rd, attid);
+
+ varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
+
+ heap_close(rd);
+
+ *type_id = vartypeid;
+ return varnode;
+}
+
+/*
+ * make_array_ref() -- Make an array reference node.
+ *
+ * Array references can hang off of arbitrary nested dot (or
+ * function invocation) expressions. This routine takes a
+ * tree generated by ParseFunc() and an array index and
+ * generates a new array reference tree. We do some simple
+ * typechecking to be sure the dereference is valid in the
+ * type system, but we don't do any bounds checking here.
+ *
+ * indirection is a list of A_Indices
+ */
+ArrayRef *
+make_array_ref(Node *expr,
+ List *indirection)
+{
+ Oid typearray;
+ HeapTuple type_tuple;
+ TypeTupleForm type_struct_array,
+ type_struct_element;
+ ArrayRef *aref;
+ Oid reftype;
+ List *upperIndexpr = NIL;
+ List *lowerIndexpr = NIL;
+
+ typearray = exprType(expr);
+
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typearray),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ /* get the array type struct from the type tuple */
+ type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ if (type_struct_array->typelem == InvalidOid)
+ {
+ elog(WARN, "make_array_ref: type %s is not an array",
+ (Name) &(type_struct_array->typname.data[0]));
+ }
+
+ /* get the type tuple for the element type */
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_struct_array->typelem),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ while (indirection != NIL)
+ {
+ A_Indices *ind = lfirst(indirection);
+
+ if (ind->lidx)
+ {
+
+ /*
+ * XXX assumes all lower indices non null in this case
+ */
+ lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
+ }
+ upperIndexpr = lappend(upperIndexpr, ind->uidx);
+ indirection = lnext(indirection);
+ }
+ aref = makeNode(ArrayRef);
+ aref->refattrlength = type_struct_array->typlen;
+ aref->refelemlength = type_struct_element->typlen;
+ aref->refelemtype = type_struct_array->typelem;
+ aref->refelembyval = type_struct_element->typbyval;
+ aref->refupperindexpr = upperIndexpr;
+ aref->reflowerindexpr = lowerIndexpr;
+ aref->refexpr = expr;
+ aref->refassgnexpr = NULL;
+
+ if (lowerIndexpr == NIL) /* accessing a single array element */
+ reftype = aref->refelemtype;
+ else
+/* request to clip a part of the array, the result is another array */
+ reftype = typearray;
+
+ /*
+ * we change it to reflect the true type; since the original
+ * refelemtype doesn't seem to get used anywhere. - ay 10/94
+ */
+ aref->refelemtype = reftype;
+
+ return aref;
+}
+
+ArrayRef *
+make_array_set(Expr *target_expr,
+ List *upperIndexpr,
+ List *lowerIndexpr,
+ Expr *expr)
+{
+ Oid typearray;
+ HeapTuple type_tuple;
+ TypeTupleForm type_struct_array;
+ TypeTupleForm type_struct_element;
+ ArrayRef *aref;
+ Oid reftype;
+
+ typearray = exprType((Node *) target_expr);
+
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typearray),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ /* get the array type struct from the type tuple */
+ type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ if (type_struct_array->typelem == InvalidOid)
+ {
+ elog(WARN, "make_array_ref: type %s is not an array",
+ (Name) &(type_struct_array->typname.data[0]));
+ }
+ /* get the type tuple for the element type */
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_struct_array->typelem),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ aref = makeNode(ArrayRef);
+ aref->refattrlength = type_struct_array->typlen;
+ aref->refelemlength = type_struct_element->typlen;
+ aref->refelemtype = type_struct_array->typelem;
+ aref->refelembyval = type_struct_element->typbyval;
+ aref->refupperindexpr = upperIndexpr;
+ aref->reflowerindexpr = lowerIndexpr;
+ aref->refexpr = (Node *) target_expr;
+ aref->refassgnexpr = (Node *) expr;
+
+ if (lowerIndexpr == NIL) /* accessing a single array element */
+ reftype = aref->refelemtype;
+ else
+/* request to set a part of the array, by another array */
+ reftype = typearray;
+
+ aref->refelemtype = reftype;
+
+ return aref;
+}
+
+/*
+ *
+ * make_const -
+ *
+ * - takes a lispvalue, (as returned to the yacc routine by the lexer)
+ * extracts the type, and makes the appropriate type constant
+ * by invoking the (c-callable) lisp routine c-make-const
+ * via the lisp_call() mechanism
+ *
+ * eventually, produces a "const" lisp-struct as per nodedefs.cl
+ */
+Const *
+make_const(Value *value)
+{
+ Type tp;
+ Datum val;
+ Const *con;
+
+ switch (nodeTag(value))
+ {
+ case T_Integer:
+ tp = typeidType(INT4OID);
+ val = Int32GetDatum(intVal(value));
+ break;
+
+ case T_Float:
+ {
+ float64 dummy;
+
+ tp = typeidType(FLOAT8OID);
+
+ dummy = (float64) palloc(sizeof(float64data));
+ *dummy = floatVal(value);
+
+ val = Float64GetDatum(dummy);
+ }
+ break;
+
+ case T_String:
+ tp = typeidType(UNKNOWNOID); /* unknown for now, will be type
+ * coerced */
+ val = PointerGetDatum(textin(strVal(value)));
+ break;
+
+ case T_Null:
+ default:
+ {
+ if (nodeTag(value) != T_Null)
+ elog(NOTICE, "unknown type : %d\n", nodeTag(value));
+
+ /* null const */
+ con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
+ return con;
+ }
+ }
+
+ con = makeConst(typeTypeId(tp),
+ typeLen(tp),
+ val,
+ false,
+ typeByVal(tp),
+ false, /* not a set */
+ false);
+
+ return (con);
+}
+