@@ -94,6 +94,7 @@ MtmDDLInProgress DDLApplyInProgress;
9494
9595static char MtmTempSchema [NAMEDATALEN ];
9696static bool TempDropRegistered ;
97+ static int TempDropAtxLevel ;
9798
9899static void const * MtmDDLStatement ;
99100
@@ -247,9 +248,11 @@ temp_schema_reset_all(int my_node_id)
247248 " nsp record; "
248249 "begin "
249250 " 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 "
251254 " 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' ); "
253256 " execute format('drop schema if exists %%I cascade', nsp.nspname); "
254257 " end loop; "
255258 "end $$; " ,
@@ -258,26 +261,27 @@ temp_schema_reset_all(int my_node_id)
258261}
259262
260263/* Drop temp schemas on peer nodes */
261- static void
262- temp_schema_reset (void )
264+ void
265+ temp_schema_reset (bool transactional )
263266{
264267 Assert (TempDropRegistered );
268+ Assert (TempDropAtxLevel == MtmTxAtxLevel );
265269
266270 /*
267271 * reset session_authorization restores permissions if previous ddl
268272 * dropped them; set_temp_schema allows us to see temporary objects,
269273 * otherwise they can't be dropped
270274 *
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.
273277 */
274278 MtmProcessDDLCommand (
275279 psprintf ("RESET session_authorization; "
276- "select mtm.set_temp_schema('%s'); "
280+ "select mtm.set_temp_schema('%s', false ); "
277281 "DROP SCHEMA IF EXISTS %s_toast CASCADE; "
278282 "DROP SCHEMA IF EXISTS %s CASCADE;" ,
279283 MtmTempSchema , MtmTempSchema , MtmTempSchema ),
280- false ,
284+ transactional ,
281285 false
282286 );
283287 MtmFinishDDLCommand ();
@@ -290,52 +294,127 @@ temp_schema_at_exit(int status, Datum arg)
290294 Assert (TempDropRegistered );
291295 AbortOutOfAnyTransaction ();
292296 StartTransactionCommand ();
293- temp_schema_reset ();
297+ for (; MtmTxAtxLevel >= 0 ; MtmTxAtxLevel -- )
298+ {
299+ temp_schema_init ();
300+ temp_schema_reset (false);
301+ }
294302 CommitTransactionCommand ();
295303}
296304
297305/* Register cleanup callback and generate temp schema name */
298- static void
306+ void
299307temp_schema_init (void )
300308{
301309 if (!TempDropRegistered )
302310 {
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 );
313311 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;
315355 }
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 ;
316364}
317365
318366Datum
319367mtm_set_temp_schema (PG_FUNCTION_ARGS )
320368{
321369 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 );
325384
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 )
327392 {
328393 nsp_oid = NamespaceCreate (temp_namespace , BOOTSTRAP_SUPERUSERID , true);
329394 toast_nsp_oid = NamespaceCreate (temp_toast_namespace , BOOTSTRAP_SUPERUSERID , true);
330395 CommandCounterIncrement ();
331396 }
332- else
397+
398+ #ifdef PGPRO_EE
399+ if (atx_level_start != NULL )
333400 {
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+ }
336409 }
337410
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
339418 PG_RETURN_VOID ();
340419}
341420
@@ -1030,7 +1109,7 @@ MtmProcessUtilitySender(PlannedStmt *pstmt, const char *queryString,
10301109 {
10311110 /* nothing to do if temp schema wasn't created at all */
10321111 if (TempDropRegistered )
1033- temp_schema_reset ();
1112+ temp_schema_reset (false );
10341113 SkipCommand (true);
10351114 MtmGucDiscard ();
10361115 }
0 commit comments