Add read support for some missing raw parse nodes

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 <tgl@sss.pgh.pa.us>
Discussion: https://www.postgresql.org/message-id/flat/4159834.1657405226@sss.pgh.pa.us
This commit is contained in:
Peter Eisentraut 2022-09-24 18:18:33 -04:00
parent 2cb1a5a8d4
commit a6bc330192
3 changed files with 253 additions and 11 deletions

View 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;
}
}

View 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)
{

View 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 */