@@ -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{
264267Assert (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 isdue to DISCARD, it is important to run it as 'V', otherwise
276+ *it might interfere with later or earlier command using the schema.
273277 */
274278MtmProcessDDLCommand (
275279psprintf ("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;" ,
279283MtmTempSchema ,MtmTempSchema ,MtmTempSchema ),
280- false ,
284+ transactional ,
281285false
282286);
283287MtmFinishDDLCommand ();
@@ -290,52 +294,127 @@ temp_schema_at_exit(int status, Datum arg)
290294Assert (TempDropRegistered );
291295AbortOutOfAnyTransaction ();
292296StartTransactionCommand ();
293- temp_schema_reset ();
297+ for (;MtmTxAtxLevel >=0 ;MtmTxAtxLevel -- )
298+ {
299+ temp_schema_init ();
300+ temp_schema_reset (false);
301+ }
294302CommitTransactionCommand ();
295303}
296304
297305/* Register cleanup callback and generate temp schema name */
298- static void
306+ void
299307temp_schema_init (void )
300308{
301309if (!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 );
313311TempDropRegistered = 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{
321369char * 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{
328393nsp_oid = NamespaceCreate (temp_namespace ,BOOTSTRAP_SUPERUSERID , true);
329394toast_nsp_oid = NamespaceCreate (temp_toast_namespace ,BOOTSTRAP_SUPERUSERID , true);
330395CommandCounterIncrement ();
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
339418PG_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 */
10321111if (TempDropRegistered )
1033- temp_schema_reset ();
1112+ temp_schema_reset (false );
10341113SkipCommand (true);
10351114MtmGucDiscard ();
10361115}