提交 9bde1b01 编写于 作者: N Ning Yu

Use a different temp schema name pattern in utility mode

A temp table's schema name is pg_temp_<session_id> in normal mode, in
utility mode the name is pg_temp_<backend_id>, however once the
normal-mode session id equals to the utility-mode backend id they will
conflict with each other and cause catalog corruption on the segment.

To fix this issue we changed the name to pg_temp_0<backend_id> in
utility mode, this still matches the pattern "pg_temp_[0-9]+", which is
expected for temp schema names.
上级 8fdf36d7
......@@ -3749,6 +3749,7 @@ InitTempTableNamespace(void)
Oid namespaceId;
Oid toastspaceId;
int session_suffix;
const char *session_infix;
/*
* First, do permission check to see if we are authorized to make temp
......@@ -3776,16 +3777,34 @@ InitTempTableNamespace(void)
case GP_ROLE_DISPATCH:
case GP_ROLE_EXECUTE:
session_suffix = gp_session_id;
session_infix = "";
break;
case GP_ROLE_UTILITY:
session_suffix = MyBackendId;
/*
* Backend id is used as the suffix of schema name in utility mode
* while session id is used in normal mode. It is possible for a
* utility-mode session's backend id to be equal to a normal-mode
* session's session id at runtime, if we use the same name pattern
* for them then they would conflict with each other and corrupt
* the catalog on the segment. So a different name pattern must be
* used in utility mode. However a temp schema name is expected to
* match the pattern "pg_temp_[0-9]+", so we put a 0 before the
* backend id in utility mode to distinct with normal mode:
*
* - utility mode: pg_temp_0[0-9]+
* - normal mode: pg_temp_[1-9][0-9]*
*/
session_infix = "0";
break;
default:
/* Should never hit this */
elog(ERROR, "invalid backend temp schema creation");
session_suffix = -1; /* keep compiler quiet */
session_infix = NULL; /* keep compiler quiet */
break;
}
......@@ -3810,7 +3829,8 @@ InitTempTableNamespace(void)
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
errmsg("cannot create temporary tables in parallel mode")));
snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", session_suffix);
snprintf(namespaceName, sizeof(namespaceName),
"pg_temp_%s%d", session_infix, session_suffix);
namespaceId = get_namespace_oid(namespaceName, true);
......@@ -3857,8 +3877,8 @@ InitTempTableNamespace(void)
* (in GPDB, though, we drop and recreate it anyway, to make sure it has
* the same OID on master and segments.)
*/
snprintf(namespaceName, sizeof(namespaceName), "pg_toast_temp_%d",
session_suffix);
snprintf(namespaceName, sizeof(namespaceName),
"pg_toast_temp_%s%d", session_infix, session_suffix);
toastspaceId = get_namespace_oid(namespaceName, true);
if (OidIsValid(toastspaceId))
......
......@@ -23,3 +23,25 @@ DROP
Optimizer: Postgres query optimizer
Execution time: 0.357 ms
(8 rows)
--
-- Temp tables should have a different schema name pattern in utility mode.
--
-- A temp table's schema name used to be pg_temp_<session_id> in normal mode
-- and pg_temp_<backend_id> in utility mode, once the normal-mode session id
-- equals to the utility-mode backend id they will conflict with each other and
-- cause catalog corruption on the segment.
--
-- We have changed the name to pg_temp_0<backend_id> in utility mode.
0U: CREATE TEMP TABLE utilitymode_tmp_tab (c1 int) DISTRIBUTED BY (c1);
CREATE
0U: SELECT substring(n.nspname FROM 1 FOR 9) FROM pg_namespace n JOIN pg_class c ON n.oid = c.relnamespace WHERE c.relname = 'utilitymode_tmp_tab';
substring
-----------
pg_temp_0
(1 row)
0U: SELECT substring(n2.nspname FROM 1 FOR 15) FROM pg_namespace n1 JOIN pg_class c ON n1.oid = c.relnamespace JOIN pg_namespace n2 ON n2.nspname = 'pg_toast_temp_0' || substring(n1.nspname FROM 10) WHERE c.relname = 'utilitymode_tmp_tab';
substring
-----------------
pg_toast_temp_0
(1 row)
......@@ -9,3 +9,26 @@
-1U: drop table utilitymode_primary_key_tab;
0U: explain analyze select * from gp_segment_configuration order by dbid;
--
-- Temp tables should have a different schema name pattern in utility mode.
--
-- A temp table's schema name used to be pg_temp_<session_id> in normal mode
-- and pg_temp_<backend_id> in utility mode, once the normal-mode session id
-- equals to the utility-mode backend id they will conflict with each other and
-- cause catalog corruption on the segment.
--
-- We have changed the name to pg_temp_0<backend_id> in utility mode.
0U: CREATE TEMP TABLE utilitymode_tmp_tab (c1 int) DISTRIBUTED BY (c1);
0U: SELECT substring(n.nspname FROM 1 FOR 9)
FROM pg_namespace n
JOIN pg_class c
ON n.oid = c.relnamespace
WHERE c.relname = 'utilitymode_tmp_tab';
0U: SELECT substring(n2.nspname FROM 1 FOR 15)
FROM pg_namespace n1
JOIN pg_class c
ON n1.oid = c.relnamespace
JOIN pg_namespace n2
ON n2.nspname = 'pg_toast_temp_0' || substring(n1.nspname FROM 10)
WHERE c.relname = 'utilitymode_tmp_tab';
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册