From 4e1ef56b5443fa11d981eb6e407dfc7c244dc60e Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 27 Dec 2021 09:52:05 +0100 Subject: [PATCH v1] Add Boolean node Before, SQL-level boolean constants were represented by a string with a cast, and internal Boolean values in DDL commands were usually represented by Integer nodes. This takes the place of both of these uses, making the intent clearer and having some amount of type safety. --- contrib/postgres_fdw/postgres_fdw.c | 32 +++--- src/backend/commands/define.c | 4 + src/backend/commands/functioncmds.c | 14 +-- src/backend/commands/sequence.c | 4 +- src/backend/commands/tsearchcmds.c | 9 ++ src/backend/commands/user.c | 28 +++--- src/backend/nodes/copyfuncs.c | 16 +++ src/backend/nodes/equalfuncs.c | 11 +++ src/backend/nodes/nodeFuncs.c | 1 + src/backend/nodes/outfuncs.c | 8 ++ src/backend/nodes/read.c | 5 + src/backend/nodes/value.c | 12 +++ src/backend/parser/gram.y | 98 +++++++++---------- src/backend/parser/parse_node.c | 8 ++ src/backend/replication/repl_gram.y | 14 +-- src/include/nodes/nodes.h | 1 + src/include/nodes/parsenodes.h | 1 + src/include/nodes/value.h | 8 ++ src/test/isolation/expected/ri-trigger.out | 60 ++++++------ .../regress/expected/create_function_3.out | 2 +- 20 files changed, 210 insertions(+), 126 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index fa9a099f13..4d61d88d7b 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -103,7 +103,7 @@ enum FdwModifyPrivateIndex FdwModifyPrivateTargetAttnums, /* Length till the end of VALUES clause (as an Integer node) */ FdwModifyPrivateLen, - /* has-returning flag (as an Integer node) */ + /* has-returning flag (as a Boolean node) */ FdwModifyPrivateHasReturning, /* Integer list of attribute numbers retrieved by RETURNING */ FdwModifyPrivateRetrievedAttrs @@ -122,11 +122,11 @@ enum FdwDirectModifyPrivateIndex { /* SQL statement to execute remotely (as a String node) */ FdwDirectModifyPrivateUpdateSql, - /* has-returning flag (as an Integer node) */ + /* has-returning flag (as a Boolean node) */ FdwDirectModifyPrivateHasReturning, /* Integer list of attribute numbers retrieved by RETURNING */ FdwDirectModifyPrivateRetrievedAttrs, - /* set-processed flag (as an Integer node) */ + /* set-processed flag (as a Boolean node) */ FdwDirectModifyPrivateSetProcessed }; @@ -280,9 +280,9 @@ typedef struct PgFdwAnalyzeState */ enum FdwPathPrivateIndex { - /* has-final-sort flag (as an Integer node) */ + /* has-final-sort flag (as a Boolean node) */ FdwPathPrivateHasFinalSort, - /* has-limit flag (as an Integer node) */ + /* has-limit flag (as a Boolean node) */ FdwPathPrivateHasLimit }; @@ -1245,9 +1245,9 @@ postgresGetForeignPlan(PlannerInfo *root, */ if (best_path->fdw_private) { - has_final_sort = intVal(list_nth(best_path->fdw_private, + has_final_sort = boolVal(list_nth(best_path->fdw_private, FdwPathPrivateHasFinalSort)); - has_limit = intVal(list_nth(best_path->fdw_private, + has_limit = boolVal(list_nth(best_path->fdw_private, FdwPathPrivateHasLimit)); } @@ -1879,7 +1879,7 @@ postgresPlanForeignModify(PlannerInfo *root, return list_make5(makeString(sql.data), targetAttrs, makeInteger(values_end_len), - makeInteger((retrieved_attrs != NIL)), + makeBoolean((retrieved_attrs != NIL)), retrieved_attrs); } @@ -1916,7 +1916,7 @@ postgresBeginForeignModify(ModifyTableState *mtstate, FdwModifyPrivateTargetAttnums); values_end_len = intVal(list_nth(fdw_private, FdwModifyPrivateLen)); - has_returning = intVal(list_nth(fdw_private, + has_returning = boolVal(list_nth(fdw_private, FdwModifyPrivateHasReturning)); retrieved_attrs = (List *) list_nth(fdw_private, FdwModifyPrivateRetrievedAttrs); @@ -2567,9 +2567,9 @@ postgresPlanDirectModify(PlannerInfo *root, * Items in the list must match enum FdwDirectModifyPrivateIndex, above. */ fscan->fdw_private = list_make4(makeString(sql.data), - makeInteger((retrieved_attrs != NIL)), + makeBoolean((retrieved_attrs != NIL)), retrieved_attrs, - makeInteger(plan->canSetTag)); + makeBoolean(plan->canSetTag)); /* * Update the foreign-join-related fields. @@ -2667,11 +2667,11 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) /* Get private info created by planner functions. */ dmstate->query = strVal(list_nth(fsplan->fdw_private, FdwDirectModifyPrivateUpdateSql)); - dmstate->has_returning = intVal(list_nth(fsplan->fdw_private, + dmstate->has_returning = boolVal(list_nth(fsplan->fdw_private, FdwDirectModifyPrivateHasReturning)); dmstate->retrieved_attrs = (List *) list_nth(fsplan->fdw_private, FdwDirectModifyPrivateRetrievedAttrs); - dmstate->set_processed = intVal(list_nth(fsplan->fdw_private, + dmstate->set_processed = boolVal(list_nth(fsplan->fdw_private, FdwDirectModifyPrivateSetProcessed)); /* Create context for per-tuple temp workspace. */ @@ -6566,7 +6566,7 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel, * Build the fdw_private list that will be used by postgresGetForeignPlan. * Items in the list must match order in enum FdwPathPrivateIndex. */ - fdw_private = list_make2(makeInteger(true), makeInteger(false)); + fdw_private = list_make2(makeBoolean(true), makeBoolean(false)); /* Create foreign ordering path */ ordered_path = create_foreign_upper_path(root, @@ -6797,8 +6797,8 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel, * Build the fdw_private list that will be used by postgresGetForeignPlan. * Items in the list must match order in enum FdwPathPrivateIndex. */ - fdw_private = list_make2(makeInteger(has_final_sort), - makeInteger(extra->limit_needed)); + fdw_private = list_make2(makeBoolean(has_final_sort), + makeBoolean(extra->limit_needed)); /* * Create foreign final path; this gets rid of a no-longer-needed outer diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 19c317a472..fbf5168649 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -59,6 +59,8 @@ defGetString(DefElem *def) return psprintf("%ld", (long) intVal(def->arg)); case T_Float: return castNode(Float, def->arg)->val; + case T_Boolean: + return boolVal(def->arg) ? "true" : "false"; case T_String: return strVal(def->arg); case T_TypeName: @@ -116,6 +118,8 @@ defGetBoolean(DefElem *def) */ switch (nodeTag(def->arg)) { + case T_Boolean: + return boolVal(def->arg); case T_Integer: switch (intVal(def->arg)) { diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 38e78f7102..ba5b23fb11 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -813,15 +813,15 @@ compute_function_attributes(ParseState *pstate, if (transform_item) *transform = transform_item->arg; if (windowfunc_item) - *windowfunc_p = intVal(windowfunc_item->arg); + *windowfunc_p = boolVal(windowfunc_item->arg); if (volatility_item) *volatility_p = interpret_func_volatility(volatility_item); if (strict_item) - *strict_p = intVal(strict_item->arg); + *strict_p = boolVal(strict_item->arg); if (security_item) - *security_definer = intVal(security_item->arg); + *security_definer = boolVal(security_item->arg); if (leakproof_item) - *leakproof_p = intVal(leakproof_item->arg); + *leakproof_p = boolVal(leakproof_item->arg); if (set_items) *proconfig = update_proconfig_value(NULL, set_items); if (cost_item) @@ -1417,12 +1417,12 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) if (volatility_item) procForm->provolatile = interpret_func_volatility(volatility_item); if (strict_item) - procForm->proisstrict = intVal(strict_item->arg); + procForm->proisstrict = boolVal(strict_item->arg); if (security_def_item) - procForm->prosecdef = intVal(security_def_item->arg); + procForm->prosecdef = boolVal(security_def_item->arg); if (leakproof_item) { - procForm->proleakproof = intVal(leakproof_item->arg); + procForm->proleakproof = boolVal(leakproof_item->arg); if (procForm->proleakproof && !superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 72bfdc07a4..81368b8b2f 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1401,7 +1401,7 @@ init_params(ParseState *pstate, List *options, bool for_identity, /* CYCLE */ if (is_cycled != NULL) { - seqform->seqcycle = intVal(is_cycled->arg); + seqform->seqcycle = boolVal(is_cycled->arg); Assert(BoolIsValid(seqform->seqcycle)); seqdataform->log_cnt = 0; } @@ -1739,7 +1739,7 @@ sequence_options(Oid relid) options = lappend(options, makeDefElem("cache", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqcache)), -1)); options = lappend(options, - makeDefElem("cycle", (Node *) makeInteger(pgsform->seqcycle), -1)); + makeDefElem("cycle", (Node *) makeBoolean(pgsform->seqcycle), -1)); options = lappend(options, makeDefElem("increment", (Node *) makeFloat(psprintf(INT64_FORMAT, pgsform->seqincrement)), -1)); options = lappend(options, diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index c47a05d10d..b7261a88d4 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -1742,6 +1742,15 @@ buildDefItem(const char *name, const char *val, bool was_quoted) return makeDefElem(pstrdup(name), (Node *) makeFloat(pstrdup(val)), -1); + + if (strcmp(val, "true") == 0) + return makeDefElem(pstrdup(name), + (Node *) makeBoolean(true), + -1); + if (strcmp(val, "false") == 0) + return makeDefElem(pstrdup(name), + (Node *) makeBoolean(false), + -1); } /* Just make it a string */ return makeDefElem(pstrdup(name), diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index c8c0dd0dd5..59ee671e8d 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -217,17 +217,17 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) if (dpassword && dpassword->arg) password = strVal(dpassword->arg); if (dissuper) - issuper = intVal(dissuper->arg) != 0; + issuper = boolVal(dissuper->arg) != 0; if (dinherit) - inherit = intVal(dinherit->arg) != 0; + inherit = boolVal(dinherit->arg) != 0; if (dcreaterole) - createrole = intVal(dcreaterole->arg) != 0; + createrole = boolVal(dcreaterole->arg) != 0; if (dcreatedb) - createdb = intVal(dcreatedb->arg) != 0; + createdb = boolVal(dcreatedb->arg) != 0; if (dcanlogin) - canlogin = intVal(dcanlogin->arg) != 0; + canlogin = boolVal(dcanlogin->arg) != 0; if (disreplication) - isreplication = intVal(disreplication->arg) != 0; + isreplication = boolVal(disreplication->arg) != 0; if (dconnlimit) { connlimit = intVal(dconnlimit->arg); @@ -245,7 +245,7 @@ CreateRole(ParseState *pstate, CreateRoleStmt *stmt) if (dvalidUntil) validUntil = strVal(dvalidUntil->arg); if (dbypassRLS) - bypassrls = intVal(dbypassRLS->arg) != 0; + bypassrls = boolVal(dbypassRLS->arg) != 0; /* Check some permissions first */ if (issuper) @@ -611,17 +611,17 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) if (dpassword && dpassword->arg) password = strVal(dpassword->arg); if (dissuper) - issuper = intVal(dissuper->arg); + issuper = boolVal(dissuper->arg); if (dinherit) - inherit = intVal(dinherit->arg); + inherit = boolVal(dinherit->arg); if (dcreaterole) - createrole = intVal(dcreaterole->arg); + createrole = boolVal(dcreaterole->arg); if (dcreatedb) - createdb = intVal(dcreatedb->arg); + createdb = boolVal(dcreatedb->arg); if (dcanlogin) - canlogin = intVal(dcanlogin->arg); + canlogin = boolVal(dcanlogin->arg); if (disreplication) - isreplication = intVal(disreplication->arg); + isreplication = boolVal(disreplication->arg); if (dconnlimit) { connlimit = intVal(dconnlimit->arg); @@ -635,7 +635,7 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) if (dvalidUntil) validUntil = strVal(dvalidUntil->arg); if (dbypassRLS) - bypassrls = intVal(dbypassRLS->arg); + bypassrls = boolVal(dbypassRLS->arg); /* * Scan the pg_authid relation to be certain the user exists. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index df0b747883..2924a6c81b 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -2749,6 +2749,9 @@ _copyA_Const(const A_Const *from) case T_Float: COPY_STRING_FIELD(val.fval.val); break; + case T_Boolean: + COPY_SCALAR_FIELD(val.boolval.val); + break; case T_String: COPY_STRING_FIELD(val.sval.val); break; @@ -4948,6 +4951,16 @@ _copyFloat(const Float *from) return newnode; } +static Boolean * +_copyBoolean(const Boolean *from) +{ + Boolean *newnode = makeNode(Boolean); + + COPY_SCALAR_FIELD(val); + + return newnode; +} + static String * _copyString(const String *from) { @@ -5355,6 +5368,9 @@ copyObjectImpl(const void *from) case T_Float: retval = _copyFloat(from); break; + case T_Boolean: + retval = _copyBoolean(from); + break; case T_String: retval = _copyString(from); break; diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index cb7ddd463c..36a003bed0 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -3138,6 +3138,14 @@ _equalFloat(const Float *a, const Float *b) return true; } +static bool +_equalBoolean(const Boolean *a, const Boolean *b) +{ + COMPARE_SCALAR_FIELD(val); + + return true; +} + static bool _equalString(const String *a, const String *b) { @@ -3374,6 +3382,9 @@ equal(const void *a, const void *b) case T_Float: retval = _equalFloat(a, b); break; + case T_Boolean: + retval = _equalBoolean(a, b); + break; case T_String: retval = _equalString(a, b); break; diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c index e276264882..397aa6de3c 100644 --- a/src/backend/nodes/nodeFuncs.c +++ b/src/backend/nodes/nodeFuncs.c @@ -3535,6 +3535,7 @@ raw_expression_tree_walker(Node *node, case T_SQLValueFunction: case T_Integer: case T_Float: + case T_Boolean: case T_String: case T_BitString: case T_ParamRef: diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 91a89b6d51..c100215f40 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -3433,6 +3433,12 @@ _outFloat(StringInfo str, const Float *node) appendStringInfoString(str, node->val); } +static void +_outBoolean(StringInfo str, const Boolean *node) +{ + appendStringInfoString(str, node->val ? "true" : "false"); +} + static void _outString(StringInfo str, const String *node) { @@ -3845,6 +3851,8 @@ outNode(StringInfo str, const void *obj) _outInteger(str, (Integer *) obj); else if (IsA(obj, Float)) _outFloat(str, (Float *) obj); + else if (IsA(obj, Boolean)) + _outBoolean(str, (Boolean *) obj); else if (IsA(obj, String)) _outString(str, (String *) obj); else if (IsA(obj, BitString)) diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c index d281f7db6c..6a82197687 100644 --- a/src/backend/nodes/read.c +++ b/src/backend/nodes/read.c @@ -283,6 +283,8 @@ nodeTokenType(const char *token, int length) retval = RIGHT_PAREN; else if (*token == '{') retval = LEFT_BRACE; + else if (strcmp(token, "true") == 0 || strcmp(token, "false") == 0) + retval = T_Boolean; else if (*token == '"' && length > 1 && token[length - 1] == '"') retval = T_String; else if (*token == 'b') @@ -438,6 +440,9 @@ nodeRead(const char *token, int tok_len) result = (Node *) makeFloat(fval); } break; + case T_Boolean: + result = (Node *) makeBoolean(token[0] == 't'); + break; case T_String: /* need to remove leading and trailing quotes, and backslashes */ result = (Node *) makeString(debackslash(token + 1, tok_len - 2)); diff --git a/src/backend/nodes/value.c b/src/backend/nodes/value.c index 515f93c223..42c2f7199c 100644 --- a/src/backend/nodes/value.c +++ b/src/backend/nodes/value.c @@ -42,6 +42,18 @@ makeFloat(char *numericStr) return v; } +/* + * makeBoolean + */ +Boolean * +makeBoolean(bool val) +{ + Boolean *v = makeNode(Boolean); + + v->val = val; + return v; +} + /* * makeString * diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 3d4dd43e47..ce06100c63 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -177,10 +177,10 @@ static Node *makeStringConst(char *str, int location); static Node *makeStringConstCast(char *str, int location, TypeName *typename); static Node *makeIntConst(int val, int location); static Node *makeFloatConst(char *str, int location); +static Node *makeBoolAConst(bool state, int location); static Node *makeBitStringConst(char *str, int location); static Node *makeNullAConst(int location); static Node *makeAConst(Node *v, int location); -static Node *makeBoolAConst(bool state, int location); static RoleSpec *makeRoleSpec(RoleSpecType type, int location); static void check_qualified_name(List *names, core_yyscan_t yyscanner); static List *check_func_name(List *names, core_yyscan_t yyscanner); @@ -1133,7 +1133,7 @@ AlterOptRoleElem: } | INHERIT { - $$ = makeDefElem("inherit", (Node *)makeInteger(true), @1); + $$ = makeDefElem("inherit", (Node *)makeBoolean(true), @1); } | CONNECTION LIMIT SignedIconst { @@ -1156,36 +1156,36 @@ AlterOptRoleElem: * size of the main parser. */ if (strcmp($1, "superuser") == 0) - $$ = makeDefElem("superuser", (Node *)makeInteger(true), @1); + $$ = makeDefElem("superuser", (Node *)makeBoolean(true), @1); else if (strcmp($1, "nosuperuser") == 0) - $$ = makeDefElem("superuser", (Node *)makeInteger(false), @1); + $$ = makeDefElem("superuser", (Node *)makeBoolean(false), @1); else if (strcmp($1, "createrole") == 0) - $$ = makeDefElem("createrole", (Node *)makeInteger(true), @1); + $$ = makeDefElem("createrole", (Node *)makeBoolean(true), @1); else if (strcmp($1, "nocreaterole") == 0) - $$ = makeDefElem("createrole", (Node *)makeInteger(false), @1); + $$ = makeDefElem("createrole", (Node *)makeBoolean(false), @1); else if (strcmp($1, "replication") == 0) - $$ = makeDefElem("isreplication", (Node *)makeInteger(true), @1); + $$ = makeDefElem("isreplication", (Node *)makeBoolean(true), @1); else if (strcmp($1, "noreplication") == 0) - $$ = makeDefElem("isreplication", (Node *)makeInteger(false), @1); + $$ = makeDefElem("isreplication", (Node *)makeBoolean(false), @1); else if (strcmp($1, "createdb") == 0) - $$ = makeDefElem("createdb", (Node *)makeInteger(true), @1); + $$ = makeDefElem("createdb", (Node *)makeBoolean(true), @1); else if (strcmp($1, "nocreatedb") == 0) - $$ = makeDefElem("createdb", (Node *)makeInteger(false), @1); + $$ = makeDefElem("createdb", (Node *)makeBoolean(false), @1); else if (strcmp($1, "login") == 0) - $$ = makeDefElem("canlogin", (Node *)makeInteger(true), @1); + $$ = makeDefElem("canlogin", (Node *)makeBoolean(true), @1); else if (strcmp($1, "nologin") == 0) - $$ = makeDefElem("canlogin", (Node *)makeInteger(false), @1); + $$ = makeDefElem("canlogin", (Node *)makeBoolean(false), @1); else if (strcmp($1, "bypassrls") == 0) - $$ = makeDefElem("bypassrls", (Node *)makeInteger(true), @1); + $$ = makeDefElem("bypassrls", (Node *)makeBoolean(true), @1); else if (strcmp($1, "nobypassrls") == 0) - $$ = makeDefElem("bypassrls", (Node *)makeInteger(false), @1); + $$ = makeDefElem("bypassrls", (Node *)makeBoolean(false), @1); else if (strcmp($1, "noinherit") == 0) { /* * Note that INHERIT is a keyword, so it's handled by main parser, but * NOINHERIT is handled here. */ - $$ = makeDefElem("inherit", (Node *)makeInteger(false), @1); + $$ = makeDefElem("inherit", (Node *)makeBoolean(false), @1); } else ereport(ERROR, @@ -3175,7 +3175,7 @@ copy_opt_item: } | FREEZE { - $$ = makeDefElem("freeze", (Node *)makeInteger(true), @1); + $$ = makeDefElem("freeze", (Node *)makeBoolean(true), @1); } | DELIMITER opt_as Sconst { @@ -3191,7 +3191,7 @@ copy_opt_item: } | HEADER_P { - $$ = makeDefElem("header", (Node *)makeInteger(true), @1); + $$ = makeDefElem("header", (Node *)makeBoolean(true), @1); } | QUOTE opt_as Sconst { @@ -4499,11 +4499,11 @@ SeqOptElem: AS SimpleTypename } | CYCLE { - $$ = makeDefElem("cycle", (Node *)makeInteger(true), @1); + $$ = makeDefElem("cycle", (Node *)makeBoolean(true), @1); } | NO CYCLE { - $$ = makeDefElem("cycle", (Node *)makeInteger(false), @1); + $$ = makeDefElem("cycle", (Node *)makeBoolean(false), @1); } | INCREMENT opt_by NumericOnly { @@ -4739,7 +4739,7 @@ create_extension_opt_item: } | CASCADE { - $$ = makeDefElem("cascade", (Node *)makeInteger(true), @1); + $$ = makeDefElem("cascade", (Node *)makeBoolean(true), @1); } ; @@ -7936,15 +7936,15 @@ createfunc_opt_list: common_func_opt_item: CALLED ON NULL_P INPUT_P { - $$ = makeDefElem("strict", (Node *)makeInteger(false), @1); + $$ = makeDefElem("strict", (Node *)makeBoolean(false), @1); } | RETURNS NULL_P ON NULL_P INPUT_P { - $$ = makeDefElem("strict", (Node *)makeInteger(true), @1); + $$ = makeDefElem("strict", (Node *)makeBoolean(true), @1); } | STRICT_P { - $$ = makeDefElem("strict", (Node *)makeInteger(true), @1); + $$ = makeDefElem("strict", (Node *)makeBoolean(true), @1); } | IMMUTABLE { @@ -7960,27 +7960,27 @@ common_func_opt_item: } | EXTERNAL SECURITY DEFINER { - $$ = makeDefElem("security", (Node *)makeInteger(true), @1); + $$ = makeDefElem("security", (Node *)makeBoolean(true), @1); } | EXTERNAL SECURITY INVOKER { - $$ = makeDefElem("security", (Node *)makeInteger(false), @1); + $$ = makeDefElem("security", (Node *)makeBoolean(false), @1); } | SECURITY DEFINER { - $$ = makeDefElem("security", (Node *)makeInteger(true), @1); + $$ = makeDefElem("security", (Node *)makeBoolean(true), @1); } | SECURITY INVOKER { - $$ = makeDefElem("security", (Node *)makeInteger(false), @1); + $$ = makeDefElem("security", (Node *)makeBoolean(false), @1); } | LEAKPROOF { - $$ = makeDefElem("leakproof", (Node *)makeInteger(true), @1); + $$ = makeDefElem("leakproof", (Node *)makeBoolean(true), @1); } | NOT LEAKPROOF { - $$ = makeDefElem("leakproof", (Node *)makeInteger(false), @1); + $$ = makeDefElem("leakproof", (Node *)makeBoolean(false), @1); } | COST NumericOnly { @@ -8020,7 +8020,7 @@ createfunc_opt_item: } | WINDOW { - $$ = makeDefElem("window", (Node *)makeInteger(true), @1); + $$ = makeDefElem("window", (Node *)makeBoolean(true), @1); } | common_func_opt_item { @@ -9943,7 +9943,7 @@ AlterSubscriptionStmt: n->kind = ALTER_SUBSCRIPTION_ENABLED; n->subname = $3; n->options = list_make1(makeDefElem("enabled", - (Node *)makeInteger(true), @1)); + (Node *)makeBoolean(true), @1)); $$ = (Node *)n; } | ALTER SUBSCRIPTION name DISABLE_P @@ -9953,7 +9953,7 @@ AlterSubscriptionStmt: n->kind = ALTER_SUBSCRIPTION_ENABLED; n->subname = $3; n->options = list_make1(makeDefElem("enabled", - (Node *)makeInteger(false), @1)); + (Node *)makeBoolean(false), @1)); $$ = (Node *)n; } ; @@ -12876,7 +12876,7 @@ xmltable_column_el: (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant NULL / NOT NULL declarations for column \"%s\"", fc->colname), parser_errposition(defel->location))); - fc->is_not_null = intVal(defel->arg); + fc->is_not_null = boolVal(defel->arg); nullability_seen = true; } else @@ -12916,9 +12916,9 @@ xmltable_column_option_el: | DEFAULT b_expr { $$ = makeDefElem("default", $2, @1); } | NOT NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeInteger(true), @1); } + { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); } | NULL_P - { $$ = makeDefElem("is_not_null", (Node *) makeInteger(false), @1); } + { $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); } ; xml_namespace_list: @@ -16707,6 +16707,18 @@ makeFloatConst(char *str, int location) return (Node *)n; } +static Node * +makeBoolAConst(bool state, int location) +{ + A_Const *n = makeNode(A_Const); + + n->val.boolval.type = T_Boolean; + n->val.boolval.val = state; + n->location = location; + + return (Node *)n; +} + static Node * makeBitStringConst(char *str, int location) { @@ -16745,26 +16757,14 @@ makeAConst(Node *v, int location) n = makeIntConst(castNode(Integer, v)->val, location); break; - case T_String: default: - n = makeStringConst(castNode(String, v)->val, location); - break; + /* currently not used */ + Assert(false); } return n; } -/* makeBoolAConst() - * Create an A_Const string node and put it inside a boolean cast. - */ -static Node * -makeBoolAConst(bool state, int location) -{ - return makeStringConstCast((state ? "t" : "f"), - location, - SystemTypeName("bool")); -} - /* makeRoleSpec * Create a RoleSpec with the given type */ diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 8cfe6f67c0..f016c61b49 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -426,6 +426,14 @@ make_const(ParseState *pstate, A_Const *aconst) } break; + case T_Boolean: + val = BoolGetDatum(aconst->val.boolval.val); + + typeid = BOOLOID; + typelen = 1; + typebyval = true; + break; + case T_String: /* diff --git a/src/backend/replication/repl_gram.y b/src/backend/replication/repl_gram.y index dcb1108579..dd23f98b44 100644 --- a/src/backend/replication/repl_gram.y +++ b/src/backend/replication/repl_gram.y @@ -212,7 +212,7 @@ base_backup_legacy_opt: | K_PROGRESS { $$ = makeDefElem("progress", - (Node *)makeInteger(true), -1); + (Node *)makeBoolean(true), -1); } | K_FAST { @@ -222,12 +222,12 @@ base_backup_legacy_opt: | K_WAL { $$ = makeDefElem("wal", - (Node *)makeInteger(true), -1); + (Node *)makeBoolean(true), -1); } | K_NOWAIT { $$ = makeDefElem("wait", - (Node *)makeInteger(false), -1); + (Node *)makeBoolean(false), -1); } | K_MAX_RATE UCONST { @@ -237,12 +237,12 @@ base_backup_legacy_opt: | K_TABLESPACE_MAP { $$ = makeDefElem("tablespace_map", - (Node *)makeInteger(true), -1); + (Node *)makeBoolean(true), -1); } | K_NOVERIFY_CHECKSUMS { $$ = makeDefElem("verify_checksums", - (Node *)makeInteger(false), -1); + (Node *)makeBoolean(false), -1); } | K_MANIFEST SCONST { @@ -313,12 +313,12 @@ create_slot_legacy_opt: | K_RESERVE_WAL { $$ = makeDefElem("reserve_wal", - (Node *)makeInteger(true), -1); + (Node *)makeBoolean(true), -1); } | K_TWO_PHASE { $$ = makeDefElem("two_phase", - (Node *)makeInteger(true), -1); + (Node *)makeBoolean(true), -1); } ; diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 7c657c1241..15444c60b7 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -292,6 +292,7 @@ typedef enum NodeTag */ T_Integer, T_Float, + T_Boolean, T_String, T_BitString, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 4c5a8a39bf..9f3fd13371 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -304,6 +304,7 @@ typedef struct A_Const Node node; Integer ival; Float fval; + Boolean boolval; String sval; BitString bsval; } val; diff --git a/src/include/nodes/value.h b/src/include/nodes/value.h index 8b71b510eb..6630518c54 100644 --- a/src/include/nodes/value.h +++ b/src/include/nodes/value.h @@ -48,6 +48,12 @@ typedef struct Float char *val; } Float; +typedef struct Boolean +{ + NodeTag type; + bool val; +} Boolean; + typedef struct String { NodeTag type; @@ -62,10 +68,12 @@ typedef struct BitString #define intVal(v) (castNode(Integer, v)->val) #define floatVal(v) atof(castNode(Float, v)->val) +#define boolVal(v) (castNode(Boolean, v)->val) #define strVal(v) (castNode(String, v)->val) extern Integer *makeInteger(int i); extern Float *makeFloat(char *numericStr); +extern Boolean *makeBoolean(bool var); extern String *makeString(char *str); extern BitString *makeBitString(char *str); diff --git a/src/test/isolation/expected/ri-trigger.out b/src/test/isolation/expected/ri-trigger.out index 842df80a90..db85618bef 100644 --- a/src/test/isolation/expected/ri-trigger.out +++ b/src/test/isolation/expected/ri-trigger.out @@ -4,9 +4,9 @@ starting permutation: wxry1 c1 r2 wyrx2 c2 step wxry1: INSERT INTO child (parent_id) VALUES (0); step c1: COMMIT; step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wyrx2: DELETE FROM parent WHERE parent_id = 0; @@ -16,9 +16,9 @@ step c2: COMMIT; starting permutation: wxry1 r2 c1 wyrx2 c2 step wxry1: INSERT INTO child (parent_id) VALUES (0); step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step c1: COMMIT; @@ -29,9 +29,9 @@ step c2: COMMIT; starting permutation: wxry1 r2 wyrx2 c1 c2 step wxry1: INSERT INTO child (parent_id) VALUES (0); step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wyrx2: DELETE FROM parent WHERE parent_id = 0; @@ -42,9 +42,9 @@ ERROR: could not serialize access due to read/write dependencies among transact starting permutation: wxry1 r2 wyrx2 c2 c1 step wxry1: INSERT INTO child (parent_id) VALUES (0); step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wyrx2: DELETE FROM parent WHERE parent_id = 0; @@ -54,9 +54,9 @@ ERROR: could not serialize access due to read/write dependencies among transact starting permutation: r2 wxry1 c1 wyrx2 c2 step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wxry1: INSERT INTO child (parent_id) VALUES (0); @@ -67,9 +67,9 @@ step c2: COMMIT; starting permutation: r2 wxry1 wyrx2 c1 c2 step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wxry1: INSERT INTO child (parent_id) VALUES (0); @@ -80,9 +80,9 @@ ERROR: could not serialize access due to read/write dependencies among transact starting permutation: r2 wxry1 wyrx2 c2 c1 step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wxry1: INSERT INTO child (parent_id) VALUES (0); @@ -93,9 +93,9 @@ ERROR: could not serialize access due to read/write dependencies among transact starting permutation: r2 wyrx2 wxry1 c1 c2 step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wyrx2: DELETE FROM parent WHERE parent_id = 0; @@ -106,9 +106,9 @@ ERROR: could not serialize access due to read/write dependencies among transact starting permutation: r2 wyrx2 wxry1 c2 c1 step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wyrx2: DELETE FROM parent WHERE parent_id = 0; @@ -119,9 +119,9 @@ ERROR: could not serialize access due to read/write dependencies among transact starting permutation: r2 wyrx2 c2 wxry1 c1 step r2: SELECT TRUE; -bool ----- -t +?column? +-------- +t (1 row) step wyrx2: DELETE FROM parent WHERE parent_id = 0; diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out index 3a4fd45147..e0c4bee893 100644 --- a/src/test/regress/expected/create_function_3.out +++ b/src/test/regress/expected/create_function_3.out @@ -403,7 +403,7 @@ SELECT pg_get_functiondef('functest_S_13'::regproc); LANGUAGE sql + BEGIN ATOMIC + SELECT 1; + - SELECT false AS bool; + + SELECT false; + END + (1 row) base-commit: 86d9888d2ead04a1a139bbaef9d7f4648022fe4b -- 2.34.1