diff options
Diffstat (limited to 'src/backend/parser/parse_node.c')
-rw-r--r-- | src/backend/parser/parse_node.c | 514 |
1 files changed, 0 insertions, 514 deletions
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c deleted file mode 100644 index 652ab54d2a9..00000000000 --- a/src/backend/parser/parse_node.c +++ /dev/null @@ -1,514 +0,0 @@ -/*------------------------------------------------------------------------- - * - * parse_node.c - * various routines that make nodes for query plans - * - * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - * - * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.66 2002/06/20 20:29:33 momjian Exp $ - * - *------------------------------------------------------------------------- - */ -#include "postgres.h" - -#include <ctype.h> -#include <errno.h> -#include <float.h> - -#include "access/heapam.h" -#include "catalog/pg_operator.h" -#include "catalog/pg_type.h" -#include "fmgr.h" -#include "nodes/makefuncs.h" -#include "parser/parsetree.h" -#include "parser/parse_coerce.h" -#include "parser/parse_expr.h" -#include "parser/parse_node.h" -#include "parser/parse_oper.h" -#include "parser/parse_relation.h" -#include "parser/parse_target.h" -#include "parser/parse_type.h" -#include "utils/builtins.h" -#include "utils/varbit.h" -#include "utils/lsyscache.h" -#include "utils/syscache.h" - -static bool fitsInFloat(Value *value); - - -/* make_parsestate() - * Allocate and initialize a new ParseState. - * The CALLER is responsible for freeing the ParseState* returned. - */ -ParseState * -make_parsestate(ParseState *parentParseState) -{ - ParseState *pstate; - - pstate = palloc(sizeof(ParseState)); - MemSet(pstate, 0, sizeof(ParseState)); - - pstate->parentParseState = parentParseState; - pstate->p_last_resno = 1; - - return pstate; -} - - -/* make_operand() - * Ensure argument type match by forcing conversion of constants. - */ -Node * -make_operand(Node *tree, Oid orig_typeId, Oid target_typeId) -{ - Node *result; - - if (tree != NULL) - { - /* must coerce? */ - if (target_typeId != orig_typeId) - result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1, - false); - else - result = tree; - } - else - { - /* otherwise, this is a NULL value */ - result = (Node *) makeNullConst(target_typeId); - } - - return result; -} /* make_operand() */ - - -/* make_op() - * Operator construction. - * - * Transform operator expression ensuring type compatibility. - * This is where some type conversion happens. - */ -Expr * -make_op(List *opname, Node *ltree, Node *rtree) -{ - Oid ltypeId, - rtypeId; - Operator tup; - Form_pg_operator opform; - Oper *newop; - Node *left, - *right; - Expr *result; - - ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree); - rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree); - - /* right operator? */ - if (rtree == NULL) - { - tup = right_oper(opname, ltypeId, false); - opform = (Form_pg_operator) GETSTRUCT(tup); - left = make_operand(ltree, ltypeId, opform->oprleft); - right = NULL; - } - - /* left operator? */ - else if (ltree == NULL) - { - tup = left_oper(opname, rtypeId, false); - opform = (Form_pg_operator) GETSTRUCT(tup); - right = make_operand(rtree, rtypeId, opform->oprright); - left = NULL; - } - - /* otherwise, binary operator */ - else - { - tup = oper(opname, ltypeId, rtypeId, false); - opform = (Form_pg_operator) GETSTRUCT(tup); - left = make_operand(ltree, ltypeId, opform->oprleft); - right = make_operand(rtree, rtypeId, opform->oprright); - } - - newop = makeOper(oprid(tup), /* opno */ - InvalidOid, /* opid */ - opform->oprresult, /* opresulttype */ - get_func_retset(opform->oprcode)); /* opretset */ - - result = makeNode(Expr); - result->typeOid = opform->oprresult; - result->opType = OP_EXPR; - result->oper = (Node *) newop; - - if (!left) - result->args = makeList1(right); - else if (!right) - result->args = makeList1(left); - else - result->args = makeList2(left, right); - - ReleaseSysCache(tup); - - return result; -} /* make_op() */ - - -/* - * make_var - * Build a Var node for an attribute identified by RTE and attrno - */ -Var * -make_var(ParseState *pstate, RangeTblEntry *rte, int attrno) -{ - int vnum, - sublevels_up; - Oid vartypeid; - int32 type_mod; - - vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); - get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod); - return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up); -} - -/* - * transformArraySubscripts() - * Transform array subscripting. This is used for both - * array fetch and array assignment. - * - * In an array fetch, we are given a source array value and we produce an - * expression that represents the result of extracting a single array element - * or an array slice. - * - * In an array assignment, we are given a destination array value plus a - * source value that is to be assigned to a single element or a slice of - * that array. We produce an expression that represents the new array value - * with the source data inserted into the right part of the array. - * - * pstate Parse state - * arrayBase Already-transformed expression for the array as a whole - * (may be NULL if we are handling an INSERT) - * arrayType OID of array's datatype - * indirection Untransformed list of subscripts (must not be NIL) - * forceSlice If true, treat subscript as array slice in all cases - * assignFrom NULL for array fetch, else transformed expression for source. - */ -ArrayRef * -transformArraySubscripts(ParseState *pstate, - Node *arrayBase, - Oid arrayType, - List *indirection, - bool forceSlice, - Node *assignFrom) -{ - Oid elementType, - resultType; - HeapTuple type_tuple_array, - type_tuple_element; - Form_pg_type type_struct_array, - type_struct_element; - bool isSlice = forceSlice; - List *upperIndexpr = NIL; - List *lowerIndexpr = NIL; - List *idx; - ArrayRef *aref; - - /* Get the type tuple for the array */ - type_tuple_array = SearchSysCache(TYPEOID, - ObjectIdGetDatum(arrayType), - 0, 0, 0); - if (!HeapTupleIsValid(type_tuple_array)) - elog(ERROR, "transformArraySubscripts: Cache lookup failed for array type %u", - arrayType); - type_struct_array = (Form_pg_type) GETSTRUCT(type_tuple_array); - - elementType = type_struct_array->typelem; - if (elementType == InvalidOid) - elog(ERROR, "transformArraySubscripts: type %s is not an array", - NameStr(type_struct_array->typname)); - - /* Get the type tuple for the array element type */ - type_tuple_element = SearchSysCache(TYPEOID, - ObjectIdGetDatum(elementType), - 0, 0, 0); - if (!HeapTupleIsValid(type_tuple_element)) - elog(ERROR, "transformArraySubscripts: Cache lookup failed for array element type %u", - elementType); - type_struct_element = (Form_pg_type) GETSTRUCT(type_tuple_element); - - /* - * A list containing only single subscripts refers to a single array - * element. If any of the items are double subscripts (lower:upper), - * then the subscript expression means an array slice operation. In - * this case, we supply a default lower bound of 1 for any items that - * contain only a single subscript. The forceSlice parameter forces us - * to treat the operation as a slice, even if no lower bounds are - * mentioned. Otherwise, we have to prescan the indirection list to - * see if there are any double subscripts. - */ - if (!isSlice) - { - foreach(idx, indirection) - { - A_Indices *ai = (A_Indices *) lfirst(idx); - - if (ai->lidx != NULL) - { - isSlice = true; - break; - } - } - } - - /* - * The type represented by the subscript expression is the element - * type if we are fetching a single element, but it is the same as the - * array type if we are fetching a slice or storing. - */ - if (isSlice || assignFrom != NULL) - resultType = arrayType; - else - resultType = elementType; - - /* - * Transform the subscript expressions. - */ - foreach(idx, indirection) - { - A_Indices *ai = (A_Indices *) lfirst(idx); - Node *subexpr; - - if (isSlice) - { - if (ai->lidx) - { - subexpr = transformExpr(pstate, ai->lidx); - /* If it's not int4 already, try to coerce */ - subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr), - INT4OID, -1, false); - if (subexpr == NULL) - elog(ERROR, "array index expressions must be integers"); - } - else - { - /* Make a constant 1 */ - subexpr = (Node *) makeConst(INT4OID, - sizeof(int32), - Int32GetDatum(1), - false, - true, /* pass by value */ - false, - false); - } - lowerIndexpr = lappend(lowerIndexpr, subexpr); - } - subexpr = transformExpr(pstate, ai->uidx); - /* If it's not int4 already, try to coerce */ - subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr), - INT4OID, -1, false); - if (subexpr == NULL) - elog(ERROR, "array index expressions must be integers"); - upperIndexpr = lappend(upperIndexpr, subexpr); - } - - /* - * If doing an array store, coerce the source value to the right type. - */ - if (assignFrom != NULL) - { - Oid typesource = exprType(assignFrom); - Oid typeneeded = isSlice ? arrayType : elementType; - - if (typesource != InvalidOid) - { - if (typesource != typeneeded) - { - /* XXX fixme: need to get the array's atttypmod? */ - assignFrom = CoerceTargetExpr(pstate, assignFrom, - typesource, typeneeded, - -1, false); - if (assignFrom == NULL) - elog(ERROR, "Array assignment requires type '%s'" - " but expression is of type '%s'" - "\n\tYou will need to rewrite or cast the expression", - format_type_be(typeneeded), - format_type_be(typesource)); - } - } - } - - /* - * Ready to build the ArrayRef node. - */ - aref = makeNode(ArrayRef); - aref->refattrlength = type_struct_array->typlen; - aref->refelemlength = type_struct_element->typlen; - aref->refelemtype = resultType; /* XXX should save element type - * too */ - aref->refelembyval = type_struct_element->typbyval; - aref->refupperindexpr = upperIndexpr; - aref->reflowerindexpr = lowerIndexpr; - aref->refexpr = arrayBase; - aref->refassgnexpr = assignFrom; - - ReleaseSysCache(type_tuple_array); - ReleaseSysCache(type_tuple_element); - - return aref; -} - -/* - * make_const - * - * Convert a Value node (as returned by the grammar) to a Const node - * of the "natural" type for the constant. Note that this routine is - * only used when there is no explicit cast for the constant, so we - * have to guess what type is wanted. - * - * For string literals we produce a constant of type UNKNOWN ---- whose - * representation is the same as text, but it indicates to later type - * resolution that we're not sure that it should be considered text. - * Explicit "NULL" constants are also typed as UNKNOWN. - * - * For integers and floats we produce int4, float8, or numeric depending - * on the value of the number. XXX In some cases it would be nice to take - * context into account when determining the type to convert to, but in - * other cases we can't delay the type choice. One possibility is to invent - * a dummy type "UNKNOWNNUMERIC" that's treated similarly to UNKNOWN; - * that would allow us to do the right thing in examples like a simple - * INSERT INTO table (numericcolumn) VALUES (1.234), since we wouldn't - * have to resolve the unknown type until we knew the destination column - * type. On the other hand UNKNOWN has considerable problems of its own. - * We would not like "SELECT 1.2 + 3.4" to claim it can't choose a type. - */ -Const * -make_const(Value *value) -{ - Datum val; - Oid typeid; - int typelen; - bool typebyval; - Const *con; - - switch (nodeTag(value)) - { - case T_Integer: - val = Int32GetDatum(intVal(value)); - - typeid = INT4OID; - typelen = sizeof(int32); - typebyval = true; - break; - - case T_Float: - if (fitsInFloat(value)) - { - val = Float8GetDatum(floatVal(value)); - - typeid = FLOAT8OID; - typelen = sizeof(float8); - typebyval = false; /* XXX might change someday */ - } - else - { - val = DirectFunctionCall3(numeric_in, - CStringGetDatum(strVal(value)), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); - - typeid = NUMERICOID; - typelen = -1; /* variable len */ - typebyval = false; - } - break; - - case T_String: - val = DirectFunctionCall1(unknownin, - CStringGetDatum(strVal(value))); - - typeid = UNKNOWNOID; /* will be coerced later */ - typelen = -1; /* variable len */ - typebyval = false; - break; - - case T_BitString: - val = DirectFunctionCall3(bit_in, - CStringGetDatum(strVal(value)), - ObjectIdGetDatum(InvalidOid), - Int32GetDatum(-1)); - typeid = BITOID; - typelen = -1; - typebyval = false; - break; - - default: - elog(WARNING, "make_const: unknown type %d", nodeTag(value)); - /* FALLTHROUGH */ - - case T_Null: - /* return a null const */ - con = makeConst(UNKNOWNOID, - -1, - (Datum) NULL, - true, - false, - false, - false); - return con; - } - - con = makeConst(typeid, - typelen, - val, - false, - typebyval, - false, /* not a set */ - false); /* not coerced */ - - return con; -} - -/* - * Decide whether a T_Float value fits in float8, or must be treated as - * type "numeric". We check the number of digits and check for overflow/ - * underflow. (With standard compilation options, Postgres' NUMERIC type - * can handle decimal exponents up to 1000, considerably more than most - * implementations of float8, so this is a sensible test.) - */ -static bool -fitsInFloat(Value *value) -{ - const char *ptr; - int ndigits; - char *endptr; - - /* - * Count digits, ignoring leading zeroes (but not trailing zeroes). - * DBL_DIG is the maximum safe number of digits for "double". - */ - ptr = strVal(value); - while (*ptr == '+' || *ptr == '-' || *ptr == '0' || *ptr == '.') - ptr++; - ndigits = 0; - for (; *ptr; ptr++) - { - if (isdigit((unsigned char) *ptr)) - ndigits++; - else if (*ptr == 'e' || *ptr == 'E') - break; /* don't count digits in exponent */ - } - if (ndigits > DBL_DIG) - return false; - - /* - * Use strtod() to check for overflow/underflow. - */ - errno = 0; - (void) strtod(strVal(value), &endptr); - if (*endptr != '\0' || errno != 0) - return false; - - return true; -} |