aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2022-11-04 10:39:52 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2022-11-04 10:39:52 -0400
commit2c6d43650d16d91a3e731d236315beffd98db729 (patch)
treeb4a48d893a7a7c11a7195928f719057bd4bb6cda
parent81173264440d7d3bd6479313b1d4611a2bfe8031 (diff)
downloadpostgresql-2c6d43650d16d91a3e731d236315beffd98db729.tar.gz
postgresql-2c6d43650d16d91a3e731d236315beffd98db729.zip
Fix CREATE DATABASE so we can pg_upgrade DBs with OIDs above 2^31.
Commit aa0105141 repeated one of the oldest mistakes in our book: thinking that OID is the same as int32. It isn't of course, and unsurprisingly the first person who came along with a database OID above 2 billion broke it. Repair. Per bug #17677 from Sergey Pankov. Back-patch to v15. Discussion: https://postgr.es/m/17677-a99fa067d7ed71c9@postgresql.org
-rw-r--r--src/backend/commands/dbcommands.c2
-rw-r--r--src/backend/commands/define.c33
-rw-r--r--src/backend/parser/gram.y4
-rw-r--r--src/include/commands/defrem.h1
4 files changed, 37 insertions, 3 deletions
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 034d14f39da..5f342478296 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -815,7 +815,7 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
}
else if (strcmp(defel->defname, "oid") == 0)
{
- dboid = defGetInt32(defel);
+ dboid = defGetObjectId(defel);
/*
* We don't normally permit new databases to be created with
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 0755ab1eae5..1e07fa97bb9 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -214,6 +214,39 @@ defGetInt64(DefElem *def)
}
/*
+ * Extract an OID value from a DefElem.
+ */
+Oid
+defGetObjectId(DefElem *def)
+{
+ if (def->arg == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires a numeric value",
+ def->defname)));
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ return (Oid) intVal(def->arg);
+ case T_Float:
+
+ /*
+ * Values too large for int4 will be represented as Float
+ * constants by the lexer. Accept these if they are valid OID
+ * strings.
+ */
+ return DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(castNode(Float, def->arg)->fval)));
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires a numeric value",
+ def->defname)));
+ }
+ return 0; /* keep compiler quiet */
+}
+
+/*
* Extract a possibly-qualified name (as a List of Strings) from a DefElem.
*/
List *
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f5bb30c5055..0b9cd62bf0c 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11067,9 +11067,9 @@ createdb_opt_items:
;
createdb_opt_item:
- createdb_opt_name opt_equal SignedIconst
+ createdb_opt_name opt_equal NumericOnly
{
- $$ = makeDefElem($1, (Node *) makeInteger($3), @1);
+ $$ = makeDefElem($1, $3, @1);
}
| createdb_opt_name opt_equal opt_boolean_or_string
{
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 56d2bb66161..1d3ce246c92 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -150,6 +150,7 @@ extern double defGetNumeric(DefElem *def);
extern bool defGetBoolean(DefElem *def);
extern int32 defGetInt32(DefElem *def);
extern int64 defGetInt64(DefElem *def);
+extern Oid defGetObjectId(DefElem *def);
extern List *defGetQualifiedName(DefElem *def);
extern TypeName *defGetTypeName(DefElem *def);
extern int defGetTypeLength(DefElem *def);