summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlog.c17
-rw-r--r--src/backend/storage/aio/method_worker.c6
-rw-r--r--src/backend/storage/ipc/procarray.c52
-rw-r--r--src/backend/utils/adt/timestamp.c20
-rw-r--r--src/include/storage/procarray.h1
-rw-r--r--src/interfaces/libpq/fe-connect.c54
-rw-r--r--src/interfaces/libpq/libpq-int.h2
-rw-r--r--src/interfaces/libpq/t/006_service.pl79
8 files changed, 145 insertions, 86 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 88fb9b45b2a..8e7827c6ed9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -449,7 +449,6 @@ typedef struct XLogCtlData
/* Protected by info_lck: */
XLogwrtRqst LogwrtRqst;
XLogRecPtr RedoRecPtr; /* a recent copy of Insert->RedoRecPtr */
- FullTransactionId ckptFullXid; /* nextXid of latest checkpoint */
XLogRecPtr asyncXactLSN; /* LSN of newest async commit/abort */
XLogRecPtr replicationSlotMinLSN; /* oldest LSN needed by any slot */
@@ -5744,7 +5743,6 @@ StartupXLOG(void)
SetMultiXactIdLimit(checkPoint.oldestMulti, checkPoint.oldestMultiDB, true);
SetCommitTsLimit(checkPoint.oldestCommitTsXid,
checkPoint.newestCommitTsXid);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
/*
* Clear out any old relcache cache files. This is *necessary* if we do
@@ -7437,11 +7435,6 @@ CreateCheckPoint(int flags)
UpdateControlFile();
LWLockRelease(ControlFileLock);
- /* Update shared-memory copy of checkpoint XID/epoch */
- SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
- SpinLockRelease(&XLogCtl->info_lck);
-
/*
* We are now done with critical updates; no need for system panic if we
* have trouble while fooling with old log segments.
@@ -8516,11 +8509,6 @@ xlog_redo(XLogReaderState *record)
ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
LWLockRelease(ControlFileLock);
- /* Update shared-memory copy of checkpoint XID/epoch */
- SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
- SpinLockRelease(&XLogCtl->info_lck);
-
/*
* We should've already switched to the new TLI before replaying this
* record.
@@ -8577,11 +8565,6 @@ xlog_redo(XLogReaderState *record)
ControlFile->checkPointCopy.nextXid = checkPoint.nextXid;
LWLockRelease(ControlFileLock);
- /* Update shared-memory copy of checkpoint XID/epoch */
- SpinLockAcquire(&XLogCtl->info_lck);
- XLogCtl->ckptFullXid = checkPoint.nextXid;
- SpinLockRelease(&XLogCtl->info_lck);
-
/* TLI should not change in an on-line checkpoint */
(void) GetCurrentReplayRecPtr(&replayTLI);
if (checkPoint.ThisTimeLineID != replayTLI)
diff --git a/src/backend/storage/aio/method_worker.c b/src/backend/storage/aio/method_worker.c
index 1ce1bcd57a0..bf8f77e6ff6 100644
--- a/src/backend/storage/aio/method_worker.c
+++ b/src/backend/storage/aio/method_worker.c
@@ -575,6 +575,12 @@ IoWorkerMain(const void *startup_data, size_t startup_data_len)
}
CHECK_FOR_INTERRUPTS();
+
+ if (ConfigReloadPending)
+ {
+ ConfigReloadPending = false;
+ ProcessConfigFile(PGC_SIGHUP);
+ }
}
error_context_stack = errcallback.previous;
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index e5b945a9ee3..2418967def6 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -1622,58 +1622,6 @@ TransactionIdIsInProgress(TransactionId xid)
return false;
}
-/*
- * TransactionIdIsActive -- is xid the top-level XID of an active backend?
- *
- * This differs from TransactionIdIsInProgress in that it ignores prepared
- * transactions, as well as transactions running on the primary if we're in
- * hot standby. Also, we ignore subtransactions since that's not needed
- * for current uses.
- */
-bool
-TransactionIdIsActive(TransactionId xid)
-{
- bool result = false;
- ProcArrayStruct *arrayP = procArray;
- TransactionId *other_xids = ProcGlobal->xids;
- int i;
-
- /*
- * Don't bother checking a transaction older than RecentXmin; it could not
- * possibly still be running.
- */
- if (TransactionIdPrecedes(xid, RecentXmin))
- return false;
-
- LWLockAcquire(ProcArrayLock, LW_SHARED);
-
- for (i = 0; i < arrayP->numProcs; i++)
- {
- int pgprocno = arrayP->pgprocnos[i];
- PGPROC *proc = &allProcs[pgprocno];
- TransactionId pxid;
-
- /* Fetch xid just once - see GetNewTransactionId */
- pxid = UINT32_ACCESS_ONCE(other_xids[i]);
-
- if (!TransactionIdIsValid(pxid))
- continue;
-
- if (proc->pid == 0)
- continue; /* ignore prepared transactions */
-
- if (TransactionIdEquals(pxid, xid))
- {
- result = true;
- break;
- }
- }
-
- LWLockRelease(ProcArrayLock);
-
- return result;
-}
-
/*
* Determine XID horizons.
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 0a5848a4ab2..25cff56c3d0 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -5312,10 +5312,10 @@ isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
int
date2isoweek(int year, int mon, int mday)
{
- float8 result;
int day0,
day4,
- dayn;
+ dayn,
+ week;
/* current day */
dayn = date2j(year, mon, mday);
@@ -5338,13 +5338,13 @@ date2isoweek(int year, int mon, int mday)
day0 = j2day(day4 - 1);
}
- result = (dayn - (day4 - day0)) / 7 + 1;
+ week = (dayn - (day4 - day0)) / 7 + 1;
/*
* Sometimes the last few days in a year will fall into the first week of
* the next year, so check for this.
*/
- if (result >= 52)
+ if (week >= 52)
{
day4 = date2j(year + 1, 1, 4);
@@ -5352,10 +5352,10 @@ date2isoweek(int year, int mon, int mday)
day0 = j2day(day4 - 1);
if (dayn >= day4 - day0)
- result = (dayn - (day4 - day0)) / 7 + 1;
+ week = (dayn - (day4 - day0)) / 7 + 1;
}
- return (int) result;
+ return week;
}
@@ -5367,10 +5367,10 @@ date2isoweek(int year, int mon, int mday)
int
date2isoyear(int year, int mon, int mday)
{
- float8 result;
int day0,
day4,
- dayn;
+ dayn,
+ week;
/* current day */
dayn = date2j(year, mon, mday);
@@ -5395,13 +5395,13 @@ date2isoyear(int year, int mon, int mday)
year--;
}
- result = (dayn - (day4 - day0)) / 7 + 1;
+ week = (dayn - (day4 - day0)) / 7 + 1;
/*
* Sometimes the last few days in a year will fall into the first week of
* the next year, so check for this.
*/
- if (result >= 52)
+ if (week >= 52)
{
day4 = date2j(year + 1, 1, 4);
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index ef0b733ebe8..e4877d88e8f 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -53,7 +53,6 @@ extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc);
extern RunningTransactions GetRunningTransactionData(void);
extern bool TransactionIdIsInProgress(TransactionId xid);
-extern bool TransactionIdIsActive(TransactionId xid);
extern TransactionId GetOldestNonRemovableTransactionId(Relation rel);
extern TransactionId GetOldestTransactionIdConsideredRunning(void);
extern TransactionId GetOldestActiveTransactionId(void);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 09eb79812ac..2a2b10d5a29 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -201,6 +201,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Database-Service", "", 20,
offsetof(struct pg_conn, pgservice)},
+ {"servicefile", "PGSERVICEFILE", NULL, NULL,
+ "Database-Service-File", "", 64,
+ offsetof(struct pg_conn, pgservicefile)},
+
{"user", "PGUSER", NULL, NULL,
"Database-User", "", 20,
offsetof(struct pg_conn, pguser)},
@@ -5062,6 +5066,7 @@ freePGconn(PGconn *conn)
free(conn->dbName);
free(conn->replication);
free(conn->pgservice);
+ free(conn->pgservicefile);
free(conn->pguser);
if (conn->pgpass)
{
@@ -5914,6 +5919,7 @@ static int
parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
{
const char *service = conninfo_getval(options, "service");
+ const char *service_fname = conninfo_getval(options, "servicefile");
char serviceFile[MAXPGPATH];
char *env;
bool group_found = false;
@@ -5933,10 +5939,13 @@ parseServiceInfo(PQconninfoOption *options, PQExpBuffer errorMessage)
return 0;
/*
- * Try PGSERVICEFILE if specified, else try ~/.pg_service.conf (if that
- * exists).
+ * First, try the "servicefile" option in connection string. Then, try
+ * the PGSERVICEFILE environment variable. Finally, check
+ * ~/.pg_service.conf (if that exists).
*/
- if ((env = getenv("PGSERVICEFILE")) != NULL)
+ if (service_fname != NULL)
+ strlcpy(serviceFile, service_fname, sizeof(serviceFile));
+ else if ((env = getenv("PGSERVICEFILE")) != NULL)
strlcpy(serviceFile, env, sizeof(serviceFile));
else
{
@@ -6092,7 +6101,17 @@ parseServiceFile(const char *serviceFile,
if (strcmp(key, "service") == 0)
{
libpq_append_error(errorMessage,
- "nested service specifications not supported in service file \"%s\", line %d",
+ "nested \"service\" specifications not supported in service file \"%s\", line %d",
+ serviceFile,
+ linenr);
+ result = 3;
+ goto exit;
+ }
+
+ if (strcmp(key, "servicefile") == 0)
+ {
+ libpq_append_error(errorMessage,
+ "nested \"servicefile\" specifications not supported in service file \"%s\", line %d",
serviceFile,
linenr);
result = 3;
@@ -6135,6 +6154,33 @@ parseServiceFile(const char *serviceFile,
}
exit:
+
+ /*
+ * If a service has been successfully found, set the "servicefile" option
+ * if not already set. This matters when we use a default service file or
+ * PGSERVICEFILE, where we want to be able track the value.
+ */
+ if (*group_found && result == 0)
+ {
+ for (i = 0; options[i].keyword; i++)
+ {
+ if (strcmp(options[i].keyword, "servicefile") != 0)
+ continue;
+
+ /* If value is already set, nothing to do */
+ if (options[i].val != NULL)
+ break;
+
+ options[i].val = strdup(serviceFile);
+ if (options[i].val == NULL)
+ {
+ libpq_append_error(errorMessage, "out of memory");
+ result = 3;
+ }
+ break;
+ }
+ }
+
fclose(f);
return result;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index a6cfd7f5c9d..70c28f2ffca 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -389,6 +389,8 @@ struct pg_conn
char *dbName; /* database name */
char *replication; /* connect as the replication standby? */
char *pgservice; /* Postgres service, if any */
+ char *pgservicefile; /* path to a service file containing
+ * service(s) */
char *pguser; /* Postgres username and password, if any */
char *pgpass;
char *pgpassfile; /* path to a file containing password(s) */
diff --git a/src/interfaces/libpq/t/006_service.pl b/src/interfaces/libpq/t/006_service.pl
index d896558a6cc..797e6232b8f 100644
--- a/src/interfaces/libpq/t/006_service.pl
+++ b/src/interfaces/libpq/t/006_service.pl
@@ -53,6 +53,13 @@ copy($srvfile_valid, $srvfile_nested)
or die "Could not copy $srvfile_valid to $srvfile_nested: $!";
append_to_file($srvfile_nested, 'service=invalid_srv' . $newline);
+# Service file with nested "servicefile" defined.
+my $srvfile_nested_2 = "$td/pg_service_nested_2.conf";
+copy($srvfile_valid, $srvfile_nested_2)
+ or die "Could not copy $srvfile_valid to $srvfile_nested_2: $!";
+append_to_file($srvfile_nested_2,
+ 'servicefile=' . $srvfile_default . $newline);
+
# Set the fallback directory lookup of the service file to the temporary
# directory of this test. PGSYSCONFDIR is used if the service file
# defined in PGSERVICEFILE cannot be found, or when a service file is
@@ -158,9 +165,77 @@ local $ENV{PGSERVICEFILE} = "$srvfile_empty";
$dummy_node->connect_fails(
'service=my_srv',
- 'connection with nested service file',
+ 'connection with "service" in nested service file',
+ expected_stderr =>
+ qr/nested "service" specifications not supported in service file/);
+
+ local $ENV{PGSERVICEFILE} = $srvfile_nested_2;
+
+ $dummy_node->connect_fails(
+ 'service=my_srv',
+ 'connection with "servicefile" in nested service file',
expected_stderr =>
- qr/nested service specifications not supported in service file/);
+ qr/nested "servicefile" specifications not supported in service file/
+ );
+}
+
+# Properly escape backslashes in the path, to ensure the generation of
+# correct connection strings.
+my $srvfile_win_cared = $srvfile_valid;
+$srvfile_win_cared =~ s/\\/\\\\/g;
+
+# Checks that the "servicefile" option works as expected
+{
+ $dummy_node->connect_ok(
+ q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with valid servicefile in connection string',
+ sql => "SELECT 'connect3_1'",
+ expected_stdout => qr/connect3_1/);
+
+ # Encode slashes and backslash
+ my $encoded_srvfile = $srvfile_valid =~ s{([\\/])}{
+ $1 eq '/' ? '%2F' : '%5C'
+ }ger;
+
+ # Additionally encode a colon in servicefile path of Windows
+ $encoded_srvfile =~ s/:/%3A/g;
+
+ $dummy_node->connect_ok(
+ 'postgresql:///?service=my_srv&servicefile=' . $encoded_srvfile,
+ 'connection with valid servicefile in URI',
+ sql => "SELECT 'connect3_2'",
+ expected_stdout => qr/connect3_2/);
+
+ local $ENV{PGSERVICE} = 'my_srv';
+ $dummy_node->connect_ok(
+ q{servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with PGSERVICE and servicefile in connection string',
+ sql => "SELECT 'connect3_3'",
+ expected_stdout => qr/connect3_3/);
+
+ $dummy_node->connect_ok(
+ 'postgresql://?servicefile=' . $encoded_srvfile,
+ 'connection with PGSERVICE and servicefile in URI',
+ sql => "SELECT 'connect3_4'",
+ expected_stdout => qr/connect3_4/);
+}
+
+# Check that the "servicefile" option takes priority over the PGSERVICEFILE
+# environment variable.
+{
+ local $ENV{PGSERVICEFILE} = 'non-existent-file.conf';
+
+ $dummy_node->connect_fails(
+ 'service=my_srv',
+ 'connection with invalid PGSERVICEFILE',
+ expected_stderr =>
+ qr/service file "non-existent-file\.conf" not found/);
+
+ $dummy_node->connect_ok(
+ q{service=my_srv servicefile='} . $srvfile_win_cared . q{'},
+ 'connection with both servicefile and PGSERVICEFILE',
+ sql => "SELECT 'connect4_1'",
+ expected_stdout => qr/connect4_1/);
}
$node->teardown_node;