@@ -94,6 +94,7 @@ MtmDDLInProgress DDLApplyInProgress;
94
94
95
95
static char MtmTempSchema [NAMEDATALEN ];
96
96
static bool TempDropRegistered ;
97
+ static int TempDropAtxLevel ;
97
98
98
99
static void const * MtmDDLStatement ;
99
100
@@ -247,9 +248,11 @@ temp_schema_reset_all(int my_node_id)
247
248
" nsp record; "
248
249
"begin "
249
250
" reset session_authorization; "
250
- " for nsp in select nspname from pg_namespace where nspname ~ '^mtm_tmp_%d_.*' loop "
251
+ " for nsp in select nspname from pg_namespace where "
252
+ " nspname ~ '^mtm_tmp_%d_.*' and"
253
+ " nspname !~ '_toast$' loop "
251
254
" perform mtm.set_temp_schema(nsp.nspname); "
252
- " execute format('drop schema if exists %%I cascade', format('%%s_toast', nsp.nspname) ); "
255
+ " execute format('drop schema if exists %%I cascade', nsp.nspname||'_toast' ); "
253
256
" execute format('drop schema if exists %%I cascade', nsp.nspname); "
254
257
" end loop; "
255
258
"end $$; " ,
@@ -258,26 +261,27 @@ temp_schema_reset_all(int my_node_id)
258
261
}
259
262
260
263
/* Drop temp schemas on peer nodes */
261
- static void
262
- temp_schema_reset (void )
264
+ void
265
+ temp_schema_reset (bool transactional )
263
266
{
264
267
Assert (TempDropRegistered );
268
+ Assert (TempDropAtxLevel == MtmTxAtxLevel );
265
269
266
270
/*
267
271
* reset session_authorization restores permissions if previous ddl
268
272
* dropped them; set_temp_schema allows us to see temporary objects,
269
273
* otherwise they can't be dropped
270
274
*
271
- * It is important to run it as 'V', otherwise it might interfere with
272
- * later (if drop is due to DISCARD) or earlier command using the schema.
275
+ * If drop is due to DISCARD, it is important to run it as 'V', otherwise
276
+ * it might interfere with later or earlier command using the schema.
273
277
*/
274
278
MtmProcessDDLCommand (
275
279
psprintf ("RESET session_authorization; "
276
- "select mtm.set_temp_schema('%s'); "
280
+ "select mtm.set_temp_schema('%s', false ); "
277
281
"DROP SCHEMA IF EXISTS %s_toast CASCADE; "
278
282
"DROP SCHEMA IF EXISTS %s CASCADE;" ,
279
283
MtmTempSchema , MtmTempSchema , MtmTempSchema ),
280
- false ,
284
+ transactional ,
281
285
false
282
286
);
283
287
MtmFinishDDLCommand ();
@@ -290,52 +294,127 @@ temp_schema_at_exit(int status, Datum arg)
290
294
Assert (TempDropRegistered );
291
295
AbortOutOfAnyTransaction ();
292
296
StartTransactionCommand ();
293
- temp_schema_reset ();
297
+ for (; MtmTxAtxLevel >= 0 ; MtmTxAtxLevel -- )
298
+ {
299
+ temp_schema_init ();
300
+ temp_schema_reset (false);
301
+ }
294
302
CommitTransactionCommand ();
295
303
}
296
304
297
305
/* Register cleanup callback and generate temp schema name */
298
- static void
306
+ void
299
307
temp_schema_init (void )
300
308
{
301
309
if (!TempDropRegistered )
302
310
{
303
- char * temp_schema ;
304
-
305
- /*
306
- * NB: namespace.c:isMtmTemp() assumes 'mtm_tmp_' prefix for mtm temp
307
- * tables to defuse autovacuum.
308
- */
309
- temp_schema = psprintf ("mtm_tmp_%d_%d" ,
310
- Mtm -> my_node_id , MyBackendId );
311
- memcpy (& MtmTempSchema , temp_schema , strlen (temp_schema ) + 1 );
312
- before_shmem_exit (temp_schema_at_exit , (Datum ) 0 );
313
311
TempDropRegistered = true;
314
- pfree (temp_schema );
312
+ before_shmem_exit (temp_schema_at_exit , (Datum ) 0 );
313
+ }
314
+ if (MtmTxAtxLevel == 0 )
315
+ snprintf (MtmTempSchema , sizeof (MtmTempSchema ),
316
+ "mtm_tmp_%d_%d" , Mtm -> my_node_id , MyBackendId );
317
+ else
318
+ snprintf (MtmTempSchema , sizeof (MtmTempSchema ),
319
+ "mtm_tmp_%d_%d_%d" , Mtm -> my_node_id , MyBackendId , MtmTxAtxLevel );
320
+ TempDropAtxLevel = MtmTxAtxLevel ;
321
+ }
322
+
323
+ /*
324
+ * temp_schema_valid check format of temp schema name.
325
+ * Namespace name should be either mtm_tmp_\d+_\d+ or
326
+ * mtm_tmp_\d+_\d+_\d+ for non-zero atx level.
327
+ */
328
+ static bool
329
+ temp_schema_valid (const char * temp_namespace , const char * * atx_level )
330
+ {
331
+ const char * c ;
332
+ const int mtm_tmp_len = strlen ("mtm_tmp_" );
333
+ int underscores = 0 ;
334
+ bool need_digit = true;
335
+ bool valid = true;
336
+
337
+ * atx_level = NULL ;
338
+ if (strlen (temp_namespace ) + strlen ("_toast" ) + 1 > NAMEDATALEN )
339
+ valid = false;
340
+ else if (strncmp (temp_namespace , "mtm_tmp_" , mtm_tmp_len ) != 0 )
341
+ valid = false;
342
+ for (c = temp_namespace + mtm_tmp_len ; * c != 0 && valid ; c ++ )
343
+ {
344
+ if (!need_digit && * c == '_' )
345
+ {
346
+ underscores ++ ;
347
+ if (underscores == 2 )
348
+ * atx_level = c ;
349
+ need_digit = true;
350
+ }
351
+ else if ((unsigned )* c - '0' <= '9' - '0' )
352
+ need_digit = false;
353
+ else
354
+ valid = false;
315
355
}
356
+ if (need_digit || underscores < 1 || underscores > 2 )
357
+ valid = false;
358
+ #ifndef PGPRO_EE
359
+ if (underscores == 2 )
360
+ valid = false;
361
+ #endif
362
+
363
+ return valid ;
316
364
}
317
365
318
366
Datum
319
367
mtm_set_temp_schema (PG_FUNCTION_ARGS )
320
368
{
321
369
char * temp_namespace = text_to_cstring (PG_GETARG_TEXT_P (0 ));
322
- char * temp_toast_namespace = psprintf ("%s_toast" , temp_namespace );
323
- Oid nsp_oid ;
324
- Oid toast_nsp_oid ;
370
+ bool force = PG_NARGS () > 1 ? PG_GETARG_BOOL (1 ) : true;
371
+ char temp_toast_namespace [NAMEDATALEN ] = {0 };
372
+ Oid nsp_oid = InvalidOid ;
373
+ Oid toast_nsp_oid = InvalidOid ;
374
+ const char * atx_level_start = NULL ;
375
+ #ifdef PGPRO_EE
376
+ char top_temp_namespace [NAMEDATALEN ] = {0 };
377
+ Oid top_nsp_oid = InvalidOid ;
378
+ Oid top_toast_nsp_oid = InvalidOid ;
379
+ #endif
380
+
381
+ if (!temp_schema_valid (temp_namespace , & atx_level_start ))
382
+ mtm_log (ERROR , "mtm_set_temp_schema: wrong namespace name '%s'" ,
383
+ temp_namespace );
325
384
326
- if (!SearchSysCacheExists1 (NAMESPACENAME , PointerGetDatum (temp_namespace )))
385
+ snprintf (temp_toast_namespace , NAMEDATALEN , "%s_toast" , temp_namespace );
386
+ if (SearchSysCacheExists1 (NAMESPACENAME , PointerGetDatum (temp_namespace )))
387
+ {
388
+ nsp_oid = get_namespace_oid (temp_namespace , false);
389
+ toast_nsp_oid = get_namespace_oid (temp_toast_namespace , false);
390
+ }
391
+ else if (force )
327
392
{
328
393
nsp_oid = NamespaceCreate (temp_namespace , BOOTSTRAP_SUPERUSERID , true);
329
394
toast_nsp_oid = NamespaceCreate (temp_toast_namespace , BOOTSTRAP_SUPERUSERID , true);
330
395
CommandCounterIncrement ();
331
396
}
332
- else
397
+
398
+ #ifdef PGPRO_EE
399
+ if (atx_level_start != NULL )
333
400
{
334
- nsp_oid = get_namespace_oid (temp_namespace , false);
335
- toast_nsp_oid = get_namespace_oid (temp_toast_namespace , false);
401
+ memcpy (top_temp_namespace , temp_namespace , atx_level_start - temp_namespace );
402
+
403
+ if (SearchSysCacheExists1 (NAMESPACENAME , PointerGetDatum (top_temp_namespace )))
404
+ {
405
+ top_nsp_oid = get_namespace_oid (top_temp_namespace , false);
406
+ strlcat (top_temp_namespace , "_toast" , NAMEDATALEN );
407
+ top_toast_nsp_oid = get_namespace_oid (top_temp_namespace , false);
408
+ }
336
409
}
337
410
338
- SetTempNamespaceState (nsp_oid , toast_nsp_oid );
411
+ SetTempNamespaceForMultimaster ();
412
+ SetTempNamespaceStateEx (nsp_oid , toast_nsp_oid ,
413
+ top_nsp_oid , top_toast_nsp_oid ,
414
+ atx_level_start != NULL );
415
+ #else
416
+ SetTempNamespace (nsp_oid , toast_nsp_oid );
417
+ #endif
339
418
PG_RETURN_VOID ();
340
419
}
341
420
@@ -1030,7 +1109,7 @@ MtmProcessUtilitySender(PlannedStmt *pstmt, const char *queryString,
1030
1109
{
1031
1110
/* nothing to do if temp schema wasn't created at all */
1032
1111
if (TempDropRegistered )
1033
- temp_schema_reset ();
1112
+ temp_schema_reset (false );
1034
1113
SkipCommand (true);
1035
1114
MtmGucDiscard ();
1036
1115
}
0 commit comments