From 2b1a58494fe7be559b1c7f830de74c07af051d49 Mon Sep 17 00:00:00 2001 From: Ilhan <70995854+xmilex-git@users.noreply.github.com> Date: Wed, 20 Nov 2024 17:50:37 +0900 Subject: [PATCH] [CBRD-25680] When using a correlated subquery that includes columns from an outer table in the select clause, it is not selected as a cache key (#5623) http://jira.cubrid.org/browse/CBRD-25680 When using a correlated subquery that includes columns from an outer table in the select clause, the subquery cache does not use those columns as keys, resulting in improper caching. Consequently, cache hits occur even in situations where cache misses are expected. To address this, we modified the code to include regu_var from xasl outptr_list as part of the caching key. Additionally, unlike pred, xasl outptr_list uses the outer table as a constant regu_var during joins, which could mistakenly utilize even non-outer columns as cache keys. Therefore, we adjusted the code to only enable caching when there is no table from the subquery that matches the specification. --- src/parser/view_transform.c | 5 ++-- src/parser/xasl_generation.c | 54 ++++++++++++++++++++++++++++++++++++ src/query/regu_var.hpp | 1 + 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/parser/view_transform.c b/src/parser/view_transform.c index e5891c8a298..bcf1d2882d2 100644 --- a/src/parser/view_transform.c +++ b/src/parser/view_transform.c @@ -4944,8 +4944,9 @@ mq_rewrite_aggregate_as_derived (PARSER_CONTEXT * parser, PT_NODE * agg_sel) * Therefore, the NO_MERGE hint is not moved to the derived subquery. * Additionally, if the subquery has the QUERY_CACHE hint, it should not be merged, so it is treated together with the NO_MERGE hint. * All hints except for NO_MERGE and QUERY_CACHE are moved to the derived subquery. */ - derived->info.query.q.select.hint = agg_sel->info.query.q.select.hint & ~(PT_HINT_NO_MERGE | PT_HINT_QUERY_CACHE); - agg_sel->info.query.q.select.hint &= (PT_HINT_NO_MERGE | PT_HINT_QUERY_CACHE); + derived->info.query.q.select.hint = + agg_sel->info.query.q.select.hint & ~(PT_HINT_NO_MERGE | PT_HINT_QUERY_CACHE | PT_HINT_NO_SUBQUERY_CACHE); + agg_sel->info.query.q.select.hint &= (PT_HINT_NO_MERGE | PT_HINT_QUERY_CACHE | PT_HINT_NO_SUBQUERY_CACHE); derived->info.query.q.select.leading = agg_sel->info.query.q.select.leading; agg_sel->info.query.q.select.leading = NULL; diff --git a/src/parser/xasl_generation.c b/src/parser/xasl_generation.c index 5dcc23ced1c..547ce892ce8 100644 --- a/src/parser/xasl_generation.c +++ b/src/parser/xasl_generation.c @@ -10125,6 +10125,7 @@ pt_attribute_to_regu (PARSER_CONTEXT * parser, PT_NODE * attr) { /* The attribute is correlated variable. Find it in an enclosing scope(s). Note that this subquery has * also just been determined to be a correlated subquery. */ + REGU_VARIABLE_SET_FLAG (regu, REGU_VARIABLE_CORRELATED); if (symbols->stack == NULL) { if (!pt_has_error (parser)) @@ -27436,6 +27437,7 @@ pt_make_sq_cache_key_struct (QPROC_DB_VALUE_LIST key_struct, void *p, int type) ACCESS_SPEC_TYPE *spec; PRED_EXPR *pred_src; REGU_VARIABLE *regu_src; + REGU_VARIABLE_LIST regu_var_list_p; if (!p) { return 0; @@ -27546,6 +27548,54 @@ pt_make_sq_cache_key_struct (QPROC_DB_VALUE_LIST key_struct, void *p, int type) cnt += ret; } } + if (xasl_src->outptr_list) + { + regu_var_list_p = xasl_src->outptr_list->valptrp; + for (i = 0; i < xasl_src->outptr_list->valptr_cnt; i++) + { + if (!regu_var_list_p) + { + assert (false); + return ER_FAILED; + } + regu_src = ®u_var_list_p->value; + ret = pt_make_sq_cache_key_struct (key_struct, (void *) regu_src, SQ_TYPE_REGU_VAR); + if (ret == ER_FAILED) + { + return ER_FAILED; + } + else + { + cnt += ret; + } + regu_var_list_p = regu_var_list_p->next; + } + } + if (xasl_src->type == BUILDVALUE_PROC || xasl_src->type == BUILDLIST_PROC) + { + AGGREGATE_TYPE *agg_list = + (xasl_src->type == + BUILDVALUE_PROC) ? xasl_src->proc.buildvalue.agg_list : xasl_src->proc.buildlist.g_agg_list; + while (agg_list) + { + regu_var_list_p = agg_list->operands; + while (regu_var_list_p) + { + ret = pt_make_sq_cache_key_struct (key_struct, (void *) ®u_var_list_p->value, SQ_TYPE_REGU_VAR); + if (ret == ER_FAILED) + { + return ER_FAILED; + } + else + { + cnt += ret; + } + regu_var_list_p = regu_var_list_p->next; + } + agg_list = agg_list->next; + } + + } break; case SQ_TYPE_PRED: pred_src = (PRED_EXPR *) p; @@ -27614,6 +27664,10 @@ pt_make_sq_cache_key_struct (QPROC_DB_VALUE_LIST key_struct, void *p, int type) switch (regu_src->type) { case TYPE_CONSTANT: + if (!REGU_VARIABLE_IS_FLAGED (regu_src, REGU_VARIABLE_CORRELATED)) + { + break; + } ret = pt_make_sq_cache_key_struct (key_struct, (void *) regu_src->value.dbvalptr, SQ_TYPE_DBVAL); if (ret == ER_FAILED) { diff --git a/src/query/regu_var.hpp b/src/query/regu_var.hpp index 672b62d5863..7311335fba8 100644 --- a/src/query/regu_var.hpp +++ b/src/query/regu_var.hpp @@ -166,6 +166,7 @@ const int REGU_VARIABLE_FETCH_NOT_CONST = 0x80; /* is not constant */ const int REGU_VARIABLE_CLEAR_AT_CLONE_DECACHE = 0x100; /* clears regu variable at clone decache */ const int REGU_VARIABLE_UPD_INS_LIST = 0x200; /* for update or insert query */ const int REGU_VARIABLE_STRICT_TYPE_CAST = 0x400;/* for update or insert query */ +const int REGU_VARIABLE_CORRELATED = 0x800; /* for correlated scalar subquery cache */ class regu_variable_node {