Skip to content

Commit 27adf95

Browse files
knizhnikkelvich
authored andcommitted
Improve DDL handling
1 parent 23e0701 commit 27adf95

File tree

1 file changed

+67
-28
lines changed

1 file changed

+67
-28
lines changed

multimaster.c

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include "catalog/indexing.h"
6565
#include "catalog/namespace.h"
6666
#include "catalog/pg_constraint_fn.h"
67+
#include "catalog/pg_proc.h"
6768
#include "pglogical_output/hooks.h"
6869
#include "parser/analyze.h"
6970
#include "parser/parse_relation.h"
@@ -258,8 +259,6 @@ bool MtmPreserveCommitOrder;
258259
bool MtmVolksWagenMode; /* Pretend to be normal postgres. This means skip some NOTICE's and use local sequences */
259260
bool MtmMajorNode;
260261

261-
TransactionId MtmUtilityProcessedInXid;
262-
263262
static char* MtmConnStrs;
264263
static char* MtmRemoteFunctionsList;
265264
static char* MtmClusterName;
@@ -277,6 +276,7 @@ static bool MtmClusterLocked;
277276
static bool MtmInsideTransaction;
278277
static bool MtmReferee;
279278
static bool MtmMonotonicSequences;
279+
static void const* MtmDDLStatement;
280280

281281
static ExecutorStart_hook_type PreviousExecutorStartHook;
282282
static ExecutorFinish_hook_type PreviousExecutorFinishHook;
@@ -923,6 +923,7 @@ MtmResetTransaction()
923923
x->csn = INVALID_CSN;
924924
x->status = TRANSACTION_STATUS_UNKNOWN;
925925
x->gid[0] = '\0';
926+
MtmDDLStatement = NULL;
926927
}
927928

928929
#if 0
@@ -986,6 +987,7 @@ MtmBeginTransaction(MtmCurrentTrans* x)
986987
MtmCheckClusterLock();
987988
}
988989
MtmInsideTransaction = true;
990+
MtmDDLStatement = NULL;
989991
Mtm->nRunningTransactions += 1;
990992

991993
x->snapshot = MtmAssignCSN();
@@ -3117,7 +3119,7 @@ _PG_init(void)
31173119
&MtmRemoteFunctionsList,
31183120
"lo_create,lo_unlink",
31193121
PGC_USERSET, /* context */
3120-
0, /* flags */
3122+
GUC_LIST_INPUT | GUC_LIST_QUOTE, /* flags */
31213123
NULL, /* GucStringCheckHook check_hook */
31223124
MtmSetRemoteFunction, /* GucStringAssignHook assign_hook */
31233125
NULL /* GucShowHook show_hook */
@@ -4630,14 +4632,17 @@ static void MtmGucDiscard()
46304632
dlist_init(&MtmGucList);
46314633

46324634
hash_destroy(MtmGucHash);
4633-
MtmGucInit();
4635+
MtmGucHash = NULL;
46344636
}
46354637

