diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index f70fe508ae..cc23555c46 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.53 1999/12/13 01:26:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.54 1999/12/24 06:43:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -144,6 +144,13 @@ _equalConst(Const *a, Const *b) if (a->constbyval != b->constbyval) return false; /* XXX What about constisset and constiscast? */ + /* + * We treat all NULL constants of the same type as equal. + * Someday this might need to change? But datumIsEqual + * doesn't work on nulls, so... + */ + if (a->constisnull) + return true; return (datumIsEqual(a->constvalue, b->constvalue, a->consttype, a->constbyval, a->constlen)); } diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 0b738a8730..dab7161c04 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.62 1999/12/17 01:25:25 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.63 1999/12/24 06:43:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -353,7 +353,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) n->val.type = T_Null; c->defresult = (Node *) n; } - c->defresult = transformExpr(pstate, (Node *) c->defresult, precedence); + c->defresult = transformExpr(pstate, c->defresult, precedence); /* now check types across result clauses... */ c->casetype = exprType(c->defresult); @@ -369,32 +369,30 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) if (wtype && (wtype != UNKNOWNOID) && (wtype != ptype)) { - /* so far, only nulls so take anything... */ - if (!ptype) + if (!ptype || ptype == UNKNOWNOID) { + /* so far, only nulls so take anything... */ ptype = wtype; pcategory = TypeCategory(ptype); } - - /* - * both types in different categories? then not - * much hope... - */ else if ((TypeCategory(wtype) != pcategory) || ((TypeCategory(wtype) == USER_TYPE) && (TypeCategory(c->casetype) == USER_TYPE))) { + /* + * both types in different categories? + * then not much hope... + */ elog(ERROR, "CASE/WHEN types '%s' and '%s' not matched", typeidTypeName(c->casetype), typeidTypeName(wtype)); } - - /* - * new one is preferred and can convert? then take - * it... - */ else if (IsPreferredType(pcategory, wtype) && can_coerce_type(1, &ptype, &wtype)) { + /* + * new one is preferred and can convert? + * then take it... + */ ptype = wtype; pcategory = TypeCategory(ptype); } @@ -404,9 +402,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) /* Convert default result clause, if necessary */ if (c->casetype != ptype) { - if (!c->casetype) + if (!c->casetype || c->casetype == UNKNOWNOID) { - /* * default clause is NULL, so assign preferred * type from WHEN clauses... @@ -694,11 +691,12 @@ exprTypmod(Node *expr) static Node * parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) { - Const *adt; - Datum lcp; + Const *con; Type tp; + Datum datum; char *const_string = NULL; bool string_palloced = false; + bool isNull = false; switch (nodeTag(expr)) { @@ -713,6 +711,9 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) string_palloced = true; const_string = float8out(&expr->val.dval); break; + case T_Null: + isNull = true; + break; default: elog(ERROR, "parser_typecast: cannot cast this expression to type '%s'", @@ -729,12 +730,15 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) else tp = (Type) typenameType(typename->name); - lcp = stringTypeDatum(tp, const_string, atttypmod); + if (isNull) + datum = (Datum) NULL; + else + datum = stringTypeDatum(tp, const_string, atttypmod); - adt = makeConst(typeTypeId(tp), + con = makeConst(typeTypeId(tp), typeLen(tp), - (Datum) lcp, - false, + datum, + isNull, typeByVal(tp), false, /* not a set */ true /* is cast */ ); @@ -742,5 +746,5 @@ parser_typecast(Value *expr, TypeName *typename, int32 atttypmod) if (string_palloced) pfree(const_string); - return (Node *) adt; + return (Node *) con; } diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 2cab730412..c660df3826 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.33 1999/11/22 17:56:21 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.34 1999/12/24 06:43:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -61,28 +61,27 @@ make_operand(char *opname, Oid target_typeId) { Node *result; - Type target_type; + Type target_type = typeidType(target_typeId); if (tree != NULL) { - result = tree; - target_type = typeidType(target_typeId); - disallow_setop(opname, target_type, result); - + disallow_setop(opname, target_type, tree); /* must coerce? */ if (target_typeId != orig_typeId) result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1); + else + result = tree; } - /* otherwise, this is a NULL value */ else { + /* otherwise, this is a NULL value */ Const *con = makeNode(Const); con->consttype = target_typeId; - con->constlen = 0; - con->constvalue = (Datum) (struct varlena *) NULL; + con->constlen = typeLen(target_type); + con->constvalue = (Datum) NULL; con->constisnull = true; - con->constbyval = true; + con->constbyval = typeByVal(target_type); con->constisset = false; result = (Node *) con; } @@ -394,7 +393,8 @@ transformArraySubscripts(ParseState *pstate, * of the "natural" type for the constant. For strings we produce * a constant of type UNKNOWN ---- representation is the same as text, * but this indicates to later type resolution that we're not sure that - * it should be considered text. + * it should be considered text. Explicit "NULL" constants are also + * typed as UNKNOWN. */ Const * make_const(Value *value) @@ -444,7 +444,13 @@ make_const(Value *value) elog(NOTICE, "make_const: unknown type %d\n", nodeTag(value)); /* return a null const */ - con = makeConst(0, 0, (Datum) NULL, true, false, false, false); + con = makeConst(UNKNOWNOID, + -1, + (Datum) NULL, + true, + false, + false, + false); return con; } diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 47fd957c99..00099791c0 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * out of it's tuple * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.35 1999/12/13 01:27:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.36 1999/12/24 06:43:34 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -1606,12 +1606,6 @@ get_const_expr(Const *constval, deparse_context *context) char *valptr; bool isnull = FALSE; - if (constval->constisnull) - { - appendStringInfo(buf, "NULL"); - return; - } - typetup = SearchSysCacheTuple(TYPEOID, ObjectIdGetDatum(constval->consttype), 0, 0, 0); @@ -1620,6 +1614,19 @@ get_const_expr(Const *constval, deparse_context *context) typeStruct = (Form_pg_type) GETSTRUCT(typetup); + if (constval->constisnull) + { + /* + * Always label the type of a NULL constant. This not only + * prevents misdecisions about the type, but it ensures that + * our output is a valid b_expr. + */ + extval = pstrdup(NameStr(typeStruct->typname)); + appendStringInfo(buf, "NULL::%s", quote_identifier(extval)); + pfree(extval); + return; + } + fmgr_info(typeStruct->typoutput, &finfo_output); extval = (char *) (*fmgr_faddr(&finfo_output)) (constval->constvalue, &isnull, -1);