From 126bc7485a8ad725acde134ef6e9c27f9c824c08 Mon Sep 17 00:00:00 2001 From: pulsar Date: Tue, 30 May 2023 16:54:59 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=A4=84=E7=90=86=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/parser/analyze.cpp | 5 ++ src/common/backend/utils/cache/typcache.cpp | 23 ++++++- src/common/backend/utils/mmgr/portalmem.cpp | 32 ++++++++++ .../process/threadpool/knl_session.cpp | 2 + src/include/knl/knl_session.h | 3 + src/include/utils/plpgsql.h | 6 ++ .../regress/sql/plpgsql_cursor_rowtype.sql | 64 +++++++++++++++++++ 7 files changed, 133 insertions(+), 2 deletions(-) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 1677ddf06..61534896f 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -4429,7 +4429,12 @@ static Query* transformDeclareCursorStmt(ParseState* pstate, DeclareCursorStmt* ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot specify both SCROLL and NO SCROLL"))); } + /*除WITH HOLD游标外,根据DeclareCursorName对使用的row type形成依赖*/ + if (!(stmt->options & CURSOR_OPT_HOLD)) { + u_sess->analyze_cxt.DeclareCursorName = stmt->portalname; + } result = transformStmt(pstate, stmt->query); + u_sess->analyze_cxt.DeclareCursorName = NULL; /* Grammar should not have allowed anything but SELECT */ if (!IsA(result, Query) || result->commandType != CMD_SELECT || result->utilityStmt != NULL) { diff --git a/src/common/backend/utils/cache/typcache.cpp b/src/common/backend/utils/cache/typcache.cpp index 380f5199b..48777cd5f 100644 --- a/src/common/backend/utils/cache/typcache.cpp +++ b/src/common/backend/utils/cache/typcache.cpp @@ -121,6 +121,7 @@ static void cache_record_field_properties(TypeCacheEntry* typentry); static void load_enum_cache_data(TypeCacheEntry* tcache); static EnumItem* find_enumitem(TypeCacheEnumData* enum_data, Oid arg); static int enum_oid_cmp(const void* left, const void* right); +static void record_cursor_rowtype(const char* CursorName, TypeCacheEntry* typentry); void init_type_cache() { @@ -393,8 +394,13 @@ TypeCacheEntry* lookup_type_cache(Oid type_id, int flags) /* * If it's a composite type (row type), get tupdesc if requested */ - if ((flags & TYPECACHE_TUPDESC) && typentry->tupDesc == NULL && typentry->typtype == TYPTYPE_COMPOSITE) { - load_typcache_tupdesc(typentry); + if ((flags & TYPECACHE_TUPDESC) && typentry->typtype == TYPTYPE_COMPOSITE) { + if (typentry->tupDesc == NULL) { + load_typcache_tupdesc(typentry); + } + if (u_sess->analyze_cxt.DeclareCursorName) { + record_cursor_rowtype(u_sess->analyze_cxt.DeclareCursorName, typentry); + } } /* @@ -1156,3 +1162,16 @@ static int enum_oid_cmp(const void* left, const void* right) return 0; } } + +static void record_cursor_rowtype(const char* CursorName, TypeCacheEntry* typentry) +{ + MemoryContext old = MemoryContextSwitchTo(u_sess->top_transaction_mem_cxt); + Relation rel = relation_open(typentry->typrelid,AccessShareLock); + RelationIncrementReferenceCount(rel); + relation_close(rel,AccessShareLock); + CursorRecordType* var = (CursorRecordType*)palloc(sizeof(CursorRecordType)); + var->cursor_name = pstrdup(CursorName); + var->type_oid = typentry->typrelid; + u_sess->plsql_cxt.CursorRecordTypeList = lappend(u_sess->plsql_cxt.CursorRecordTypeList,var); + (void)MemoryContextSwitchTo(old); +} \ No newline at end of file diff --git a/src/common/backend/utils/mmgr/portalmem.cpp b/src/common/backend/utils/mmgr/portalmem.cpp index 3e7df1ede..fc95ea131 100755 --- a/src/common/backend/utils/mmgr/portalmem.cpp +++ b/src/common/backend/utils/mmgr/portalmem.cpp @@ -44,6 +44,7 @@ extern void ReleaseSharedCachedPlan(CachedPlan* plan, bool useResOwner); +static void CursorRecordTypeUnbind(const char* portal_name); /* * Estimate of the maximum number of open portals a user would have, * used in initially sizing the PortalHashTable in EnablePortalManager(). @@ -568,6 +569,11 @@ void PortalDrop(Portal portal, bool isTopCommit) /* drop cached plan reference, if any */ PortalReleaseCachedPlan(portal); + /*if cursor record row type*/ + if (portal->name[0] != '\0' && u_sess->plsql_cxt.CursorRecordTypeList) { + CursorRecordTypeUnbind(portal->name); + } + /* * Release any resources still attached to the portal. There are several * cases being covered here: @@ -1396,3 +1402,29 @@ HoldPinnedPortals(bool is_rollback) } } } + +/*解除游标与row type类型的依赖关系*/ +static void CursorRecordTypeUnbind(const char* portal_name) +{ + ListCell* cell = NULL; + MemoryContext old = MemoryContextSwitchTo(u_sess->top_transaction_mem_cxt); + ResourceOwner save = t_thrd.utils_cxt.CurrentResourceOwner; + t_thrd.utils_cxt.CurrentResourceOwner = t_thrd.utils_cxt.TopTransactionResourceOwner; + List* temp_list = list_copy(u_sess->plsql_cxt.CursorRecordTypeList); + foreach(cell,temp_list) { + CursorRecordType* var = (CursorRecordType*)lfirst(cell); + if (strcmp(portal_name,var->cursor_name) == 0) { + Relation rel = relation_open(var->type_oid,AccessShareLock); + if (rel->rd_refcnt > 1) { + RelationDecrementReferenceCount(rel); + } + relation_close(rel,AccessShareLock); + u_sess->plsql_cxt.CursorRecordTypeList = list_delete_ptr(u_sess->plsql_cxt.CursorRecordTypeList,var); + pfree(var->cursor_name); + pfree(var); + } + } + list_free(temp_list); + t_thrd.utils_cxt.CurrentResourceOwner = save; + (void)MemoryContextSwitchTo(old); +} diff --git a/src/gausskernel/process/threadpool/knl_session.cpp b/src/gausskernel/process/threadpool/knl_session.cpp index 57ac1b77c..f7a14e452 100755 --- a/src/gausskernel/process/threadpool/knl_session.cpp +++ b/src/gausskernel/process/threadpool/knl_session.cpp @@ -89,6 +89,7 @@ static void knl_u_analyze_init(knl_u_analyze_context* anl_cxt) anl_cxt->autoanalyze_process = NULL; anl_cxt->autoanalyze_timeinfo = NULL; anl_cxt->vac_strategy = (BufferAccessStrategyData*)palloc0(sizeof(BufferAccessStrategyData)); + anl_cxt->DeclareCursorName = NULL; } static void knl_u_attr_init(knl_session_attr* attr) @@ -865,6 +866,7 @@ static void knl_u_plpgsql_init(knl_u_plpgsql_context* plsql_cxt) plsql_cxt->cur_exception_cxt = NULL; plsql_cxt->pragma_autonomous = false; plsql_cxt->is_insert_gs_source = false; + plsql_cxt->CursorRecordTypeList = NIL; } static void knl_u_stat_init(knl_u_stat_context* stat_cxt) diff --git a/src/include/knl/knl_session.h b/src/include/knl/knl_session.h index 3089c8a4c..2c6276358 100644 --- a/src/include/knl/knl_session.h +++ b/src/include/knl/knl_session.h @@ -304,6 +304,8 @@ typedef struct knl_u_analyze_context { struct StringInfoData* autoanalyze_timeinfo; struct BufferAccessStrategyData* vac_strategy; + + char* DeclareCursorName; } knl_u_analyze_context; #define PATH_SEED_FACTOR_LEN 3 @@ -1662,6 +1664,7 @@ typedef struct knl_u_plpgsql_context { bool pragma_autonomous; /* save autonomous flag */ char* debug_query_string; bool is_insert_gs_source; /* is doing insert gs_source? */ + List* CursorRecordTypeList; /*Save the type recorded during the cursor definition*/ } knl_u_plpgsql_context; //this is used to define functions in package diff --git a/src/include/utils/plpgsql.h b/src/include/utils/plpgsql.h index e9ad4e26a..f6c454967 100644 --- a/src/include/utils/plpgsql.h +++ b/src/include/utils/plpgsql.h @@ -1915,6 +1915,12 @@ typedef struct ExceptionContext { PLpgSQL_declare_handler handler_type; } ExceptionContext; +/*Save the type recorded during the cursor definition*/ +typedef struct CursorRecordType { + char* cursor_name; + Oid type_oid; +} CursorRecordType; + /* Quick access array state */ #define IS_ARRAY_STATE(state_list, state) ((state_list && u_sess->attr.attr_sql.sql_compatibility == A_FORMAT) ? \ (linitial_int(state_list) == state) : false) diff --git a/src/test/regress/sql/plpgsql_cursor_rowtype.sql b/src/test/regress/sql/plpgsql_cursor_rowtype.sql index 9b82a565f..7698c70e6 100644 --- a/src/test/regress/sql/plpgsql_cursor_rowtype.sql +++ b/src/test/regress/sql/plpgsql_cursor_rowtype.sql @@ -694,6 +694,70 @@ set behavior_compat_options=''; drop procedure check_compile; +--游标依赖row type,后续alter type +create type foo as (a int, b int); + +--游标依赖type,alter type报错 +begin; +declare c cursor for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; +fetch c; +alter type foo alter attribute b type text;--error +end; + +--第二次开始从缓存中获取type +begin; +cursor c for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; +fetch c; +alter type foo alter attribute b type text;--error +end; + +--close后,可以成功alter +begin; +declare c cursor for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; +fetch c; +close c; +alter type foo alter attribute b type text;--success +declare c cursor for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; +fetch c; +rollback; + +begin; +cursor c for select (i,2^30)::foo from generate_series(1,10) i; +close c; +alter type foo alter attribute b type text;--success +end; + +--多个游标依赖,只关闭一个 +begin; +cursor c1 for select (i,2^30)::foo from generate_series(1,10) i; +cursor c2 for select (i,2^30)::foo from generate_series(1,10) i; +close c1; +alter type foo alter attribute b type text;--error +end; + +--多个游标依赖,都关闭 +begin; +cursor c1 for select (i,2^30)::foo from generate_series(1,10) i; +cursor c2 for select (i,2^30)::foo from generate_series(1,10) i; +close c1; +close c2; +alter type foo alter attribute b type text;--success +end; + +--WITH HOLD游标,事务结束继续保留 +begin; +cursor c3 WITH HOLD for select (i,2^30)::foo from generate_series(1,10) i; +fetch c3; +end; +fetch c3; +alter type foo alter attribute b type text;--success +fetch c3; +close c3; + ---- clean ---- drop package pck1; drop package pck2; From 976ff14babf831bc8f53e1a4e1742da6068d5ae8 Mon Sep 17 00:00:00 2001 From: pulsar Date: Tue, 27 Jun 2023 16:50:06 +0800 Subject: [PATCH 2/6] update --- src/common/backend/utils/mmgr/portalmem.cpp | 39 +++++++++++++-------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/common/backend/utils/mmgr/portalmem.cpp b/src/common/backend/utils/mmgr/portalmem.cpp index fc95ea131..a21a12148 100755 --- a/src/common/backend/utils/mmgr/portalmem.cpp +++ b/src/common/backend/utils/mmgr/portalmem.cpp @@ -570,7 +570,7 @@ void PortalDrop(Portal portal, bool isTopCommit) PortalReleaseCachedPlan(portal); /*if cursor record row type*/ - if (portal->name[0] != '\0' && u_sess->plsql_cxt.CursorRecordTypeList) { + if (portal->name[0] != '\0' && u_sess->plsql_cxt.CursorRecordTypeList && IsTransactionBlock()) { CursorRecordTypeUnbind(portal->name); } @@ -1407,24 +1407,35 @@ HoldPinnedPortals(bool is_rollback) static void CursorRecordTypeUnbind(const char* portal_name) { ListCell* cell = NULL; + ListCell* pnext = NULL; MemoryContext old = MemoryContextSwitchTo(u_sess->top_transaction_mem_cxt); ResourceOwner save = t_thrd.utils_cxt.CurrentResourceOwner; - t_thrd.utils_cxt.CurrentResourceOwner = t_thrd.utils_cxt.TopTransactionResourceOwner; - List* temp_list = list_copy(u_sess->plsql_cxt.CursorRecordTypeList); - foreach(cell,temp_list) { - CursorRecordType* var = (CursorRecordType*)lfirst(cell); - if (strcmp(portal_name,var->cursor_name) == 0) { - Relation rel = relation_open(var->type_oid,AccessShareLock); - if (rel->rd_refcnt > 1) { - RelationDecrementReferenceCount(rel); + PG_TRY(); + { + t_thrd.utils_cxt.CurrentResourceOwner = t_thrd.utils_cxt.TopTransactionResourceOwner; + for (cell = list_head(u_sess->plsql_cxt.CursorRecordTypeList); cell != NULL; cell = pnext) { + pnext = lnext(cell); + CursorRecordType* var = (CursorRecordType*)lfirst(cell); + if (strcmp(portal_name,var->cursor_name) == 0) { + Relation rel = relation_open(var->type_oid,AccessShareLock); + if (rel->rd_refcnt > 1) { + RelationDecrementReferenceCount(rel); + } + relation_close(rel,AccessShareLock); + u_sess->plsql_cxt.CursorRecordTypeList = list_delete_ptr(u_sess->plsql_cxt.CursorRecordTypeList,var); + pfree(var->cursor_name); + pfree(var); } - relation_close(rel,AccessShareLock); - u_sess->plsql_cxt.CursorRecordTypeList = list_delete_ptr(u_sess->plsql_cxt.CursorRecordTypeList,var); - pfree(var->cursor_name); - pfree(var); } } - list_free(temp_list); + PG_CATCH(); + { + t_thrd.utils_cxt.CurrentResourceOwner = save; + (void)MemoryContextSwitchTo(old); + PG_RE_THROW(); + } + PG_END_TRY(); + t_thrd.utils_cxt.CurrentResourceOwner = save; (void)MemoryContextSwitchTo(old); } From e13a8ad0336ea0018a43209b751b7320abeece43 Mon Sep 17 00:00:00 2001 From: pulsar Date: Thu, 6 Jul 2023 10:26:38 +0800 Subject: [PATCH 3/6] add PG_TRY --- src/common/backend/parser/analyze.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index 61534896f..a444c2236 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -4430,10 +4430,20 @@ static Query* transformDeclareCursorStmt(ParseState* pstate, DeclareCursorStmt* } /*除WITH HOLD游标外,根据DeclareCursorName对使用的row type形成依赖*/ - if (!(stmt->options & CURSOR_OPT_HOLD)) { - u_sess->analyze_cxt.DeclareCursorName = stmt->portalname; + PG_TRY(); + { + if (!(stmt->options & CURSOR_OPT_HOLD)) { + u_sess->analyze_cxt.DeclareCursorName = stmt->portalname; + } + result = transformStmt(pstate, stmt->query); } - result = transformStmt(pstate, stmt->query); + PG_CATCH(); + { + u_sess->analyze_cxt.DeclareCursorName = NULL; + PG_RE_THROW(); + } + PG_END_TRY(); + u_sess->analyze_cxt.DeclareCursorName = NULL; /* Grammar should not have allowed anything but SELECT */ From 3bb76dc41fc8f0ed92d3378d6525ec78f5b3fa8e Mon Sep 17 00:00:00 2001 From: pulsar Date: Tue, 18 Jul 2023 10:16:23 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E8=8B=B1=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/parser/analyze.cpp | 2 +- src/common/backend/utils/mmgr/portalmem.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/backend/parser/analyze.cpp b/src/common/backend/parser/analyze.cpp index a444c2236..a2a5b52c4 100644 --- a/src/common/backend/parser/analyze.cpp +++ b/src/common/backend/parser/analyze.cpp @@ -4429,9 +4429,9 @@ static Query* transformDeclareCursorStmt(ParseState* pstate, DeclareCursorStmt* ERROR, (errcode(ERRCODE_INVALID_CURSOR_DEFINITION), errmsg("cannot specify both SCROLL and NO SCROLL"))); } - /*除WITH HOLD游标外,根据DeclareCursorName对使用的row type形成依赖*/ PG_TRY(); { + /* according to DeclareCursorName to form a dependency on the used ROW type */ if (!(stmt->options & CURSOR_OPT_HOLD)) { u_sess->analyze_cxt.DeclareCursorName = stmt->portalname; } diff --git a/src/common/backend/utils/mmgr/portalmem.cpp b/src/common/backend/utils/mmgr/portalmem.cpp index a21a12148..53780e8da 100755 --- a/src/common/backend/utils/mmgr/portalmem.cpp +++ b/src/common/backend/utils/mmgr/portalmem.cpp @@ -1403,7 +1403,7 @@ HoldPinnedPortals(bool is_rollback) } } -/*解除游标与row type类型的依赖关系*/ +/* Release the dependency between CURSOR and ROW type */ static void CursorRecordTypeUnbind(const char* portal_name) { ListCell* cell = NULL; From e13e3d09bc1b868e3a2f8bdb9ddce7464c0d3488 Mon Sep 17 00:00:00 2001 From: pulsar Date: Tue, 18 Jul 2023 15:13:57 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E8=A1=A5=E5=85=85=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=E6=9C=9F=E6=9C=9B=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expected/plpgsql_cursor_rowtype.out | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/src/test/regress/expected/plpgsql_cursor_rowtype.out b/src/test/regress/expected/plpgsql_cursor_rowtype.out index 31a2e3422..1981e9116 100644 --- a/src/test/regress/expected/plpgsql_cursor_rowtype.out +++ b/src/test/regress/expected/plpgsql_cursor_rowtype.out @@ -845,6 +845,120 @@ INFO: aa set behavior_compat_options=''; drop procedure check_compile; +--游标依赖row type,后续alter type +create type foo as (a int, b int); +--游标依赖type,alter type报错 +begin; +declare c cursor for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; + row +---------------- + (1,1073741824) +(1 row) + +fetch c; + row +---------------- + (2,1073741824) +(1 row) + +alter type foo alter attribute b type text;--error +ERROR: cannot ALTER TABLE "foo" because it is being used by active queries in this session +end; +--第二次开始从缓存中获取type +begin; +cursor c for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; + row +---------------- + (1,1073741824) +(1 row) + +fetch c; + row +---------------- + (2,1073741824) +(1 row) + +alter type foo alter attribute b type text;--error +ERROR: cannot ALTER TABLE "foo" because it is being used by active queries in this session +end; +--close后,可以成功alter +begin; +declare c cursor for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; + row +---------------- + (1,1073741824) +(1 row) + +fetch c; + row +---------------- + (2,1073741824) +(1 row) + +close c; +alter type foo alter attribute b type text;--success +declare c cursor for select (i,2^30)::foo from generate_series(1,10) i; +fetch c; + row +---------------- + (1,1073741824) +(1 row) + +fetch c; + row +---------------- + (2,1073741824) +(1 row) + +rollback; +begin; +cursor c for select (i,2^30)::foo from generate_series(1,10) i; +close c; +alter type foo alter attribute b type text;--success +end; +--多个游标依赖,只关闭一个 +begin; +cursor c1 for select (i,2^30)::foo from generate_series(1,10) i; +cursor c2 for select (i,2^30)::foo from generate_series(1,10) i; +close c1; +alter type foo alter attribute b type text;--error +ERROR: cannot ALTER TABLE "foo" because it is being used by active queries in this session +end; +--多个游标依赖,都关闭 +begin; +cursor c1 for select (i,2^30)::foo from generate_series(1,10) i; +cursor c2 for select (i,2^30)::foo from generate_series(1,10) i; +close c1; +close c2; +alter type foo alter attribute b type text;--success +end; +--WITH HOLD游标,事务结束继续保留 +begin; +cursor c3 WITH HOLD for select (i,2^30)::foo from generate_series(1,10) i; +fetch c3; + row +---------------- + (1,1073741824) +(1 row) + +end; +fetch c3; + row +---------------- + (2,1073741824) +(1 row) + +alter type foo alter attribute b type text;--success +fetch c3; + row +---------------- + (3,1073741824) +(1 row) + +close c3; ---- clean ---- drop package pck1; NOTICE: drop cascades to function plpgsql_cursor_rowtype.p1() From 19911b4dfa2eb05f296165d6da957bab94aaaa25 Mon Sep 17 00:00:00 2001 From: pulsar Date: Fri, 21 Jul 2023 17:11:10 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9C=9F=E6=9C=9B?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/regress/expected/plpgsql_cursor_rowtype.out | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/regress/expected/plpgsql_cursor_rowtype.out b/src/test/regress/expected/plpgsql_cursor_rowtype.out index 1981e9116..8b7665a1f 100644 --- a/src/test/regress/expected/plpgsql_cursor_rowtype.out +++ b/src/test/regress/expected/plpgsql_cursor_rowtype.out @@ -988,7 +988,7 @@ NOTICE: drop cascades to function plpgsql_cursor_rowtype.p1() drop package pckg_test2; NOTICE: drop cascades to function plpgsql_cursor_rowtype.p1() drop schema plpgsql_cursor_rowtype cascade; -NOTICE: drop cascades to 13 other objects +NOTICE: drop cascades to 14 other objects DETAIL: drop cascades to table emp drop cascades to function pro_cursor_no_args_1() drop cascades to function pro_cursor_no_args_2() @@ -1002,5 +1002,6 @@ drop cascades to function test_forloop_001() drop cascades to function pro_close_cursor1() drop cascades to function pro_close_cursor2() drop cascades to function check_compile_1() +drop cascades to type foo drop schema schema1 cascade; NOTICE: drop cascades to table schema1.t11