From eb4bdfc511f1c0f2e8f3971699c33fcfb8cf6105 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Mon, 3 Jan 2022 11:19:52 +0100 Subject: [PATCH v2 3/3] 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 | 2 + 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 | 9 +- 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(+), 128 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 0fe7e471d9..f17cfb5ade 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)->fval; + case T_Boolean: + return boolVal(def->arg) ? "true" : "false"; case T_String: return strVal(def->arg); case T_TypeName: 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 0aae87ff4a..288805ba78 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); if (dinherit) - inherit = intVal(dinherit->arg) != 0; + inherit = boolVal(dinherit->arg); if (dcreaterole) - createrole = intVal(dcreaterole->arg) != 0; + createrole = boolVal(dcreaterole->arg); if (dcreatedb) - createdb = intVal(dcreatedb->arg) != 0; + createdb = boolVal(dcreatedb->arg); if (dcanlogin) - canlogin = intVal(dcanlogin->arg) != 0; + canlogin = boolVal(dcanlogin->arg); if (disreplication) - isreplication = intVal(disreplication->arg) != 0; + isreplication = boolVal(disreplication->arg); 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); /* Check some permissions first */ if (issuper) @@ -700,37 +700,37 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) */ if (dissuper) { - new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(intVal(dissuper->arg)); + new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(boolVal(dissuper->arg)); new_record_repl[Anum_pg_authid_rolsuper - 1] = true; } if (dinherit) { - new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(intVal(dinherit->arg)); + new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(boolVal(dinherit->arg)); new_record_repl[Anum_pg_authid_rolinherit - 1] = true; } if (dcreaterole) { - new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(intVal(dcreaterole->arg)); + new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(boolVal(dcreaterole->arg)); new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true; } if (dcreatedb) { - new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(intVal(dcreatedb->arg)); + new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(boolVal(dcreatedb->arg)); new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true; } if (dcanlogin) { - new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(intVal(dcanlogin->arg)); + new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(boolVal(dcanlogin->arg)); new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true; } if (disreplication) { - new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(intVal(disreplication->arg)); + new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(boolVal(disreplication->arg)); new_record_repl[Anum_pg_authid_rolreplication - 1] = true; } @@ -779,7 +779,7 @@ AlterRole(ParseState *pstate, AlterRoleStmt *stmt) if (dbypassRLS) { - new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(intVal(dbypassRLS->arg)); + new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(boolVal(dbypassRLS->arg)); new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true; } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 439b903eb8..e0b440b9f6 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.fval); break; + case T_Boolean: + COPY_SCALAR_FIELD(val.boolval.boolval); + break; case T_String: COPY_STRING_FIELD(val.sval.sval); break; @@ -4948,6 +4951,16 @@ _copyFloat(const Float *from) return newnode; } +static Boolean * +_copyBoolean(const Boolean *from) +{ + Boolean *newnode = makeNode(Boolean); + + COPY_SCALAR_FIELD(boolval); + + 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 be09f91ee2..64522e8db0 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(boolval); + + 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 1accbc1e78..598adcd844 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->fval); } +static void +_outBoolean(StringInfo str, const Boolean *node) +{ + appendStringInfoString(str, node->boolval ? "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..b2330f2002 100644 --- a/src/backend/nodes/read.c +++ b/src/backend/nodes/read.c @@ -235,7 +235,7 @@ debackslash(const char *token, int length) * nodeTokenType - * returns the type of the node token contained in token. * It returns one of the following valid NodeTags: - * T_Integer, T_Float, T_String, T_BitString + * T_Integer, T_Float, T_Boolean, T_String, T_BitString * and some of its own: * RIGHT_PAREN, LEFT_PAREN, LEFT_BRACE, OTHER_TOKEN * @@ -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') @@ -298,7 +300,7 @@ nodeTokenType(const char *token, int length) * * This routine applies some semantic knowledge on top of the purely * lexical tokenizer pg_strtok(). It can read - * * Value token nodes (integers, floats, or strings); + * * Value token nodes (integers, floats, booleans, or strings); * * General nodes (via parseNodeString() from readfuncs.c); * * Lists of the above; * * Lists of integers or OIDs. @@ -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 ab2d6f74d3..937bf90e83 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->boolval = val; + return v; +} + /* * makeString * diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index adce748a69..1f6498f0a9 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); } ; @@ -7934,15 +7934,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 { @@ -7958,27 +7958,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 { @@ -8018,7 +8018,7 @@ createfunc_opt_item: } | WINDOW { - $$ = makeDefElem("window", (Node *)makeInteger(true), @1); + $$ = makeDefElem("window", (Node *)makeBoolean(true), @1); } | common_func_opt_item { @@ -9941,7 +9941,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 @@ -9951,7 +9951,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; } ; @@ -12874,7 +12874,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 @@ -12914,9 +12914,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: @@ -16705,6 +16705,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.boolval = state; + n->location = location; + + return (Node *)n; +} + static Node * makeBitStringConst(char *str, int location) { @@ -16743,26 +16755,14 @@ makeAConst(Node *v, int location) n = makeIntConst(castNode(Integer, v)->ival, location); break; - case T_String: default: - n = makeStringConst(castNode(String, v)->sval, 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 bd92133b21..533669e37e 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(boolVal(&aconst->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 784164b32a..ef12148b1f 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 cc3a4a639c..5f877ea9ea 100644 --- a/src/include/nodes/value.h +++ b/src/include/nodes/value.h @@ -48,6 +48,12 @@ typedef struct Float char *fval; } Float; +typedef struct Boolean +{ + NodeTag type; + bool boolval; +} Boolean; + typedef struct String { NodeTag type; @@ -62,10 +68,12 @@ typedef struct BitString #define intVal(v) (castNode(Integer, v)->ival) #define floatVal(v) atof(castNode(Float, v)->fval) +#define boolVal(v) (castNode(Boolean, v)->boolval) #define strVal(v) (castNode(String, v)->sval) 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) -- 2.34.1