Add read support for some missing raw parse nodes
authorPeter Eisentraut <[email protected]>
Sat, 24 Sep 2022 22:18:33 +0000 (18:18 -0400)
committerPeter Eisentraut <[email protected]>
Sat, 24 Sep 2022 22:18:33 +0000 (18:18 -0400)
The node types A_Const, Constraint, and A_Expr had custom output
functions, but no read functions were implemented so far.

The A_Expr output format had to be tweaked a bit to make it easier to
parse.

Be a bit more cautious about applying strncmp to unterminated strings.

Also error out if an unrecognized enum value is found in each case,
instead of just printing a placeholder value.  That was maybe ok for
debugging but won't work if we want to have robust round-tripping.

Reviewed-by: Tom Lane <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/4159834.1657405226@sss.pgh.pa.us

src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/include/nodes/parsenodes.h

index 60610e3a4bd5aa19e5c0696dcc37b01cc10aa84c..24ea0487e7fc4e542a0468a5389274211c22a2de 100644 (file)
@@ -548,12 +548,12 @@ _outA_Expr(StringInfo str, const A_Expr *node)
            WRITE_NODE_FIELD(name);
            break;
        case AEXPR_OP_ANY:
-           WRITE_NODE_FIELD(name);
            appendStringInfoString(str, " ANY");
+           WRITE_NODE_FIELD(name);
            break;
        case AEXPR_OP_ALL:
-           WRITE_NODE_FIELD(name);
            appendStringInfoString(str, " ALL");
+           WRITE_NODE_FIELD(name);
            break;
        case AEXPR_DISTINCT:
            appendStringInfoString(str, " DISTINCT");
@@ -600,7 +600,7 @@ _outA_Expr(StringInfo str, const A_Expr *node)
            WRITE_NODE_FIELD(name);
            break;
        default:
-           appendStringInfoString(str, " ??");
+           elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
            break;
    }
 
@@ -782,8 +782,7 @@ _outConstraint(StringInfo str, const Constraint *node)
            break;
 
        default:
-           appendStringInfo(str, "<unrecognized_constraint %d>",
-                            (int) node->contype);
+           elog(ERROR, "unrecognized ConstrType: %d", (int) node->contype);
            break;
    }
 }
index bee62fc15cd58cba6f705d565183b9517c94abfc..89a9a50f7cbdab744e312474bba1264d27e630c5 100644 (file)
@@ -270,11 +270,11 @@ _readBoolExpr(void)
    /* do-it-yourself enum representation */
    token = pg_strtok(&length); /* skip :boolop */
    token = pg_strtok(&length); /* get field value */
-   if (strncmp(token, "and", 3) == 0)
+   if (length == 3 && strncmp(token, "and", 3) == 0)
        local_node->boolop = AND_EXPR;
-   else if (strncmp(token, "or", 2) == 0)
+   else if (length == 2 && strncmp(token, "or", 2) == 0)
        local_node->boolop = OR_EXPR;
-   else if (strncmp(token, "not", 3) == 0)
+   else if (length == 3 && strncmp(token, "not", 3) == 0)
        local_node->boolop = NOT_EXPR;
    else
        elog(ERROR, "unrecognized boolop \"%.*s\"", length, token);
@@ -285,6 +285,162 @@ _readBoolExpr(void)
    READ_DONE();
 }
 
