Introduce new latest version 13.3 for postgresql
This introduces 13.3 postgresql version into openEuler, and now, 13.3 is the latest version like upstream postgresql community. The latest develop branch of postgresql community is 14.X, and the 14.X version is in beta status, means not stable. So we introduce 13.3 this time.
This commit is contained in:
parent
1b9765d8a5
commit
5bb860cbef
@ -1,108 +0,0 @@
|
||||
From 90adc16ea13750a6b6f704c6cf65dc0f1bdb845c Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Mon, 17 Jun 2019 21:48:34 +0900
|
||||
Subject: [PATCH] Fix buffer overflow when parsing SCRAM verifiers in backend
|
||||
|
||||
Any authenticated user can overflow a stack-based buffer by changing the
|
||||
user's own password to a purpose-crafted value. This often suffices to
|
||||
execute arbitrary code as the PostgreSQL operating system account.
|
||||
|
||||
This fix is contributed by multiple folks, based on an initial analysis
|
||||
from Tom Lane. This issue has been introduced by 68e61ee, so it was
|
||||
possible to make use of it at authentication time. It became more
|
||||
easily to trigger after ccae190 which has made the SCRAM parsing more
|
||||
strict when changing a password, in the case where the client passes
|
||||
down a verifier already hashed using SCRAM. Back-patch to v10 where
|
||||
SCRAM has been introduced.
|
||||
|
||||
Reported-by: Alexander Lakhin
|
||||
Author: Jonathan Katz, Heikki Linnakangas, Michael Paquier
|
||||
Security: CVE-2019-10164
|
||||
Backpatch-through: 10
|
||||
---
|
||||
src/backend/libpq/auth-scram.c | 35 ++++++++++++++++++++++++++--------
|
||||
src/test/regress/expected/password.out | 23 ++++++++++++++++++++++
|
||||
src/test/regress/sql/password.sql | 18 +++++++++++++++++
|
||||
3 files changed, 68 insertions(+), 8 deletions(-)
|
||||
|
||||
diff -Nurp postgresql-10.5/src/backend/libpq/auth-scram.c postgresql-10.5-bak/src/backend/libpq/auth-scram.c
|
||||
--- postgresql-10.5/src/backend/libpq/auth-scram.c 2018-08-06 16:05:31.000000000 -0400
|
||||
+++ postgresql-10.5-bak/src/backend/libpq/auth-scram.c 2019-08-01 10:03:08.505000000 -0400
|
||||
@@ -474,6 +474,12 @@ scram_verify_plain_password(const char *
|
||||
/*
|
||||
* Parse and validate format of given SCRAM verifier.
|
||||
*
|
||||
+ * On success, the iteration count, salt, stored key, and server key are
|
||||
+ * extracted from the verifier, and returned to the caller. For 'stored_key'
|
||||
+ * and 'server_key', the caller must pass pre-allocated buffers of size
|
||||
+ * SCRAM_KEY_LEN. Salt is returned as a base64-encoded, null-terminated
|
||||
+ * string. The buffer for the salt is palloc'd by this function.
|
||||
+ *
|
||||
* Returns true if the SCRAM verifier has been parsed, and false otherwise.
|
||||
*/
|
||||
static bool
|
||||
@@ -489,6 +495,8 @@ parse_scram_verifier(const char *verifie
|
||||
char *serverkey_str;
|
||||
int decoded_len;
|
||||
char *decoded_salt_buf;
|
||||
+ char *decoded_stored_buf;
|
||||
+ char *decoded_server_buf;
|
||||
|
||||
/*
|
||||
* The verifier is of form:
|
||||
@@ -521,7 +529,8 @@ parse_scram_verifier(const char *verifie
|
||||
* although we return the encoded version to the caller.
|
||||
*/
|
||||
decoded_salt_buf = palloc(pg_b64_dec_len(strlen(salt_str)));
|
||||
- decoded_len = pg_b64_decode(salt_str, strlen(salt_str), decoded_salt_buf);
|
||||
+ decoded_len = pg_b64_decode(salt_str, strlen(salt_str),
|
||||
+ decoded_salt_buf);
|
||||
if (decoded_len < 0)
|
||||
goto invalid_verifier;
|
||||
*salt = pstrdup(salt_str);
|
||||
@@ -529,28 +538,38 @@ parse_scram_verifier(const char *verifie
|
||||
/*
|
||||
* Decode StoredKey and ServerKey.
|
||||
*/
|
||||
- if (pg_b64_dec_len(strlen(storedkey_str) != SCRAM_KEY_LEN))
|
||||
- goto invalid_verifier;
|
||||
+ decoded_stored_buf = palloc(pg_b64_dec_len(strlen(storedkey_str)));
|
||||
decoded_len = pg_b64_decode(storedkey_str, strlen(storedkey_str),
|
||||
- (char *) stored_key);
|
||||
+ decoded_stored_buf);
|
||||
if (decoded_len != SCRAM_KEY_LEN)
|
||||
goto invalid_verifier;
|
||||
+ memcpy(stored_key, decoded_stored_buf, SCRAM_KEY_LEN);
|
||||
|
||||
- if (pg_b64_dec_len(strlen(serverkey_str) != SCRAM_KEY_LEN))
|
||||
- goto invalid_verifier;
|
||||
+ decoded_server_buf = palloc(pg_b64_dec_len(strlen(serverkey_str)));
|
||||
decoded_len = pg_b64_decode(serverkey_str, strlen(serverkey_str),
|
||||
- (char *) server_key);
|
||||
+ decoded_server_buf);
|
||||
if (decoded_len != SCRAM_KEY_LEN)
|
||||
goto invalid_verifier;
|
||||
+ memcpy(server_key, decoded_server_buf, SCRAM_KEY_LEN);
|
||||
|
||||
return true;
|
||||
|
||||
invalid_verifier:
|
||||
- pfree(v);
|
||||
*salt = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Generate plausible SCRAM verifier parameters for mock authentication.
|
||||
+ *
|
||||
+ * In a normal authentication, these are extracted from the verifier
|
||||
+ * stored in the server. This function generates values that look
|
||||
+ * realistic, for when there is no stored verifier.
|
||||
+ *
|
||||
+ * Like in parse_scram_verifier(), for 'stored_key' and 'server_key', the
|
||||
+ * caller must pass pre-allocated buffers of size SCRAM_KEY_LEN, and
|
||||
+ * the buffer for the salt is palloc'd by this function.
|
||||
+ */
|
||||
static void
|
||||
mock_scram_verifier(const char *username, int *iterations, char **salt,
|
||||
uint8 *stored_key, uint8 *server_key)
|
||||
@ -1,77 +0,0 @@
|
||||
From d72a7e4da1001b29a661a4b1a52cb5c4d708bab0 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Mon, 17 Jun 2019 22:14:09 +0900
|
||||
Subject: [PATCH] Fix buffer overflow when processing SCRAM final message in
|
||||
libpq
|
||||
|
||||
When a client connects to a rogue server sending specifically-crafted
|
||||
messages, this can suffice to execute arbitrary code as the operating
|
||||
system account used by the client.
|
||||
|
||||
While on it, fix one error handling when decoding an incorrect salt
|
||||
included in the first message received from server.
|
||||
|
||||
Author: Michael Paquier
|
||||
Reviewed-by: Jonathan Katz, Heikki Linnakangas
|
||||
Security: CVE-2019-10164
|
||||
Backpatch-through: 10
|
||||
---
|
||||
src/interfaces/libpq/fe-auth-scram.c | 21 ++++++++++++++++++++-
|
||||
1 file changed, 20 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/interfaces/libpq/fe-auth-scram.c b/src/interfaces/libpq/fe-auth-scram.c
|
||||
index 7fa7f34c80..4cdf9ba93b 100644
|
||||
--- a/src/interfaces/libpq/fe-auth-scram.c
|
||||
+++ b/src/interfaces/libpq/fe-auth-scram.c
|
||||
@@ -462,6 +462,12 @@ read_server_first_message(fe_scram_state *state, char *input,
|
||||
state->saltlen = pg_b64_decode(encoded_salt,
|
||||
strlen(encoded_salt),
|
||||
state->salt);
|
||||
+ if (state->saltlen < 0)
|
||||
+ {
|
||||
+ printfPQExpBuffer(errormessage,
|
||||
+ libpq_gettext("malformed SCRAM message (invalid salt)\n"));
|
||||
+ return false;
|
||||
+ }
|
||||
|
||||
iterations_str = read_attr_value(&input, 'i', errormessage);
|
||||
if (iterations_str == NULL)
|
||||
@@ -492,6 +498,7 @@ read_server_final_message(fe_scram_state *state, char *input,
|
||||
PQExpBuffer errormessage)
|
||||
{
|
||||
char *encoded_server_signature;
|
||||
+ char *decoded_server_signature;
|
||||
int server_signature_len;
|
||||
|
||||
state->server_final_message = strdup(input);
|
||||
@@ -525,15 +532,27 @@ read_server_final_message(fe_scram_state *state, char *input,
|
||||
printfPQExpBuffer(errormessage,
|
||||
libpq_gettext("malformed SCRAM message (garbage at end of server-final-message)\n"));
|
||||
|
||||
+ server_signature_len = pg_b64_dec_len(strlen(encoded_server_signature));
|
||||
+ decoded_server_signature = malloc(server_signature_len);
|
||||
+ if (!decoded_server_signature)
|
||||
+ {
|
||||
+ printfPQExpBuffer(errormessage,
|
||||
+ libpq_gettext("out of memory\n"));
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
server_signature_len = pg_b64_decode(encoded_server_signature,
|
||||
strlen(encoded_server_signature),
|
||||
- state->ServerSignature);
|
||||
+ decoded_server_signature);
|
||||
if (server_signature_len != SCRAM_KEY_LEN)
|
||||
{
|
||||
+ free(decoded_server_signature);
|
||||
printfPQExpBuffer(errormessage,
|
||||
libpq_gettext("malformed SCRAM message (invalid server signature)\n"));
|
||||
return false;
|
||||
}
|
||||
+ memcpy(state->ServerSignature, decoded_server_signature, SCRAM_KEY_LEN);
|
||||
+ free(decoded_server_signature);
|
||||
|
||||
return true;
|
||||
}
|
||||
--
|
||||
2.11.0
|
||||
@ -1,224 +0,0 @@
|
||||
From 2062007cbf7008de383c8f2f4a9ad466ea243acf Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 5 Aug 2019 07:48:41 -0700
|
||||
Subject: [PATCH] Require the schema qualification in pg_temp.type_name(arg).
|
||||
|
||||
Commit aa27977fe21a7dfa4da4376ad66ae37cb8f0d0b5 introduced this
|
||||
restriction for pg_temp.function_name(arg); do likewise for types
|
||||
created in temporary schemas. Programs that this breaks should add
|
||||
"pg_temp." schema qualification or switch to arg::type_name syntax.
|
||||
Back-patch to 9.4 (all supported versions).
|
||||
|
||||
Reviewed by Tom Lane. Reported by Tom Lane.
|
||||
|
||||
Security: CVE-2019-10208
|
||||
---
|
||||
src/backend/catalog/namespace.c | 15 ++++++++++++++-
|
||||
src/backend/parser/parse_func.c | 7 ++++++-
|
||||
src/backend/parser/parse_type.c | 24 +++++++++++++++++++++---
|
||||
src/backend/utils/adt/ruleutils.c | 8 ++++++++
|
||||
src/include/catalog/namespace.h | 1 +
|
||||
src/include/parser/parse_type.h | 3 +++
|
||||
src/test/regress/expected/temp.out | 15 +++++++++++++++
|
||||
src/test/regress/sql/temp.sql | 12 ++++++++++++
|
||||
8 files changed, 79 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
|
||||
index 5a737c8ab3..6b75ce10da 100644
|
||||
--- a/src/backend/catalog/namespace.c
|
||||
+++ b/src/backend/catalog/namespace.c
|
||||
@@ -739,13 +739,23 @@ RelationIsVisible(Oid relid)
|
||||
|
||||
/*
|
||||
* TypenameGetTypid
|
||||
+ * Wrapper for binary compatibility.
|
||||
+ */
|
||||
+Oid
|
||||
+TypenameGetTypid(const char *typname)
|
||||
+{
|
||||
+ return TypenameGetTypidExtended(typname, true);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * TypenameGetTypidExtended
|
||||
* Try to resolve an unqualified datatype name.
|
||||
* Returns OID if type found in search path, else InvalidOid.
|
||||
*
|
||||
* This is essentially the same as RelnameGetRelid.
|
||||
*/
|
||||
Oid
|
||||
-TypenameGetTypid(const char *typname)
|
||||
+TypenameGetTypidExtended(const char *typname, bool temp_ok)
|
||||
{
|
||||
Oid typid;
|
||||
ListCell *l;
|
||||
@@ -756,6 +766,9 @@ TypenameGetTypid(const char *typname)
|
||||
{
|
||||
Oid namespaceId = lfirst_oid(l);
|
||||
|
||||
+ if (!temp_ok && namespaceId == myTempNamespace)
|
||||
+ continue; /* do not look in temp namespace */
|
||||
+
|
||||
typid = GetSysCacheOid2(TYPENAMENSP,
|
||||
PointerGetDatum(typname),
|
||||
ObjectIdGetDatum(namespaceId));
|
||||
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
|
||||
index 25ae4e5949..571d3d1b62 100644
|
||||
--- a/src/backend/parser/parse_func.c
|
||||
+++ b/src/backend/parser/parse_func.c
|
||||
@@ -1769,7 +1769,12 @@ FuncNameAsType(List *funcname)
|
||||
Oid result;
|
||||
Type typtup;
|
||||
|
||||
- typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
|
||||
+ /*
|
||||
+ * temp_ok=false protects the <refsect1 id="sql-createfunction-security">
|
||||
+ * contract for writing SECURITY DEFINER functions safely.
|
||||
+ */
|
||||
+ typtup = LookupTypeNameExtended(NULL, makeTypeNameFromNameList(funcname),
|
||||
+ NULL, false, false);
|
||||
if (typtup == NULL)
|
||||
return InvalidOid;
|
||||
|
||||
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
|
||||
index d0b3fbeb57..1171381487 100644
|
||||
--- a/src/backend/parser/parse_type.c
|
||||
+++ b/src/backend/parser/parse_type.c
|
||||
@@ -33,6 +33,18 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
|
||||
|
||||
/*
|
||||
* LookupTypeName
|
||||
+ * Wrapper for typical case.
|
||||
+ */
|
||||
+Type
|
||||
+LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
+ int32 *typmod_p, bool missing_ok)
|
||||
+{
|
||||
+ return LookupTypeNameExtended(pstate,
|
||||
+ typeName, typmod_p, true, missing_ok);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * LookupTypeNameExtended
|
||||
* Given a TypeName object, lookup the pg_type syscache entry of the type.
|
||||
* Returns NULL if no such type can be found. If the type is found,
|
||||
* the typmod value represented in the TypeName struct is computed and
|
||||
@@ -51,11 +63,17 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
|
||||
* found but is a shell, and there is typmod decoration, an error will be
|
||||
* thrown --- this is intentional.
|
||||
*
|
||||
+ * If temp_ok is false, ignore types in the temporary namespace. Pass false
|
||||
+ * when the caller will decide, using goodness of fit criteria, whether the
|
||||
+ * typeName is actually a type or something else. If typeName always denotes
|
||||
+ * a type (or denotes nothing), pass true.
|
||||
+ *
|
||||
* pstate is only used for error location info, and may be NULL.
|
||||
*/
|
||||
Type
|
||||
-LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
- int32 *typmod_p, bool missing_ok)
|
||||
+LookupTypeNameExtended(ParseState *pstate,
|
||||
+ const TypeName *typeName, int32 *typmod_p,
|
||||
+ bool temp_ok, bool missing_ok)
|
||||
{
|
||||
Oid typoid;
|
||||
HeapTuple tup;
|
||||
@@ -172,7 +190,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
else
|
||||
{
|
||||
/* Unqualified type name, so search the search path */
|
||||
- typoid = TypenameGetTypid(typname);
|
||||
+ typoid = TypenameGetTypidExtended(typname, temp_ok);
|
||||
}
|
||||
|
||||
/* If an array reference, return the array type instead */
|
||||
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
|
||||
index 3d1a701775..01789291bb 100644
|
||||
--- a/src/backend/utils/adt/ruleutils.c
|
||||
+++ b/src/backend/utils/adt/ruleutils.c
|
||||
@@ -9273,6 +9273,14 @@ get_coercion_expr(Node *arg, deparse_context *context,
|
||||
if (!PRETTY_PAREN(context))
|
||||
appendStringInfoChar(buf, ')');
|
||||
}
|
||||
+
|
||||
+ /*
|
||||
+ * Never emit resulttype(arg) functional notation. A pg_proc entry could
|
||||
+ * take precedence, and a resulttype in pg_temp would require schema
|
||||
+ * qualification that format_type_with_typemod() would usually omit. We've
|
||||
+ * standardized on arg::resulttype, but CAST(arg AS resulttype) notation
|
||||
+ * would work fine.
|
||||
+ */
|
||||
appendStringInfo(buf, "::%s",
|
||||
format_type_with_typemod(resulttype, resulttypmod));
|
||||
}
|
||||
diff --git a/src/include/catalog/namespace.h b/src/include/catalog/namespace.h
|
||||
index f2ee935623..59c5ea5be2 100644
|
||||
--- a/src/include/catalog/namespace.h
|
||||
+++ b/src/include/catalog/namespace.h
|
||||
@@ -66,6 +66,7 @@ extern Oid RelnameGetRelid(const char *relname);
|
||||
extern bool RelationIsVisible(Oid relid);
|
||||
|
||||
extern Oid TypenameGetTypid(const char *typname);
|
||||
+extern Oid TypenameGetTypidExtended(const char *typname, bool temp_ok);
|
||||
extern bool TypeIsVisible(Oid typid);
|
||||
|
||||
extern FuncCandidateList FuncnameGetCandidates(List *names,
|
||||
diff --git a/src/include/parser/parse_type.h b/src/include/parser/parse_type.h
|
||||
index 7b843d0b9d..ac1bf1009e 100644
|
||||
--- a/src/include/parser/parse_type.h
|
||||
+++ b/src/include/parser/parse_type.h
|
||||
@@ -21,6 +21,9 @@ typedef HeapTuple Type;
|
||||
|
||||
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||
int32 *typmod_p, bool missing_ok);
|
||||
+extern Type LookupTypeNameExtended(ParseState *pstate,
|
||||
+ const TypeName *typeName, int32 *typmod_p,
|
||||
+ bool temp_ok, bool missing_ok);
|
||||
extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
|
||||
bool missing_ok);
|
||||
extern Type typenameType(ParseState *pstate, const TypeName *typeName,
|
||||
diff --git a/src/test/regress/expected/temp.out b/src/test/regress/expected/temp.out
|
||||
index 7046deb0c8..aad562791e 100644
|
||||
--- a/src/test/regress/expected/temp.out
|
||||
+++ b/src/test/regress/expected/temp.out
|
||||
@@ -199,3 +199,18 @@ select pg_temp.whoami();
|
||||
(1 row)
|
||||
|
||||
drop table public.whereami;
|
||||
+-- types in temp schema
|
||||
+set search_path = pg_temp, public;
|
||||
+create domain pg_temp.nonempty as text check (value <> '');
|
||||
+-- function-syntax invocation of types matches rules for functions
|
||||
+select nonempty('');
|
||||
+ERROR: function nonempty(unknown) does not exist
|
||||
+LINE 1: select nonempty('');
|
||||
+ ^
|
||||
+HINT: No function matches the given name and argument types. You might need to add explicit type casts.
|
||||
+select pg_temp.nonempty('');
|
||||
+ERROR: value for domain nonempty violates check constraint "nonempty_check"
|
||||
+-- other syntax matches rules for tables
|
||||
+select ''::nonempty;
|
||||
+ERROR: value for domain nonempty violates check constraint "nonempty_check"
|
||||
+reset search_path;
|
||||
diff --git a/src/test/regress/sql/temp.sql b/src/test/regress/sql/temp.sql
|
||||
index d69a243fe7..c14c11444c 100644
|
||||
--- a/src/test/regress/sql/temp.sql
|
||||
+++ b/src/test/regress/sql/temp.sql
|
||||
@@ -151,3 +151,15 @@ select pg_temp.whoami();
|
||||
select pg_temp.whoami();
|
||||
|
||||
drop table public.whereami;
|
||||
+
|
||||
+-- types in temp schema
|
||||
+set search_path = pg_temp, public;
|
||||
+create domain pg_temp.nonempty as text check (value <> '');
|
||||
+-- function-syntax invocation of types matches rules for functions
|
||||
+select nonempty('');
|
||||
+select pg_temp.nonempty('');
|
||||
+-- other syntax matches rules for tables
|
||||
+select ''::nonempty;
|
||||
+
|
||||
+reset search_path;
|
||||
+
|
||||
--
|
||||
2.11.0
|
||||
@ -1,44 +0,0 @@
|
||||
From 21a134a26100b377191735ad49f996eac03047de Mon Sep 17 00:00:00 2001
|
||||
From: guiyao <guiyao@huawei.com>
|
||||
Date: Thu, 17 Dec 2020 09:34:13 -0500
|
||||
Subject: [PATCH] backport to fix CVE-2018-16850
|
||||
|
||||
---
|
||||
src/backend/utils/adt/ruleutils.c | 10 ++++++----
|
||||
1 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
|
||||
index 4c9a49c..0eea491 100644
|
||||
--- a/src/backend/utils/adt/ruleutils.c
|
||||
+++ b/src/backend/utils/adt/ruleutils.c
|
||||
@@ -952,22 +952,24 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
|
||||
value = fastgetattr(ht_trig, Anum_pg_trigger_tgoldtable,
|
||||
tgrel->rd_att, &isnull);
|
||||
if (!isnull)
|
||||
- tgoldtable = NameStr(*((NameData *) DatumGetPointer(value)));
|
||||
+ tgoldtable = NameStr(*DatumGetName(value));
|
||||
else
|
||||
tgoldtable = NULL;
|
||||
value = fastgetattr(ht_trig, Anum_pg_trigger_tgnewtable,
|
||||
tgrel->rd_att, &isnull);
|
||||
if (!isnull)
|
||||
- tgnewtable = NameStr(*((NameData *) DatumGetPointer(value)));
|
||||
+ tgnewtable = NameStr(*DatumGetName(value));
|
||||
else
|
||||
tgnewtable = NULL;
|
||||
if (tgoldtable != NULL || tgnewtable != NULL)
|
||||
{
|
||||
appendStringInfoString(&buf, "REFERENCING ");
|
||||
if (tgoldtable != NULL)
|
||||
- appendStringInfo(&buf, "OLD TABLE AS %s ", tgoldtable);
|
||||
+ appendStringInfo(&buf, "OLD TABLE AS %s ",
|
||||
+ quote_identifier(tgoldtable));
|
||||
if (tgnewtable != NULL)
|
||||
- appendStringInfo(&buf, "NEW TABLE AS %s ", tgnewtable);
|
||||
+ appendStringInfo(&buf, "NEW TABLE AS %s ",
|
||||
+ quote_identifier(tgnewtable));
|
||||
}
|
||||
|
||||
if (TRIGGER_FOR_ROW(trigrec->tgtype))
|
||||
--
|
||||
1.8.3.1
|
||||
@ -1,75 +0,0 @@
|
||||
From 1aebfbea83c4a3e1a0aba4b0910135dc5a45666c Mon Sep 17 00:00:00 2001
|
||||
From: Dean Rasheed <dean.a.rasheed@gmail.com>
|
||||
Date: Mon, 6 May 2019 11:38:43 +0100
|
||||
Subject: [PATCH] Fix security checks for selectivity estimation functions with
|
||||
RLS.
|
||||
|
||||
In commit e2d4ef8de8, security checks were added to prevent
|
||||
user-supplied operators from running over data from pg_statistic
|
||||
unless the user has table or column privileges on the table, or the
|
||||
operator is leakproof. For a table with RLS, however, checking for
|
||||
table or column privileges is insufficient, since that does not
|
||||
guarantee that the user has permission to view all of the column's
|
||||
data.
|
||||
|
||||
Fix this by also checking for securityQuals on the RTE, and insisting
|
||||
that the operator be leakproof if there are any. Thus the
|
||||
leakproofness check will only be skipped if there are no securityQuals
|
||||
and the user has table or column privileges on the table -- i.e., only
|
||||
if we know that the user has access to all the data in the column.
|
||||
|
||||
Back-patch to 9.5 where RLS was added.
|
||||
|
||||
Dean Rasheed, reviewed by Jonathan Katz and Stephen Frost.
|
||||
|
||||
Security: CVE-2019-10130
|
||||
---
|
||||
src/backend/utils/adt/selfuncs.c | 21 +++++++++++++++------
|
||||
src/test/regress/expected/rowsecurity.out | 21 +++++++++++++++++++++
|
||||
src/test/regress/sql/rowsecurity.sql | 20 ++++++++++++++++++++
|
||||
3 files changed, 56 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
|
||||
index b41991315520..514612857ad6 100644
|
||||
--- a/src/backend/utils/adt/selfuncs.c
|
||||
+++ b/src/backend/utils/adt/selfuncs.c
|
||||
@@ -4597,9 +4597,13 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
|
||||
* For simplicity, we insist on the whole
|
||||
* table being selectable, rather than trying
|
||||
* to identify which column(s) the index
|
||||
- * depends on.
|
||||
+ * depends on. Also require all rows to be
|
||||
+ * selectable --- there must be no
|
||||
+ * securityQuals from security barrier views
|
||||
+ * or RLS policies.
|
||||
*/
|
||||
vardata->acl_ok =
|
||||
+ rte->securityQuals == NIL &&
|
||||
(pg_class_aclcheck(rte->relid, GetUserId(),
|
||||
ACL_SELECT) == ACLCHECK_OK);
|
||||
}
|
||||
@@ -4663,12 +4667,17 @@ examine_simple_variable(PlannerInfo *root, Var *var,
|
||||
|
||||
if (HeapTupleIsValid(vardata->statsTuple))
|
||||
{
|
||||
- /* check if user has permission to read this column */
|
||||
+ /*
|
||||
+ * Check if user has permission to read this column. We require
|
||||
+ * all rows to be accessible, so there must be no securityQuals
|
||||
+ * from security barrier views or RLS policies.
|
||||
+ */
|
||||
vardata->acl_ok =
|
||||
- (pg_class_aclcheck(rte->relid, GetUserId(),
|
||||
- ACL_SELECT) == ACLCHECK_OK) ||
|
||||
- (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
|
||||
- ACL_SELECT) == ACLCHECK_OK);
|
||||
+ rte->securityQuals == NIL &&
|
||||
+ ((pg_class_aclcheck(rte->relid, GetUserId(),
|
||||
+ ACL_SELECT) == ACLCHECK_OK) ||
|
||||
+ (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
|
||||
+ ACL_SELECT) == ACLCHECK_OK));
|
||||
}
|
||||
else
|
||||
{
|
||||
--
|
||||
2.11.0
|
||||
@ -1,42 +0,0 @@
|
||||
From b048f558dd7c26a0c630a2cff29d3d8981eaf6b9 Mon Sep 17 00:00:00 2001
|
||||
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
|
||||
Date: Mon, 10 Feb 2020 11:47:09 -0300
|
||||
Subject: [PATCH] Fix priv checks for ALTER <object> DEPENDS ON EXTENSION
|
||||
|
||||
Marking an object as dependant on an extension did not have any
|
||||
privilege check whatsoever; this allowed any user to mark objects as
|
||||
droppable by anyone able to DROP EXTENSION, which could be used to cause
|
||||
system-wide havoc. Disallow by checking that the calling user owns the
|
||||
mentioned object.
|
||||
|
||||
(No constraints are placed on the extension.)
|
||||
|
||||
Security: CVE-2020-1720
|
||||
Reported-by: Tom Lane
|
||||
Discussion: 31605.1566429043@sss.pgh.pa.us
|
||||
---
|
||||
src/backend/commands/alter.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
|
||||
index fca85ba2c17f..1cb84182b05f 100644
|
||||
--- a/src/backend/commands/alter.c
|
||||
+++ b/src/backend/commands/alter.c
|
||||
@@ -430,6 +430,17 @@ ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddre
|
||||
get_object_address_rv(stmt->objectType, stmt->relation, (List *) stmt->object,
|
||||
&rel, AccessExclusiveLock, false);
|
||||
|
||||
+ /*
|
||||
+ * Verify that the user is entitled to run the command.
|
||||
+ *
|
||||
+ * We don't check any privileges on the extension, because that's not
|
||||
+ * needed. The object owner is stipulating, by running this command, that
|
||||
+ * the extension owner can drop the object whenever they feel like it,
|
||||
+ * which is not considered a problem.
|
||||
+ */
|
||||
+ check_object_ownership(GetUserId(),
|
||||
+ stmt->objectType, address, stmt->object, rel);
|
||||
+
|
||||
/*
|
||||
* If a relation was involved, it would have been opened and locked. We
|
||||
* don't need the relation here, but we'll retain the lock until commit.
|
||||
@ -1,96 +0,0 @@
|
||||
From 11da97024abbe76b8c81e3f2375b2a62e9717c67 Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 10 Aug 2020 09:22:54 -0700
|
||||
Subject: [PATCH] Empty search_path in logical replication apply worker and
|
||||
walsender.
|
||||
|
||||
This is like CVE-2018-1058 commit
|
||||
582edc369cdbd348d68441fc50fa26a84afd0c1a. Today, a malicious user of a
|
||||
publisher or subscriber database can invoke arbitrary SQL functions
|
||||
under an identity running replication, often a superuser. This fix may
|
||||
cause "does not exist" or "no schema has been selected to create in"
|
||||
errors in a replication process. After upgrading, consider watching
|
||||
server logs for these errors. Objects accruing schema qualification in
|
||||
the wake of the earlier commit are unlikely to need further correction.
|
||||
Back-patch to v10, which introduced logical replication.
|
||||
|
||||
Security: CVE-2020-14349
|
||||
reason: fix CVE-2020-14349
|
||||
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=11da97024abbe76b8c81e3f2375b2a62e9717c67
|
||||
|
||||
Signed-off-by: Noah Misch <noah@leadboat.com>
|
||||
---
|
||||
.../libpqwalreceiver/libpqwalreceiver.c | 17 +++++++++++++++++
|
||||
src/backend/replication/logical/worker.c | 6 ++++++
|
||||
src/test/subscription/t/001_rep_changes.pl | 4 ++++
|
||||
3 files changed, 27 insertions(+)
|
||||
|
||||
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
|
||||
index 37b481c..564e6d3 100644
|
||||
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
|
||||
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "pqexpbuffer.h"
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/pg_type.h"
|
||||
+#include "fe_utils/connect.h"
|
||||
#include "funcapi.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -210,6 +211,22 @@ libpqrcv_connect(const char *conninfo, bool logical, const char *appname,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+ if (logical)
|
||||
+ {
|
||||
+ PGresult *res;
|
||||
+
|
||||
+ res = libpqrcv_PQexec(conn->streamConn,
|
||||
+ ALWAYS_SECURE_SEARCH_PATH_SQL);
|
||||
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
+ {
|
||||
+ PQclear(res);
|
||||
+ ereport(ERROR,
|
||||
+ (errmsg("could not clear search path: %s",
|
||||
+ pchomp(PQerrorMessage(conn->streamConn)))));
|
||||
+ }
|
||||
+ PQclear(res);
|
||||
+ }
|
||||
+
|
||||
conn->logical = logical;
|
||||
|
||||
return conn;
|
||||
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
|
||||
index bd60094..07b765a 100644
|
||||
--- a/src/backend/replication/logical/worker.c
|
||||
+++ b/src/backend/replication/logical/worker.c
|
||||
@@ -1548,6 +1548,12 @@ ApplyWorkerMain(Datum main_arg)
|
||||
BackgroundWorkerInitializeConnectionByOid(MyLogicalRepWorker->dbid,
|
||||
MyLogicalRepWorker->userid);
|
||||
|
||||
+ /*
|
||||
+ * Set always-secure search path, so malicious users can't redirect user
|
||||
+ * code (e.g. pg_index.indexprs).
|
||||
+ */
|
||||
+ SetConfigOption("search_path", "", PGC_SUSET, PGC_S_OVERRIDE);
|
||||
+
|
||||
/* Load the subscription into persistent memory context. */
|
||||
ApplyContext = AllocSetContextCreate(TopMemoryContext,
|
||||
"ApplyContext",
|
||||
diff --git a/src/test/subscription/t/001_rep_changes.pl b/src/test/subscription/t/001_rep_changes.pl
|
||||
index 0136c79..cda275b 100644
|
||||
--- a/src/test/subscription/t/001_rep_changes.pl
|
||||
+++ b/src/test/subscription/t/001_rep_changes.pl
|
||||
@@ -16,6 +16,10 @@ $node_subscriber->init(allows_streaming => 'logical');
|
||||
$node_subscriber->start;
|
||||
|
||||
# Create some preexisting content on publisher
|
||||
+$node_publisher->safe_psql(
|
||||
+ 'postgres',
|
||||
+ "CREATE FUNCTION public.pg_get_replica_identity_index(int)
|
||||
+ RETURNS regclass LANGUAGE sql AS 'SELECT 1/0'"); # shall not call
|
||||
$node_publisher->safe_psql('postgres',
|
||||
"CREATE TABLE tab_notrep AS SELECT generate_series(1,10) AS a");
|
||||
$node_publisher->safe_psql('postgres',
|
||||
--
|
||||
2.23.0
|
||||
@ -1,54 +0,0 @@
|
||||
From cec57b1a0fbcd3833086ba686897c5883e0a2afc Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 10 Aug 2020 09:22:54 -0700
|
||||
Subject: [PATCH] Document clashes between logical replication and untrusted
|
||||
users.
|
||||
|
||||
Back-patch to v10, which introduced logical replication.
|
||||
|
||||
Security: CVE-2020-14349
|
||||
reason: fix CVE-2020-14349
|
||||
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=cec57b1a0fbcd3833086ba686897c5883e0a2afc
|
||||
|
||||
Signed-off-by: Noah Misch <noah@leadboat.com>
|
||||
---
|
||||
doc/src/sgml/logical-replication.sgml | 22 +++++++++++++++++++---
|
||||
1 file changed, 19 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/doc/src/sgml/logical-replication.sgml b/doc/src/sgml/logical-replication.sgml
|
||||
index 41770a4..f5086b2 100644
|
||||
--- a/doc/src/sgml/logical-replication.sgml
|
||||
+++ b/doc/src/sgml/logical-replication.sgml
|
||||
@@ -490,11 +490,27 @@
|
||||
<sect1 id="logical-replication-security">
|
||||
<title>Security</title>
|
||||
|
||||
+ <para>
|
||||
+ A user able to modify the schema of subscriber-side tables can execute
|
||||
+ arbitrary code as a superuser. Limit ownership
|
||||
+ and <literal>TRIGGER</literal> privilege on such tables to roles that
|
||||
+ superusers trust. Moreover, if untrusted users can create tables, use only
|
||||
+ publications that list tables explicitly. That is to say, create a
|
||||
+ subscription <literal>FOR ALL TABLES</literal> only when superusers trust
|
||||
+ every user permitted to create a non-temp table on the publisher or the
|
||||
+ subscriber.
|
||||
+ </para>
|
||||
+
|
||||
<para>
|
||||
The role used for the replication connection must have
|
||||
- the <literal>REPLICATION</literal> attribute (or be a superuser). Access for the role must be
|
||||
- configured in <filename>pg_hba.conf</filename> and it must have the
|
||||
- <literal>LOGIN</literal> attribute.
|
||||
+ the <literal>REPLICATION</literal> attribute (or be a superuser). If the
|
||||
+ role lacks <literal>SUPERUSER</literal> and <literal>BYPASSRLS</literal>,
|
||||
+ publisher row security policies can execute. If the role does not trust
|
||||
+ all table owners, include <literal>options=-crow_security=off</literal> in
|
||||
+ the connection string; if a table owner then adds a row security policy,
|
||||
+ that setting will cause replication to halt rather than execute the policy.
|
||||
+ Access for the role must be configured in <filename>pg_hba.conf</filename>
|
||||
+ and it must have the <literal>LOGIN</literal> attribute.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
--
|
||||
2.23.0
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,492 +0,0 @@
|
||||
From a062fb822382398c7282810029016400feecf644 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Lane <tgl@sss.pgh.pa.us>
|
||||
Date: Wed, 21 Oct 2020 16:18:41 -0400
|
||||
Subject: [PATCH] Fix connection string handling in psql's \connect command.
|
||||
|
||||
psql's \connect claims to be able to re-use previous connection
|
||||
parameters, but in fact it only re-uses the database name, user name,
|
||||
host name (and possibly hostaddr, depending on version), and port.
|
||||
This is problematic for assorted use cases. Notably, pg_dump[all]
|
||||
emits "\connect databasename" commands which we would like to have
|
||||
re-use all other parameters. If such a script is loaded in a psql run
|
||||
that initially had "-d connstring" with some non-default parameters,
|
||||
those other parameters would be lost, potentially causing connection
|
||||
failure. (Thus, this is the same kind of bug addressed in commits
|
||||
a45bc8a4f and 8e5793ab6, although the details are much different.)
|
||||
|
||||
To fix, redesign do_connect() so that it pulls out all properties
|
||||
of the old PGconn using PQconninfo(), and then replaces individual
|
||||
properties in that array. In the case where we don't wish to re-use
|
||||
anything, get libpq's default settings using PQconndefaults() and
|
||||
replace entries in that, so that we don't need different code paths
|
||||
for the two cases.
|
||||
|
||||
This does result in an additional behavioral change for cases where
|
||||
the original connection parameters allowed multiple hosts, say
|
||||
"psql -h host1,host2", and the \connect request allows re-use of the
|
||||
host setting. Because the previous coding relied on PQhost(), it
|
||||
would only permit reconnection to the same host originally selected.
|
||||
Although one can think of scenarios where that's a good thing, there
|
||||
are others where it is not. Moreover, that behavior doesn't seem to
|
||||
meet the principle of least surprise, nor was it documented; nor is
|
||||
it even clear it was intended, since that coding long pre-dates the
|
||||
addition of multi-host support to libpq. Hence, this patch is content
|
||||
to drop it and re-use the host list as given.
|
||||
|
||||
Per Peter Eisentraut's comments on bug #16604. Back-patch to all
|
||||
supported branches.
|
||||
|
||||
Discussion: https://postgr.es/m/16604-933f4b8791227b15@postgresql.org
|
||||
---
|
||||
doc/src/sgml/ref/psql-ref.sgml | 44 ++++--
|
||||
src/bin/psql/command.c | 272 ++++++++++++++++++++++++---------
|
||||
2 files changed, 230 insertions(+), 86 deletions(-)
|
||||
|
||||
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
|
||||
index c8388513b8..7fda949f3b 100644
|
||||
--- a/doc/src/sgml/ref/psql-ref.sgml
|
||||
+++ b/doc/src/sgml/ref/psql-ref.sgml
|
||||
@@ -875,21 +875,17 @@ testdb=>
|
||||
<term><literal>\c</literal> or <literal>\connect [ -reuse-previous=<replaceable class="parameter">on|off</replaceable> ] [ <replaceable class="parameter">dbname</replaceable> [ <replaceable class="parameter">username</replaceable> ] [ <replaceable class="parameter">host</replaceable> ] [ <replaceable class="parameter">port</replaceable> ] | <replaceable class="parameter">conninfo</replaceable> ]</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
- Establishes a new connection to a <productname>PostgreSQL</>
|
||||
+ Establishes a new connection to a <productname>PostgreSQL</productname>
|
||||
server. The connection parameters to use can be specified either
|
||||
- using a positional syntax, or using <replaceable>conninfo</> connection
|
||||
- strings as detailed in <xref linkend="libpq-connstring">.
|
||||
+ using a positional syntax (one or more of database name, user,
|
||||
+ host, and port), or using a <replaceable>conninfo</replaceable>
|
||||
+ connection string as detailed in
|
||||
+ <xref linkend="libpq-connstring">. If no arguments are given, a
|
||||
+ new connection is made using the same parameters as before.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
- Where the command omits database name, user, host, or port, the new
|
||||
- connection can reuse values from the previous connection. By default,
|
||||
- values from the previous connection are reused except when processing
|
||||
- a <replaceable>conninfo</> string. Passing a first argument
|
||||
- of <literal>-reuse-previous=on</>
|
||||
- or <literal>-reuse-previous=off</literal> overrides that default.
|
||||
- When the command neither specifies nor reuses a particular parameter,
|
||||
- the <application>libpq</application> default is used. Specifying any
|
||||
+ Specifying any
|
||||
of <replaceable class="parameter">dbname</replaceable>,
|
||||
<replaceable class="parameter">username</replaceable>,
|
||||
<replaceable class="parameter">host</replaceable> or
|
||||
@@ -897,12 +893,31 @@ testdb=>
|
||||
as <literal>-</literal> is equivalent to omitting that parameter.
|
||||
</para>
|
||||
|
||||
+ <para>
|
||||
+ The new connection can re-use connection parameters from the previous
|
||||
+ connection; not only database name, user, host, and port, but other
|
||||
+ settings such as <replaceable>sslmode</replaceable>. By default,
|
||||
+ parameters are re-used in the positional syntax, but not when
|
||||
+ a <replaceable>conninfo</replaceable> string is given. Passing a
|
||||
+ first argument of <literal>-reuse-previous=on</literal>
|
||||
+ or <literal>-reuse-previous=off</literal> overrides that default. If
|
||||
+ parameters are re-used, then any parameter not explicitly specified as
|
||||
+ a positional parameter or in the <replaceable>conninfo</replaceable>
|
||||
+ string is taken from the existing connection's parameters. An
|
||||
+ exception is that if the <replaceable>host</replaceable> setting
|
||||
+ is changed from its previous value using the positional syntax,
|
||||
+ any <replaceable>hostaddr</replaceable> setting present in the
|
||||
+ existing connection's parameters is dropped.
|
||||
+ When the command neither specifies nor reuses a particular parameter,
|
||||
+ the <application>libpq</application> default is used.
|
||||
+ </para>
|
||||
+
|
||||
<para>
|
||||
If the new connection is successfully made, the previous
|
||||
connection is closed.
|
||||
- If the connection attempt failed (wrong user name, access
|
||||
- denied, etc.), the previous connection will only be kept if
|
||||
- <application>psql</application> is in interactive mode. When
|
||||
+ If the connection attempt fails (wrong user name, access
|
||||
+ denied, etc.), the previous connection will be kept if
|
||||
+ <application>psql</application> is in interactive mode. But when
|
||||
executing a non-interactive script, processing will
|
||||
immediately stop with an error. This distinction was chosen as
|
||||
a user convenience against typos on the one hand, and a safety
|
||||
@@ -917,6 +932,7 @@ testdb=>
|
||||
=> \c mydb myuser host.dom 6432
|
||||
=> \c service=foo
|
||||
=> \c "host=localhost port=5432 dbname=mydb connect_timeout=10 sslmode=disable"
|
||||
+=> \c -reuse-previous=on sslmode=require -- changes only sslmode
|
||||
=> \c postgresql://tom@localhost/mydb?application_name=myapp
|
||||
</programlisting>
|
||||
</listitem>
|
||||
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
|
||||
index a30a5f8ea0..91f7f0adc3 100644
|
||||
--- a/src/bin/psql/command.c
|
||||
+++ b/src/bin/psql/command.c
|
||||
@@ -2979,12 +2979,15 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
char *dbname, char *user, char *host, char *port)
|
||||
{
|
||||
PGconn *o_conn = pset.db,
|
||||
- *n_conn;
|
||||
+ *n_conn = NULL;
|
||||
+ PQconninfoOption *cinfo;
|
||||
+ int nconnopts = 0;
|
||||
+ bool same_host = false;
|
||||
char *password = NULL;
|
||||
- bool keep_password;
|
||||
+ bool success = true;
|
||||
+ bool keep_password = true;
|
||||
bool has_connection_string;
|
||||
bool reuse_previous;
|
||||
- PQExpBufferData connstr;
|
||||
|
||||
if (!o_conn && (!dbname || !user || !host || !port))
|
||||
{
|
||||
@@ -3012,6 +3015,11 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
reuse_previous = !has_connection_string;
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ /* If the old connection does not exist, there is nothing to reuse. */
|
||||
+ if (!o_conn)
|
||||
+ reuse_previous = false;
|
||||
+
|
||||
/* Silently ignore arguments subsequent to a connection string. */
|
||||
if (has_connection_string)
|
||||
{
|
||||
@@ -3020,41 +3028,126 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
port = NULL;
|
||||
}
|
||||
|
||||
- /* grab missing values from the old connection */
|
||||
- if (!user && reuse_previous)
|
||||
- user = PQuser(o_conn);
|
||||
- if (!host && reuse_previous)
|
||||
- host = PQhost(o_conn);
|
||||
- if (!port && reuse_previous)
|
||||
- port = PQport(o_conn);
|
||||
-
|
||||
/*
|
||||
- * Any change in the parameters read above makes us discard the password.
|
||||
- * We also discard it if we're to use a conninfo rather than the
|
||||
- * positional syntax.
|
||||
+ * If we intend to re-use connection parameters, collect them out of the
|
||||
+ * old connection, then replace individual values as necessary. Otherwise,
|
||||
+ * obtain a PQconninfoOption array containing libpq's defaults, and modify
|
||||
+ * that. Note this function assumes that PQconninfo, PQconndefaults, and
|
||||
+ * PQconninfoParse will all produce arrays containing the same options in
|
||||
+ * the same order.
|
||||
*/
|
||||
- if (has_connection_string)
|
||||
- keep_password = false;
|
||||
+ if (reuse_previous)
|
||||
+ cinfo = PQconninfo(o_conn);
|
||||
else
|
||||
- keep_password =
|
||||
- (user && PQuser(o_conn) && strcmp(user, PQuser(o_conn)) == 0) &&
|
||||
- (host && PQhost(o_conn) && strcmp(host, PQhost(o_conn)) == 0) &&
|
||||
- (port && PQport(o_conn) && strcmp(port, PQport(o_conn)) == 0);
|
||||
+ cinfo = PQconndefaults();
|
||||
|
||||
- /*
|
||||
- * Grab missing dbname from old connection. No password discard if this
|
||||
- * changes: passwords aren't (usually) database-specific.
|
||||
- */
|
||||
- if (!dbname && reuse_previous)
|
||||
+ if (cinfo)
|
||||
{
|
||||
- initPQExpBuffer(&connstr);
|
||||
- appendPQExpBuffer(&connstr, "dbname=");
|
||||
- appendConnStrVal(&connstr, PQdb(o_conn));
|
||||
- dbname = connstr.data;
|
||||
- /* has_connection_string=true would be a dead store */
|
||||
+ if (has_connection_string)
|
||||
+ {
|
||||
+ /* Parse the connstring and insert values into cinfo */
|
||||
+ PQconninfoOption *replcinfo;
|
||||
+ char *errmsg;
|
||||
+
|
||||
+ replcinfo = PQconninfoParse(dbname, &errmsg);
|
||||
+ if (replcinfo)
|
||||
+ {
|
||||
+ PQconninfoOption *ci;
|
||||
+ PQconninfoOption *replci;
|
||||
+
|
||||
+ for (ci = cinfo, replci = replcinfo;
|
||||
+ ci->keyword && replci->keyword;
|
||||
+ ci++, replci++)
|
||||
+ {
|
||||
+ Assert(strcmp(ci->keyword, replci->keyword) == 0);
|
||||
+ /* Insert value from connstring if one was provided */
|
||||
+ if (replci->val)
|
||||
+ {
|
||||
+ /*
|
||||
+ * We know that both val strings were allocated by
|
||||
+ * libpq, so the least messy way to avoid memory leaks
|
||||
+ * is to swap them.
|
||||
+ */
|
||||
+ char *swap = replci->val;
|
||||
+
|
||||
+ replci->val = ci->val;
|
||||
+ ci->val = swap;
|
||||
+ }
|
||||
+ }
|
||||
+ Assert(ci->keyword == NULL && replci->keyword == NULL);
|
||||
+
|
||||
+ /* While here, determine how many option slots there are */
|
||||
+ nconnopts = ci - cinfo;
|
||||
+
|
||||
+ PQconninfoFree(replcinfo);
|
||||
+
|
||||
+ /* We never re-use a password with a conninfo string. */
|
||||
+ keep_password = false;
|
||||
+
|
||||
+ /* Don't let code below try to inject dbname into params. */
|
||||
+ dbname = NULL;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* PQconninfoParse failed */
|
||||
+ if (errmsg)
|
||||
+ {
|
||||
+ psql_error("%s", errmsg);
|
||||
+ PQfreemem(errmsg);
|
||||
+ }
|
||||
+ else
|
||||
+ psql_error("out of memory\n");
|
||||
+ success = false;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /*
|
||||
+ * If dbname isn't a connection string, then we'll inject it and
|
||||
+ * the other parameters into the keyword array below. (We can't
|
||||
+ * easily insert them into the cinfo array because of memory
|
||||
+ * management issues: PQconninfoFree would misbehave on Windows.)
|
||||
+ * However, to avoid dependencies on the order in which parameters
|
||||
+ * appear in the array, make a preliminary scan to set
|
||||
+ * keep_password and same_host correctly.
|
||||
+ *
|
||||
+ * While any change in user, host, or port causes us to ignore the
|
||||
+ * old connection's password, we don't force that for dbname,
|
||||
+ * since passwords aren't database-specific.
|
||||
+ */
|
||||
+ PQconninfoOption *ci;
|
||||
+
|
||||
+ for (ci = cinfo; ci->keyword; ci++)
|
||||
+ {
|
||||
+ if (user && strcmp(ci->keyword, "user") == 0)
|
||||
+ {
|
||||
+ if (!(ci->val && strcmp(user, ci->val) == 0))
|
||||
+ keep_password = false;
|
||||
+ }
|
||||
+ else if (host && strcmp(ci->keyword, "host") == 0)
|
||||
+ {
|
||||
+ if (ci->val && strcmp(host, ci->val) == 0)
|
||||
+ same_host = true;
|
||||
+ else
|
||||
+ keep_password = false;
|
||||
+ }
|
||||
+ else if (port && strcmp(ci->keyword, "port") == 0)
|
||||
+ {
|
||||
+ if (!(ci->val && strcmp(port, ci->val) == 0))
|
||||
+ keep_password = false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* While here, determine how many option slots there are */
|
||||
+ nconnopts = ci - cinfo;
|
||||
+ }
|
||||
}
|
||||
else
|
||||
- connstr.data = NULL;
|
||||
+ {
|
||||
+ /* We failed to create the cinfo structure */
|
||||
+ psql_error("out of memory\n");
|
||||
+ success = false;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* If the user asked to be prompted for a password, ask for one now. If
|
||||
@@ -3066,7 +3159,7 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
* the postmaster's log. But libpq offers no API that would let us obtain
|
||||
* a password and then continue with the first connection attempt.
|
||||
*/
|
||||
- if (pset.getPassword == TRI_YES)
|
||||
+ if (pset.getPassword == TRI_YES && success)
|
||||
{
|
||||
password = prompt_for_password(user);
|
||||
}
|
||||
@@ -3079,52 +3172,60 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
password = NULL;
|
||||
}
|
||||
|
||||
- while (true)
|
||||
+ /* Loop till we have a connection or fail, which we might've already */
|
||||
+ while (success)
|
||||
{
|
||||
-#define PARAMS_ARRAY_SIZE 8
|
||||
- const char **keywords = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*keywords));
|
||||
- const char **values = pg_malloc(PARAMS_ARRAY_SIZE * sizeof(*values));
|
||||
- int paramnum = -1;
|
||||
-
|
||||
- keywords[++paramnum] = "host";
|
||||
- values[paramnum] = host;
|
||||
- keywords[++paramnum] = "port";
|
||||
- values[paramnum] = port;
|
||||
- keywords[++paramnum] = "user";
|
||||
- values[paramnum] = user;
|
||||
+ const char **keywords = pg_malloc((nconnopts + 1) * sizeof(*keywords));
|
||||
+ const char **values = pg_malloc((nconnopts + 1) * sizeof(*values));
|
||||
+ int paramnum = 0;
|
||||
+ PQconninfoOption *ci;
|
||||
|
||||
/*
|
||||
- * Position in the array matters when the dbname is a connection
|
||||
- * string, because settings in a connection string override earlier
|
||||
- * array entries only. Thus, user= in the connection string always
|
||||
- * takes effect, but client_encoding= often will not.
|
||||
+ * Copy non-default settings into the PQconnectdbParams parameter
|
||||
+ * arrays; but override any values specified old-style, as well as the
|
||||
+ * password and a couple of fields we want to set forcibly.
|
||||
*
|
||||
- * If you change this code, also change the initial-connection code in
|
||||
+ * If you change this code, see also the initial-connection code in
|
||||
* main(). For no good reason, a connection string password= takes
|
||||
* precedence in main() but not here.
|
||||
*/
|
||||
- keywords[++paramnum] = "dbname";
|
||||
- values[paramnum] = dbname;
|
||||
- keywords[++paramnum] = "password";
|
||||
- values[paramnum] = password;
|
||||
- keywords[++paramnum] = "fallback_application_name";
|
||||
- values[paramnum] = pset.progname;
|
||||
- keywords[++paramnum] = "client_encoding";
|
||||
- values[paramnum] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
|
||||
-
|
||||
+ for (ci = cinfo; ci->keyword; ci++)
|
||||
+ {
|
||||
+ keywords[paramnum] = ci->keyword;
|
||||
+
|
||||
+ if (dbname && strcmp(ci->keyword, "dbname") == 0)
|
||||
+ values[paramnum++] = dbname;
|
||||
+ else if (user && strcmp(ci->keyword, "user") == 0)
|
||||
+ values[paramnum++] = user;
|
||||
+ else if (host && strcmp(ci->keyword, "host") == 0)
|
||||
+ values[paramnum++] = host;
|
||||
+ else if (host && !same_host && strcmp(ci->keyword, "hostaddr") == 0)
|
||||
+ {
|
||||
+ /* If we're changing the host value, drop any old hostaddr */
|
||||
+ values[paramnum++] = NULL;
|
||||
+ }
|
||||
+ else if (port && strcmp(ci->keyword, "port") == 0)
|
||||
+ values[paramnum++] = port;
|
||||
+ else if (strcmp(ci->keyword, "password") == 0)
|
||||
+ values[paramnum++] = password;
|
||||
+ else if (strcmp(ci->keyword, "fallback_application_name") == 0)
|
||||
+ values[paramnum++] = pset.progname;
|
||||
+ else if (strcmp(ci->keyword, "client_encoding") == 0)
|
||||
+ values[paramnum++] = (pset.notty || getenv("PGCLIENTENCODING")) ? NULL : "auto";
|
||||
+ else if (ci->val)
|
||||
+ values[paramnum++] = ci->val;
|
||||
+ /* else, don't bother making libpq parse this keyword */
|
||||
+ }
|
||||
/* add array terminator */
|
||||
- keywords[++paramnum] = NULL;
|
||||
+ keywords[paramnum] = NULL;
|
||||
values[paramnum] = NULL;
|
||||
|
||||
- n_conn = PQconnectdbParams(keywords, values, true);
|
||||
+ /* Note we do not want libpq to re-expand the dbname parameter */
|
||||
+ n_conn = PQconnectdbParams(keywords, values, false);
|
||||
|
||||
pg_free(keywords);
|
||||
pg_free(values);
|
||||
|
||||
- /* We can immediately discard the password -- no longer needed */
|
||||
- if (password)
|
||||
- pg_free(password);
|
||||
-
|
||||
if (PQstatus(n_conn) == CONNECTION_OK)
|
||||
break;
|
||||
|
||||
@@ -3134,11 +3235,34 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
*/
|
||||
if (!password && PQconnectionNeedsPassword(n_conn) && pset.getPassword != TRI_NO)
|
||||
{
|
||||
+ /*
|
||||
+ * Prompt for password using the username we actually connected
|
||||
+ * with --- it might've come out of "dbname" rather than "user".
|
||||
+ */
|
||||
+ password = prompt_for_password(PQuser(n_conn));
|
||||
PQfinish(n_conn);
|
||||
- password = prompt_for_password(user);
|
||||
+ n_conn = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * We'll report the error below ... unless n_conn is NULL, indicating
|
||||
+ * that libpq didn't have enough memory to make a PGconn.
|
||||
+ */
|
||||
+ if (n_conn == NULL)
|
||||
+ psql_error("out of memory\n");
|
||||
+
|
||||
+ success = false;
|
||||
+ } /* end retry loop */
|
||||
+
|
||||
+ /* Release locally allocated data, whether we succeeded or not */
|
||||
+ if (password)
|
||||
+ pg_free(password);
|
||||
+ if (cinfo)
|
||||
+ PQconninfoFree(cinfo);
|
||||
+
|
||||
+ if (!success)
|
||||
+ {
|
||||
/*
|
||||
* Failed to connect to the database. In interactive mode, keep the
|
||||
* previous connection to the DB; in scripting mode, close our
|
||||
@@ -3146,7 +3270,11 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
*/
|
||||
if (pset.cur_cmd_interactive)
|
||||
{
|
||||
- psql_error("%s", PQerrorMessage(n_conn));
|
||||
+ if (n_conn)
|
||||
+ {
|
||||
+ psql_error("%s", PQerrorMessage(n_conn));
|
||||
+ PQfinish(n_conn);
|
||||
+ }
|
||||
|
||||
/* pset.db is left unmodified */
|
||||
if (o_conn)
|
||||
@@ -3154,7 +3282,12 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
}
|
||||
else
|
||||
{
|
||||
- psql_error("\\connect: %s", PQerrorMessage(n_conn));
|
||||
+ if (n_conn)
|
||||
+ {
|
||||
+ psql_error("\\connect: %s", PQerrorMessage(n_conn));
|
||||
+ PQfinish(n_conn);
|
||||
+ }
|
||||
+
|
||||
if (o_conn)
|
||||
{
|
||||
PQfinish(o_conn);
|
||||
@@ -3162,13 +3295,8 @@ do_connect(enum trivalue reuse_previous_specification,
|
||||
}
|
||||
}
|
||||
|
||||
- PQfinish(n_conn);
|
||||
- if (connstr.data)
|
||||
- termPQExpBuffer(&connstr);
|
||||
return false;
|
||||
}
|
||||
- if (connstr.data)
|
||||
- termPQExpBuffer(&connstr);
|
||||
|
||||
/*
|
||||
* Replace the old connection with the new one, and update
|
||||
--
|
||||
2.23.0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,782 +0,0 @@
|
||||
From bb3ab8bfb690721923e987d2dfab683b462c1e88 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Lane <tgl@sss.pgh.pa.us>
|
||||
Date: Thu, 24 Sep 2020 18:19:39 -0400
|
||||
Subject: [PATCH] Fix handling of -d "connection string" in pg_dump/pg_restore.
|
||||
|
||||
Parallel pg_dump failed if its -d parameter was a connection string
|
||||
containing any essential information other than host, port, or username.
|
||||
The same was true for pg_restore with --create.
|
||||
|
||||
The reason is that these scenarios failed to preserve the connection
|
||||
string from the command line; the code felt free to replace that with
|
||||
just the database name when reconnecting from a pg_dump parallel worker
|
||||
or after creating the target database. By chance, parallel pg_restore
|
||||
did not suffer this defect, as long as you didn't say --create.
|
||||
|
||||
In practice it seems that the error would be obvious only if the
|
||||
connstring included essential, non-default SSL or GSS parameters.
|
||||
This may explain why it took us so long to notice. (It also makes
|
||||
it very difficult to craft a regression test case illustrating the
|
||||
problem, since the test would fail in builds without those options.)
|
||||
|
||||
Fix by refactoring so that ConnectDatabase always receives all the
|
||||
relevant options directly from the command line, rather than
|
||||
reconstructed values. Inject a different database name, when necessary,
|
||||
by relying on libpq's rules for handling multiple "dbname" parameters.
|
||||
|
||||
While here, let's get rid of the essentially duplicate _connectDB
|
||||
function, as well as some obsolete nearby cruft.
|
||||
|
||||
Per bug #16604 from Zsolt Ero. Back-patch to all supported branches.
|
||||
|
||||
Discussion: https://postgr.es/m/16604-933f4b8791227b15@postgresql.org
|
||||
---
|
||||
src/bin/pg_dump/pg_backup.h | 36 ++--
|
||||
src/bin/pg_dump/pg_backup_archiver.c | 96 +++--------
|
||||
src/bin/pg_dump/pg_backup_archiver.h | 3 +-
|
||||
src/bin/pg_dump/pg_backup_db.c | 249 +++++++--------------------
|
||||
src/bin/pg_dump/pg_dump.c | 24 +--
|
||||
src/bin/pg_dump/pg_restore.c | 14 +-
|
||||
6 files changed, 131 insertions(+), 291 deletions(-)
|
||||
|
||||
diff --git a/src/bin/pg_dump/pg_backup.h b/src/bin/pg_dump/pg_backup.h
|
||||
index 560de01884..72c6a8db6c 100644
|
||||
--- a/src/bin/pg_dump/pg_backup.h
|
||||
+++ b/src/bin/pg_dump/pg_backup.h
|
||||
@@ -58,6 +58,20 @@ typedef enum _teSection
|
||||
SECTION_POST_DATA /* stuff to be processed after data */
|
||||
} teSection;
|
||||
|
||||
+/* Parameters needed by ConnectDatabase; same for dump and restore */
|
||||
+typedef struct _connParams
|
||||
+{
|
||||
+ /* These fields record the actual command line parameters */
|
||||
+ char *dbname; /* this may be a connstring! */
|
||||
+ char *pgport;
|
||||
+ char *pghost;
|
||||
+ char *username;
|
||||
+ trivalue promptPassword;
|
||||
+ /* If not NULL, this overrides the dbname obtained from command line */
|
||||
+ /* (but *only* the DB name, not anything else in the connstring) */
|
||||
+ char *override_dbname;
|
||||
+} ConnParams;
|
||||
+
|
||||
typedef struct _restoreOptions
|
||||
{
|
||||
int createDB; /* Issue commands to create the database */
|
||||
@@ -106,12 +120,9 @@ typedef struct _restoreOptions
|
||||
SimpleStringList tableNames;
|
||||
|
||||
int useDB;
|
||||
- char *dbname; /* subject to expand_dbname */
|
||||
- char *pgport;
|
||||
- char *pghost;
|
||||
- char *username;
|
||||
+ ConnParams cparams; /* parameters to use if useDB */
|
||||
+
|
||||
int noDataForFailedTables;
|
||||
- trivalue promptPassword;
|
||||
int exit_on_error;
|
||||
int compression;
|
||||
int suppressDumpWarnings; /* Suppress output of WARNING entries
|
||||
@@ -126,10 +137,8 @@ typedef struct _restoreOptions
|
||||
|
||||
typedef struct _dumpOptions
|
||||
{
|
||||
- const char *dbname; /* subject to expand_dbname */
|
||||
- const char *pghost;
|
||||
- const char *pgport;
|
||||
- const char *username;
|
||||
+ ConnParams cparams;
|
||||
+
|
||||
bool oids;
|
||||
|
||||
int binary_upgrade;
|
||||
@@ -239,12 +248,9 @@ typedef void (*SetupWorkerPtrType) (Archive *AH);
|
||||
* Main archiver interface.
|
||||
*/
|
||||
|
||||
-extern void ConnectDatabase(Archive *AH,
|
||||
- const char *dbname,
|
||||
- const char *pghost,
|
||||
- const char *pgport,
|
||||
- const char *username,
|
||||
- trivalue prompt_password);
|
||||
+extern void ConnectDatabase(Archive *AHX,
|
||||
+ const ConnParams *cparams,
|
||||
+ bool isReconnect);
|
||||
extern void DisconnectDatabase(Archive *AHX);
|
||||
extern PGconn *GetConnection(Archive *AHX);
|
||||
|
||||
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
|
||||
index 8892b17790..4003ab3b13 100644
|
||||
--- a/src/bin/pg_dump/pg_backup_archiver.c
|
||||
+++ b/src/bin/pg_dump/pg_backup_archiver.c
|
||||
@@ -144,6 +144,7 @@ InitDumpOptions(DumpOptions *opts)
|
||||
memset(opts, 0, sizeof(DumpOptions));
|
||||
/* set any fields that shouldn't default to zeroes */
|
||||
opts->include_everything = true;
|
||||
+ opts->cparams.promptPassword = TRI_DEFAULT;
|
||||
opts->dumpSections = DUMP_UNSECTIONED;
|
||||
}
|
||||
|
||||
@@ -157,6 +158,11 @@ dumpOptionsFromRestoreOptions(RestoreOptions *ropt)
|
||||
DumpOptions *dopt = NewDumpOptions();
|
||||
|
||||
/* this is the inverse of what's at the end of pg_dump.c's main() */
|
||||
+ dopt->cparams.dbname = ropt->cparams.dbname ? pg_strdup(ropt->cparams.dbname) : NULL;
|
||||
+ dopt->cparams.pgport = ropt->cparams.pgport ? pg_strdup(ropt->cparams.pgport) : NULL;
|
||||
+ dopt->cparams.pghost = ropt->cparams.pghost ? pg_strdup(ropt->cparams.pghost) : NULL;
|
||||
+ dopt->cparams.username = ropt->cparams.username ? pg_strdup(ropt->cparams.username) : NULL;
|
||||
+ dopt->cparams.promptPassword = ropt->cparams.promptPassword;
|
||||
dopt->outputClean = ropt->dropSchema;
|
||||
dopt->dataOnly = ropt->dataOnly;
|
||||
dopt->schemaOnly = ropt->schemaOnly;
|
||||
@@ -401,9 +407,7 @@ RestoreArchive(Archive *AHX)
|
||||
AHX->minRemoteVersion = 0;
|
||||
AHX->maxRemoteVersion = 9999999;
|
||||
|
||||
- ConnectDatabase(AHX, ropt->dbname,
|
||||
- ropt->pghost, ropt->pgport, ropt->username,
|
||||
- ropt->promptPassword);
|
||||
+ ConnectDatabase(AHX, &ropt->cparams, false);
|
||||
|
||||
/*
|
||||
* If we're talking to the DB directly, don't send comments since they
|
||||
@@ -823,16 +827,8 @@ restore_toc_entry(ArchiveHandle *AH, TocEntry *te, bool is_parallel)
|
||||
/* If we created a DB, connect to it... */
|
||||
if (strcmp(te->desc, "DATABASE") == 0)
|
||||
{
|
||||
- PQExpBufferData connstr;
|
||||
-
|
||||
- initPQExpBuffer(&connstr);
|
||||
- appendPQExpBufferStr(&connstr, "dbname=");
|
||||
- appendConnStrVal(&connstr, te->tag);
|
||||
- /* Abandon struct, but keep its buffer until process exit. */
|
||||
-
|
||||
ahlog(AH, 1, "connecting to new database \"%s\"\n", te->tag);
|
||||
_reconnectToDB(AH, te->tag);
|
||||
- ropt->dbname = connstr.data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,7 +962,7 @@ NewRestoreOptions(void)
|
||||
|
||||
/* set any fields that shouldn't default to zeroes */
|
||||
opts->format = archUnknown;
|
||||
- opts->promptPassword = TRI_DEFAULT;
|
||||
+ opts->cparams.promptPassword = TRI_DEFAULT;
|
||||
opts->dumpSections = DUMP_UNSECTIONED;
|
||||
|
||||
return opts;
|
||||
@@ -2388,8 +2384,6 @@ _allocAH(const char *FileSpec, const ArchiveFormat fmt,
|
||||
else
|
||||
AH->format = fmt;
|
||||
|
||||
- AH->promptPassword = TRI_DEFAULT;
|
||||
-
|
||||
switch (AH->format)
|
||||
{
|
||||
case archCustom:
|
||||
@@ -3157,27 +3151,20 @@ _doSetWithOids(ArchiveHandle *AH, const bool withOids)
|
||||
* If we're currently restoring right into a database, this will
|
||||
* actually establish a connection. Otherwise it puts a \connect into
|
||||
* the script output.
|
||||
- *
|
||||
- * NULL dbname implies reconnecting to the current DB (pretty useless).
|
||||
*/
|
||||
static void
|
||||
_reconnectToDB(ArchiveHandle *AH, const char *dbname)
|
||||
{
|
||||
if (RestoringToDB(AH))
|
||||
- ReconnectToServer(AH, dbname, NULL);
|
||||
+ ReconnectToServer(AH, dbname);
|
||||
else
|
||||
{
|
||||
- if (dbname)
|
||||
- {
|
||||
- PQExpBufferData connectbuf;
|
||||
+ PQExpBufferData connectbuf;
|
||||
|
||||
- initPQExpBuffer(&connectbuf);
|
||||
- appendPsqlMetaConnect(&connectbuf, dbname);
|
||||
- ahprintf(AH, "%s\n", connectbuf.data);
|
||||
- termPQExpBuffer(&connectbuf);
|
||||
- }
|
||||
- else
|
||||
- ahprintf(AH, "%s\n", "\\connect -\n");
|
||||
+ initPQExpBuffer(&connectbuf);
|
||||
+ appendPsqlMetaConnect(&connectbuf, dbname);
|
||||
+ ahprintf(AH, "%s\n", connectbuf.data);
|
||||
+ termPQExpBuffer(&connectbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4107,9 +4094,7 @@ restore_toc_entries_postfork(ArchiveHandle *AH, TocEntry *pending_list)
|
||||
/*
|
||||
* Now reconnect the single parent connection.
|
||||
*/
|
||||
- ConnectDatabase((Archive *) AH, ropt->dbname,
|
||||
- ropt->pghost, ropt->pgport, ropt->username,
|
||||
- ropt->promptPassword);
|
||||
+ ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
||||
|
||||
/* re-establish fixed state */
|
||||
_doSetFixedOutputState(AH);
|
||||
@@ -4690,54 +4675,15 @@ CloneArchive(ArchiveHandle *AH)
|
||||
clone->public.n_errors = 0;
|
||||
|
||||
/*
|
||||
- * Connect our new clone object to the database: In parallel restore the
|
||||
- * parent is already disconnected, because we can connect the worker
|
||||
- * processes independently to the database (no snapshot sync required). In
|
||||
- * parallel backup we clone the parent's existing connection.
|
||||
+ * Connect our new clone object to the database, using the same connection
|
||||
+ * parameters used for the original connection.
|
||||
*/
|
||||
- if (AH->mode == archModeRead)
|
||||
- {
|
||||
- RestoreOptions *ropt = AH->public.ropt;
|
||||
-
|
||||
- Assert(AH->connection == NULL);
|
||||
-
|
||||
- /* this also sets clone->connection */
|
||||
- ConnectDatabase((Archive *) clone, ropt->dbname,
|
||||
- ropt->pghost, ropt->pgport, ropt->username,
|
||||
- ropt->promptPassword);
|
||||
+ ConnectDatabase((Archive *) clone, &clone->public.ropt->cparams, true);
|
||||
|
||||
- /* re-establish fixed state */
|
||||
+ /* re-establish fixed state */
|
||||
+ if (AH->mode == archModeRead)
|
||||
_doSetFixedOutputState(clone);
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- PQExpBufferData connstr;
|
||||
- char *pghost;
|
||||
- char *pgport;
|
||||
- char *username;
|
||||
-
|
||||
- Assert(AH->connection != NULL);
|
||||
-
|
||||
- /*
|
||||
- * Even though we are technically accessing the parent's database
|
||||
- * object here, these functions are fine to be called like that
|
||||
- * because all just return a pointer and do not actually send/receive
|
||||
- * any data to/from the database.
|
||||
- */
|
||||
- initPQExpBuffer(&connstr);
|
||||
- appendPQExpBuffer(&connstr, "dbname=");
|
||||
- appendConnStrVal(&connstr, PQdb(AH->connection));
|
||||
- pghost = PQhost(AH->connection);
|
||||
- pgport = PQport(AH->connection);
|
||||
- username = PQuser(AH->connection);
|
||||
-
|
||||
- /* this also sets clone->connection */
|
||||
- ConnectDatabase((Archive *) clone, connstr.data,
|
||||
- pghost, pgport, username, TRI_NO);
|
||||
-
|
||||
- termPQExpBuffer(&connstr);
|
||||
- /* setupDumpWorker will fix up connection state */
|
||||
- }
|
||||
+ /* in write case, setupDumpWorker will fix up connection state */
|
||||
|
||||
/* Let the format-specific code have a chance too */
|
||||
(clone->ClonePtr) (clone);
|
||||
diff --git a/src/bin/pg_dump/pg_backup_archiver.h b/src/bin/pg_dump/pg_backup_archiver.h
|
||||
index 3b69868359..50829c4b2e 100644
|
||||
--- a/src/bin/pg_dump/pg_backup_archiver.h
|
||||
+++ b/src/bin/pg_dump/pg_backup_archiver.h
|
||||
@@ -304,7 +304,6 @@ struct _archiveHandle
|
||||
|
||||
/* Stuff for direct DB connection */
|
||||
char *archdbname; /* DB name *read* from archive */
|
||||
- trivalue promptPassword;
|
||||
char *savedPassword; /* password for ropt->username, if known */
|
||||
char *use_role;
|
||||
PGconn *connection;
|
||||
@@ -450,7 +449,7 @@ extern void InitArchiveFmt_Tar(ArchiveHandle *AH);
|
||||
|
||||
extern bool isValidTarHeader(char *header);
|
||||
|
||||
-extern int ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *newUser);
|
||||
+extern void ReconnectToServer(ArchiveHandle *AH, const char *dbname);
|
||||
extern void DropBlobIfExists(ArchiveHandle *AH, Oid oid);
|
||||
|
||||
void ahwrite(const void *ptr, size_t size, size_t nmemb, ArchiveHandle *AH);
|
||||
diff --git a/src/bin/pg_dump/pg_backup_db.c b/src/bin/pg_dump/pg_backup_db.c
|
||||
index 43f5941f93..4eaea4af4f 100644
|
||||
--- a/src/bin/pg_dump/pg_backup_db.c
|
||||
+++ b/src/bin/pg_dump/pg_backup_db.c
|
||||
@@ -30,7 +30,6 @@
|
||||
static const char *modulename = gettext_noop("archiver (db)");
|
||||
|
||||
static void _check_database_version(ArchiveHandle *AH);
|
||||
-static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
|
||||
static void notice_processor(void *arg, const char *message);
|
||||
|
||||
static void
|
||||
@@ -76,186 +75,51 @@ _check_database_version(ArchiveHandle *AH)
|
||||
|
||||
/*
|
||||
* Reconnect to the server. If dbname is not NULL, use that database,
|
||||
- * else the one associated with the archive handle. If username is
|
||||
- * not NULL, use that user name, else the one from the handle. If
|
||||
- * both the database and the user match the existing connection already,
|
||||
- * nothing will be done.
|
||||
- *
|
||||
- * Returns 1 in any case.
|
||||
+ * else the one associated with the archive handle.
|
||||
*/
|
||||
-int
|
||||
-ReconnectToServer(ArchiveHandle *AH, const char *dbname, const char *username)
|
||||
-{
|
||||
- PGconn *newConn;
|
||||
- const char *newdbname;
|
||||
- const char *newusername;
|
||||
-
|
||||
- if (!dbname)
|
||||
- newdbname = PQdb(AH->connection);
|
||||
- else
|
||||
- newdbname = dbname;
|
||||
-
|
||||
- if (!username)
|
||||
- newusername = PQuser(AH->connection);
|
||||
- else
|
||||
- newusername = username;
|
||||
-
|
||||
- /* Let's see if the request is already satisfied */
|
||||
- if (strcmp(newdbname, PQdb(AH->connection)) == 0 &&
|
||||
- strcmp(newusername, PQuser(AH->connection)) == 0)
|
||||
- return 1;
|
||||
-
|
||||
- newConn = _connectDB(AH, newdbname, newusername);
|
||||
-
|
||||
- /* Update ArchiveHandle's connCancel before closing old connection */
|
||||
- set_archive_cancel_info(AH, newConn);
|
||||
-
|
||||
- PQfinish(AH->connection);
|
||||
- AH->connection = newConn;
|
||||
-
|
||||
- /* Start strict; later phases may override this. */
|
||||
- PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
||||
- ALWAYS_SECURE_SEARCH_PATH_SQL));
|
||||
-
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * Connect to the db again.
|
||||
- *
|
||||
- * Note: it's not really all that sensible to use a single-entry password
|
||||
- * cache if the username keeps changing. In current usage, however, the
|
||||
- * username never does change, so one savedPassword is sufficient. We do
|
||||
- * update the cache on the off chance that the password has changed since the
|
||||
- * start of the run.
|
||||
- */
|
||||
-static PGconn *
|
||||
-_connectDB(ArchiveHandle *AH, const char *reqdb, const char *requser)
|
||||
+void
|
||||
+ReconnectToServer(ArchiveHandle *AH, const char *dbname)
|
||||
{
|
||||
- PQExpBufferData connstr;
|
||||
- PGconn *newConn;
|
||||
- const char *newdb;
|
||||
- const char *newuser;
|
||||
- char *password;
|
||||
- char passbuf[100];
|
||||
- bool new_pass;
|
||||
-
|
||||
- if (!reqdb)
|
||||
- newdb = PQdb(AH->connection);
|
||||
- else
|
||||
- newdb = reqdb;
|
||||
-
|
||||
- if (!requser || strlen(requser) == 0)
|
||||
- newuser = PQuser(AH->connection);
|
||||
- else
|
||||
- newuser = requser;
|
||||
-
|
||||
- ahlog(AH, 1, "connecting to database \"%s\" as user \"%s\"\n",
|
||||
- newdb, newuser);
|
||||
-
|
||||
- password = AH->savedPassword;
|
||||
-
|
||||
- if (AH->promptPassword == TRI_YES && password == NULL)
|
||||
- {
|
||||
- simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
||||
- password = passbuf;
|
||||
- }
|
||||
-
|
||||
- initPQExpBuffer(&connstr);
|
||||
- appendPQExpBuffer(&connstr, "dbname=");
|
||||
- appendConnStrVal(&connstr, newdb);
|
||||
-
|
||||
- do
|
||||
- {
|
||||
- const char *keywords[7];
|
||||
- const char *values[7];
|
||||
-
|
||||
- keywords[0] = "host";
|
||||
- values[0] = PQhost(AH->connection);
|
||||
- keywords[1] = "port";
|
||||
- values[1] = PQport(AH->connection);
|
||||
- keywords[2] = "user";
|
||||
- values[2] = newuser;
|
||||
- keywords[3] = "password";
|
||||
- values[3] = password;
|
||||
- keywords[4] = "dbname";
|
||||
- values[4] = connstr.data;
|
||||
- keywords[5] = "fallback_application_name";
|
||||
- values[5] = progname;
|
||||
- keywords[6] = NULL;
|
||||
- values[6] = NULL;
|
||||
-
|
||||
- new_pass = false;
|
||||
- newConn = PQconnectdbParams(keywords, values, true);
|
||||
-
|
||||
- if (!newConn)
|
||||
- exit_horribly(modulename, "failed to reconnect to database\n");
|
||||
-
|
||||
- if (PQstatus(newConn) == CONNECTION_BAD)
|
||||
- {
|
||||
- if (!PQconnectionNeedsPassword(newConn))
|
||||
- exit_horribly(modulename, "could not reconnect to database: %s",
|
||||
- PQerrorMessage(newConn));
|
||||
- PQfinish(newConn);
|
||||
-
|
||||
- if (password)
|
||||
- fprintf(stderr, "Password incorrect\n");
|
||||
-
|
||||
- fprintf(stderr, "Connecting to %s as %s\n",
|
||||
- newdb, newuser);
|
||||
-
|
||||
- if (AH->promptPassword != TRI_NO)
|
||||
- {
|
||||
- simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
||||
- password = passbuf;
|
||||
- }
|
||||
- else
|
||||
- exit_horribly(modulename, "connection needs password\n");
|
||||
-
|
||||
- new_pass = true;
|
||||
- }
|
||||
- } while (new_pass);
|
||||
+ PGconn *oldConn = AH->connection;
|
||||
+ RestoreOptions *ropt = AH->public.ropt;
|
||||
|
||||
/*
|
||||
- * We want to remember connection's actual password, whether or not we got
|
||||
- * it by prompting. So we don't just store the password variable.
|
||||
+ * Save the dbname, if given, in override_dbname so that it will also
|
||||
+ * affect any later reconnection attempt.
|
||||
*/
|
||||
- if (PQconnectionUsedPassword(newConn))
|
||||
- {
|
||||
- if (AH->savedPassword)
|
||||
- free(AH->savedPassword);
|
||||
- AH->savedPassword = pg_strdup(PQpass(newConn));
|
||||
- }
|
||||
+ if (dbname)
|
||||
+ ropt->cparams.override_dbname = pg_strdup(dbname);
|
||||
|
||||
- termPQExpBuffer(&connstr);
|
||||
-
|
||||
- /* check for version mismatch */
|
||||
- _check_database_version(AH);
|
||||
+ /*
|
||||
+ * Note: we want to establish the new connection, and in particular update
|
||||
+ * ArchiveHandle's connCancel, before closing old connection. Otherwise
|
||||
+ * an ill-timed SIGINT could try to access a dead connection.
|
||||
+ */
|
||||
+ AH->connection = NULL; /* dodge error check in ConnectDatabase */
|
||||
|
||||
- PQsetNoticeProcessor(newConn, notice_processor, NULL);
|
||||
+ ConnectDatabase((Archive *) AH, &ropt->cparams, true);
|
||||
|
||||
- return newConn;
|
||||
+ PQfinish(oldConn);
|
||||
}
|
||||
|
||||
-
|
||||
/*
|
||||
- * Make a database connection with the given parameters. The
|
||||
- * connection handle is returned, the parameters are stored in AHX.
|
||||
- * An interactive password prompt is automatically issued if required.
|
||||
+ * Make, or remake, a database connection with the given parameters.
|
||||
+ *
|
||||
+ * The resulting connection handle is stored in AHX->connection.
|
||||
*
|
||||
+ * An interactive password prompt is automatically issued if required.
|
||||
+ * We store the results of that in AHX->savedPassword.
|
||||
* Note: it's not really all that sensible to use a single-entry password
|
||||
* cache if the username keeps changing. In current usage, however, the
|
||||
* username never does change, so one savedPassword is sufficient.
|
||||
*/
|
||||
void
|
||||
ConnectDatabase(Archive *AHX,
|
||||
- const char *dbname,
|
||||
- const char *pghost,
|
||||
- const char *pgport,
|
||||
- const char *username,
|
||||
- trivalue prompt_password)
|
||||
+ const ConnParams *cparams,
|
||||
+ bool isReconnect)
|
||||
{
|
||||
ArchiveHandle *AH = (ArchiveHandle *) AHX;
|
||||
+ trivalue prompt_password;
|
||||
char *password;
|
||||
char passbuf[100];
|
||||
bool new_pass;
|
||||
@@ -263,6 +127,9 @@ ConnectDatabase(Archive *AHX,
|
||||
if (AH->connection)
|
||||
exit_horribly(modulename, "already connected to a database\n");
|
||||
|
||||
+ /* Never prompt for a password during a reconnection */
|
||||
+ prompt_password = isReconnect ? TRI_NO : cparams->promptPassword;
|
||||
+
|
||||
password = AH->savedPassword;
|
||||
|
||||
if (prompt_password == TRI_YES && password == NULL)
|
||||
@@ -270,7 +137,6 @@ ConnectDatabase(Archive *AHX,
|
||||
simple_prompt("Password: ", passbuf, sizeof(passbuf), false);
|
||||
password = passbuf;
|
||||
}
|
||||
- AH->promptPassword = prompt_password;
|
||||
|
||||
/*
|
||||
* Start the connection. Loop until we have a password if requested by
|
||||
@@ -278,23 +144,35 @@ ConnectDatabase(Archive *AHX,
|
||||
*/
|
||||
do
|
||||
{
|
||||
- const char *keywords[7];
|
||||
- const char *values[7];
|
||||
-
|
||||
- keywords[0] = "host";
|
||||
- values[0] = pghost;
|
||||
- keywords[1] = "port";
|
||||
- values[1] = pgport;
|
||||
- keywords[2] = "user";
|
||||
- values[2] = username;
|
||||
- keywords[3] = "password";
|
||||
- values[3] = password;
|
||||
- keywords[4] = "dbname";
|
||||
- values[4] = dbname;
|
||||
- keywords[5] = "fallback_application_name";
|
||||
- values[5] = progname;
|
||||
- keywords[6] = NULL;
|
||||
- values[6] = NULL;
|
||||
+ const char *keywords[8];
|
||||
+ const char *values[8];
|
||||
+ int i = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * If dbname is a connstring, its entries can override the other
|
||||
+ * values obtained from cparams; but in turn, override_dbname can
|
||||
+ * override the dbname component of it.
|
||||
+ */
|
||||
+ keywords[i] = "host";
|
||||
+ values[i++] = cparams->pghost;
|
||||
+ keywords[i] = "port";
|
||||
+ values[i++] = cparams->pgport;
|
||||
+ keywords[i] = "user";
|
||||
+ values[i++] = cparams->username;
|
||||
+ keywords[i] = "password";
|
||||
+ values[i++] = password;
|
||||
+ keywords[i] = "dbname";
|
||||
+ values[i++] = cparams->dbname;
|
||||
+ if (cparams->override_dbname)
|
||||
+ {
|
||||
+ keywords[i] = "dbname";
|
||||
+ values[i++] = cparams->override_dbname;
|
||||
+ }
|
||||
+ keywords[i] = "fallback_application_name";
|
||||
+ values[i++] = progname;
|
||||
+ keywords[i] = NULL;
|
||||
+ values[i++] = NULL;
|
||||
+ Assert(i <= lengthof(keywords));
|
||||
|
||||
new_pass = false;
|
||||
AH->connection = PQconnectdbParams(keywords, values, true);
|
||||
@@ -316,9 +194,16 @@ ConnectDatabase(Archive *AHX,
|
||||
|
||||
/* check to see that the backend connection was successfully made */
|
||||
if (PQstatus(AH->connection) == CONNECTION_BAD)
|
||||
- exit_horribly(modulename, "connection to database \"%s\" failed: %s",
|
||||
- PQdb(AH->connection) ? PQdb(AH->connection) : "",
|
||||
- PQerrorMessage(AH->connection));
|
||||
+ {
|
||||
+ if (isReconnect)
|
||||
+ exit_horribly(modulename, "reconnection to database \"%s\" failed: %s",
|
||||
+ PQdb(AH->connection) ? PQdb(AH->connection) : "",
|
||||
+ PQerrorMessage(AH->connection));
|
||||
+ else
|
||||
+ exit_horribly(modulename, "connection to database \"%s\" failed: %s",
|
||||
+ PQdb(AH->connection) ? PQdb(AH->connection) : "",
|
||||
+ PQerrorMessage(AH->connection));
|
||||
+ }
|
||||
|
||||
/* Start strict; later phases may override this. */
|
||||
PQclear(ExecuteSqlQueryForSingleRow((Archive *) AH,
|
||||
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
|
||||
index 8080155a95..abcee89d10 100644
|
||||
--- a/src/bin/pg_dump/pg_dump.c
|
||||
+++ b/src/bin/pg_dump/pg_dump.c
|
||||
@@ -302,7 +302,6 @@ main(int argc, char **argv)
|
||||
const char *dumpsnapshot = NULL;
|
||||
char *use_role = NULL;
|
||||
int numWorkers = 1;
|
||||
- trivalue prompt_password = TRI_DEFAULT;
|
||||
int compressLevel = -1;
|
||||
int plainText = 0;
|
||||
ArchiveFormat archiveFormat = archUnknown;
|
||||
@@ -431,7 +430,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'd': /* database name */
|
||||
- dopt.dbname = pg_strdup(optarg);
|
||||
+ dopt.cparams.dbname = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'E': /* Dump encoding */
|
||||
@@ -447,7 +446,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'h': /* server host */
|
||||
- dopt.pghost = pg_strdup(optarg);
|
||||
+ dopt.cparams.pghost = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'j': /* number of dump jobs */
|
||||
@@ -472,7 +471,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'p': /* server port */
|
||||
- dopt.pgport = pg_strdup(optarg);
|
||||
+ dopt.cparams.pgport = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
@@ -497,7 +496,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
- dopt.username = pg_strdup(optarg);
|
||||
+ dopt.cparams.username = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'v': /* verbose */
|
||||
@@ -505,11 +504,11 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
- prompt_password = TRI_NO;
|
||||
+ dopt.cparams.promptPassword = TRI_NO;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
- prompt_password = TRI_YES;
|
||||
+ dopt.cparams.promptPassword = TRI_YES;
|
||||
break;
|
||||
|
||||
case 'x': /* skip ACL dump */
|
||||
@@ -563,8 +562,8 @@ main(int argc, char **argv)
|
||||
* Non-option argument specifies database name as long as it wasn't
|
||||
* already specified with -d / --dbname
|
||||
*/
|
||||
- if (optind < argc && dopt.dbname == NULL)
|
||||
- dopt.dbname = argv[optind++];
|
||||
+ if (optind < argc && dopt.cparams.dbname == NULL)
|
||||
+ dopt.cparams.dbname = argv[optind++];
|
||||
|
||||
/* Complain if any arguments remain */
|
||||
if (optind < argc)
|
||||
@@ -677,7 +676,7 @@ main(int argc, char **argv)
|
||||
* Open the database using the Archiver, so it knows about it. Errors mean
|
||||
* death.
|
||||
*/
|
||||
- ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
|
||||
+ ConnectDatabase(fout, &dopt.cparams, false);
|
||||
setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
|
||||
|
||||
/*
|
||||
@@ -860,6 +859,11 @@ main(int argc, char **argv)
|
||||
ropt->filename = filename;
|
||||
|
||||
/* if you change this list, see dumpOptionsFromRestoreOptions */
|
||||
+ ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
|
||||
+ ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
|
||||
+ ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
|
||||
+ ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
|
||||
+ ropt->cparams.promptPassword = dopt.cparams.promptPassword;
|
||||
ropt->dropSchema = dopt.outputClean;
|
||||
ropt->dataOnly = dopt.dataOnly;
|
||||
ropt->schemaOnly = dopt.schemaOnly;
|
||||
diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c
|
||||
index 860a211a3c..ce03ded8ec 100644
|
||||
--- a/src/bin/pg_dump/pg_restore.c
|
||||
+++ b/src/bin/pg_dump/pg_restore.c
|
||||
@@ -163,7 +163,7 @@ main(int argc, char **argv)
|
||||
opts->createDB = 1;
|
||||
break;
|
||||
case 'd':
|
||||
- opts->dbname = pg_strdup(optarg);
|
||||
+ opts->cparams.dbname = pg_strdup(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
opts->exit_on_error = true;
|
||||
@@ -177,7 +177,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
case 'h':
|
||||
if (strlen(optarg) != 0)
|
||||
- opts->pghost = pg_strdup(optarg);
|
||||
+ opts->cparams.pghost = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'j': /* number of restore jobs */
|
||||
@@ -206,7 +206,7 @@ main(int argc, char **argv)
|
||||
|
||||
case 'p':
|
||||
if (strlen(optarg) != 0)
|
||||
- opts->pgport = pg_strdup(optarg);
|
||||
+ opts->cparams.pgport = pg_strdup(optarg);
|
||||
break;
|
||||
case 'R':
|
||||
/* no-op, still accepted for backwards compatibility */
|
||||
@@ -240,7 +240,7 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'U':
|
||||
- opts->username = pg_strdup(optarg);
|
||||
+ opts->cparams.username = pg_strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'v': /* verbose */
|
||||
@@ -248,11 +248,11 @@ main(int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
- opts->promptPassword = TRI_NO;
|
||||
+ opts->cparams.promptPassword = TRI_NO;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
- opts->promptPassword = TRI_YES;
|
||||
+ opts->cparams.promptPassword = TRI_YES;
|
||||
break;
|
||||
|
||||
case 'x': /* skip ACL dump */
|
||||
@@ -302,7 +302,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Should get at most one of -d and -f, else user is confused */
|
||||
- if (opts->dbname)
|
||||
+ if (opts->cparams.dbname)
|
||||
{
|
||||
if (opts->filename)
|
||||
{
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,241 +0,0 @@
|
||||
From f97ecea1ed7b09c6f1398540a1d72a57eee70c9f Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 9 Nov 2020 07:32:09 -0800
|
||||
Subject: [PATCH] In security-restricted operations, block enqueue of at-commit
|
||||
user code.
|
||||
|
||||
Specifically, this blocks DECLARE ... WITH HOLD and firing of deferred
|
||||
triggers within index expressions and materialized view queries. An
|
||||
attacker having permission to create non-temp objects in at least one
|
||||
schema could execute arbitrary SQL functions under the identity of the
|
||||
bootstrap superuser. One can work around the vulnerability by disabling
|
||||
autovacuum and not manually running ANALYZE, CLUSTER, REINDEX, CREATE
|
||||
INDEX, VACUUM FULL, or REFRESH MATERIALIZED VIEW. (Don't restore from
|
||||
pg_dump, since it runs some of those commands.) Plain VACUUM (without
|
||||
FULL) is safe, and all commands are fine when a trusted user owns the
|
||||
target object. Performance may degrade quickly under this workaround,
|
||||
however. Back-patch to 9.5 (all supported versions).
|
||||
|
||||
Reviewed by Robert Haas. Reported by Etienne Stalmans.
|
||||
|
||||
Security: CVE-2020-25695
|
||||
---
|
||||
contrib/postgres_fdw/connection.c | 4 +++
|
||||
src/backend/access/transam/xact.c | 13 ++++----
|
||||
src/backend/commands/portalcmds.c | 5 +++
|
||||
src/backend/commands/trigger.c | 12 +++++++
|
||||
src/test/regress/expected/privileges.out | 42 ++++++++++++++++++++++++
|
||||
src/test/regress/sql/privileges.sql | 34 +++++++++++++++++++
|
||||
6 files changed, 104 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
|
||||
index 885bd075798c..5dcff3d07624 100644
|
||||
--- a/contrib/postgres_fdw/connection.c
|
||||
+++ b/contrib/postgres_fdw/connection.c
|
||||
@@ -645,6 +645,10 @@ pgfdw_report_error(int elevel, PGresult *res, PGconn *conn,
|
||||
|
||||
/*
|
||||
* pgfdw_xact_callback --- cleanup at main-transaction end.
|
||||
+ *
|
||||
+ * This runs just late enough that it must not enter user-defined code
|
||||
+ * locally. (Entering such code on the remote side is fine. Its remote
|
||||
+ * COMMIT TRANSACTION may run deferred triggers.)
|
||||
*/
|
||||
static void
|
||||
pgfdw_xact_callback(XactEvent event, void *arg)
|
||||
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
|
||||
index 37f31a2c31ea..00cec50e8402 100644
|
||||
--- a/src/backend/access/transam/xact.c
|
||||
+++ b/src/backend/access/transam/xact.c
|
||||
@@ -1994,9 +1994,10 @@ CommitTransaction(void)
|
||||
|
||||
/*
|
||||
* Do pre-commit processing that involves calling user-defined code, such
|
||||
- * as triggers. Since closing cursors could queue trigger actions,
|
||||
- * triggers could open cursors, etc, we have to keep looping until there's
|
||||
- * nothing left to do.
|
||||
+ * as triggers. SECURITY_RESTRICTED_OPERATION contexts must not queue an
|
||||
+ * action that would run here, because that would bypass the sandbox.
|
||||
+ * Since closing cursors could queue trigger actions, triggers could open
|
||||
+ * cursors, etc, we have to keep looping until there's nothing left to do.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
@@ -2014,9 +2015,6 @@ CommitTransaction(void)
|
||||
break;
|
||||
}
|
||||
|
||||
- CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_PRE_COMMIT
|
||||
- : XACT_EVENT_PRE_COMMIT);
|
||||
-
|
||||
/*
|
||||
* The remaining actions cannot call any user-defined code, so it's safe
|
||||
* to start shutting down within-transaction services. But note that most
|
||||
@@ -2024,6 +2022,9 @@ CommitTransaction(void)
|
||||
* the transaction-abort path.
|
||||
*/
|
||||
|
||||
+ CallXactCallbacks(is_parallel_worker ? XACT_EVENT_PARALLEL_PRE_COMMIT
|
||||
+ : XACT_EVENT_PRE_COMMIT);
|
||||
+
|
||||
/* If we might have parallel workers, clean them up now. */
|
||||
if (IsInParallelMode())
|
||||
AtEOXact_Parallel(true);
|
||||
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
|
||||
index 46369cf3dbee..3d01a782da06 100644
|
||||
--- a/src/backend/commands/portalcmds.c
|
||||
+++ b/src/backend/commands/portalcmds.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "commands/portalcmds.h"
|
||||
#include "executor/executor.h"
|
||||
#include "executor/tstoreReceiver.h"
|
||||
+#include "miscadmin.h"
|
||||
#include "rewrite/rewriteHandler.h"
|
||||
#include "tcop/pquery.h"
|
||||
#include "tcop/tcopprot.h"
|
||||
@@ -64,6 +65,10 @@ PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params,
|
||||
*/
|
||||
if (!(cstmt->options & CURSOR_OPT_HOLD))
|
||||
RequireTransactionChain(isTopLevel, "DECLARE CURSOR");
|
||||
+ else if (InSecurityRestrictedOperation())
|
||||
+ ereport(ERROR,
|
||||
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
+ errmsg("cannot create a cursor WITH HOLD within security-restricted operation")));
|
||||
|
||||
/*
|
||||
* Parse analysis was done already, but we still have to run the rule
|
||||
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
|
||||
index f83840625348..9c04eee48422 100644
|
||||
--- a/src/backend/commands/trigger.c
|
||||
+++ b/src/backend/commands/trigger.c
|
||||
@@ -4144,6 +4144,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events,
|
||||
bool immediate_only)
|
||||
{
|
||||
bool found = false;
|
||||
+ bool deferred_found = false;
|
||||
AfterTriggerEvent event;
|
||||
AfterTriggerEventChunk *chunk;
|
||||
|
||||
@@ -4179,6 +4180,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events,
|
||||
*/
|
||||
if (defer_it && move_list != NULL)
|
||||
{
|
||||
+ deferred_found = true;
|
||||
/* add it to move_list */
|
||||
afterTriggerAddEvent(move_list, event, evtshared);
|
||||
/* mark original copy "done" so we don't do it again */
|
||||
@@ -4186,6 +4188,16 @@ afterTriggerMarkEvents(AfterTriggerEventList *events,
|
||||
}
|
||||
}
|
||||
|
||||
+ /*
|
||||
+ * We could allow deferred triggers if, before the end of the
|
||||
+ * security-restricted operation, we were to verify that a SET CONSTRAINTS
|
||||
+ * ... IMMEDIATE has fired all such triggers. For now, don't bother.
|
||||
+ */
|
||||
+ if (deferred_found && InSecurityRestrictedOperation())
|
||||
+ ereport(ERROR,
|
||||
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
||||
+ errmsg("cannot fire deferred trigger within security-restricted operation")));
|
||||
+
|
||||
return found;
|
||||
}
|
||||
|
||||
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
|
||||
index dacc98450514..26ee16a0c370 100644
|
||||
--- a/src/test/regress/expected/privileges.out
|
||||
+++ b/src/test/regress/expected/privileges.out
|
||||
@@ -1253,6 +1253,48 @@ SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION'
|
||||
t
|
||||
(1 row)
|
||||
|
||||
+-- security-restricted operations
|
||||
+\c -
|
||||
+CREATE ROLE regress_sro_user;
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
+ 'GRANT regress_group2 TO regress_sro_user';
|
||||
+CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true';
|
||||
+-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||
+CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot create a cursor WITH HOLD within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot create a cursor WITH HOLD within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+-- INSERT to this table will queue a GRANT at end of transaction
|
||||
+CREATE TABLE sro_trojan_table ();
|
||||
+CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
||||
+ 'BEGIN PERFORM unwanted_grant(); RETURN NULL; END';
|
||||
+CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||
+ INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||
+-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||
+CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'INSERT INTO sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot fire deferred trigger within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+ERROR: cannot fire deferred trigger within security-restricted operation
|
||||
+CONTEXT: SQL function "mv_action" statement 1
|
||||
+BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
|
||||
+ERROR: must have admin option on role "regress_group2"
|
||||
+CONTEXT: SQL function "unwanted_grant" statement 1
|
||||
+SQL statement "SELECT unwanted_grant()"
|
||||
+PL/pgSQL function sro_trojan() line 1 at PERFORM
|
||||
+SQL function "mv_action" statement 1
|
||||
+DROP OWNED BY regress_sro_user;
|
||||
+DROP ROLE regress_sro_user;
|
||||
-- Admin options
|
||||
SET SESSION AUTHORIZATION regress_user4;
|
||||
CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
|
||||
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
|
||||
index 4263315a2d87..f979cccea03f 100644
|
||||
--- a/src/test/regress/sql/privileges.sql
|
||||
+++ b/src/test/regress/sql/privileges.sql
|
||||
@@ -761,6 +761,40 @@ SELECT has_table_privilege('regress_user3', 'atest4', 'SELECT'); -- false
|
||||
SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true
|
||||
|
||||
|
||||
+-- security-restricted operations
|
||||
+\c -
|
||||
+CREATE ROLE regress_sro_user;
|
||||
+
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
+ 'GRANT regress_group2 TO regress_sro_user';
|
||||
+CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true';
|
||||
+-- REFRESH of this MV will queue a GRANT at end of transaction
|
||||
+CREATE MATERIALIZED VIEW sro_mv AS SELECT mv_action() WITH NO DATA;
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+
|
||||
+SET SESSION AUTHORIZATION regress_sro_user;
|
||||
+-- INSERT to this table will queue a GRANT at end of transaction
|
||||
+CREATE TABLE sro_trojan_table ();
|
||||
+CREATE FUNCTION sro_trojan() RETURNS trigger LANGUAGE plpgsql AS
|
||||
+ 'BEGIN PERFORM unwanted_grant(); RETURN NULL; END';
|
||||
+CREATE CONSTRAINT TRIGGER t AFTER INSERT ON sro_trojan_table
|
||||
+ INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE sro_trojan();
|
||||
+-- Now, REFRESH will issue such an INSERT, queueing the GRANT
|
||||
+CREATE OR REPLACE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS
|
||||
+ 'INSERT INTO sro_trojan_table DEFAULT VALUES; SELECT true';
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+\c -
|
||||
+REFRESH MATERIALIZED VIEW sro_mv;
|
||||
+BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT;
|
||||
+
|
||||
+DROP OWNED BY regress_sro_user;
|
||||
+DROP ROLE regress_sro_user;
|
||||
+
|
||||
+
|
||||
-- Admin options
|
||||
|
||||
SET SESSION AUTHORIZATION regress_user4;
|
||||
@ -1,121 +0,0 @@
|
||||
From a498db87be103f93856dd515a574b2d67d3c1237 Mon Sep 17 00:00:00 2001
|
||||
From: Noah Misch <noah@leadboat.com>
|
||||
Date: Mon, 9 Nov 2020 07:32:09 -0800
|
||||
Subject: [PATCH] Ignore attempts to \gset into specially treated variables.
|
||||
|
||||
If an interactive psql session used \gset when querying a compromised
|
||||
server, the attacker could execute arbitrary code as the operating
|
||||
system account running psql. Using a prefix not found among specially
|
||||
treated variables, e.g. every lowercase string, precluded the attack.
|
||||
Fix by issuing a warning and setting no variable for the column in
|
||||
question. Users wanting the old behavior can use a prefix and then a
|
||||
meta-command like "\set HISTSIZE :prefix_HISTSIZE". Back-patch to 9.5
|
||||
(all supported versions).
|
||||
|
||||
Reviewed by Robert Haas. Reported by Nick Cleaton.
|
||||
|
||||
Security: CVE-2020-25696
|
||||
---
|
||||
src/bin/psql/common.c | 7 +++++++
|
||||
src/bin/psql/variables.c | 26 ++++++++++++++++++++++++++
|
||||
src/bin/psql/variables.h | 1 +
|
||||
src/test/regress/expected/psql.out | 4 ++++
|
||||
src/test/regress/sql/psql.sql | 3 +++
|
||||
5 files changed, 41 insertions(+)
|
||||
|
||||
diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c
|
||||
index d04a7943d6a9..4e342c180a6c 100644
|
||||
--- a/src/bin/psql/common.c
|
||||
+++ b/src/bin/psql/common.c
|
||||
@@ -894,6 +894,13 @@ StoreQueryTuple(const PGresult *result)
|
||||
/* concatenate prefix and column name */
|
||||
varname = psprintf("%s%s", pset.gset_prefix, colname);
|
||||
|
||||
+ if (VariableHasHook(pset.vars, varname))
|
||||
+ {
|
||||
+ psql_error("attempt to \\gset into specially treated variable \"%s\" ignored\n",
|
||||
+ varname);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (!PQgetisnull(result, 0, i))
|
||||
value = PQgetvalue(result, 0, i);
|
||||
else
|
||||
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
|
||||
index 120b25c69661..0d28ba9c92bb 100644
|
||||
--- a/src/bin/psql/variables.c
|
||||
+++ b/src/bin/psql/variables.c
|
||||
@@ -360,6 +360,32 @@ SetVariableHooks(VariableSpace space, const char *name,
|
||||
(void) (*ahook) (current->value);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Return true iff the named variable has substitute and/or assign hook
|
||||
+ * functions.
|
||||
+ */
|
||||
+bool
|
||||
+VariableHasHook(VariableSpace space, const char *name)
|
||||
+{
|
||||
+ struct _variable *current;
|
||||
+
|
||||
+ Assert(space);
|
||||
+ Assert(name);
|
||||
+
|
||||
+ for (current = space->next; current; current = current->next)
|
||||
+ {
|
||||
+ int cmp = strcmp(current->name, name);
|
||||
+
|
||||
+ if (cmp == 0)
|
||||
+ return (current->substitute_hook != NULL ||
|
||||
+ current->assign_hook != NULL);
|
||||
+ if (cmp > 0)
|
||||
+ break; /* it's not there */
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Convenience function to set a variable's value to "on".
|
||||
*/
|
||||
diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h
|
||||
index 02d85b1bc2e4..8dc5c20ee8fc 100644
|
||||
--- a/src/bin/psql/variables.h
|
||||
+++ b/src/bin/psql/variables.h
|
||||
@@ -90,6 +90,7 @@ bool DeleteVariable(VariableSpace space, const char *name);
|
||||
void SetVariableHooks(VariableSpace space, const char *name,
|
||||
VariableSubstituteHook shook,
|
||||
VariableAssignHook ahook);
|
||||
+bool VariableHasHook(VariableSpace space, const char *name);
|
||||
|
||||
void PsqlVarEnumError(const char *name, const char *value, const char *suggestions);
|
||||
|
||||
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
|
||||
index 0c94144575af..1ae81912c734 100644
|
||||
--- a/src/test/regress/expected/psql.out
|
||||
+++ b/src/test/regress/expected/psql.out
|
||||
@@ -84,6 +84,10 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
|
||||
select 10 as "bad name"
|
||||
\gset
|
||||
invalid variable name: "bad name"
|
||||
+select 97 as "EOF", 'ok' as _foo \gset IGNORE
|
||||
+attempt to \gset into specially treated variable "IGNOREEOF" ignored
|
||||
+\echo :IGNORE_foo :IGNOREEOF
|
||||
+ok 0
|
||||
-- multiple backslash commands in one line
|
||||
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
|
||||
1
|
||||
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
|
||||
index 4a676c311955..7f8ab2e5c218 100644
|
||||
--- a/src/test/regress/sql/psql.sql
|
||||
+++ b/src/test/regress/sql/psql.sql
|
||||
@@ -48,6 +48,9 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_
|
||||
select 10 as "bad name"
|
||||
\gset
|
||||
|
||||
+select 97 as "EOF", 'ok' as _foo \gset IGNORE
|
||||
+\echo :IGNORE_foo :IGNOREEOF
|
||||
+
|
||||
-- multiple backslash commands in one line
|
||||
select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x
|
||||
select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y
|
||||
@ -1,163 +0,0 @@
|
||||
From eeede2470a8ec902c80de449d2c4822330c689ca Mon Sep 17 00:00:00 2001
|
||||
From: wang_yue111 <648774160@qq.com>
|
||||
Date: Fri, 26 Feb 2021 12:57:48 +0800
|
||||
Subject: [PATCH] Fix mishandling of column-level SELECT privileges for join
|
||||
aliases.
|
||||
|
||||
scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would
|
||||
pass the wrong RTE to markVarForSelectPriv when dealing with a join
|
||||
ParseNamespaceItem: they'd pass the join RTE, when what we need to
|
||||
mark is the base table that the join column came from. The end
|
||||
result was to not fill the base table's selectedCols bitmap correctly,
|
||||
resulting in an understatement of the set of columns that are read
|
||||
by the query. The executor would still insist on there being at
|
||||
least one selectable column; but with a correctly crafted query,
|
||||
a user having SELECT privilege on just one column of a table would
|
||||
nonetheless be allowed to read all its columns.
|
||||
|
||||
To fix, make markRTEForSelectPriv fetch the correct RTE for itself,
|
||||
ignoring the possibly-mismatched RTE passed by the caller. Later,
|
||||
we'll get rid of some now-unused RTE arguments, but that risks
|
||||
API breaks so we won't do it in released branches.
|
||||
|
||||
This problem was introduced by commit 9ce77d75c, so back-patch
|
||||
to v13 where that came in. Thanks to Sven Klemm for reporting
|
||||
the problem.
|
||||
|
||||
Security: CVE-2021-20229
|
||||
|
||||
---
|
||||
src/backend/parser/parse_relation.c | 40 ++++++++++-----------
|
||||
src/backend/parser/parse_target.c | 8 +++--
|
||||
4 files changed, 91 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
|
||||
index bbbb0b6..7ab4ba7 100644
|
||||
--- a/src/backend/parser/parse_relation.c
|
||||
+++ b/src/backend/parser/parse_relation.c
|
||||
@@ -43,7 +43,8 @@ static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
|
||||
int location);
|
||||
static void check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem,
|
||||
int location);
|
||||
-static void markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
+static void markRTEForSelectPriv(ParseState *pstate,
|
||||
+
|
||||
int rtindex, AttrNumber col);
|
||||
static void expandRelation(Oid relid, Alias *eref,
|
||||
int rtindex, int sublevels_up,
|
||||
@@ -897,20 +898,15 @@ searchRangeTableForCol(ParseState *pstate, const char *alias, char *colname,
|
||||
|
||||
/*
|
||||
* markRTEForSelectPriv
|
||||
- * Mark the specified column of an RTE as requiring SELECT privilege
|
||||
+ * Mark the specified column of the RTE with index rtindex
|
||||
+ * as requiring SELECT privilege
|
||||
*
|
||||
* col == InvalidAttrNumber means a "whole row" reference
|
||||
- *
|
||||
- * The caller should pass the actual RTE if it has it handy; otherwise pass
|
||||
- * NULL, and we'll look it up here. (This uglification of the API is
|
||||
- * worthwhile because nearly all external callers have the RTE at hand.)
|
||||
*/
|
||||
static void
|
||||
-markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
- int rtindex, AttrNumber col)
|
||||
+markRTEForSelectPriv(ParseState *pstate, int rtindex, AttrNumber col)
|
||||
{
|
||||
- if (rte == NULL)
|
||||
- rte = rt_fetch(rtindex, pstate->p_rtable);
|
||||
+ RangeTblEntry *rte = rt_fetch(rtindex, pstate->p_rtable);
|
||||
|
||||
if (rte->rtekind == RTE_RELATION)
|
||||
{
|
||||
@@ -942,13 +938,13 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
{
|
||||
int varno = ((RangeTblRef *) j->larg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else if (IsA(j->larg, JoinExpr))
|
||||
{
|
||||
int varno = ((JoinExpr *) j->larg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
@@ -957,13 +953,13 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
{
|
||||
int varno = ((RangeTblRef *) j->rarg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else if (IsA(j->rarg, JoinExpr))
|
||||
{
|
||||
int varno = ((JoinExpr *) j->rarg)->rtindex;
|
||||
|
||||
- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber);
|
||||
+ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
@@ -994,10 +990,10 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte,
|
||||
|
||||
/*
|
||||
* markVarForSelectPriv
|
||||
- * Mark the RTE referenced by a Var as requiring SELECT privilege
|
||||
+ * Mark the RTE referenced by the Var as requiring SELECT privilege
|
||||
+ * for the Var's column (the Var could be a whole-row Var, too)
|
||||
*
|
||||
- * The caller should pass the Var's referenced RTE if it has it handy
|
||||
- * (nearly all do); otherwise pass NULL.
|
||||
+ * The rte argument is unused and will be removed later.
|
||||
*/
|
||||
void
|
||||
markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
|
||||
@@ -1008,7 +1004,7 @@ markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte)
|
||||
/* Find the appropriate pstate if it's an uplevel Var */
|
||||
for (lv = 0; lv < var->varlevelsup; lv++)
|
||||
pstate = pstate->parentParseState;
|
||||
- markRTEForSelectPriv(pstate, rte, var->varno, var->varattno);
|
||||
+ markRTEForSelectPriv(pstate, var->varno, var->varattno);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2629,9 +2625,13 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
|
||||
/*
|
||||
* Require read access to the table. This is normally redundant with the
|
||||
* markVarForSelectPriv calls below, but not if the table has zero
|
||||
- * columns.
|
||||
+ * columns. We need not do anything if the nsitem is for a join: its
|
||||
+ * component tables will have been marked ACL_SELECT when they were added
|
||||
+ * to the rangetable. (This step changes things only for the target
|
||||
+ * relation of UPDATE/DELETE, which cannot be under a join.)
|
||||
*/
|
||||
- rte->requiredPerms |= ACL_SELECT;
|
||||
+ if (rte->rtekind == RTE_RELATION)
|
||||
+ rte->requiredPerms |= ACL_SELECT;
|
||||
|
||||
forboth(name, names, var, vars)
|
||||
{
|
||||
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
|
||||
index 64a1b75..c7165cb 100644
|
||||
--- a/src/backend/parser/parse_target.c
|
||||
+++ b/src/backend/parser/parse_target.c
|
||||
@@ -1328,9 +1328,13 @@ ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte,
|
||||
/*
|
||||
* Require read access to the table. This is normally redundant with
|
||||
* the markVarForSelectPriv calls below, but not if the table has zero
|
||||
- * columns.
|
||||
+ * columns. We need not do anything if the nsitem is for a join: its
|
||||
+ * component tables will have been marked ACL_SELECT when they were
|
||||
+ * added to the rangetable. (This step changes things only for the
|
||||
+ * target relation of UPDATE/DELETE, which cannot be under a join.)
|
||||
*/
|
||||
- rte->requiredPerms |= ACL_SELECT;
|
||||
+ if (rte->rtekind == RTE_RELATION)
|
||||
+ rte->requiredPerms |= ACL_SELECT;
|
||||
|
||||
/* Require read access to each column */
|
||||
foreach(l, vars)
|
||||
@ -1,70 +0,0 @@
|
||||
From eec462367ee2b41e02c6e29135c857ad6f2da66a Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Mon, 26 Aug 2019 11:14:33 +0900
|
||||
Subject: [PATCH] Fix error handling of vacuumdb when running out of fds
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When trying to use a high number of jobs, vacuumdb has only checked for
|
||||
a maximum number of jobs used, causing confusing failures when running
|
||||
out of file descriptors when the jobs open connections to Postgres.
|
||||
This commit changes the error handling so as we do not check anymore for
|
||||
a maximum number of allowed jobs when parsing the option value with
|
||||
FD_SETSIZE, but check instead if a file descriptor is within the
|
||||
supported range when opening the connections for the jobs so as this is
|
||||
detected at the earliest time possible.
|
||||
|
||||
Also, improve the error message to give a hint about the number of jobs
|
||||
recommended, using a wording given by the reviewers of the patch.
|
||||
|
||||
Reported-by: Andres Freund
|
||||
Author: Michael Paquier
|
||||
Reviewed-by: Andres Freund, Álvaro Herrera, Tom Lane
|
||||
Discussion: https://postgr.es/m/20190818001858.ho3ev4z57fqhs7a5@alap3.anarazel.de
|
||||
Backpatch-through: 9.5
|
||||
---
|
||||
src/bin/scripts/vacuumdb.c | 20 ++++++++++++++------
|
||||
1 file changed, 14 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
|
||||
index f888bf73bc..4ac765244a 100644
|
||||
--- a/src/bin/scripts/vacuumdb.c
|
||||
+++ b/src/bin/scripts/vacuumdb.c
|
||||
@@ -200,12 +200,6 @@ main(int argc, char *argv[])
|
||||
progname);
|
||||
exit(1);
|
||||
}
|
||||
- if (concurrentCons > FD_SETSIZE - 1)
|
||||
- {
|
||||
- fprintf(stderr, _("%s: too many parallel jobs requested (maximum: %d)\n"),
|
||||
- progname, FD_SETSIZE - 1);
|
||||
- exit(1);
|
||||
- }
|
||||
break;
|
||||
case 2:
|
||||
maintenance_db = pg_strdup(optarg);
|
||||
@@ -443,6 +437,20 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
|
||||
{
|
||||
conn = connectDatabase(dbname, host, port, username, prompt_password,
|
||||
progname, echo, false, true);
|
||||
+
|
||||
+ /*
|
||||
+ * Fail and exit immediately if trying to use a socket in an
|
||||
+ * unsupported range. POSIX requires open(2) to use the lowest
|
||||
+ * unused file descriptor and the hint given relies on that.
|
||||
+ */
|
||||
+ if (PQsocket(conn) >= FD_SETSIZE)
|
||||
+ {
|
||||
+ fprintf(stderr,
|
||||
+ _("%s: too many jobs for this platform -- try %d"),
|
||||
+ progname, i);
|
||||
+ exit(1);
|
||||
+ }
|
||||
+
|
||||
init_slot(slots + i, conn);
|
||||
}
|
||||
}
|
||||
--
|
||||
2.23.0
|
||||
|
||||
69
Makefile.regress
Normal file
69
Makefile.regress
Normal file
@ -0,0 +1,69 @@
|
||||
#
|
||||
# Simplified makefile for running the PostgreSQL regression tests
|
||||
# in an RPM installation
|
||||
#
|
||||
|
||||
# maximum simultaneous connections for parallel tests
|
||||
MAXCONNOPT =
|
||||
ifdef MAX_CONNECTIONS
|
||||
MAXCONNOPT += --max-connections=$(MAX_CONNECTIONS)
|
||||
endif
|
||||
|
||||
# locale
|
||||
NOLOCALE =
|
||||
ifdef NO_LOCALE
|
||||
NOLOCALE += --no-locale
|
||||
endif
|
||||
|
||||
srcdir := .
|
||||
|
||||
REGRESS_OPTS += --dlpath=.
|
||||
|
||||
pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE)
|
||||
|
||||
pg_regress_installcheck = ./pg_regress --inputdir=$(srcdir) --bindir=@bindir@ $(pg_regress_locale_flags)
|
||||
|
||||
# Test input and expected files. These are created by pg_regress itself, so we
|
||||
# don't have a rule to create them. We do need rules to clean them however.
|
||||
ifile_list := $(subst .source,, $(notdir $(wildcard $(srcdir)/input/*.source)))
|
||||
input_files := $(foreach file, $(ifile_list), sql/$(file).sql)
|
||||
ofile_list := $(subst .source,, $(notdir $(wildcard $(srcdir)/output/*.source)))
|
||||
output_files := $(foreach file, $(ofile_list), expected/$(file).out)
|
||||
|
||||
abs_srcdir := $(shell pwd)
|
||||
abs_builddir := $(shell pwd)
|
||||
|
||||
check: installcheck-parallel
|
||||
|
||||
installcheck: cleandirs
|
||||
$(pg_regress_installcheck) $(REGRESS_OPTS) --schedule=$(srcdir)/serial_schedule $(EXTRA_TESTS)
|
||||
|
||||
installcheck-parallel: cleandirs
|
||||
$(pg_regress_installcheck) $(REGRESS_OPTS) --schedule=$(srcdir)/parallel_schedule $(MAXCONNOPT) $(EXTRA_TESTS)
|
||||
|
||||
# The tests command the server to write into testtablespace and results.
|
||||
# On a SELinux-enabled system this will fail unless we mark those directories
|
||||
# as writable by the server.
|
||||
cleandirs:
|
||||
-rm -rf testtablespace results
|
||||
mkdir testtablespace results
|
||||
if test -x /usr/bin/chcon && ! test -f /.dockerenv; then \
|
||||
/usr/bin/chcon -u system_u -r object_r -t postgresql_db_t testtablespace results ; \
|
||||
fi
|
||||
|
||||
# old interfaces follow...
|
||||
|
||||
runcheck: check
|
||||
runtest: installcheck
|
||||
runtest-parallel: installcheck-parallel
|
||||
|
||||
|
||||
##
|
||||
## Clean up
|
||||
##
|
||||
|
||||
clean distclean maintainer-clean:
|
||||
rm -f $(output_files) $(input_files)
|
||||
rm -rf testtablespace
|
||||
rm -rf results tmp_check log
|
||||
rm -f regression.diffs regression.out regress.out run_check.out
|
||||
@ -1,50 +0,0 @@
|
||||
From 57ba539775f1dd0b0460f1dfe673da00eeef3a2f Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Tue, 7 May 2019 14:20:01 +0900
|
||||
Subject: [PATCH] Remove some code related to 7.3 and older servers from tools
|
||||
of src/bin/
|
||||
|
||||
This code was broken as of 582edc3, and is most likely not used anymore.
|
||||
Note that pg_dump supports servers down to 8.0, and psql has code to
|
||||
support servers down to 7.4.
|
||||
|
||||
Author: Julien Rouhaud
|
||||
Reviewed-by: Tom Lane
|
||||
Discussion: https://postgr.es/m/CAOBaU_Y5y=zo3+2gf+2NJC1pvMYPcbRXoQaPXx=U7+C8Qh4CzQ@mail.gmail.com
|
||||
---
|
||||
src/bin/scripts/common.c | 12 ++----------
|
||||
1 file changed, 2 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/bin/scripts/common.c b/src/bin/scripts/common.c
|
||||
index 8073ee0d0e..5088c4c48e 100644
|
||||
--- a/src/bin/scripts/common.c
|
||||
+++ b/src/bin/scripts/common.c
|
||||
@@ -145,9 +145,8 @@ connectDatabase(const char *dbname, const char *pghost,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
- if (PQserverVersion(conn) >= 70300)
|
||||
- PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL,
|
||||
- progname, echo));
|
||||
+ PQclear(executeQuery(conn, ALWAYS_SECURE_SEARCH_PATH_SQL,
|
||||
+ progname, echo));
|
||||
|
||||
return conn;
|
||||
}
|
||||
@@ -311,13 +310,6 @@ appendQualifiedRelation(PQExpBuffer buf, const char *spec,
|
||||
PGresult *res;
|
||||
int ntups;
|
||||
|
||||
- /* Before 7.3, the concept of qualifying a name did not exist. */
|
||||
- if (PQserverVersion(conn) < 70300)
|
||||
- {
|
||||
- appendPQExpBufferStr(&sql, spec);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
split_table_columns_spec(spec, PQclientEncoding(conn), &table, &columns);
|
||||
|
||||
/*
|
||||
--
|
||||
2.23.0
|
||||
|
||||
@ -1,76 +0,0 @@
|
||||
From a1413123f80f470da1ec422592f228aebe4a8866 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Paquier <michael@paquier.xyz>
|
||||
Date: Thu, 27 Feb 2020 11:21:14 +0900
|
||||
Subject: [PATCH 1/2] createdb: Fix quoting of --encoding, --lc-ctype and
|
||||
--lc-collate
|
||||
|
||||
The original coding failed to properly quote those arguments, leading to
|
||||
failures when using quotes in the values used. As the quoting can be
|
||||
encoding-sensitive, the connection to the backend needs to be taken
|
||||
before applying the correct quoting.
|
||||
|
||||
Author: Michael Paquier
|
||||
Reviewed-by: Daniel Gustafsson
|
||||
Discussion: https://postgr.es/m/20200214041004.GB1998@paquier.xyz
|
||||
Backpatch-through: 9.5
|
||||
---
|
||||
src/bin/scripts/createdb.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/src/bin/scripts/createdb.c b/src/bin/scripts/createdb.c
|
||||
index 8116b084ff..45d26ecb8c 100644
|
||||
--- a/src/bin/scripts/createdb.c
|
||||
+++ b/src/bin/scripts/createdb.c
|
||||
@@ -177,6 +177,13 @@ main(int argc, char *argv[])
|
||||
dbname = get_user_name_or_exit(progname);
|
||||
}
|
||||
|
||||
+ /* No point in trying to use postgres db when creating postgres db. */
|
||||
+ if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
|
||||
+ maintenance_db = "template1";
|
||||
+
|
||||
+ conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
|
||||
+ prompt_password, progname, echo);
|
||||
+
|
||||
initPQExpBuffer(&sql);
|
||||
|
||||
appendPQExpBuffer(&sql, "CREATE DATABASE %s",
|
||||
@@ -187,23 +194,25 @@ main(int argc, char *argv[])
|
||||
if (tablespace)
|
||||
appendPQExpBuffer(&sql, " TABLESPACE %s", fmtId(tablespace));
|
||||
if (encoding)
|
||||
- appendPQExpBuffer(&sql, " ENCODING '%s'", encoding);
|
||||
+ {
|
||||
+ appendPQExpBufferStr(&sql, " ENCODING ");
|
||||
+ appendStringLiteralConn(&sql, encoding, conn);
|
||||
+ }
|
||||
if (template)
|
||||
appendPQExpBuffer(&sql, " TEMPLATE %s", fmtId(template));
|
||||
if (lc_collate)
|
||||
- appendPQExpBuffer(&sql, " LC_COLLATE '%s'", lc_collate);
|
||||
+ {
|
||||
+ appendPQExpBufferStr(&sql, " LC_COLLATE ");
|
||||
+ appendStringLiteralConn(&sql, lc_collate, conn);
|
||||
+ }
|
||||
if (lc_ctype)
|
||||
- appendPQExpBuffer(&sql, " LC_CTYPE '%s'", lc_ctype);
|
||||
+ {
|
||||
+ appendPQExpBufferStr(&sql, " LC_CTYPE ");
|
||||
+ appendStringLiteralConn(&sql, lc_ctype, conn);
|
||||
+ }
|
||||
|
||||
appendPQExpBufferChar(&sql, ';');
|
||||
|
||||
- /* No point in trying to use postgres db when creating postgres db. */
|
||||
- if (maintenance_db == NULL && strcmp(dbname, "postgres") == 0)
|
||||
- maintenance_db = "template1";
|
||||
-
|
||||
- conn = connectMaintenanceDatabase(maintenance_db, host, port, username,
|
||||
- prompt_password, progname, echo);
|
||||
-
|
||||
if (echo)
|
||||
printf("%s\n", sql.data);
|
||||
result = PQexec(conn, sql.data);
|
||||
--
|
||||
2.23.0
|
||||
|
||||
58
generate-pdf.sh
Normal file
58
generate-pdf.sh
Normal file
@ -0,0 +1,58 @@
|
||||
#! /bin/sh
|
||||
|
||||
# This script builds the PDF version of the PostgreSQL documentation.
|
||||
#
|
||||
# In principle we could do this as part of the RPM build, but there are
|
||||
# good reasons not to:
|
||||
# 1. The build would take longer and have a larger BuildRequires footprint.
|
||||
# 2. The generated PDF has timestamps in it, which would inevitably result
|
||||
# in multilib conflicts due to slightly different timestamps.
|
||||
# So instead, we run this manually when rebasing to a new upstream release,
|
||||
# and treat the resulting PDF as a separate Source file.
|
||||
#
|
||||
# You will need to have the docbook packages installed to run this.
|
||||
# Expect it to take about 20 minutes and use about 160MB of disk.
|
||||
|
||||
set -e
|
||||
|
||||
# Pass package version (e.g., 9.1.2) as argument
|
||||
VERSION=$1
|
||||
|
||||
test -z "$VERSION" && VERSION=`awk '/^Version:/ { print $2; }' postgresql.spec`
|
||||
|
||||
TARGETFILE=postgresql-$VERSION-US.pdf
|
||||
test -f "$TARGETFILE" && echo "$TARGETFILE exists" && exit 1
|
||||
|
||||
echo Building $TARGETFILE ...
|
||||
|
||||
# Unpack postgresql
|
||||
|
||||
rm -rf postgresql-$VERSION
|
||||
|
||||
tar xfj postgresql-$VERSION.tar.bz2
|
||||
|
||||
cd postgresql-$VERSION
|
||||
|
||||
# Apply any patches that affect the PDF documentation
|
||||
|
||||
# patch -p1 < ../xxx.patch
|
||||
|
||||
# Configure ...
|
||||
|
||||
./configure >/dev/null
|
||||
|
||||
# Build the PDF docs
|
||||
|
||||
cd doc/src/sgml
|
||||
|
||||
make postgres-US.pdf >make.log
|
||||
|
||||
mv -f postgres-US.pdf ../../../../$TARGETFILE
|
||||
|
||||
# Clean up
|
||||
|
||||
cd ../../../..
|
||||
|
||||
rm -rf postgresql-$VERSION
|
||||
|
||||
exit 0
|
||||
12
generate-sources.sh
Normal file
12
generate-sources.sh
Normal file
@ -0,0 +1,12 @@
|
||||
#! /bin/sh
|
||||
|
||||
rm sources
|
||||
set -e
|
||||
spectool -S *.spec | cut -d' ' -f2 \
|
||||
| grep -E -e 'postgresql-.*\.tar\.*' -e 'postgresql.*\.pdf' | sort | \
|
||||
while read line
|
||||
do
|
||||
base=`basename "$line"`
|
||||
echo " * handling $base"
|
||||
sha512sum --tag "$base" >> sources
|
||||
done
|
||||
62
library.sh
62
library.sh
@ -1,62 +0,0 @@
|
||||
die() { echo >&2 $"FATAL: $@" ; exit 1 ; }
|
||||
error() { echo >&2 $"ERROR: $@" ; }
|
||||
error_q() { echo >&2 $" $@" ; }
|
||||
warn() { echo >&2 $"WARNING: $@" ; }
|
||||
warn_q() { echo >&2 $" $@" ; }
|
||||
info() { echo >&2 $" * $@" ; }
|
||||
info_q() { echo >&2 $" $@" ; }
|
||||
debug() { test "$option_debug" != "1" || echo >&2 $"DEBUG: $@"; }
|
||||
|
||||
|
||||
set_var()
|
||||
{
|
||||
eval "$1=\"$2\""
|
||||
}
|
||||
|
||||
|
||||
root_prereq()
|
||||
{
|
||||
test -z "$PGSETUP_TEST" || return 0
|
||||
test "$(id -u)" -eq 0 || die "$0 requires root access for this action"
|
||||
}
|
||||
|
||||
|
||||
read_config_file()
|
||||
{
|
||||
local key="" val=""
|
||||
|
||||
test -r "$1" || die "can't read file '$1'"
|
||||
|
||||
for i in $2; do
|
||||
eval "unset __pg_conf_$i"
|
||||
done
|
||||
|
||||
# No easy (and secure) way to read configuration files from bash script,
|
||||
# sorry.
|
||||
while read key val; do
|
||||
[[ $key =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] || return 1
|
||||
|
||||
case " $2 " in
|
||||
*" $key "*)
|
||||
;;
|
||||
*)
|
||||
warn "config file '$1': unknown key '$key'"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
|
||||
# Strip double quotes
|
||||
case "$val" in
|
||||
\"*\")
|
||||
val=${val##\"}
|
||||
val=${val%%\"}
|
||||
;;
|
||||
esac
|
||||
|
||||
# Make it reasonably safe. Keep dolar-sign escaped.
|
||||
eval "__pg_conf_$key=\$val"
|
||||
|
||||
done < <(grep -v -e "^$" -e "^#" < "$1")
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +0,0 @@
|
||||
# Macros from this file should exist on system only once, so it package
|
||||
# maintainer's responsibility to guarantee that all packages which install
|
||||
# these macros collide, or that (during package-build time) only one such
|
||||
# package is installed (e.g. similarly to %%scl macro defined installed by
|
||||
# *-build subpackage).
|
||||
|
||||
%postgresql_major 10
|
||||
|
||||
%postgresql_module_requires Requires: postgresql-server(:MODULE_COMPAT_10)
|
||||
@ -1,18 +0,0 @@
|
||||
# Initialize the PostgreSQL tests environment. This is supposed to be invoked
|
||||
# in prep/build/install (where you plan to run the testsuite), while it defines
|
||||
# several useful shell variables and provies useful commands. Effect of this
|
||||
# command end with shell exit.
|
||||
%postgresql_tests_init . "/usr/share/postgresql-setup/postgresql_pkg_tests.sh"
|
||||
|
||||
# Start the testing postgresql server, setting the actual unix user to be the
|
||||
# PostgreSQL admin. The $PGHOST/$PGPORT are set appropriately, so psql is able
|
||||
# to run without passwords. This also sets shell exit trap callback so that if
|
||||
# something goes wrong and package build fails, the temporary database is
|
||||
# automatically cleaned up.
|
||||
%postgresql_tests_start pgtests_start
|
||||
|
||||
# Initialize database and run server in one step, if this works well-enough.
|
||||
%postgresql_tests_run %postgresql_tests_init ; %postgresql_tests_start
|
||||
|
||||
%pgtests_init echo 2>&1 WARN: macro pgtests_init will be removed, use postgresql_tests_init ; %postgresql_tests_init
|
||||
%pgtests_start echo 2>&1 WARN: macro pgtests_start will be removed, use postgresql_tests_start ; %postgresql_tests_start
|
||||
@ -1 +0,0 @@
|
||||
6c8e616c91a45142b85c0aeb1f29ebba4a361309e86469e0fb4617b6a73c4011 postgresql-10.5.tar.bz2
|
||||
Binary file not shown.
1
postgresql-12.7.tar.bz2.sha256
Normal file
1
postgresql-12.7.tar.bz2.sha256
Normal file
@ -0,0 +1 @@
|
||||
8490741f47c88edc8b6624af009ce19fda4dc9b31c4469ce2551d84075d5d995 postgresql-12.7.tar.bz2
|
||||
BIN
postgresql-13.3-US.pdf
Normal file
BIN
postgresql-13.3-US.pdf
Normal file
Binary file not shown.
BIN
postgresql-13.3.tar.bz2
Normal file
BIN
postgresql-13.3.tar.bz2
Normal file
Binary file not shown.
1
postgresql-13.3.tar.bz2.sha256
Normal file
1
postgresql-13.3.tar.bz2.sha256
Normal file
@ -0,0 +1 @@
|
||||
3cd9454fa8c7a6255b6743b767700925ead1b9ab0d7a0f9dcb1151010f8eb4a1 postgresql-13.3.tar.bz2
|
||||
@ -1,104 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script verifies that the postgresql data directory has been correctly
|
||||
# initialized. We do not want to automatically initdb it, because that has
|
||||
# a risk of catastrophic failure (ie, overwriting a valuable database) in
|
||||
# corner cases, such as a remotely mounted database on a volume that's a
|
||||
# bit slow to mount. But we can at least emit a message advising newbies
|
||||
# what to do.
|
||||
|
||||
if test -z "$1"; then
|
||||
echo "Maintainer error: $0 must be run with one argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
service_name="$1"
|
||||
|
||||
if [ -z "$PGDATA" ]; then
|
||||
echo $"You try to start '$service_name' service"
|
||||
echo $"but the required \$PGDATA environment variable is not set."
|
||||
|
||||
if test 0 -eq 1; then
|
||||
echo $"You should use the /etc/sysconfig/pgsql/$service_name"
|
||||
else
|
||||
echo $"You should use the /etc/systemd/system/$service_name.service.d/ANYTHING.conf"
|
||||
fi
|
||||
|
||||
echo $"configuration file to set \$PGDATA. For more info see"
|
||||
echo $"the /usr/share/doc/postgresql/README.rpm-dist file."
|
||||
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
# Warn the user that the configuration should be adjusted via drop-in, in case
|
||||
# the $PGDATA variable is set different way (and non-default service name is
|
||||
# used, systemd systems only).
|
||||
conf_dir="/etc/systemd/system/$service_name.service.d"
|
||||
if test 0 = 0 && [[ "$service_name" == *@* ]] && test ! -d "$conf_dir"; then
|
||||
echo >&2 $"WARNING: Note that the '$conf_dir'"
|
||||
echo >&2 $"directory does not exist while you are using non-default service"
|
||||
echo >&2 $"name '$service_name'. You are encouraged to use the"
|
||||
echo >&2 $"$conf_dir directory for systemd configuration according"
|
||||
echo >&2 $"to /usr/share/doc/postgresql/README.rpm-dist documentation."
|
||||
fi
|
||||
|
||||
# Full PostgreSQL version, e.g. 9.0.2
|
||||
PGVERSION=10.5
|
||||
|
||||
# Major version of PostgreSQL, e.g. 9.0
|
||||
PGMAJORVERSION=10
|
||||
|
||||
# Distribution README file
|
||||
README_DIST=/usr/share/doc/postgresql/README.rpm-dist
|
||||
|
||||
bad_version()
|
||||
{
|
||||
local real_version="$1"
|
||||
|
||||
. "/usr/share/postgresql-setup/library.sh"
|
||||
|
||||
while read id version; do
|
||||
test "$version" = "$real_version" || continue
|
||||
|
||||
local cmd="postgresql-setup --upgrade"
|
||||
|
||||
test "postgresql" = "$id" \
|
||||
|| cmd="$cmd --upgrade-from $id"
|
||||
|
||||
echo $"An old version of the database format was found."
|
||||
echo $"Use '$cmd' to upgrade to version '$PGMAJORVERSION'"
|
||||
echo $"See $README_DIST for more information."
|
||||
|
||||
return
|
||||
done < <(parse_upgrade_setup list)
|
||||
|
||||
echo $"An old version '$real_version' of the database format was found."
|
||||
echo $"You need to dump and reload before using PostgreSQL $PGVERSION."
|
||||
echo $"See $README_DIST for more information."
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
# Check for the PGDATA structure
|
||||
if [ -f "$PGDATA/PG_VERSION" ] && [ -d "$PGDATA/base" ]
|
||||
then
|
||||
real_version=`cat "$PGDATA/PG_VERSION"`
|
||||
# Check version of existing PGDATA
|
||||
if [ x"$real_version" = x"$PGMAJORVERSION" ]
|
||||
then
|
||||
: A-OK
|
||||
else
|
||||
bad_version "$real_version"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# No existing PGDATA! Warn the user to initdb it.
|
||||
echo $"Directory \"$PGDATA\" is missing or empty."
|
||||
echo $"Use \"/usr/bin/postgresql-setup --initdb\""
|
||||
echo $"to initialize the database cluster."
|
||||
echo $"See $README_DIST for more information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
99
postgresql-datalayout-mismatch-on-s390.patch
Normal file
99
postgresql-datalayout-mismatch-on-s390.patch
Normal file
@ -0,0 +1,99 @@
|
||||
From 0edaa982336823d4d7af8f10b91579fe0099ef3d Mon Sep 17 00:00:00 2001
|
||||
From: Tom Stellard <tstellar@redhat.com>
|
||||
Date: Tue, 20 Apr 2021 20:14:21 -0700
|
||||
Subject: [PATCH] jit: Workaround potential datalayout mismatch on s390x
|
||||
|
||||
LLVM's s390x target uses a different datalayout for z13 and newer processors.
|
||||
If llvmjit_types.bc is compiled to target a processor older than z13, and
|
||||
then the JIT runs on a z13 or newer processor, then there will be a mismatch
|
||||
in datalayouts between llvmjit_types.bc and the JIT engine. This mismatch
|
||||
causes the JIT to fail at runtime.
|
||||
---
|
||||
src/backend/jit/llvm/llvmjit.c | 46 ++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 44 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
|
||||
index 98a27f08bf..05b6438ba8 100644
|
||||
--- a/src/backend/jit/llvm/llvmjit.c
|
||||
+++ b/src/backend/jit/llvm/llvmjit.c
|
||||
@@ -776,6 +776,35 @@ llvm_compile_module(LLVMJitContext *context)
|
||||
errhidecontext(true)));
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * For the systemz target, LLVM uses a different datalayout for z13 and newer
|
||||
+ * CPUs than it does for older CPUs. This can cause a mismatch in datalayouts
|
||||
+ * in the case where the llvm_types_module is compiled with a pre-z13 CPU
|
||||
+ * and the JIT is running on z13 or newer.
|
||||
+ * See computeDataLayout() function in
|
||||
+ * llvm/lib/Target/SystemZ/SystemZTargetMachine.cpp for information on the
|
||||
+ * datalayout differences.
|
||||
+ */
|
||||
+static bool
|
||||
+needs_systemz_workaround(void)
|
||||
+{
|
||||
+ bool ret = false;
|
||||
+ LLVMContextRef llvm_context;
|
||||
+ LLVMTypeRef vec_type;
|
||||
+ LLVMTargetDataRef llvm_layoutref;
|
||||
+ if (strncmp(LLVMGetTargetName(llvm_targetref), "systemz", strlen("systemz")))
|
||||
+ {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ llvm_context = LLVMGetModuleContext(llvm_types_module);
|
||||
+ vec_type = LLVMVectorType(LLVMIntTypeInContext(llvm_context, 32), 4);
|
||||
+ llvm_layoutref = LLVMCreateTargetData(llvm_layout);
|
||||
+ ret = (LLVMABIAlignmentOfType(llvm_layoutref, vec_type) == 16);
|
||||
+ LLVMDisposeTargetData(llvm_layoutref);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Per session initialization.
|
||||
*/
|
||||
@@ -785,6 +814,7 @@ llvm_session_initialize(void)
|
||||
MemoryContext oldcontext;
|
||||
char *error = NULL;
|
||||
char *cpu = NULL;
|
||||
+ char *host_features = NULL;
|
||||
char *features = NULL;
|
||||
LLVMTargetMachineRef opt0_tm;
|
||||
LLVMTargetMachineRef opt3_tm;
|
||||
@@ -816,10 +846,17 @@ llvm_session_initialize(void)
|
||||
* features not all CPUs have (weird, huh).
|
||||
*/
|
||||
cpu = LLVMGetHostCPUName();
|
||||
- features = LLVMGetHostCPUFeatures();
|
||||
+ features = host_features = LLVMGetHostCPUFeatures();
|
||||
elog(DEBUG2, "LLVMJIT detected CPU \"%s\", with features \"%s\"",
|
||||
cpu, features);
|
||||
|
||||
+ if (needs_systemz_workaround())
|
||||
+ {
|
||||
+ const char *no_vector =",-vector";
|
||||
+ features = malloc(sizeof(char) * (strlen(host_features) + strlen(no_vector) + 1));
|
||||
+ sprintf(features, "%s%s", host_features, no_vector);
|
||||
+ }
|
||||
+
|
||||
opt0_tm =
|
||||
LLVMCreateTargetMachine(llvm_targetref, llvm_triple, cpu, features,
|
||||
LLVMCodeGenLevelNone,
|
||||
@@ -833,8 +870,13 @@ llvm_session_initialize(void)
|
||||
|
||||
LLVMDisposeMessage(cpu);
|
||||
cpu = NULL;
|
||||
- LLVMDisposeMessage(features);
|
||||
+ if (features != host_features)
|
||||
+ {
|
||||
+ free(features);
|
||||
+ }
|
||||
features = NULL;
|
||||
+ LLVMDisposeMessage(host_features);
|
||||
+ host_features = NULL;
|
||||
|
||||
/* force symbols in main binary to be loaded */
|
||||
LLVMLoadLibraryPermanently(NULL);
|
||||
--
|
||||
2.27.0
|
||||
|
||||
43
postgresql-external-libpq.patch
Normal file
43
postgresql-external-libpq.patch
Normal file
@ -0,0 +1,43 @@
|
||||
We don't build/install interfaces by upstream's implicit rules.
|
||||
|
||||
This patch is used on two places; postgresql.spec and libecpg.spec -- keep those
|
||||
in sync!
|
||||
|
||||
Related: rhbz#1618698
|
||||
|
||||
diff --git a/src/Makefile b/src/Makefile
|
||||
index bcdbd95..4bea236 100644
|
||||
--- a/src/Makefile
|
||||
+++ b/src/Makefile
|
||||
@@ -20,7 +20,6 @@ SUBDIRS = \
|
||||
backend/utils/mb/conversion_procs \
|
||||
backend/snowball \
|
||||
include \
|
||||
- interfaces \
|
||||
backend/replication/libpqwalreceiver \
|
||||
backend/replication/pgoutput \
|
||||
fe_utils \
|
||||
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
|
||||
index b9d86ac..29df69f 100644
|
||||
--- a/src/Makefile.global.in
|
||||
+++ b/src/Makefile.global.in
|
||||
@@ -549,7 +549,7 @@ endif
|
||||
# How to link to libpq. (This macro may be used as-is by backend extensions.
|
||||
# Client-side code should go through libpq_pgport or libpq_pgport_shlib,
|
||||
# instead.)
|
||||
-libpq = -L$(libpq_builddir) -lpq
|
||||
+libpq = -lpq
|
||||
|
||||
# libpq_pgport is for use by client executables (not libraries) that use libpq.
|
||||
# We force clients to pull symbols from the non-shared libraries libpgport
|
||||
@@ -579,7 +579,6 @@ endif
|
||||
# Commonly used submake targets
|
||||
|
||||
submake-libpq: | submake-generated-headers
|
||||
- $(MAKE) -C $(libpq_builddir) all
|
||||
|
||||
submake-libpgport: | submake-generated-headers
|
||||
$(MAKE) -C $(top_builddir)/src/port all
|
||||
--
|
||||
2.21.0
|
||||
|
||||
41
postgresql-logging.patch
Normal file
41
postgresql-logging.patch
Normal file
@ -0,0 +1,41 @@
|
||||
Default to stderr-based logging with a week's worth of daily logfiles.
|
||||
|
||||
|
||||
diff -Naur postgresql-9.1rc1.orig/src/backend/utils/misc/postgresql.conf.sample postgresql-9.1rc1/src/backend/utils/misc/postgresql.conf.sample
|
||||
--- postgresql-9.1rc1.orig/src/backend/utils/misc/postgresql.conf.sample 2011-08-18 17:23:13.000000000 -0400
|
||||
+++ postgresql-9.1rc1/src/backend/utils/misc/postgresql.conf.sample 2011-08-18 18:39:39.697526799 -0400
|
||||
@@ -279,7 +279,7 @@
|
||||
# requires logging_collector to be on.
|
||||
|
||||
# This is used when logging to stderr:
|
||||
-#logging_collector = off # Enable capturing of stderr and csvlog
|
||||
+logging_collector = on # Enable capturing of stderr and csvlog
|
||||
# into log files. Required to be on for
|
||||
# csvlogs.
|
||||
# (change requires restart)
|
||||
@@ -355,11 +355,11 @@
|
||||
# These are only used if logging_collector is on:
|
||||
#log_directory = 'log' # directory where log files are written,
|
||||
# can be absolute or relative to PGDATA
|
||||
-#log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,
|
||||
+log_filename = 'postgresql-%a.log' # log file name pattern,
|
||||
# can include strftime() escapes
|
||||
#log_file_mode = 0600 # creation mode for log files,
|
||||
# begin with 0 to use octal notation
|
||||
-#log_truncate_on_rotation = off # If on, an existing log file with the
|
||||
+log_truncate_on_rotation = on # If on, an existing log file with the
|
||||
# same name as the new log file will be
|
||||
# truncated rather than appended to.
|
||||
# But such truncation only occurs on
|
||||
@@ -367,9 +367,9 @@
|
||||
# or size-driven rotation. Default is
|
||||
# off, meaning append to existing files
|
||||
# in all cases.
|
||||
-#log_rotation_age = 1d # Automatic rotation of logfiles will
|
||||
+log_rotation_age = 1d # Automatic rotation of logfiles will
|
||||
# happen after that time. 0 disables.
|
||||
-#log_rotation_size = 10MB # Automatic rotation of logfiles will
|
||||
+log_rotation_size = 0 # Automatic rotation of logfiles will
|
||||
# happen after that much log output.
|
||||
# 0 disables.
|
||||
|
||||
49
postgresql-man.patch
Normal file
49
postgresql-man.patch
Normal file
@ -0,0 +1,49 @@
|
||||
PostgreSQL ecpg/initdb manual page fixes
|
||||
|
||||
This was generated based on automatic Red Hat manual page scan (private
|
||||
RHBZ#948933).
|
||||
|
||||
diff -up postgresql-13.1/doc/src/sgml/man1/ecpg.1.patch6 postgresql-13.1/doc/src/sgml/man1/ecpg.1
|
||||
--- postgresql-13.1/doc/src/sgml/man1/ecpg.1.patch6 2020-11-09 23:38:03.000000000 +0100
|
||||
+++ postgresql-13.1/doc/src/sgml/man1/ecpg.1 2020-11-18 09:26:40.547324791 +0100
|
||||
@@ -81,6 +81,11 @@ ORACLE\&.
|
||||
Define a C preprocessor symbol\&.
|
||||
.RE
|
||||
.PP
|
||||
+\fB\-h \fR
|
||||
+.RS 4
|
||||
+Parse a header file, this option includes option \fB\-c\fR\&.
|
||||
+.RE
|
||||
+.PP
|
||||
\fB\-h\fR
|
||||
.RS 4
|
||||
Process header files\&. When this option is specified, the output file extension becomes
|
||||
@@ -144,6 +149,11 @@ Allow question mark as placeholder for c
|
||||
.RE
|
||||
.RE
|
||||
.PP
|
||||
+\fB\-\-regression\fR
|
||||
+.RS 4
|
||||
+Run in regression testing mode\&.
|
||||
+.RE
|
||||
+.PP
|
||||
\fB\-t\fR
|
||||
.RS 4
|
||||
Turn on autocommit of transactions\&. In this mode, each SQL command is automatically committed unless it is inside an explicit transaction block\&. In the default mode, commands are committed only when
|
||||
diff -up postgresql-13.1/doc/src/sgml/man1/initdb.1.patch6 postgresql-13.1/doc/src/sgml/man1/initdb.1
|
||||
--- postgresql-13.1/doc/src/sgml/man1/initdb.1.patch6 2020-11-09 23:38:05.000000000 +0100
|
||||
+++ postgresql-13.1/doc/src/sgml/man1/initdb.1 2020-11-18 09:25:05.082348424 +0100
|
||||
@@ -311,6 +311,13 @@ determines that an error prevented it fr
|
||||
.PP
|
||||
Other options:
|
||||
.PP
|
||||
+\fB\-s\fR
|
||||
+.br
|
||||
+\fB\-\-show\fR
|
||||
+.RS 4
|
||||
+Print the internal settings, then exit\&.
|
||||
+.RE
|
||||
+.PP
|
||||
\fB\-V\fR
|
||||
.br
|
||||
\fB\-\-version\fR
|
||||
12
postgresql-no-libecpg.patch
Normal file
12
postgresql-no-libecpg.patch
Normal file
@ -0,0 +1,12 @@
|
||||
diff -up postgresql-13.1/src/interfaces/Makefile.patch10 postgresql-13.1/src/interfaces/Makefile
|
||||
--- postgresql-13.1/src/interfaces/Makefile.patch10 2021-02-02 21:33:23.235292305 +0100
|
||||
+++ postgresql-13.1/src/interfaces/Makefile 2021-02-02 21:33:30.281365440 +0100
|
||||
@@ -12,7 +12,7 @@ subdir = src/interfaces
|
||||
top_builddir = ../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
|
||||
-SUBDIRS = libpq ecpg
|
||||
+SUBDIRS = libpq
|
||||
|
||||
$(recurse)
|
||||
|
||||
58
postgresql-server-pg_config.patch
Normal file
58
postgresql-server-pg_config.patch
Normal file
@ -0,0 +1,58 @@
|
||||
We should ideally provide '/bin/pg_config' in postgresql-server-devel, and
|
||||
provide no pg_config binary in libpq package. But most of the Fedora packages
|
||||
that use pg_config actually only build against PG libraries (and
|
||||
postgresql-server-devel isn't needed). So.., to avoid the initial rush around
|
||||
rhbz#1618698 change, rather provide pg_server_config binary, which int urn means
|
||||
that we'll have to fix only a minimal set of packages which really build
|
||||
PostgreSQL server modules.
|
||||
|
||||
diff -up postgresql-13.1/src/bin/pg_config/Makefile.patch9 postgresql-13.1/src/bin/pg_config/Makefile
|
||||
--- postgresql-13.1/src/bin/pg_config/Makefile.patch9 2020-11-18 09:28:30.885453275 +0100
|
||||
+++ postgresql-13.1/src/bin/pg_config/Makefile 2020-11-18 09:31:33.926325327 +0100
|
||||
@@ -11,6 +11,8 @@
|
||||
PGFILEDESC = "pg_config - report configuration information"
|
||||
PGAPPICON=win32
|
||||
|
||||
+PG_CONFIG = pg_server_config$(X)
|
||||
+
|
||||
subdir = src/bin/pg_config
|
||||
top_builddir = ../../..
|
||||
include $(top_builddir)/src/Makefile.global
|
||||
@@ -19,22 +21,22 @@ OBJS = \
|
||||
$(WIN32RES) \
|
||||
pg_config.o
|
||||
|
||||
-all: pg_config
|
||||
+all: $(PG_CONFIG)
|
||||
|
||||
-pg_config: $(OBJS) | submake-libpgport
|
||||
- $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
|
||||
+$(PG_CONFIG): $(OBJS) | submake-libpgport
|
||||
+ $(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
|
||||
|
||||
install: all installdirs
|
||||
- $(INSTALL_SCRIPT) pg_config$(X) '$(DESTDIR)$(bindir)/pg_config$(X)'
|
||||
+ $(INSTALL_SCRIPT) $(PG_CONFIG) '$(DESTDIR)$(bindir)/$(PG_CONFIG)'
|
||||
|
||||
installdirs:
|
||||
$(MKDIR_P) '$(DESTDIR)$(bindir)'
|
||||
|
||||
uninstall:
|
||||
- rm -f '$(DESTDIR)$(bindir)/pg_config$(X)'
|
||||
+ rm -f '$(DESTDIR)$(bindir)/$(PG_CONFIG)'
|
||||
|
||||
clean distclean maintainer-clean:
|
||||
- rm -f pg_config$(X) $(OBJS)
|
||||
+ rm -f $(PG_CONFIG) $(OBJS)
|
||||
rm -rf tmp_check
|
||||
|
||||
check:
|
||||
diff -up postgresql-13.1/src/bin/pg_config/nls.mk.patch9 postgresql-13.1/src/bin/pg_config/nls.mk
|
||||
--- postgresql-13.1/src/bin/pg_config/nls.mk.patch9 2020-11-18 09:28:30.885453275 +0100
|
||||
+++ postgresql-13.1/src/bin/pg_config/nls.mk 2020-11-18 09:32:00.735599526 +0100
|
||||
@@ -1,4 +1,4 @@
|
||||
# src/bin/pg_config/nls.mk
|
||||
-CATALOG_NAME = pg_config
|
||||
+CATALOG_NAME = pg_server_config
|
||||
AVAIL_LANGUAGES = cs de es fr he it ja ko pl pt_BR ru sv tr uk vi zh_CN
|
||||
GETTEXT_FILES = pg_config.c ../../common/config_info.c ../../common/exec.c
|
||||
777
postgresql-setup
777
postgresql-setup
@ -1,777 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# postgresql-setup - Initialization and upgrade operations for PostgreSQL
|
||||
|
||||
if test "$(id -u)" -eq 0; then
|
||||
cmd=
|
||||
for v in PGSETUP_DEBUG PGSETUP_INITDB_OPTIONS PGSETUP_PGUPGRADE_OPTIONS; do
|
||||
eval var_content=\$$v
|
||||
test -z "$var_content" && continue
|
||||
cmd+=$v="$(printf %q "$var_content") "
|
||||
done
|
||||
cmd+=$(printf %q "$(readlink -f "$0")")
|
||||
for arg; do cmd+=" $(printf %q "$arg")" ; done
|
||||
# Drop root privileges asap. It's not recommended to run postgresql-setup
|
||||
# script under root nowadays; so we take the liberty to switch to the
|
||||
# PostgreSQL admin user (by default 'postgres') without any other option.
|
||||
exec /usr/sbin/runuser -s /bin/sh -l postgres -c "$cmd"
|
||||
fi
|
||||
|
||||
# ensure privacy
|
||||
umask 0077
|
||||
|
||||
: ${RESTORECON=/sbin/restorecon}
|
||||
test -x $RESTORECON || RESTORECON=:
|
||||
|
||||
test -z "$PATH" && export PATH="/sbin:/usr/sbin:/bin:/usr/bin"
|
||||
|
||||
test x"$PGSETUP_DEBUG" != x && set -x && PS4='${LINENO}: '
|
||||
|
||||
# The current user name.
|
||||
USER=$(id -u -n)
|
||||
|
||||
# Directory containing the postmaster executable
|
||||
PGENGINE=/usr/bin
|
||||
|
||||
# Distribution README file
|
||||
README_DIST=/usr/share/doc/postgresql/README.rpm-dist
|
||||
|
||||
# Home directory of postgres user
|
||||
POSTGRES_HOMEDIR=/var/lib/pgsql
|
||||
|
||||
# The where PostgreSQL server listens by default
|
||||
PGPORT_DEF=5432
|
||||
|
||||
|
||||
. "/usr/share/postgresql-setup/library.sh"
|
||||
|
||||
:
|
||||
|
||||
# We upgrade by default from system's default PostgreSQL installation
|
||||
option_upgradefrom="postgresql"
|
||||
|
||||
srvsuff=
|
||||
test 0 -eq 0 && srvsuff=".service"
|
||||
|
||||
USAGE_STRING=$"\
|
||||
Usage: $0 MODE_OPTION [--unit=UNIT_NAME] [OPTION...]
|
||||
|
||||
Script is aimed to help sysadmin with basic database cluster administration.
|
||||
Usually, \"postgresql-setup --initdb\" and \"postgresql-setup --upgrade\" is
|
||||
enough, however there are other options described below.
|
||||
|
||||
For more info and howto/when use this script please look at the documentation
|
||||
file $README_DIST.
|
||||
|
||||
Available operation mode:
|
||||
--initdb Initialize new PostgreSQL database cluster. This is usually the
|
||||
first action you perform after PostgreSQL server installation.
|
||||
--upgrade Upgrade database cluster for new major version of PostgreSQL
|
||||
server. See the --upgrade-from option for more info.
|
||||
|
||||
Options:
|
||||
--unit=UNIT_NAME The UNIT_NAME is used to select proper unit
|
||||
configuration (unit == service or initscript name
|
||||
on non-systemd systems). For example, if you want
|
||||
to work with unit called
|
||||
'postgresql@com_example.service', you should use
|
||||
'postgresql@com_example' (without trailing .service
|
||||
string). When no UNIT_NAME is explicitly passed,
|
||||
the 'postgresql' string is used by default.
|
||||
--port=PORT port where the initialized server will listen for
|
||||
connections"
|
||||
|
||||
test 0 -eq 0 && \
|
||||
USAGE_STRING+="
|
||||
--new-systemd-unit We dropped this option for security reasons.
|
||||
Nowadays, please use the root-only script
|
||||
/usr/sbin/postgresql-new-systemd-unit.
|
||||
--datadir Dropped with --new-systemd-unit."
|
||||
|
||||
USAGE_STRING+="
|
||||
--upgrade-from-unit=UNIT Select proper unit name to upgrade from. This
|
||||
has similar semantics as --unit option.
|
||||
--upgrade-ids Print list of available IDs of upgrade scenarios to
|
||||
standard output.
|
||||
--upgrade-from=ID Specify id \"old\" postgresql stack to upgrade
|
||||
from. List of available IDs can be listed by
|
||||
--upgrade-ids. Default is '$option_upgradefrom'.
|
||||
|
||||
Other options:
|
||||
--help show this help
|
||||
--version show version of this package
|
||||
--debug show basic debugging information
|
||||
|
||||
Environment:
|
||||
PGSETUP_INITDB_OPTIONS Options carried by this variable are passed to
|
||||
subsequent call of \`initdb\` binary (see man
|
||||
initdb(1)). This variable is used also during
|
||||
'upgrade' mode because the new cluster is actually
|
||||
re-initialized from the old one.
|
||||
PGSETUP_PGUPGRADE_OPTIONS Options in this variable are passed next to the
|
||||
subsequent call of \`pg_upgrade\`. For more info
|
||||
about possible options please look at man
|
||||
pg_upgrade(1).
|
||||
PGSETUP_DEBUG Set to '1' if you want to see very verbose shell
|
||||
debugging output."
|
||||
|
||||
|
||||
print_version()
|
||||
{
|
||||
echo "postgresql-setup 8.2"
|
||||
echo $"Built against PostgreSQL version 10.5."
|
||||
}
|
||||
|
||||
|
||||
check_not_initialized()
|
||||
{
|
||||
if test -f "$pgdata/PG_VERSION"; then
|
||||
error $"Data directory $pgdata is not empty!"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
# code shared between initdb and upgrade actions
|
||||
perform_initdb()
|
||||
{
|
||||
if [ ! -e "$pgdata" ]; then
|
||||
mkdir "$pgdata" || return 1
|
||||
fi
|
||||
$RESTORECON "$pgdata"
|
||||
test -w "$pgdata" || die "$pgdata is not writeable by $USER"
|
||||
|
||||
# Clean up SELinux tagging for pgdata
|
||||
[ -x /sbin/restorecon ] && /sbin/restorecon "$pgdata"
|
||||
|
||||
# Create the initdb log file if needed
|
||||
if [ ! -e "$initdb_log" ]; then
|
||||
touch "$initdb_log" || return 1
|
||||
fi
|
||||
$RESTORECON "$initdb_log"
|
||||
test -w "$initdb_log" || echo "$initdb_log is not writeable by $USER"
|
||||
|
||||
# Initialize the database
|
||||
initdbcmd+=( "$PGENGINE"/initdb --pgdata="$pgdata" --auth=ident )
|
||||
eval "initdbcmd+=( $PGSETUP_INITDB_OPTIONS )"
|
||||
"${initdbcmd[@]}" >> "$initdb_log" 2>&1 < /dev/null
|
||||
|
||||
# Create directory for postmaster log files
|
||||
mkdir "$pgdata/pg_log"
|
||||
$RESTORECON "$pgdata/pg_log"
|
||||
|
||||
# This if-fork is just to not unnecessarily overwrite what upstream
|
||||
# generates by initdb (upstream implicitly uses PGPORT_DEF).
|
||||
if test "$pgport" != "$PGPORT_DEF"; then
|
||||
local pgconf="$pgdata/postgresql.conf"
|
||||
sed -i "s|^[[:space:]#]*port[[:space:]]=[^#]*|port = $pgport |g" \
|
||||
"$pgconf" \
|
||||
&& grep "^port = " "$pgconf" >/dev/null
|
||||
|
||||
if test $? -ne 0; then
|
||||
error "can not change port in $pgdata/postgresql.conf"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
test -f "$pgdata/PG_VERSION"
|
||||
}
|
||||
|
||||
|
||||
initdb()
|
||||
{
|
||||
port_info=
|
||||
test "$pgport" != "$PGPORT_DEF" \
|
||||
&& port_info=$", listening on port '$pgport'"
|
||||
|
||||
info $"Initializing database in '$pgdata'$port_info"
|
||||
if check_not_initialized && perform_initdb; then
|
||||
info $"Initialized, logs are in ${initdb_log}"
|
||||
else
|
||||
error $"Initializing database failed, possibly see $initdb_log"
|
||||
script_result=1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
old_data_in_use()
|
||||
{
|
||||
local pidfile="$pgdataold/postmaster.pid"
|
||||
test -f "$pidfile" || return 1
|
||||
error $"The pidfile '$pidfile' exists. Verify that there is no postmaster"
|
||||
error_q $"running the $pgdataold directory."
|
||||
}
|
||||
|
||||
|
||||
upgrade()
|
||||
{
|
||||
local inplace=false
|
||||
test "$pgdata" = "$upgradefrom_data" && inplace=true
|
||||
|
||||
debug "running inplace upgrade: $inplace"
|
||||
|
||||
# must see previous version in PG_VERSION
|
||||
local old_data_version="`cat "$upgradefrom_data/PG_VERSION"`"
|
||||
if [ ! -f "$upgradefrom_data/PG_VERSION" -o \
|
||||
x"$old_data_version" != x"$upgradefrom_major" ]
|
||||
then
|
||||
error $"Cannot upgrade because the database in $upgradefrom_data is of"
|
||||
error_q $"version $old_data_version but it should be $upgradefrom_major"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -x "$upgradefrom_engine/postgres" ]; then
|
||||
error $"Please install the $upgradefrom_package package."
|
||||
exit 5
|
||||
fi
|
||||
if [ ! -x "$PGENGINE/pg_upgrade" ]; then
|
||||
# The "$PGENGINE/postgres" depends transitively on
|
||||
# pg_upgrade binary in rather newer packaging, but SCL with PostgreSQL
|
||||
# 9.4 provides '*-upgrade' package having `pg_upgrade` inside. We need
|
||||
# to have this installed, too. Keep till {rh,sclo}-postgresql94 is
|
||||
# still a thing.
|
||||
error $"Please install the postgresql-upgrade package."
|
||||
exit 5
|
||||
fi
|
||||
|
||||
# Set up log file for pg_upgrade
|
||||
rm -f "$upgrade_log"
|
||||
touch "$upgrade_log" || die "can't write into $upgrade_log file"
|
||||
$RESTORECON "$upgrade_log"
|
||||
|
||||
# Move old DB to pgdataold
|
||||
|
||||
if $inplace; then
|
||||
pgdataold="${pgdata}-old"
|
||||
rm -rf "$pgdataold"
|
||||
mv "$pgdata" "$pgdataold" || exit 1
|
||||
else
|
||||
pgdataold="$upgradefrom_data"
|
||||
fi
|
||||
|
||||
# Create configuration file for upgrade process
|
||||
HBA_CONF_BACKUP="$pgdataold/pg_hba.conf.postgresql-setup.`date +%s`"
|
||||
HBA_CONF_BACKUP_EXISTS=0
|
||||
|
||||
if [ ! -f $HBA_CONF_BACKUP ]; then
|
||||
mv "$pgdataold/pg_hba.conf" "$HBA_CONF_BACKUP"
|
||||
HBA_CONF_BACKUP_EXISTS=1
|
||||
|
||||
# For fluent upgrade 'postgres' user should be able to connect
|
||||
# to any database without password. Temporarily, no other type
|
||||
# of connection is needed.
|
||||
echo "local all postgres ident" > "$pgdataold/pg_hba.conf"
|
||||
$RESTORECON "$pgdataold"
|
||||
fi
|
||||
|
||||
info $"Upgrading database."
|
||||
|
||||
scls_upgrade_hacks=
|
||||
test -n "$upgradefrom_scls" && {
|
||||
debug "scls [$upgradefrom_scls] will be enabled"
|
||||
scls_upgrade_hacks="source scl_source enable $upgradefrom_scls"
|
||||
}
|
||||
|
||||
test x"$upgradefrom_redhat_sockets_hack" = xyes && {
|
||||
debug "upgrading from redhat server"
|
||||
socket_hacks="export REDHAT_PGUPGRADE_FROM_RHEL=yes"
|
||||
}
|
||||
|
||||
test -n "$upgradefrom_pghost_override" && {
|
||||
pghost_override="export PGHOST='$upgradefrom_pghost_override'"
|
||||
}
|
||||
|
||||
local failure_cleanup=true
|
||||
if old_data_in_use; then
|
||||
script_result=1
|
||||
# Cleanup makes sense once perform_initdb gets called.
|
||||
failure_cleanup=false
|
||||
elif ! check_not_initialized; then
|
||||
# Don't try to re-init initialized data directory and also do not
|
||||
# remove it after this unsuccessful upgrade.
|
||||
script_result=1
|
||||
failure_cleanup=false
|
||||
elif perform_initdb; then
|
||||
$inplace && link_option=--link
|
||||
|
||||
# After creating the empty new-format database, do the upgrade
|
||||
(
|
||||
cd # pg_upgrade writes to $PWD
|
||||
eval "
|
||||
$scls_upgrade_hacks
|
||||
$socket_hacks
|
||||
$pghost_override
|
||||
"
|
||||
eval "add_options=( $PGSETUP_PGUPGRADE_OPTIONS )"
|
||||
|
||||
"$PGENGINE"/pg_upgrade \
|
||||
--old-bindir="$upgradefrom_engine" \
|
||||
--new-bindir="$PGENGINE" \
|
||||
--old-datadir="$pgdataold" \
|
||||
--new-datadir="$pgdata" \
|
||||
$link_option \
|
||||
--old-port="$PGPORT" \
|
||||
--new-port="$PGPORT" \
|
||||
--username=postgres \
|
||||
"${add_options[@]}" \
|
||||
>>"$upgrade_log" 2>>"$upgrade_log"
|
||||
)
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
# pg_upgrade failed
|
||||
error $"pg_upgrade tool failed"
|
||||
script_result=1
|
||||
fi
|
||||
else
|
||||
error $"initdb failed"
|
||||
script_result=1
|
||||
fi
|
||||
|
||||
# Move back the backed-up pg_hba.conf regardless of the script_result.
|
||||
if [ x$HBA_CONF_BACKUP_EXISTS = x1 ]; then
|
||||
mv -f "$HBA_CONF_BACKUP" "$pgdataold/pg_hba.conf"
|
||||
fi
|
||||
|
||||
if [ $script_result -eq 0 ]; then
|
||||
info $"Upgraded OK."
|
||||
warn $"The configuration files were replaced by default configuration."
|
||||
warn $"The previous configuration and data are stored in folder"
|
||||
warn $pgdataold.
|
||||
else
|
||||
# Clean up after failure.
|
||||
$failure_cleanup && rm -rf "$pgdata"
|
||||
$inplace && mv "$pgdataold" "$pgdata"
|
||||
error $"Upgrade failed."
|
||||
fi
|
||||
info $"See $upgrade_log for details."
|
||||
}
|
||||
|
||||
|
||||
check_daemon_reload()
|
||||
{
|
||||
local nr_option=NeedDaemonReload
|
||||
|
||||
test 0 = 1 && return 0
|
||||
|
||||
local nr_out="`systemctl show -p $nr_option $option_service.service 2>/dev/null`"
|
||||
if [[ "$nr_out" != "$nr_option=no" ]]; then
|
||||
error $"Note that systemd configuration for '$option_service' changed."
|
||||
error_q $"You need to perform 'systemctl daemon-reload' otherwise the"
|
||||
error_q $"results of this script can be inadequate."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
handle_service_env()
|
||||
{
|
||||
local service="$1"
|
||||
|
||||
local systemd_env="$(systemctl show -p Environment "${service}.service")" \
|
||||
|| { return; }
|
||||
|
||||
for env_var in `echo "$systemd_env" | sed 's/^Environment=//'`; do
|
||||
# If one variable name is defined multiple times the last definition wins.
|
||||
case "$env_var" in
|
||||
PGDATA=*)
|
||||
unit_pgdata="${env_var##PGDATA=}"
|
||||
debug "unit's datadir: '$unit_pgdata'"
|
||||
;;
|
||||
PGPORT=*)
|
||||
unit_pgport="${env_var##PGPORT=}"
|
||||
debug "unit's pgport: $unit_pgport"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
handle_envfile()
|
||||
{
|
||||
local file="$1"
|
||||
|
||||
debug "trying to read '$file' env file"
|
||||
if test ! -r "$file"; then
|
||||
if test 0 = 1; then
|
||||
return
|
||||
fi
|
||||
error "Can not read EnvironmentFile '$file' specified"
|
||||
error_q "in ${service}.service"
|
||||
fi
|
||||
|
||||
# Note that the env file parser in systemd does not perform exactly the
|
||||
# same job.
|
||||
unset PGPORT PGDATA
|
||||
. "$file"
|
||||
envfile_pgdata="$PGDATA"
|
||||
envfile_pgport="$PGPORT"
|
||||
unset PGPORT PGDATA
|
||||
}
|
||||
|
||||
|
||||
handle_service_envfiles()
|
||||
{
|
||||
local mode="$1"
|
||||
local service="$2"
|
||||
|
||||
local envfiles="$(systemctl show -p EnvironmentFiles "${service}.service")"\
|
||||
|| return
|
||||
|
||||
test -z "$envfiles" && return
|
||||
|
||||
envfiles=$(echo $envfiles | \
|
||||
sed -e 's/^EnvironmentFile=//' \
|
||||
-e 's| ([^)]*)$||'
|
||||
)
|
||||
|
||||
# Read the file names line-by-line (spaces may be inside)
|
||||
while read line; do
|
||||
handle_envfile "$line"
|
||||
done <<<"$envfiles"
|
||||
}
|
||||
|
||||
|
||||
handle_pgconf()
|
||||
{
|
||||
local datadir="$1"
|
||||
local conffile="$datadir/postgresql.conf"
|
||||
|
||||
debug "postgresql.conf: $conffile"
|
||||
|
||||
test -r "$conffile" || {
|
||||
error "config file $conffile is not readable or does not exist"
|
||||
die "Old cluster in '$data' does not seem to be initialized"
|
||||
}
|
||||
|
||||
local sp='[[:space:]]'
|
||||
local sed_expr="s/^$sp*port$sp*=$sp\([0-9]\+\).*/\1/p"
|
||||
|
||||
rv=0
|
||||
conf_pgport=`sed -n "$sed_expr" $conffile | tail -1` || rv=1
|
||||
test -n "$conf_pgport" && debug "postgresql.conf pgport: $conf_pgport"
|
||||
return $rv
|
||||
}
|
||||
|
||||
|
||||
service_configuration()
|
||||
{
|
||||
local data=
|
||||
local port=
|
||||
local unit_pgport=
|
||||
local unit_pgdata=
|
||||
local envfile_pgport=
|
||||
local envfile_pgdata=
|
||||
|
||||
# 'mode' is 'initdb' or 'upgrade'. Basically, if called with mode=initdb, we
|
||||
# parse configuration of the current (maybe already configured) service.
|
||||
# When run with mode=upgrade, we try to parse the configuration of the old
|
||||
# PostgreSQL configuration that we try to upgrade from.
|
||||
|
||||
local mode="$1" datavar="$2" portvar="$3" service="$4"
|
||||
|
||||
debug "running service_configuration() for $service, mode: $mode"
|
||||
|
||||
if test "0" = 1; then
|
||||
# Sysvinit has the default PGDATA (for default unit name only)
|
||||
# configured directly in the initscript, so no additional configuration
|
||||
# must exist. Set the default value of pgdata here to match whats in
|
||||
# initscript for the cases when no additional configuration file exists.
|
||||
# This is done to avoid parsing of whole initscript (for the real value)
|
||||
# and mainly to not fail in the logic following 'service_configuration'
|
||||
# call, where we usually want to error that pgdata is not defined..
|
||||
# Don't set the default pgdata for upgrade case, however, as we must
|
||||
# upgrade only from already properly configured & working stack (missing
|
||||
# pgdata here is a good reason to die later).
|
||||
test initdb = "$mode" && test "$service" = "postgresql" \
|
||||
&& set_var "$datavar" "/var/lib/pgsql/data"
|
||||
handle_envfile "/etc/sysconfig/pgsql/$service"
|
||||
else
|
||||
# We ship two service files, postgresql.service and
|
||||
# postgresql@.service. The former has PGDATA set by default
|
||||
# similarly to sysvinit case.
|
||||
handle_service_env "$service"
|
||||
handle_service_envfiles "$option_mode" "$service"
|
||||
fi
|
||||
|
||||
# EnvironmentFile beats Environment configuration in systemd. In sysvinit
|
||||
# there is no "unit_pgdata". So make sure the envfile_gpdata is used later
|
||||
# than unit_pgdata.
|
||||
test -n "$unit_pgdata" && set_var "$datavar" "$unit_pgdata"
|
||||
test -n "$envfile_pgdata" && set_var "$datavar" "$envfile_pgdata"
|
||||
|
||||
# skip for the first run
|
||||
test initdb = "$mode" && return
|
||||
|
||||
set_var data "\$$datavar"
|
||||
handle_pgconf "$data"
|
||||
|
||||
test -n "$conf_pgport" && set_var "$portvar" "$conf_pgport"
|
||||
test -n "$unit_pgport" && set_var "$portvar" "$unit_pgport"
|
||||
test -n "$envfile_pgport" && set_var "$portvar" "$envfile_pgport"
|
||||
}
|
||||
|
||||
# <Compat>
|
||||
# Alow users to use the old style arguments like
|
||||
# 'postgresql-setup initdb $SERVICE_NAME'.
|
||||
case "$1" in initdb|upgrade)
|
||||
action="--$1"
|
||||
shift
|
||||
|
||||
warn "using obsoleted argument syntax, try --help"
|
||||
old_long_args="help,usage,version,debug"
|
||||
oldargs=`getopt -o "" -l "$old_long_args" -n "old-options" -- "$@"` \
|
||||
|| die "can't parse old arguments"
|
||||
eval set -- "$oldargs"
|
||||
additional_opts=
|
||||
while true; do
|
||||
case "$1" in
|
||||
--version|--help|--usage|--debug)
|
||||
additional_opts="$additional_opts $1"
|
||||
shift
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
service="postgresql"
|
||||
if test -n "$1"; then
|
||||
service=$1
|
||||
shift
|
||||
fi
|
||||
|
||||
set -- $additional_opts "$action" --unit "$service" "$@"
|
||||
warn "arguments transformed to: ${0##*/} $*"
|
||||
esac
|
||||
# </Compat>
|
||||
|
||||
|
||||
# postgresql-setup arguments are parsed into those variables
|
||||
option_mode=none
|
||||
option_service="postgresql"
|
||||
option_port=
|
||||
option_debug=0
|
||||
option_upgradefrom_unit=
|
||||
|
||||
# Content of EnvironmentFile= files fills those:
|
||||
envfile_pgdata=
|
||||
envfile_pgport=
|
||||
|
||||
# Configuration from (/etc/systemd/system/$option_service.service) fills those
|
||||
# variables.
|
||||
unit_pgdata=
|
||||
unit_pgport=
|
||||
|
||||
# Configuration from postgresql.conf:
|
||||
conf_pgport=
|
||||
|
||||
# Key variables. Try to fill them by postgresql.conf, Environment= statement in
|
||||
# service file or EnvironmentFile= content (the later mentioned has more
|
||||
# priority).
|
||||
pgdata=default
|
||||
pgport=default
|
||||
|
||||
## PARSE SCRIPT ARGUMENTS ##
|
||||
|
||||
short_opts=""
|
||||
long_opts="\
|
||||
initdb,upgrade,\
|
||||
new-systemd-unit,upgrade-ids,\
|
||||
unit:,service:,port:,datadir:,upgrade-from:,upgrade-from-unit:,\
|
||||
debug,\
|
||||
version,help,usage"
|
||||
|
||||
args=`getopt -o "$short_opts" -l "$long_opts" -n "postgresql-setup" -- "$@"` \
|
||||
|| die "can't parse arguments"
|
||||
eval set -- "$args"
|
||||
parse_fail=0
|
||||
while true; do
|
||||
case "$1" in
|
||||
--initdb|--upgrade)
|
||||
if test "$option_mode" != none; then
|
||||
error "bad argument $1, mode already specified: --$option_mode"
|
||||
parse_fail=1
|
||||
else
|
||||
option_mode=${1##--}
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
|
||||
--unit|--service)
|
||||
option_service=$2
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--port)
|
||||
option_port=$2
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--datadir|--new-systemd-unit)
|
||||
error $"Removed option --new-systemd-unit/--datadir, please use"
|
||||
error_q $"/usr/sbin/postgresql-new-systemd-unit script"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
--debug)
|
||||
option_debug=1
|
||||
shift
|
||||
;;
|
||||
|
||||
--help|--usage)
|
||||
echo "$USAGE_STRING"
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--upgrade-from)
|
||||
option_upgradefrom="$2"
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--upgrade-from-unit)
|
||||
option_upgradefrom_unit="$2"
|
||||
shift 2
|
||||
;;
|
||||
|
||||
--version)
|
||||
print_version
|
||||
exit 0
|
||||
;;
|
||||
|
||||
--)
|
||||
shift
|
||||
break
|
||||
;;
|
||||
|
||||
*)
|
||||
die "author's fault: option $1 not handled"
|
||||
break
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
test $parse_fail -ne 0 && die "can't parse arguments"
|
||||
|
||||
test "$option_mode" = none \
|
||||
&& die "no mode specified, use --initdb or --upgrade, or --help"
|
||||
|
||||
## GATHER THE SETUP FIRST ##
|
||||
|
||||
initdb_log="$POSTGRES_HOMEDIR/initdb_${option_service}.log"
|
||||
upgrade_log="$POSTGRES_HOMEDIR/upgrade_${option_service}.log"
|
||||
|
||||
debug "mode used: $option_mode"
|
||||
debug "service name: $option_service"
|
||||
|
||||
# load service's pgdata
|
||||
service_configuration initdb pgdata UNUSED "$option_service"
|
||||
|
||||
test "$pgdata" = default \
|
||||
&& die $"no db datadir (PGDATA) configured for '$option_service$srvsuff' unit"
|
||||
|
||||
[[ "$pgdata" =~ ^/.* ]] \
|
||||
|| die $"the PostgreSQL datadir not absolute path: '$pgdata', try --debug"
|
||||
|
||||
## GATHER DATA FROM INITIALIZED DATADIR ##
|
||||
|
||||
test -n "$option_port" && pgport=$option_port
|
||||
|
||||
if test upgrade = "$option_mode"; then
|
||||
upgradefrom_data="$upgradefrom_data_default"
|
||||
|
||||
if test -z "$option_upgradefrom_unit"; then
|
||||
if test "postgresql" = "postgresql"; then
|
||||
# Fedora usecase -> upgrade while keeping the same name of
|
||||
# service/unit.
|
||||
option_upgradefrom_unit=$option_service
|
||||
else
|
||||
# PGRPMs/RHSCL usecase -> we upgrade from one service/unit name to
|
||||
# a different one, e.g. from postgresql92 to postgresql93, or from
|
||||
# postgresql (system version) to postgresql94 (scl).
|
||||
option_upgradefrom_unit=$upgradefrom_id
|
||||
|
||||
# Try to predict situations: postgresql93@second -> postgresql94@second
|
||||
if [[ "$option_service" =~ ^postgresql@(.*)$ ]]; then
|
||||
option_upgradefrom_unit="$upgradefrom_id@${BASH_REMATCH[1]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
test "$option_service" = "$option_upgradefrom_unit" \
|
||||
|| info "upgrading from '$option_upgradefrom_unit$srvsuff'" \
|
||||
"to '$option_service$srvsuff'"
|
||||
|
||||
service_configuration upgrade upgradefrom_data pgport \
|
||||
"$option_upgradefrom_unit"
|
||||
test -n "$option_port" -a "$option_port" != "$pgport" \
|
||||
&& warn "Old pgport $pgport has bigger priority than --pgport value."
|
||||
fi
|
||||
|
||||
# We expect that for upgrade - the previous stack was in working state (thus
|
||||
# running on the default port).
|
||||
test "$option_mode" = upgrade -a "$pgport" = default \
|
||||
&& pgport=$PGPORT_DEF
|
||||
|
||||
# This is mostly for 'initdb'. We assume that the default port is $PGPORT_DEF
|
||||
# if not set explicitly for default service name 'postgresql'.
|
||||
if test "$pgport" = default -a "$option_service" = "postgresql"; then
|
||||
debug $"Using the default port '$PGPORT_DEF'"
|
||||
pgport=$PGPORT_DEF
|
||||
fi
|
||||
|
||||
if test "$pgport" = default; then
|
||||
# initdb case.. Note that this may be called by initscripts. If this gets
|
||||
# called by legacy script, we can't help too much because systemd does not
|
||||
# allow passing additional arguments to 'service XX initdb' command.
|
||||
die $"For non-default unit names you must specify port by --port option."
|
||||
fi
|
||||
|
||||
[[ "$option_port" =~ ^[0-9]*$ ]] \
|
||||
|| die $"port set to '$option_port', must be integer number"
|
||||
|
||||
## LAST CHECK THE SETUP ##
|
||||
|
||||
check_daemon_reload
|
||||
|
||||
# These variables are read by underlying utilites, rather export them.
|
||||
export PGDATA=$pgdata
|
||||
export PGPORT=$pgport
|
||||
|
||||
debug "final pgdata: $pgdata"
|
||||
debug "final pgport: $pgport"
|
||||
|
||||
script_result=0
|
||||
|
||||
test -w "/var/lib/pgsql" || {
|
||||
# pg_upgrade binary needs to have write-able $PWD (and we use 'su -')
|
||||
error $"The /var/lib/pgsql directory has wrong permissions."
|
||||
error_q $"Please make sure the directory is writable by $USER."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if /usr/bin/mountpoint -q "$pgdata" || /usr/bin/mountpoint -q "$(dirname "$pgdata")"; then
|
||||
warn $"Note that either your data directory '$pgdata' or"
|
||||
warn_q $"the parent directory '$(dirname "$pgdata")'"
|
||||
warn_q $"is a direct mountpoint. This is usually a bad idea and your"
|
||||
warn_q $"filesystem layout should ideally look like:"
|
||||
warn_q $"/ROOT_OWNED_MOUNTPOINT/POSTGRES_OWNED_DIRECTORY/DATADIR."
|
||||
warn_q $"See the upstream documentation for more info:"
|
||||
warn_q $"http://www.postgresql.org/docs/10/static/creating-cluster.html"
|
||||
fi
|
||||
|
||||
# See how we were called.
|
||||
case "$option_mode" in
|
||||
initdb)
|
||||
initdb
|
||||
;;
|
||||
upgrade)
|
||||
upgrade
|
||||
;;
|
||||
*)
|
||||
echo >&2 "$USAGE_STRING"
|
||||
exit 2
|
||||
esac
|
||||
|
||||
exit $script_result
|
||||
BIN
postgresql-setup-8.5.tar.gz
Normal file
BIN
postgresql-setup-8.5.tar.gz
Normal file
Binary file not shown.
@ -42,12 +42,12 @@ diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
|
||||
index e278fa0..9ee15d4 100644
|
||||
--- a/src/include/pg_config_manual.h
|
||||
+++ b/src/include/pg_config_manual.h
|
||||
@@ -169,7 +169,7 @@
|
||||
* here's where to twiddle it. You can also override this at runtime
|
||||
* with the postmaster's -k switch.
|
||||
@@ -201,7 +201,7 @@
|
||||
* support them yet.
|
||||
*/
|
||||
#ifndef WIN32
|
||||
-#define DEFAULT_PGSOCKET_DIR "/tmp"
|
||||
+#define DEFAULT_PGSOCKET_DIR "/var/run/postgresql"
|
||||
|
||||
/*
|
||||
* This is the default event source for Windows event log.
|
||||
#else
|
||||
#define DEFAULT_PGSOCKET_DIR ""
|
||||
#endif
|
||||
3
postgresql.pam
Normal file
3
postgresql.pam
Normal file
@ -0,0 +1,3 @@
|
||||
#%PAM-1.0
|
||||
auth include password-auth
|
||||
account include password-auth
|
||||
@ -1,23 +0,0 @@
|
||||
[Unit]
|
||||
Description=PostgreSQL database server
|
||||
After=network.target
|
||||
[Service]
|
||||
Type=notify
|
||||
|
||||
User=postgres
|
||||
Group=postgres
|
||||
OOMScoreAdjust=-1000
|
||||
Environment=PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
|
||||
Environment=PG_OOM_ADJUST_VALUE=0
|
||||
Environment=PGDATA=/var/lib/pgsql/data
|
||||
|
||||
ExecStartPre=/usr/libexec/postgresql-check-db-dir %N
|
||||
ExecStart=/usr/bin/postmaster -D ${PGDATA}
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillMode=mixed
|
||||
KillSignal=SIGINT
|
||||
|
||||
TimeoutSec=0
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1420
postgresql.spec
1420
postgresql.spec
File diff suppressed because it is too large
Load Diff
@ -1,193 +0,0 @@
|
||||
#! /bin/sh
|
||||
|
||||
# Do some "integration" testing against running PostgreSQL server.
|
||||
|
||||
# This file is to be sourced.
|
||||
|
||||
try_random_port ()
|
||||
{
|
||||
_port=$RANDOM
|
||||
if test -n "$_port" && eval '_port=$(( $_port + 32000 ))' 2>/dev/null; then
|
||||
echo "$_port"
|
||||
elif test -x /usr/bin/shuf; then
|
||||
/usr/bin/shuf -r -n 1 -i 32000-64767
|
||||
else
|
||||
echo 54321
|
||||
fi
|
||||
}
|
||||
|
||||
: ${PGTESTS_DATADIR=`pwd`/datadir}
|
||||
: ${PGTESTS_ADMIN=`id -u -n`}
|
||||
: ${PGTESTS_ADMINDB=$PGTESTS_ADMIN}
|
||||
: ${PGTESTS_ADMINPASS=$PGTESTS_ADMIN}
|
||||
: ${PGTESTS_PORT=`try_random_port`}
|
||||
: ${PGTESTS_SOCKETDIR=/tmp}
|
||||
: ${PGTESTS_USERS=test:test}
|
||||
: ${PGTESTS_DATABASES=test:test}
|
||||
|
||||
# Stop the old cluster and/or remove it's data.
|
||||
: ${PGTESTS_STARTCLEANUP=:}
|
||||
|
||||
# Cleanup once we exit the script.
|
||||
: ${PGTESTS_CLEANUP=:}
|
||||
|
||||
# Cleanup once we exit the script.
|
||||
: ${PGTESTS_CLEANUP=:}
|
||||
|
||||
export PGPORT=$PGTESTS_PORT
|
||||
export PGHOST=$PGTESTS_SOCKETDIR
|
||||
|
||||
:
|
||||
|
||||
warning ()
|
||||
{
|
||||
echo >&2 " ! $*"
|
||||
}
|
||||
|
||||
|
||||
__trap_cb ()
|
||||
{
|
||||
IFS=' '
|
||||
for __func in $__TRAP_ACTIONS
|
||||
do
|
||||
$__func
|
||||
done
|
||||
}
|
||||
trap __trap_cb EXIT
|
||||
|
||||
|
||||
__pgtests_initdb ()
|
||||
{
|
||||
initdb "$PGTESTS_DATADIR" -U "$PGTESTS_ADMIN" \
|
||||
--auth-local=peer --auth-host=md5 \
|
||||
${PGTESTS_LOCALE+--locale="$PGTESTS_LOCALE"}
|
||||
}
|
||||
|
||||
|
||||
__pgtests_start ()
|
||||
{
|
||||
pg_ctl -D "$PGTESTS_DATADIR" -l "$PGTESTS_DATADIR"/start.log start \
|
||||
-o "-k $PGTESTS_SOCKETDIR -p $PGTESTS_PORT" -w || {
|
||||
cat >&2 "$PGTESTS_DATADIR"/start.log
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
__pgtests_create_admins_db ()
|
||||
{
|
||||
createdb -h "$PGTESTS_SOCKETDIR" "$PGTESTS_ADMINDB" --owner "$PGTESTS_ADMIN" -p "$PGTESTS_PORT"
|
||||
}
|
||||
|
||||
|
||||
__pgtests_passwd()
|
||||
{
|
||||
psql -d postgres --set=user="$1" --set=pass="$2" -tA \
|
||||
<<<"ALTER USER :\"user\" WITH ENCRYPTED PASSWORD :'pass';"
|
||||
}
|
||||
|
||||
pgtests_start ()
|
||||
{
|
||||
unset __TRAP_ACTIONS
|
||||
|
||||
if $PGTESTS_STARTCLEANUP; then
|
||||
# We don't plan to be serious here. This pgtests_* effort is just to
|
||||
# ease _testing_ against running postgresql server without too much
|
||||
# writing.
|
||||
if test -f "$PGTESTS_DATADIR"/postmaster.pid; then
|
||||
# Give it a try.
|
||||
warning "Seems like server works, trying to stop."
|
||||
pg_ctl stop -D "$PGTESTS_DATADIR" -w
|
||||
fi
|
||||
|
||||
# Cleanup testing directory
|
||||
if test -e "$PGTESTS_DATADIR"; then
|
||||
warning "Removing old data directory."
|
||||
rm -r "$PGTESTS_DATADIR"
|
||||
fi
|
||||
fi
|
||||
|
||||
__pgtests_initdb
|
||||
__TRAP_ACTIONS="pgtests_cleanup $__TRAP_ACTIONS"
|
||||
__pgtests_start
|
||||
__TRAP_ACTIONS="pgtests_stop $__TRAP_ACTIONS"
|
||||
__pgtests_create_admins_db
|
||||
|
||||
__pgtests_passwd "$PGTESTS_ADMIN" "$PGTESTS_ADMINPASS"
|
||||
|
||||
|
||||
for _pgt_user in $PGTESTS_USERS
|
||||
do
|
||||
save_IFS=$IFS
|
||||
IFS=:
|
||||
_user=
|
||||
_pass=
|
||||
for _part in $_pgt_user
|
||||
do
|
||||
if test -z "$_user"; then
|
||||
_user=$_part
|
||||
else
|
||||
_pass=$_part
|
||||
fi
|
||||
done
|
||||
|
||||
createuser "$_user"
|
||||
__pgtests_passwd "$_user" "$_pass"
|
||||
IFS=$save_IFS
|
||||
done
|
||||
|
||||
|
||||
for _pgt_db in $PGTESTS_DATABASES
|
||||
do
|
||||
save_IFS=$IFS
|
||||
IFS=:
|
||||
_db=
|
||||
_user=
|
||||
for _part in $_pgt_db
|
||||
do
|
||||
if test -z "$_user"; then
|
||||
_user=$_part
|
||||
else
|
||||
_db=$_part
|
||||
fi
|
||||
done
|
||||
|
||||
createdb "$_db" --owner "$_part"
|
||||
|
||||
IFS=$save_IFS
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
__clean_trap_action ()
|
||||
{
|
||||
__new_actions=
|
||||
for __action in $__TRAP_ACTIONS
|
||||
do
|
||||
if test "$__action" = "$1"; then
|
||||
:
|
||||
else
|
||||
__new_actions="$__action $__new_actions"
|
||||
fi
|
||||
done
|
||||
|
||||
__TRAP_ACTIONS=$__new_actions
|
||||
}
|
||||
|
||||
|
||||
pgtests_cleanup ()
|
||||
{
|
||||
if $PGTESTS_CLEANUP && $PGTESTS_AUTOSTOP; then
|
||||
rm -r "$PGTESTS_DATADIR"
|
||||
fi
|
||||
__clean_trap_action pgtests_cleanup
|
||||
}
|
||||
|
||||
|
||||
pgtests_stop ()
|
||||
{
|
||||
if $PGTESTS_AUTOSTOP; then
|
||||
pg_ctl stop -D "$PGTESTS_DATADIR" -w
|
||||
fi
|
||||
__clean_trap_action pgtests_stop
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user