46364638
static inline void MtmGucUpdate(const char *key, char *value)
46374639
{
46384640
MtmGucEntry *hentry;
46394641
bool found;
46404642

4643+
if (!MtmGucHash)
4644+
MtmGucInit();
4645+
46414646
hentry = (MtmGucEntry*)hash_search(MtmGucHash, key, HASH_ENTER, &found);
46424647
if (found)
46434648
{
@@ -4653,6 +4658,9 @@ static inline void MtmGucRemove(const char *key)
46534658
MtmGucEntry *hentry;
46544659
bool found;
46554660

4661+
if (!MtmGucHash)
4662+
MtmGucInit();
4663+
46564664
hentry = (MtmGucEntry*)hash_search(MtmGucHash, key, HASH_FIND, &found);
46574665
if (found)
46584666
{
@@ -4711,23 +4719,19 @@ char* MtmGucSerialize(void)
47114719

47124720
serialized_gucs = makeStringInfo();
47134721

4714-
/*
4715-
* Crutch for scheduler. It sets search_path through SetConfigOption()
4716-
* so our callback do not react on that.
4717-
*/
4718-
search_path = GetConfigOption("search_path", false, true);
4719-
appendStringInfo(serialized_gucs, "SET search_path TO %s; ", search_path);
4720-
47214722
dlist_foreach(iter, &MtmGucList)
47224723
{
47234724
MtmGucEntry *cur_entry = dlist_container(MtmGucEntry, list_node, iter.cur);
47244725

4726+
if (strcmp(cur_entry->key, "search_path") == 0)
4727+
continue;
4728+
47254729
appendStringInfoString(serialized_gucs, "SET ");
47264730
appendStringInfoString(serialized_gucs, cur_entry->key);
47274731
appendStringInfoString(serialized_gucs, " TO ");
47284732

47294733
/* quite a crutch */
4730-
if (strstr(cur_entry->key, "_mem") != NULL || *(cur_entry->value) == '\0' || strchr(cur_entry->value, ',') != NULL)
4734+
if (strstr(cur_entry->key, "_mem") != NULL || *(cur_entry->value) == '\0')
47314735
{
47324736
appendStringInfoString(serialized_gucs, "'");
47334737
appendStringInfoString(serialized_gucs, cur_entry->value);
@@ -4740,6 +4744,13 @@ char* MtmGucSerialize(void)
47404744
appendStringInfoString(serialized_gucs, "; ");
47414745
}
47424746

4747+
/*
4748+
* Crutch for scheduler. It sets search_path through SetConfigOption()
4749+
* so our callback do not react on that.
4750+
*/
4751+
search_path = GetConfigOption("search_path", false, true);
4752+
appendStringInfo(serialized_gucs, "SET search_path TO %s; ", search_path);
4753+
47434754
return serialized_gucs->data;
47444755
}
47454756

@@ -5032,6 +5043,11 @@ static void MtmProcessUtility(Node *parsetree, const char *queryString,
50325043
return;
50335044
}
50345045
}
5046+
else if (stmt->removeType == OBJECT_FUNCTION && MtmTx.isReplicated)
5047+
{
5048+
/* Make it possible to drop functions which were not replicated */
5049+
stmt->missing_ok = true;
5050+
}
50355051
}
50365052
break;
50375053

@@ -5064,16 +5080,14 @@ static void MtmProcessUtility(Node *parsetree, const char *queryString,
50645080
break;
50655081
}
50665082

5067-
if (!skipCommand && !MtmTx.isReplicated && (context == PROCESS_UTILITY_TOPLEVEL || MtmUtilityProcessedInXid != GetCurrentTransactionId()))
5083+
if (!skipCommand && !MtmTx.isReplicated && !MtmDDLStatement)
50685084
{
5069-
MtmUtilityProcessedInXid = GetCurrentTransactionId();
5070-
if (context == PROCESS_UTILITY_TOPLEVEL || !ActivePortal) {
5071-
MtmProcessDDLCommand(queryString, true);
5072-
} else {
5073-
MtmProcessDDLCommand(ActivePortal->sourceText, true);
5074-
}
5085+
MTM_LOG3("Process DDL statement '%s', MtmTx.isReplicated=%d, MtmIsLogicalReceiver=%d", queryString, MtmTx.isReplicated, MtmIsLogicalReceiver);
5086+
MtmProcessDDLCommand(queryString, true);
50755087
executed = true;
5088+
MtmDDLStatement = queryString;
50765089
}
5090+
else MTM_LOG3("Skip utility statement '%s': skip=%d, insideDDL=%d", queryString, skipCommand, MtmDDLStatement != NULL);
50775091

50785092
if (PreviousProcessUtilityHook != NULL)
50795093
{
@@ -5092,16 +5106,17 @@ static void MtmProcessUtility(Node *parsetree, const char *queryString,
50925106
#endif
50935107
if (MyXactAccessedTempRel)
50945108
{
5095-
MTM_LOG1("Xact accessed temp table, stopping replication");
5109+
MTM_LOG1("Xact accessed temp table, stopping replication of statement '%s'", queryString);
50965110
MtmTx.isDistributed = false; /* Skip */
50975111
MtmTx.snapshot = INVALID_CSN;
50985112
}
50995113

51005114
if (executed)
51015115
{
51025116
MtmFinishDDLCommand();
5117+
MtmDDLStatement = NULL;
51035118
}
5104-
if (nodeTag(parsetree) == T_CreateStmt)
5119+
if (IsA(parsetree, CreateStmt))
51055120
{
51065121
CreateStmt* create = (CreateStmt*)parsetree;
51075122
Oid relid = RangeVarGetRelid(create->relation, NoLock, true);
@@ -5118,15 +5133,12 @@ static void MtmProcessUtility(Node *parsetree, const char *queryString,
51185133
}
51195134
}
51205135
}
5121-
if (context == PROCESS_UTILITY_TOPLEVEL) {
5122-
MtmUtilityProcessedInXid = InvalidTransactionId;
5123-
}
51245136
}
51255137

51265138
static void
51275139
MtmExecutorStart(QueryDesc *queryDesc, int eflags)
51285140
{
5129-
if (!MtmTx.isReplicated && ActivePortal)
5141+
if (!MtmTx.isReplicated && !MtmDDLStatement)
51305142
{
51315143
ListCell *tlist;
51325144

@@ -5140,11 +5152,32 @@ MtmExecutorStart(QueryDesc *queryDesc, int eflags)
51405152
TargetEntry *tle = (TargetEntry *) lfirst(tlist);
51415153
if (tle->expr && IsA(tle->expr, FuncExpr))
51425154
{
5143-
if (hash_search(MtmRemoteFunctions, &((FuncExpr*)tle->expr)->funcid, HASH_FIND, NULL))
5155+
Oid func_oid = ((FuncExpr*)tle->expr)->funcid;
5156+
if (!hash_search(MtmRemoteFunctions, &func_oid, HASH_FIND, NULL))
51445157
{
5145-
MtmProcessDDLCommand(ActivePortal->sourceText, true);
5146-
break;
5158+
Form_pg_proc funcform;
5159+
bool is_sec_def;
5160+
HeapTuple func_tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(func_oid));
5161+
if (!HeapTupleIsValid(func_tuple))
5162+
elog(ERROR, "cache lookup failed for function %u", func_oid);
5163+
funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
5164+
is_sec_def = funcform->prosecdef;
5165+
ReleaseSysCache(func_tuple);
5166+
elog(LOG, "Function %s security defined=%d", tle->resname, is_sec_def);
5167+
if (!is_sec_def)
5168+
{
5169+
continue;
5170+
}
51475171
}
5172+
/*
5173+
* Execute security defined functions or functions marked as remote at replicated nodes.
5174+
* Them are executed as DDL statements.
5175+
* All data modifications done inside this function are not replicated.
5176+
* As a result generated content can vary at different nodes.
5177+
*/
5178+
MtmProcessDDLCommand(queryDesc->sourceText, true);
5179+
MtmDDLStatement = queryDesc;
5180+
break;
51485181
}
51495182
}
51505183
}
@@ -5193,6 +5226,12 @@ MtmExecutorFinish(QueryDesc *queryDesc)
51935226
{
51945227
standard_ExecutorFinish(queryDesc);
51955228
}
5229+
5230+
if (MtmDDLStatement == queryDesc)
5231+
{
5232+
MtmFinishDDLCommand();
5233+
MtmDDLStatement = NULL;
5234+
}
51965235
}
51975236

51985237
static void MtmSeqNextvalHook(Oid seqid, int64 next)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy