68
68
#include "parser/analyze.h"
69
69
#include "parser/parse_relation.h"
70
70
#include "parser/parse_type.h"
71
+ #include "parser/parse_func.h"
71
72
#include "catalog/pg_class.h"
72
73
#include "catalog/pg_type.h"
73
74
#include "tcop/pquery.h"
@@ -158,6 +159,7 @@ static void MtmInitializeSequence(int64* start, int64* step);
158
159
static void * MtmCreateSavepointContext (void );
159
160
static void MtmRestoreSavepointContext (void * ctx );
160
161
static void MtmReleaseSavepointContext (void * ctx );
162
+ static void MtmSetRemoteFunction (char const * list , void * extra );
161
163
162
164
static void MtmCheckClusterLock (void );
163
165
static void MtmCheckSlots (void );
@@ -184,6 +186,7 @@ MtmConnectionInfo* MtmConnections;
184
186
185
187
HTAB * MtmXid2State ;
186
188
HTAB * MtmGid2State ;
189
+ static HTAB * MtmRemoteFunctions ;
187
190
static HTAB * MtmLocalTables ;
188
191
189
192
static bool MtmIsRecoverySession ;
@@ -258,6 +261,7 @@ bool MtmMajorNode;
258
261
TransactionId MtmUtilityProcessedInXid ;
259
262
260
263
static char * MtmConnStrs ;
264
+ static char * MtmRemoteFunctionsList ;
261
265
static char * MtmClusterName ;
262
266
static int MtmQueueSize ;
263
267
static int MtmWorkers ;
@@ -2229,7 +2233,7 @@ MtmCreateLocalTableMap(void)
2229
2233
"MtmLocalTables" ,
2230
2234
MULTIMASTER_MAX_LOCAL_TABLES , MULTIMASTER_MAX_LOCAL_TABLES ,
2231
2235
& info ,
2232
- HASH_ELEM
2236
+ HASH_ELEM | HASH_BLOBS
2233
2237
);
2234
2238
return htab ;
2235
2239
}
@@ -2423,6 +2427,48 @@ MtmShmemStartup(void)
2423
2427
MtmInitialize ();
2424
2428
}
2425
2429
2430
+ static void MtmSetRemoteFunction (char const * list , void * extra )
2431
+ {
2432
+ if (MtmRemoteFunctions ) {
2433
+ hash_destroy (MtmRemoteFunctions );
2434
+ MtmRemoteFunctions = NULL ;
2435
+ }
2436
+ }
2437
+
2438
+ static void MtmInitializeRemoteFunctionsMap ()
2439
+ {
2440
+ HASHCTL info ;
2441
+ char * p , * q ;
2442
+ int n_funcs = 1 ;
2443
+ FuncCandidateList clist ;
2444
+
2445
+ for (p = MtmRemoteFunctionsList ; (q = strchr (p , ',' )) != NULL ; p = q + 1 , n_funcs ++ );
2446
+
2447
+ Assert (MtmRemoteFunctions == NULL );
2448
+
2449
+ memset (& info , 0 , sizeof (info ));
2450
+ info .entrysize = info .keysize = sizeof (Oid );
2451
+ info .hcxt = TopMemoryContext ;
2452
+ MtmRemoteFunctions = hash_create ("MtmRemoteFunctions" , n_funcs , & info ,
2453
+ HASH_ELEM | HASH_BLOBS | HASH_CONTEXT );
2454
+
2455
+ p = pstrdup (MtmRemoteFunctionsList );
2456
+ do {
2457
+ q = strchr (p , ',' );
2458
+ if (q != NULL ) {
2459
+ * q ++ = '\0' ;
2460
+ }
2461
+ clist = FuncnameGetCandidates (stringToQualifiedNameList (p ), -1 , NIL , false, false, true);
2462
+ if (clist == NULL ) {
2463
+ MTM_ELOG (ERROR , "Failed to lookup function %s" , p );
2464
+ } else if (clist -> next != NULL ) {
2465
+ MTM_ELOG (ERROR , "Ambigious function %s" , p );
2466
+ }
2467
+ hash_search (MtmRemoteFunctions , & clist -> oid , HASH_ENTER , NULL );
2468
+ p = q ;
2469
+ } while (p != NULL );
2470
+ }
2471
+
2426
2472
/*
2427
2473
* Parse node connection string.
2428
2474
* This function is called at cluster startup and while adding new cluster node
@@ -3052,6 +3098,19 @@ _PG_init(void)
3052
3098
NULL /* GucShowHook show_hook */
3053
3099
);
3054
3100
3101
+ DefineCustomStringVariable (
3102
+ "multimaster.remote_functions" ,
3103
+ "List of fnuction names which should be executed remotely at all multimaster nodes instead of executing them at master and replicating result of their work" ,
3104
+ NULL ,
3105
+ & MtmRemoteFunctionsList ,
3106
+ "lo_create,lo_unlink" ,
3107
+ PGC_USERSET , /* context */
3108
+ 0 , /* flags */
3109
+ NULL , /* GucStringCheckHook check_hook */
3110
+ MtmSetRemoteFunction , /* GucStringAssignHook assign_hook */
3111
+ NULL /* GucShowHook show_hook */
3112
+ );
3113
+
3055
3114
DefineCustomStringVariable (
3056
3115
"multimaster.cluster_name" ,
3057
3116
"Name of the cluster" ,
@@ -3541,7 +3600,7 @@ lsn_t MtmGetFlushPosition(int nodeId)
3541
3600
* Keep track of progress of WAL writer.
3542
3601
* We need to notify WAL senders at other nodes which logical records
3543
3602
* are flushed to the disk and so can survive failure. In asynchronous commit mode
3544
- * WAL is flushed by WAL writer. Current flish position can be obtained by GetFlushRecPtr().
3603
+ * WAL is flushed by WAL writer. Current flush position can be obtained by GetFlushRecPtr().
3545
3604
* So on applying new logical record we insert it in the MtmLsnMapping and compare
3546
3605
* their poistions in local WAL log with current flush position.
3547
3606
* The records which are flushed to the disk by WAL writer are removed from the list
@@ -4656,7 +4715,7 @@ char* MtmGucSerialize(void)
4656
4715
appendStringInfoString (serialized_gucs , " TO " );
4657
4716
4658
4717
/* quite a crutch */
4659
- if (strstr (cur_entry -> key , "_mem" ) != NULL || * (cur_entry -> value ) == '\0' )
4718
+ if (strstr (cur_entry -> key , "_mem" ) != NULL || * (cur_entry -> value ) == '\0' || strchr ( cur_entry -> value , ',' ) != NULL )
4660
4719
{
4661
4720
appendStringInfoString (serialized_gucs , "'" );
4662
4721
appendStringInfoString (serialized_gucs , cur_entry -> value );
@@ -4686,10 +4745,7 @@ static void MtmProcessDDLCommand(char const* queryString, bool transactional)
4686
4745
if (transactional )
4687
4746
{
4688
4747
char * gucCtx = MtmGucSerialize ();
4689
- if (* gucCtx )
4690
- queryString = psprintf ("RESET SESSION AUTHORIZATION; reset all; %s %s" , gucCtx , queryString );
4691
- else
4692
- queryString = psprintf ("RESET SESSION AUTHORIZATION; reset all; %s" , queryString );
4748
+ queryString = psprintf ("RESET SESSION AUTHORIZATION; reset all; %s %s" , gucCtx , queryString );
4693
4749
4694
4750
/* Transactional DDL */
4695
4751
MTM_LOG3 ("Sending DDL: %s" , queryString );
@@ -5058,29 +5114,28 @@ static void MtmProcessUtility(Node *parsetree, const char *queryString,
5058
5114
static void
5059
5115
MtmExecutorStart (QueryDesc * queryDesc , int eflags )
5060
5116
{
5061
- bool ddl_generating_call = false;
5062
- ListCell * tlist ;
5063
-
5064
- foreach (tlist , queryDesc -> plannedstmt -> planTree -> targetlist )
5117
+ if (!MtmTx .isReplicated && ActivePortal )
5065
5118
{
5066
- TargetEntry * tle = ( TargetEntry * ) lfirst ( tlist ) ;
5119
+ ListCell * tlist ;
5067
5120
5068
- if (tle -> resname && strcmp ( tle -> resname , "lo_create" ) == 0 )
5121
+ if (! MtmRemoteFunctions )
5069
5122
{
5070
- ddl_generating_call = true;
5071
- break ;
5123
+ MtmInitializeRemoteFunctionsMap ();
5072
5124
}
5073
5125
5074
- if ( tle -> resname && strcmp ( tle -> resname , "lo_unlink" ) == 0 )
5126
+ foreach ( tlist , queryDesc -> plannedstmt -> planTree -> targetlist )
5075
5127
{
5076
- ddl_generating_call = true;
5077
- break ;
5128
+ TargetEntry * tle = (TargetEntry * ) lfirst (tlist );
5129
+ if (tle -> expr && IsA (tle -> expr , FuncExpr ))
5130
+ {
5131
+ if (hash_search (MtmRemoteFunctions , & ((FuncExpr * )tle -> expr )-> funcid , HASH_FIND , NULL ))
5132
+ {
5133
+ MtmProcessDDLCommand (ActivePortal -> sourceText , true);
5134
+ break ;
5135
+ }
5136
+ }
5078
5137
}
5079
5138
}
5080
-
5081
- if (ddl_generating_call && !MtmTx .isReplicated )
5082
- MtmProcessDDLCommand (ActivePortal -> sourceText , true);
5083
-
5084
5139
if (PreviousExecutorStartHook != NULL )
5085
5140
PreviousExecutorStartHook (queryDesc , eflags );
5086
5141
else
0 commit comments