+static A_Const *
+_readA_Const(void)
+{
+   READ_LOCALS(A_Const);
+
+   token = pg_strtok(&length);
+   if (length == 4 && strncmp(token, "NULL", 4) == 0)
+       local_node->isnull = true;
+   else
+   {
+       union ValUnion *tmp = nodeRead(NULL, 0);
+
+       memcpy(&local_node->val, tmp, sizeof(*tmp));
+   }
+
+   READ_LOCATION_FIELD(location);
+
+   READ_DONE();
+}
+
+/*
+ * _readConstraint
+ */
+static Constraint *
+_readConstraint(void)
+{
+   READ_LOCALS(Constraint);
+
+   READ_STRING_FIELD(conname);
+   READ_BOOL_FIELD(deferrable);
+   READ_BOOL_FIELD(initdeferred);
+   READ_LOCATION_FIELD(location);
+
+   token = pg_strtok(&length); /* skip :contype */
+   token = pg_strtok(&length); /* get field value */
+   if (length == 4 && strncmp(token, "NULL", 4) == 0)
+       local_node->contype = CONSTR_NULL;
+   else if (length == 8 && strncmp(token, "NOT_NULL", 8) == 0)
+       local_node->contype = CONSTR_NOTNULL;
+   else if (length == 7 && strncmp(token, "DEFAULT", 7) == 0)
+       local_node->contype = CONSTR_DEFAULT;
+   else if (length == 8 && strncmp(token, "IDENTITY", 8) == 0)
+       local_node->contype = CONSTR_IDENTITY;
+   else if (length == 9 && strncmp(token, "GENERATED", 9) == 0)
+       local_node->contype = CONSTR_GENERATED;
+   else if (length == 5 && strncmp(token, "CHECK", 5) == 0)
+       local_node->contype = CONSTR_CHECK;
+   else if (length == 11 && strncmp(token, "PRIMARY_KEY", 11) == 0)
+       local_node->contype = CONSTR_PRIMARY;
+   else if (length == 6 && strncmp(token, "UNIQUE", 6) == 0)
+       local_node->contype = CONSTR_UNIQUE;
+   else if (length == 9 && strncmp(token, "EXCLUSION", 9) == 0)
+       local_node->contype = CONSTR_EXCLUSION;
+   else if (length == 11 && strncmp(token, "FOREIGN_KEY", 11) == 0)
+       local_node->contype = CONSTR_FOREIGN;
+   else if (length == 15 && strncmp(token, "ATTR_DEFERRABLE", 15) == 0)
+       local_node->contype = CONSTR_ATTR_DEFERRABLE;
+   else if (length == 19 && strncmp(token, "ATTR_NOT_DEFERRABLE", 19) == 0)
+       local_node->contype = CONSTR_ATTR_NOT_DEFERRABLE;
+   else if (length == 13 && strncmp(token, "ATTR_DEFERRED", 13) == 0)
+       local_node->contype = CONSTR_ATTR_DEFERRED;
+   else if (length == 14 && strncmp(token, "ATTR_IMMEDIATE", 14) == 0)
+       local_node->contype = CONSTR_ATTR_IMMEDIATE;
+
+   switch (local_node->contype)
+   {
+       case CONSTR_NULL:
+       case CONSTR_NOTNULL:
+           /* no extra fields */
+           break;
+
+       case CONSTR_DEFAULT:
+           READ_NODE_FIELD(raw_expr);
+           READ_STRING_FIELD(cooked_expr);
+           break;
+
+       case CONSTR_IDENTITY:
+           READ_NODE_FIELD(options);
+           READ_CHAR_FIELD(generated_when);
+           break;
+
+       case CONSTR_GENERATED:
+           READ_NODE_FIELD(raw_expr);
+           READ_STRING_FIELD(cooked_expr);
+           READ_CHAR_FIELD(generated_when);
+           break;
+
+       case CONSTR_CHECK:
+           READ_BOOL_FIELD(is_no_inherit);
+           READ_NODE_FIELD(raw_expr);
+           READ_STRING_FIELD(cooked_expr);
+           READ_BOOL_FIELD(skip_validation);
+           READ_BOOL_FIELD(initially_valid);
+           break;
+
+       case CONSTR_PRIMARY:
+           READ_NODE_FIELD(keys);
+           READ_NODE_FIELD(including);
+           READ_NODE_FIELD(options);
+           READ_STRING_FIELD(indexname);
+           READ_STRING_FIELD(indexspace);
+           READ_BOOL_FIELD(reset_default_tblspc);
+           /* access_method and where_clause not currently used */
+           break;
+
+       case CONSTR_UNIQUE:
+           READ_BOOL_FIELD(nulls_not_distinct);
+           READ_NODE_FIELD(keys);
+           READ_NODE_FIELD(including);
+           READ_NODE_FIELD(options);
+           READ_STRING_FIELD(indexname);
+           READ_STRING_FIELD(indexspace);
+           READ_BOOL_FIELD(reset_default_tblspc);
+           /* access_method and where_clause not currently used */
+           break;
+
+       case CONSTR_EXCLUSION:
+           READ_NODE_FIELD(exclusions);
+           READ_NODE_FIELD(including);
+           READ_NODE_FIELD(options);
+           READ_STRING_FIELD(indexname);
+           READ_STRING_FIELD(indexspace);
+           READ_BOOL_FIELD(reset_default_tblspc);
+           READ_STRING_FIELD(access_method);
+           READ_NODE_FIELD(where_clause);
+           break;
+
+       case CONSTR_FOREIGN:
+           READ_NODE_FIELD(pktable);
+           READ_NODE_FIELD(fk_attrs);
+           READ_NODE_FIELD(pk_attrs);
+           READ_CHAR_FIELD(fk_matchtype);
+           READ_CHAR_FIELD(fk_upd_action);
+           READ_CHAR_FIELD(fk_del_action);
+           READ_NODE_FIELD(fk_del_set_cols);
+           READ_NODE_FIELD(old_conpfeqop);
+           READ_OID_FIELD(old_pktable_oid);
+           READ_BOOL_FIELD(skip_validation);
+           READ_BOOL_FIELD(initially_valid);
+           break;
+
+       case CONSTR_ATTR_DEFERRABLE:
+       case CONSTR_ATTR_NOT_DEFERRABLE:
+       case CONSTR_ATTR_DEFERRED:
+       case CONSTR_ATTR_IMMEDIATE:
+           /* no extra fields */
+           break;
+
+       default:
+           elog(ERROR, "unrecognized ConstrType: %d", (int) local_node->contype);
+           break;
+   }
+
+   READ_DONE();
+}
+
 static RangeTblEntry *
 _readRangeTblEntry(void)
 {
@@ -376,6 +532,93 @@ _readRangeTblEntry(void)
    READ_DONE();
 }
 
+static A_Expr *
+_readA_Expr(void)
+{
+   READ_LOCALS(A_Expr);
+
+   token = pg_strtok(&length);
+
+   if (length == 3 && strncmp(token, "ANY", 3) == 0)
+   {
+       local_node->kind = AEXPR_OP_ANY;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 3 && strncmp(token, "ALL", 3) == 0)
+   {
+       local_node->kind = AEXPR_OP_ALL;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 8 && strncmp(token, "DISTINCT", 8) == 0)
+   {
+       local_node->kind = AEXPR_DISTINCT;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 12 && strncmp(token, "NOT_DISTINCT", 12) == 0)
+   {
+       local_node->kind = AEXPR_NOT_DISTINCT;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 6 && strncmp(token, "NULLIF", 6) == 0)
+   {
+       local_node->kind = AEXPR_NULLIF;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 2 && strncmp(token, "IN", 2) == 0)
+   {
+       local_node->kind = AEXPR_IN;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 4 && strncmp(token, "LIKE", 4) == 0)
+   {
+       local_node->kind = AEXPR_LIKE;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 5 && strncmp(token, "ILIKE", 5) == 0)
+   {
+       local_node->kind = AEXPR_ILIKE;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 7 && strncmp(token, "SIMILAR", 7) == 0)
+   {
+       local_node->kind = AEXPR_SIMILAR;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 7 && strncmp(token, "BETWEEN", 7) == 0)
+   {
+       local_node->kind = AEXPR_BETWEEN;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 11 && strncmp(token, "NOT_BETWEEN", 11) == 0)
+   {
+       local_node->kind = AEXPR_NOT_BETWEEN;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 11 && strncmp(token, "BETWEEN_SYM", 11) == 0)
+   {
+       local_node->kind = AEXPR_BETWEEN_SYM;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 15 && strncmp(token, "NOT_BETWEEN_SYM", 15) == 0)
+   {
+       local_node->kind = AEXPR_NOT_BETWEEN_SYM;
+       READ_NODE_FIELD(name);
+   }
+   else if (length == 5 && strncmp(token, ":name", 5) == 0)
+   {
+       local_node->kind = AEXPR_OP;
+       local_node->name = nodeRead(NULL, 0);
+   }
+   else
+       elog(ERROR, "unrecognized A_Expr kind: \"%.*s\"", length, token);
+
+   READ_NODE_FIELD(lexpr);
+   READ_NODE_FIELD(rexpr);
+   READ_LOCATION_FIELD(location);
+
+   READ_DONE();
+}
+
 static ExtensibleNode *
 _readExtensibleNode(void)
 {
index 6958306a7dcfe64afedb4dc1d9c52016c5259058..aead2afd6ef70c30181dcdafd99ff2802ca697e0 100644 (file)
@@ -291,7 +291,7 @@ typedef enum A_Expr_Kind
 
 typedef struct A_Expr
 {
-   pg_node_attr(custom_read_write, no_read)
+   pg_node_attr(custom_read_write)
 
    NodeTag     type;
    A_Expr_Kind kind;           /* see above */
@@ -319,7 +319,7 @@ union ValUnion
 
 typedef struct A_Const
 {
-   pg_node_attr(custom_copy_equal, custom_read_write, no_read)
+   pg_node_attr(custom_copy_equal, custom_read_write)
 
    NodeTag     type;
    union ValUnion val;
@@ -2332,7 +2332,7 @@ typedef enum ConstrType           /* types of constraints */
 
 typedef struct Constraint
 {
-   pg_node_attr(custom_read_write, no_read)
+   pg_node_attr(custom_read_write)
 
    NodeTag     type;
    ConstrType  contype;        /* see above */