]> granicus.if.org Git - postgresql/commitdiff
Clean up handling of explicit NULL constants. Cases like
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 24 Dec 1999 06:43:34 +0000 (06:43 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 24 Dec 1999 06:43:34 +0000 (06:43 +0000)
SELECT null::text;
SELECT int4fac(null);
work as expected now.  In some cases a NULL must be surrounded by
parentheses:
SELECT 2 + null;                 fails
SELECT 2 + (null);               OK
This is a grammatical ambiguity that seems difficult to avoid.  Other
than that, NULLs seem to behave about like you'd expect.  The internal
implementation is that NULL constants are typed as UNKNOWN (like
untyped string constants) until the parser can deduce the right type.

src/backend/nodes/equalfuncs.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_node.c
src/backend/utils/adt/ruleutils.c

index f70fe508ae58dbb110e633b8b513d1179a795841..cc23555c46f2429e1dd6808a35e6f49603934658 100644 (file)
@@ -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));
 }
index 0b738a873079ae59f994cc0873848ac4fe7b6f61..dab7161c0428b4e3ccb7dffc754fc37b19e8e962 100644 (file)
@@ -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;
 }
index 2cab730412dffff003929bb60250e99b222b6992..c660df38261ae59dcf67df27b17035c016af7b9e 100644 (file)
@@ -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;
        }
 
index 47fd957c9948cbb2e19c718d57a32859607d0a28..00099791c09097dccc383550a4977f3caeab896b 100644 (file)
@@ -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);