diff --git a/src/gausskernel/storage/mot/fdw_adapter/src/mot_internal.cpp b/src/gausskernel/storage/mot/fdw_adapter/src/mot_internal.cpp index e4978f56faf96cdf089b001c041c148215034dd1..408101f9b0bc0c6694b964de1f6ae1490b7464e5 100644 --- a/src/gausskernel/storage/mot/fdw_adapter/src/mot_internal.cpp +++ b/src/gausskernel/storage/mot/fdw_adapter/src/mot_internal.cpp @@ -101,6 +101,9 @@ DECLARE_LOGGER(InternalExecutor, FDW) /** @brief on_proc_exit() callback for cleaning up current thread - only when thread pool is ENABLED. */ static void MOTCleanupThread(int status, Datum ptr); +/** @brief Helper for cleaning up all JIT context objects stored in all CachedPlanSource of the current session. */ +static void DestroySessionJitContexts(); + extern void MOTOnThreadShutdown(); // in a thread-pooled environment we need to ensure thread-locals are initialized properly @@ -211,6 +214,8 @@ static void SessionCleanup(void* key) if (sessionId != INVALID_SESSION_ID) { MOT_LOG_WARN("Encountered unclosed session %u (missing call to DestroyTxn()?)", (unsigned)sessionId); ClearSessionDetails(sessionId); + MOT_LOG_DEBUG("SessionCleanup(): Calling DestroySessionJitContext()"); + DestroySessionJitContexts(); if (MOTAdaptor::m_engine) { MOT::SessionContext* sessionContext = MOT::GetSessionManager()->GetSessionContext(sessionId); if (sessionContext != nullptr) { @@ -925,6 +930,25 @@ MOT::TxnManager* MOTAdaptor::InitTxnManager(MOT::ConnectionId connection_id /* = return u_sess->mot_cxt.txn_manager; } +static void DestroySessionJitContexts() +{ + // we must release all JIT context objects associated with this session now. + // it seems that when thread pool is disabled, all cached plan sources for the session are not + // released explicitly, but rather implicitly as part of the release of the memory context of the session. + // in any case, we guard against repeated destruction of the JIT context by nullifying it + MOT_LOG_DEBUG("Cleaning up all JIT context objects for current session"); + CachedPlanSource* psrc = u_sess->pcache_cxt.first_saved_plan; + while (psrc != nullptr) { + if (psrc->mot_jit_context != nullptr) { + MOT_LOG_DEBUG("DestroySessionJitContexts(): Calling DestroyJitContext(%p)", psrc->mot_jit_context); + JitExec::DestroyJitContext(psrc->mot_jit_context); + psrc->mot_jit_context = nullptr; + } + psrc = psrc->next_saved; + } + MOT_LOG_DEBUG("DONE Cleaning up all JIT context objects for current session"); +} + /** @brief Notification from thread pool that a session ended (only when thread pool is ENABLED). */ extern void MOTOnSessionClose() { @@ -933,6 +957,8 @@ extern void MOTOnSessionClose() u_sess->mot_cxt.connection_id); if (u_sess->mot_cxt.session_id != INVALID_SESSION_ID) { ClearCurrentSessionDetails(); + MOT_LOG_DEBUG("MOTOnSessionClose(): Calling DestroySessionJitContexts()"); + DestroySessionJitContexts(); if (!MOTAdaptor::m_engine) { MOT_LOG_ERROR("MOTOnSessionClose(): MOT engine is not initialized"); } else { @@ -957,7 +983,7 @@ extern void MOTOnThreadShutdown() return; } - MOT_LOG_DEBUG("Received thread shutdown notification"); + MOT_LOG_TRACE("Received thread shutdown notification"); if (!MOTAdaptor::m_engine) { MOT_LOG_ERROR("MOTOnThreadShutdown(): MOT engine is not initialized"); } else { @@ -973,6 +999,7 @@ extern void MOTOnThreadShutdown() static void MOTCleanupThread(int status, Datum ptr) { MOT_ASSERT(g_instance.attr.attr_common.enable_thread_pool); + MOT_LOG_TRACE("Received thread cleanup notification (thread-pool ON)"); // when thread pool is used we just cleanup current thread // this might be a duplicate because thread pool also calls MOTOnThreadShutdown() - this is still ok @@ -989,6 +1016,8 @@ void MOTAdaptor::DestroyTxn(int status, Datum ptr) CancelSessionCleanup(); } ClearCurrentSessionDetails(); + MOT_LOG_DEBUG("DestroyTxn(): Calling DestroySessionJitContexts()"); + DestroySessionJitContexts(); MOT::SessionContext* session = (MOT::SessionContext*)DatumGetPointer(ptr); if (m_engine == nullptr) { elog(ERROR, "destroyTxn: MOT engine is not initialized"); @@ -1003,7 +1032,7 @@ void MOTAdaptor::DestroyTxn(int status, Datum ptr) if (gc != nullptr) { gc->GcEndTxn(); } - MOT::GetSessionManager()->DestroySessionContext(session); + DestroySession(session); } // clean up thread @@ -1691,7 +1720,7 @@ MOT::RC MOTAdaptor::CreateTable(CreateForeignTableStmt* table, ::TransactionId t tname.append(table->base.relation->relname); if (!currentTable->Init( - table->base.relation->relname, tname.c_str(), columnCount, table->base.relation->foreignOid)) { + table->base.relation->relname, tname.c_str(), columnCount, table->base.relation->foreignOid)) { delete currentTable; currentTable = nullptr; report_pg_error(MOT::RC_MEMORY_ALLOCATION_ERROR, txn); diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_common.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_common.cpp index 199f149516f7577a3ca6619203f59c9d28751f59..2d5a3c0226c4ad444b8b833f0a9d9bc5767a0d14 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_common.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_common.cpp @@ -27,6 +27,8 @@ #include "catalog/pg_operator.h" #include "jit_common.h" #include "utilities.h" +#include "jit_plan.h" +#include "mm_global_api.h" namespace JitExec { DECLARE_LOGGER(JitCommon, JitExec) @@ -86,6 +88,8 @@ extern const char* CommandToString(JitCommandType commandType) return "Range-Join"; case JIT_COMMAND_AGGREGATE_JOIN: return "Aggregate-Range-Join"; + case JIT_COMMAND_COMPOUND_SELECT: + return "Compound-Select"; case JIT_COMMAND_INVALID: default: @@ -161,7 +165,11 @@ extern int MapTableColumnToIndex(MOT::Table* table, const MOT::Index* index, int int keyColumnCount = index->GetNumFields(); for (int i = 0; i < keyColumnCount; ++i) { if (indexColumnIds[i] == columnId) { - MOT_LOG_DEBUG("Table column %d mapped to index column %d", columnId, i); + MOT_LOG_TRACE("Table %s column %d mapped to index %s column %d", + table->GetTableName().c_str(), + columnId, + index->GetName().c_str(), + i); return i; } } @@ -193,6 +201,7 @@ extern int BuildIndexColumnOffsets(MOT::Table* table, const MOT::Index* index, i if (*offsets) { int offset = 0; for (int i = 0; i < indexColumnCount; ++i) { + MOT_LOG_TRACE("Setting index %s column %d offset to %d", index->GetName().c_str(), i, offset); (*offsets)[i] = offset; offset += keyLength[i]; } @@ -452,7 +461,7 @@ extern bool InitTableInfo(TableInfo* tableInfo, MOT::Table* table, MOT::Index* i } tableInfo->m_indexColumnCount = BuildIndexColumnOffsets(table, index, &tableInfo->m_indexColumnOffsets); if (tableInfo->m_indexColumnOffsets == nullptr) { - pfree(tableInfo->m_columnMap); + MOT::MemSessionFree(tableInfo->m_columnMap); return false; } @@ -471,4 +480,101 @@ extern void DestroyTableInfo(TableInfo* tableInfo) } } } + +extern bool PrepareSubQueryData(JitContext* jitContext, JitCompoundPlan* plan) +{ + bool result = true; + + // allocate sub-query data array + int subQueryCount = plan->_sub_query_count; + MOT_LOG_TRACE("Preparing %u sub-query data items", subQueryCount); + uint32_t allocSize = sizeof(JitContext::SubQueryData) * subQueryCount; + jitContext->m_subQueryData = (JitContext::SubQueryData*)MOT::MemGlobalAllocAligned(allocSize, L1_CACHE_LINE); + if (jitContext->m_subQueryData == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "Generate JIT code", + "Failed to allocate %u bytes for %d sub-query data items in JIT context object", + allocSize, + subQueryCount); + result = false; + } else { + // traverse all search expressions and for each sub-link expression prepare a sub-query data item + jitContext->m_subQueryCount = subQueryCount; + for (int i = 0; i < plan->_outer_query_plan->_query._search_exprs._count; ++i) { + if (plan->_outer_query_plan->_query._search_exprs._exprs[i]._expr->_expr_type == JIT_EXPR_TYPE_SUBLINK) { + // get sub-query index from sub-link expression + JitSubLinkExpr* subLinkExpr = + (JitSubLinkExpr*)plan->_outer_query_plan->_query._search_exprs._exprs[i]._expr; + int subQueryIndex = subLinkExpr->_sub_query_index; + MOT_ASSERT(subQueryIndex < subQueryCount); + MOT_LOG_TRACE("Preparing sub-query %u data", subQueryIndex); + JitContext::SubQueryData* subQueryData = &jitContext->m_subQueryData[subQueryIndex]; + + // nullify unknown members + subQueryData->m_tupleDesc = nullptr; + subQueryData->m_slot = nullptr; + subQueryData->m_searchKey = nullptr; + subQueryData->m_endIteratorKey = nullptr; + + // prepare sub-query data items according to sub-plan type + JitPlan* subPlan = plan->_sub_query_plans[subQueryIndex]; + JitPlanType subPlanType = subPlan->_plan_type; + MOT_ASSERT((subPlanType == JIT_PLAN_POINT_QUERY) || (subPlanType == JIT_PLAN_RANGE_SCAN)); + + if (subPlanType == JIT_PLAN_POINT_QUERY) { // simple point-select + MOT_ASSERT(((JitPointQueryPlan*)subPlan)->_command_type == JIT_COMMAND_SELECT); + JitPointQueryPlan* subPointQueryPlan = (JitPointQueryPlan*)subPlan; + if (subPointQueryPlan->_command_type == JIT_COMMAND_SELECT) { + MOT_LOG_TRACE("Detected point-query select sub-plan"); + subQueryData->m_commandType = JIT_COMMAND_SELECT; + JitSelectPlan* selectPlan = (JitSelectPlan*)subPlan; + subQueryData->m_table = selectPlan->_query._table; + subQueryData->m_index = subQueryData->m_table->GetPrimaryIndex(); + } else { + MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, + "Generate JIT code", + "Invalid sub-point-query plan command type: %s", + CommandToString(subPointQueryPlan->_command_type)); + result = false; + break; + } + } else if (subPlanType == JIT_PLAN_RANGE_SCAN) { // aggregate or "limit 1" range select + MOT_ASSERT(((JitRangeScanPlan*)subPlan)->_command_type == JIT_COMMAND_SELECT); + JitRangeScanPlan* subRangeScanPlan = (JitRangeScanPlan*)subPlan; + if (subRangeScanPlan->_command_type == JIT_COMMAND_SELECT) { + MOT_LOG_TRACE("Detected range-scan select sub-plan"); + JitRangeSelectPlan* rangeSelectPlan = (JitRangeSelectPlan*)subPlan; + subQueryData->m_table = rangeSelectPlan->_index_scan._table; + subQueryData->m_index = subQueryData->m_table->GetIndex(rangeSelectPlan->_index_scan._index_id); + if (rangeSelectPlan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) { // aggregate range-scan + subQueryData->m_commandType = JIT_COMMAND_AGGREGATE_RANGE_SELECT; + } else if (rangeSelectPlan->_limit_count == 1) { + subQueryData->m_commandType = JIT_COMMAND_RANGE_SELECT; // implies "limit 1" clause + } else { + MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, + "Generate JIT code", + "Invalid sub-query range-scan plan: neither aggregate nor \"limit 1\" clause found"); + result = false; + break; + } + } else { + MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, + "Generate JIT code", + "Invalid sub-query range-scan plan command type: %s", + CommandToString(subRangeScanPlan->_command_type)); + result = false; + break; + } + } else { + MOT_REPORT_ERROR( + MOT_ERROR_INTERNAL, "Generate JIT code", "Invalid sub-query plan type: %d", (int)subPlanType); + result = false; + break; + } + } + } + } + + return result; +} } // namespace JitExec diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_common.h b/src/gausskernel/storage/mot/jit_exec/src/jit_common.h index 9c1925ca459d8ac14c2b13621875ab47478a1fb1..3612cc4452424d93458d89c80ca8caa16e810ea6 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_common.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_common.h @@ -33,6 +33,9 @@ // This file contains definitions used both by LLVM and TVM jitted code namespace JitExec { +// forward declaration +struct JitCompoundPlan; + // common helpers for code generation /** @brief Converts a PG command type to LLVM command type. */ extern JitCommandType ConvertCommandType(int pgCommandType, bool isPKey); @@ -111,6 +114,14 @@ extern bool InitTableInfo(TableInfo* table_info, MOT::Table* table, MOT::Index* * @param table_info The table information structure to cleanup. */ extern void DestroyTableInfo(TableInfo* table_info); + +/** + * @brief Prepares sub-query data items for a JIT context (table, index and tuple descriptor). + * @param jitContext The JIT context to prepare. + * @param plan The compound plan for the query. + * @return True if operations succeeded, otherwise false. + */ +extern bool PrepareSubQueryData(JitContext* jitContext, JitCompoundPlan* plan); } // namespace JitExec #endif diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_context.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_context.cpp index d02cd42939783abccfde89f491de82ff37eb48e0..4dec3d43b82b0f4e2990503ebf6c9c576c0c7cc9 100755 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_context.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_context.cpp @@ -32,18 +32,21 @@ #include "jit_tvm.h" #include "mot_internal.h" #include "jit_source.h" +#include "mm_global_api.h" namespace JitExec { DECLARE_LOGGER(JitContext, JitExec); // The global JIT context pool -static JitContextPool g_globalJitCtxPool; +static JitContextPool g_globalJitCtxPool __attribute__((aligned(64))) = {0}; // forward declarations static JitContextPool* AllocSessionJitContextPool(); static MOT::Key* PrepareJitSearchKey(JitContext* jitContext, MOT::Index* index); static void CleanupJitContextPrimary(JitContext* jitContext); static void CleanupJitContextInner(JitContext* jitContext); +static void CleanupJitContextSubQueryDataArray(JitContext* jitContext); +static void CleanupJitContextSubQueryData(JitContext::SubQueryData* subQueryData); // Helpers to allocate/free from top memory context inline void* palloc_top(size_t size_bytes) @@ -122,11 +125,129 @@ extern JitContext* CloneJitContext(JitContext* sourceJitContext) result->m_queryString = sourceJitContext->m_queryString; result->m_innerTable = sourceJitContext->m_innerTable; result->m_innerIndex = sourceJitContext->m_innerIndex; + result->m_subQueryCount = sourceJitContext->m_subQueryCount; + + // clone sub-query tuple descriptor array + MOT_LOG_TRACE("Cloning %u sub-query data items", (unsigned)sourceJitContext->m_subQueryCount); + if (sourceJitContext->m_subQueryCount > 0) { + uint32_t allocSize = sizeof(JitContext::SubQueryData) * sourceJitContext->m_subQueryCount; + result->m_subQueryData = (JitContext::SubQueryData*)MOT::MemGlobalAllocAligned(allocSize, L1_CACHE_LINE); + if (result->m_subQueryData == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "Generate JIT Code", + "Failed to allocate %u bytes for %u sub-query data array in JIT context object", + allocSize, + (unsigned)sourceJitContext->m_subQueryCount); + FreeJitContext(result); + result = nullptr; + } else { + for (uint32_t i = 0; i < sourceJitContext->m_subQueryCount; ++i) { + // copy known members + result->m_subQueryData[i].m_commandType = sourceJitContext->m_subQueryData[i].m_commandType; + result->m_subQueryData[i].m_table = sourceJitContext->m_subQueryData[i].m_table; + result->m_subQueryData[i].m_index = sourceJitContext->m_subQueryData[i].m_index; + + // nullify other members + result->m_subQueryData[i].m_tupleDesc = nullptr; + result->m_subQueryData[i].m_slot = nullptr; + result->m_subQueryData[i].m_searchKey = nullptr; + result->m_subQueryData[i].m_endIteratorKey = nullptr; + } + } + } + } + + if (result != nullptr) { MOT_LOG_TRACE("Cloned JIT context %p into %p (table=%p)", sourceJitContext, result, result->m_table); } return result; } +static inline List* GetSubExprTargetList(Query* query, Expr* expr, int subQueryIndex, int* subQueryCount); + +static List* GetSubExprListTargetList(Query* query, List* exprList, int subQueryIndex, int* subQueryCount) +{ + // traverse all arguments, for each encountered sub-link increment the global sub-query count + // if encountered the sub-link at the searched index, then return its target list + List* targetList = nullptr; + ListCell* lc = nullptr; + foreach (lc, exprList) { + Expr* expr = (Expr*)lfirst(lc); + if (expr->type == T_SubLink) { + if (*subQueryCount == subQueryIndex) { + SubLink* subLink = (SubLink*)expr; + Query* subQuery = (Query*)subLink->subselect; + targetList = subQuery->targetList; + break; + } else { + ++(*subQueryCount); + } + } else { + // go deeper recursively + targetList = GetSubExprTargetList(query, expr, subQueryIndex, subQueryCount); + if (targetList != nullptr) { // we are done + break; + } + // continue searching + } + } + return targetList; +} + +static inline List* GetSubOpExprTargetList(Query* query, OpExpr* op_expr, int subQueryIndex, int* subQueryCount) +{ + // check the operator argument list + List* targetList = GetSubExprListTargetList(query, op_expr->args, subQueryIndex, subQueryCount); + return targetList; +} + +static inline List* GetSubBoolExprTargetList(Query* query, BoolExpr* bool_expr, int subQueryIndex, int* subQueryCount) +{ + // check the operator argument list + List* targetList = GetSubExprListTargetList(query, bool_expr->args, subQueryIndex, subQueryCount); + return targetList; +} + +static inline List* GetSubExprTargetList(Query* query, Expr* expr, int subQueryIndex, int* subQueryCount) +{ + // we expect either an operator or boolean expression + List* targetList = nullptr; + if (expr->type == T_OpExpr) { + targetList = GetSubOpExprTargetList(query, (OpExpr*)expr, subQueryIndex, subQueryCount); + } else if (expr->type == T_BoolExpr) { + targetList = GetSubBoolExprTargetList(query, (BoolExpr*)expr, subQueryIndex, subQueryCount); + } + return targetList; +} + +static inline List* GetSubQueryTargetList(Query* query, int subQueryIndex, int* subQueryCount) +{ + // search in the qualifier list for the sub-link expression at the specified index + Node* quals = query->jointree->quals; + Expr* expr = (Expr*)&quals[0]; + List* targetList = GetSubExprTargetList(query, expr, subQueryIndex, subQueryCount); + return targetList; +} + +static List* GetSubQueryTargetList(const char* queryString, int subQueryIndex) +{ + // search in all saved plans of current session for the plan matching the given query text + List* targetList = nullptr; + CachedPlanSource* psrc = u_sess->pcache_cxt.first_saved_plan; + int subQueryCount = 0; + while (psrc != nullptr) { + if (strcmp(psrc->query_string, queryString) == 0) { // query plan source found + List* stmtList = psrc->query_list; + Query* query = (Query*)linitial(stmtList); + // get the target list from the sub-query in the specified index + targetList = GetSubQueryTargetList(query, subQueryIndex, &subQueryCount); + break; // whether found or not, we are done + } + psrc = psrc->next_saved; + } + return targetList; +} + extern bool PrepareJitContext(JitContext* jitContext) { // allocate argument-is-null array @@ -194,6 +315,7 @@ extern bool PrepareJitContext(JitContext* jitContext) } } + // allocate inner loop search key for JOIN commands if ((jitContext->m_innerSearchKey == NULL) && IsJoinCommand(jitContext->m_commandType)) { MOT_LOG_TRACE( "Preparing inner search key for JOIN command from index %s", jitContext->m_innerIndex->GetName().c_str()); @@ -210,6 +332,7 @@ extern bool PrepareJitContext(JitContext* jitContext) } } + // allocate inner loop end-iterator search key for JOIN commands if ((jitContext->m_innerEndIteratorKey == NULL) && IsJoinCommand(jitContext->m_commandType)) { MOT_LOG_TRACE("Preparing inner end iterator key for JOIN command from index %s", jitContext->m_innerIndex->GetName().c_str()); @@ -226,6 +349,7 @@ extern bool PrepareJitContext(JitContext* jitContext) } } + // preparing outer row copy for JOIN commands if ((jitContext->m_outerRowCopy == NULL) && IsJoinCommand(jitContext->m_commandType)) { MOT_LOG_TRACE("Preparing outer row copy for JOIN command"); jitContext->m_outerRowCopy = jitContext->m_table->CreateNewRow(); @@ -235,6 +359,65 @@ extern bool PrepareJitContext(JitContext* jitContext) } } + // prepare sub-query data for COMPOUND commands + if (jitContext->m_subQueryCount > 0) { + // allocate sub-query search keys and generate tuple table slot array using session top memory context + MemoryContext oldCtx = CurrentMemoryContext; + CurrentMemoryContext = u_sess->top_mem_cxt; + for (uint32_t i = 0; i < jitContext->m_subQueryCount; ++i) { + JitContext::SubQueryData* subQueryData = &jitContext->m_subQueryData[i]; + if (subQueryData->m_tupleDesc == nullptr) { + MOT_LOG_TRACE("Preparing sub-query %u tuple descriptor", i); + List* targetList = GetSubQueryTargetList(jitContext->m_queryString, i); + if (targetList == nullptr) { + MOT_LOG_TRACE("Failed to locate sub-query %u target list", i); + CurrentMemoryContext = oldCtx; + return false; // safe cleanup during destroy + } else { + subQueryData->m_tupleDesc = ExecCleanTypeFromTL(targetList, false); + if (subQueryData->m_tupleDesc == nullptr) { + MOT_LOG_TRACE("Failed to create sub-query %u tuple descriptor from target list", i); + CurrentMemoryContext = oldCtx; + return false; // safe cleanup during destroy + } + } + } + if (subQueryData->m_slot == nullptr) { + MOT_ASSERT(subQueryData->m_tupleDesc != nullptr); + MOT_LOG_TRACE("Preparing sub-query %u result slot", i); + subQueryData->m_slot = MakeSingleTupleTableSlot(subQueryData->m_tupleDesc); + if (subQueryData->m_slot == nullptr) { + MOT_LOG_TRACE("Failed to generate sub-query %u tuple table slot", i); + CurrentMemoryContext = oldCtx; + return false; // safe cleanup during destroy + } + } + if (subQueryData->m_searchKey == nullptr) { + MOT_LOG_TRACE( + "Preparing sub-query %u search key from index %s", i, subQueryData->m_index->GetName().c_str()); + subQueryData->m_searchKey = PrepareJitSearchKey(jitContext, subQueryData->m_index); + if (subQueryData->m_searchKey == nullptr) { + MOT_LOG_TRACE("Failed to generate sub-query %u search key", i); + CurrentMemoryContext = oldCtx; + return false; // safe cleanup during destroy + } + } + if ((subQueryData->m_commandType == JIT_COMMAND_AGGREGATE_RANGE_SELECT) && + (subQueryData->m_endIteratorKey == nullptr)) { + MOT_LOG_TRACE("Preparing sub-query %u end-iterator search key from index %s", + i, + subQueryData->m_index->GetName().c_str()); + subQueryData->m_endIteratorKey = PrepareJitSearchKey(jitContext, subQueryData->m_index); + if (subQueryData->m_endIteratorKey == nullptr) { + MOT_LOG_TRACE("Failed to generate sub-query %u end-iterator search key", i); + CurrentMemoryContext = oldCtx; + return false; // safe cleanup during destroy + } + } + } + CurrentMemoryContext = oldCtx; + } + return true; } @@ -259,6 +442,9 @@ extern void DestroyJitContext(JitContext* jitContext) jitContext->m_jitSource = nullptr; } + // cleanup sub-query data array + CleanupJitContextSubQueryDataArray(jitContext); + // cleanup keys(s) CleanupJitContextPrimary(jitContext); @@ -327,6 +513,13 @@ extern void PurgeJitContext(JitContext* jitContext, uint64_t relationId) if ((jitContext->m_innerTable != nullptr) && (jitContext->m_innerTable->GetTableExId() == relationId)) { CleanupJitContextInner(jitContext); } + + // cleanup sub-query keys + for (uint32_t i = 0; i < jitContext->m_subQueryCount; ++i) { + JitContext::SubQueryData* subQueryData = &jitContext->m_subQueryData[i]; + MOT_LOG_TRACE("Cleaning up sub-query %u data in JIT context %p", i, jitContext); + CleanupJitContextSubQueryData(subQueryData); + } } } @@ -369,9 +562,45 @@ static void CleanupJitContextInner(JitContext* jitContext) } } +static void CleanupJitContextSubQueryDataArray(JitContext* jitContext) +{ + MOT_LOG_TRACE("Cleaning up sub-query data array in JIT context %p", jitContext); + for (uint32_t i = 0; i < jitContext->m_subQueryCount; ++i) { + JitContext::SubQueryData* subQueryData = &jitContext->m_subQueryData[i]; + MOT_LOG_TRACE("Cleaning up sub-query %u data in JIT context %p", i, jitContext); + CleanupJitContextSubQueryData(subQueryData); + } + if (jitContext->m_subQueryData != nullptr) { + MOT::MemGlobalFree(jitContext->m_subQueryData); + jitContext->m_subQueryData = nullptr; + } +} + +static void CleanupJitContextSubQueryData(JitContext::SubQueryData* subQueryData) +{ + if (subQueryData->m_slot != nullptr) { + ExecDropSingleTupleTableSlot(subQueryData->m_slot); + subQueryData->m_slot = nullptr; + } + if (subQueryData->m_tupleDesc != nullptr) { + FreeTupleDesc(subQueryData->m_tupleDesc); + subQueryData->m_tupleDesc = nullptr; + } + if (subQueryData->m_index != nullptr) { + if (subQueryData->m_searchKey != nullptr) { + subQueryData->m_index->DestroyKey(subQueryData->m_searchKey); + subQueryData->m_searchKey = nullptr; + } + if (subQueryData->m_endIteratorKey != nullptr) { + subQueryData->m_index->DestroyKey(subQueryData->m_endIteratorKey); + subQueryData->m_endIteratorKey = nullptr; + } + } +} + static JitContextPool* AllocSessionJitContextPool() { - JitContextPool* result = (JitContextPool*)palloc_top(sizeof(JitContextPool)); + JitContextPool* result = (JitContextPool*)MOT::MemGlobalAllocAligned(sizeof(JitContextPool), L1_CACHE_LINE); if (result == NULL) { MOT_REPORT_ERROR(MOT_ERROR_OOM, "Allocate JIT Context", "Failed to allocate buffer for JIT context"); return NULL; @@ -387,7 +616,7 @@ static JitContextPool* AllocSessionJitContextPool() extern void FreeSessionJitContextPool(JitContextPool* jitContextPool) { DestroyJitContextPool(jitContextPool); - pfree_top(jitContextPool); + MOT::MemGlobalFree(jitContextPool); } static MOT::Key* PrepareJitSearchKey(JitContext* jitContext, MOT::Index* index) diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_context.h b/src/gausskernel/storage/mot/jit_exec/src/jit_context.h index 7ecdfa53863740cc8be6f05f8ad6f577c432a254..67b3f52eb2689c00d0cfbd0cecd69e49d868f566 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_context.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_context.h @@ -150,17 +150,53 @@ struct JitContext { /** @var Scan ended flag (stateful execution). */ uint64_t m_innerScanEnded; // L1 offset 40 + /*---------------------- Compound Query Execution -------------------*/ + struct SubQueryData { + /** @var The sub-query command type (point-select, aggregate range select or limit 1 range-select). */ + JitCommandType m_commandType; // L1 offset 0 + + /** @var Align next member to 8-byte offset. */ + uint8_t m_padding[7]; // L1 offset 1 + + /** @var Tuple descriptor for the sub-query result. */ + TupleDesc m_tupleDesc; // L1 offset 8 + + /** @var Sub-query execution result. */ + TupleTableSlot* m_slot; // L1 offset 16 + + /** @var The table used by the sub-query. */ + MOT::Table* m_table; // L1 offset 24 + + /** @var The index used by the sub-query. */ + MOT::Index* m_index; // L1 offset 32 + + /** @var The search key used by the sub-query. */ + MOT::Key* m_searchKey; // L1 offset 40 + + /** @var The search key used by a range select sub-query (whether aggregated or limited). */ + MOT::Key* m_endIteratorKey; // L1 offset 48 + + /** @var Align whole struct size to one cache line. */ + uint8_t m_padding2[8]; // L1 offset 56 + }; + + /** @var Array of tuple descriptors for each sub-query. */ + SubQueryData* m_subQueryData; // L1 offset 48 + + /** @var The number of sub-queries used. */ + uint64_t m_subQueryCount; // L1 offset 56 + /*---------------------- Cleanup -------------------*/ /** @var Chain all context objects related to the same source, for cleanup during relation modification. */ - JitContext* m_nextInSource; // L1 offset 48 + JitContext* m_nextInSource; // L1 offset 0 /** @var The JIT source from which this context originated. */ - JitSource* m_jitSource; // L1 offset 56 + JitSource* m_jitSource; // L1 offset 8 /*---------------------- Debug execution state -------------------*/ /** @var The number of times this context was invoked for execution. */ #ifdef MOT_JIT_DEBUG - uint64_t m_execCount; // L1 offset 0 + uint64_t m_execCount; // L1 offset 16 #endif }; @@ -210,9 +246,16 @@ extern bool PrepareJitContext(JitContext* jitContext); extern void DestroyJitContext(JitContext* jitContext); /** - * @brief Release all resources related to the primary table. + * @brief Release all resources related to any table used by the JIT context object. + * @detail When a DDL command is executed (such as DROP table), all resources associated with the table must be + * reclaimed immediately. Any attempt to do so at a later phase (i.e. after DDL ends, and other cached plans are + * invalidated), will result in a crash (because the key/row pools, into which cached plan objects are to be returned, + * are already destroyed during DDL execution). So we provide API to purge a JIT context object from all resources + * associated with a relation, which can be invoked during DDL execution (so by the time the cached plan containing the + * JIT context is invalidated, the members related to the affected MOT relation had already been reclaimed). * @param jitContext The JIT context to be purged. * @param relationId The external identifier of the modified relation that triggered purge. + * @see SetJitSourceExpired(). */ extern void PurgeJitContext(JitContext* jitContext, uint64_t relationId); } // namespace JitExec diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_context_pool.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_context_pool.cpp index faee244b78354cb7cd6b476e1011fd4a1e1f104d..d682711643bd7108a13985d945e143e65e8f891e 100755 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_context_pool.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_context_pool.cpp @@ -28,18 +28,18 @@ #include "jit_context_pool.h" #include "utilities.h" +#include "mm_global_api.h" namespace JitExec { DECLARE_LOGGER(JitContextPool, JitExec) extern bool InitJitContextPool(JitContextPool* contextPool, JitContextUsage usage, uint32_t poolSize) { - bool result = false; - + MOT_ASSERT(contextPool->m_contextPool == nullptr); contextPool->m_usage = usage; - contextPool->m_contextPool = NULL; + contextPool->m_contextPool = nullptr; contextPool->m_poolSize = 0; - contextPool->m_freeContextList = NULL; + contextPool->m_freeContextList = nullptr; contextPool->m_freeContextCount = 0; if (usage == JIT_CONTEXT_GLOBAL) { @@ -54,22 +54,14 @@ extern bool InitJitContextPool(JitContextPool* contextPool, JitContextUsage usag } size_t allocSize = sizeof(JitContext) * poolSize; - int res = posix_memalign((void**)&contextPool->m_contextPool, 64, allocSize); - if (res != 0) { - // report OOM first to make sure error is reported correctly to user + contextPool->m_contextPool = (JitContext*)MOT::MemGlobalAllocAligned(allocSize, L1_CACHE_LINE); + if (contextPool->m_contextPool == nullptr) { MOT_REPORT_ERROR(MOT_ERROR_OOM, "JIT Context Pool Initialization", "Failed to allocate %u JIT context objects (64-byte aligned %u bytes) for %s JIT context pool", poolSize, allocSize, usage == JIT_CONTEXT_GLOBAL ? "global" : "session-local"); - MOT_REPORT_SYSTEM_ERROR_CODE(res, - posix_memalign, - "JIT Context Pool Initialization", - "Failed to allocate %u JIT context objects (64-byte aligned %u bytes) for %s JIT context pool", - poolSize, - allocSize, - usage == JIT_CONTEXT_GLOBAL ? "global" : "session-local"); pthread_spin_destroy(&contextPool->m_lock); return false; } @@ -77,7 +69,6 @@ extern bool InitJitContextPool(JitContextPool* contextPool, JitContextUsage usag securec_check(erc, "\0", "\0"); // fill the free list - result = true; contextPool->m_poolSize = poolSize; for (uint32_t i = 0; i < poolSize; ++i) { JitContext* jitContext = &contextPool->m_contextPool[i]; @@ -86,12 +77,16 @@ extern bool InitJitContextPool(JitContextPool* contextPool, JitContextUsage usag } contextPool->m_freeContextCount = contextPool->m_poolSize; - return result; + return true; } extern void DestroyJitContextPool(JitContextPool* contextPool) { - free(contextPool->m_contextPool); + if (contextPool->m_contextPool == nullptr) { + return; + } + + MOT::MemGlobalFree(contextPool->m_contextPool); if (contextPool->m_usage == JIT_CONTEXT_GLOBAL) { int res = pthread_spin_destroy(&contextPool->m_lock); @@ -103,9 +98,9 @@ extern void DestroyJitContextPool(JitContextPool* contextPool) } } - contextPool->m_contextPool = NULL; + contextPool->m_contextPool = nullptr; contextPool->m_poolSize = 0; - contextPool->m_freeContextList = NULL; + contextPool->m_freeContextList = nullptr; contextPool->m_freeContextCount = 0; } @@ -120,7 +115,7 @@ extern JitContext* AllocPooledJitContext(JitContextPool* contextPool) } } - MOT_LOG_DEBUG("%s JIT context pool free-count before alloc context: %u", + MOT_LOG_TRACE("%s JIT context pool free-count before alloc context: %u", contextPool->m_usage == JIT_CONTEXT_GLOBAL ? "global" : "session-local", contextPool->m_freeContextCount); JitContext* result = contextPool->m_freeContextList; @@ -145,7 +140,7 @@ extern JitContext* AllocPooledJitContext(JitContextPool* contextPool) if (result == nullptr) { MOT_REPORT_ERROR(MOT_ERROR_RESOURCE_LIMIT, - "Global JIT Context Allocation", + "JIT Context Allocation", "Failed to allocate %s JIT context: pool with %u context objects depleted", contextPool->m_usage == JIT_CONTEXT_GLOBAL ? "global" : "session-local", contextPool->m_poolSize); @@ -176,7 +171,7 @@ extern void FreePooledJitContext(JitContextPool* contextPool, JitContext* jitCon jitContext->m_next = contextPool->m_freeContextList; contextPool->m_freeContextList = jitContext; ++contextPool->m_freeContextCount; - MOT_LOG_DEBUG("%s JIT context pool free-count after free context: %u", + MOT_LOG_TRACE("%s JIT context pool free-count after free context: %u", contextPool->m_usage == JIT_CONTEXT_GLOBAL ? "global" : "session-local", contextPool->m_freeContextCount); diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp index 832abd5f21518ac996051ea6cd9724f7f6e89cc4..aebc89ee94c1618657e395e3b9db2a4f566c1fe2 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_exec.cpp @@ -106,7 +106,11 @@ extern JitPlan* IsJittable(Query* query, const char* queryString) // plan generated so query is jittable, but... // we disqualify plan if we see distinct operator, until integrated with PG if (JitPlanHasDistinct(jitPlan)) { - MOT_LOG_TRACE("Disqualifying JOIN DISTINCT plan"); + MOT_LOG_TRACE("Disqualifying plan with DISTINCT aggregate"); + JitDestroyPlan(jitPlan); + jitPlan = nullptr; + } else if (JitPlanHasSort(jitPlan)) { + MOT_LOG_TRACE("Disqualifying plan with ORDER BY specifier"); JitDestroyPlan(jitPlan); jitPlan = nullptr; } else { @@ -141,7 +145,8 @@ static void ProcessJitResult(MOT::RC result, JitContext* jitContext) // we ignore "local row not found" in SELECT and DELETE scenarios if (result == MOT::RC_LOCAL_ROW_NOT_FOUND) { if ((jitContext->m_commandType == JIT_COMMAND_DELETE) || (jitContext->m_commandType == JIT_COMMAND_SELECT) || - (jitContext->m_commandType == JIT_COMMAND_RANGE_SELECT)) { + (jitContext->m_commandType == JIT_COMMAND_RANGE_SELECT) || + (jitContext->m_commandType == JIT_COMMAND_COMPOUND_SELECT)) { // this is considered as successful execution JitStatisticsProvider::GetInstance().AddExecQuery(); return; @@ -205,6 +210,7 @@ static JitContext* GenerateJitContext(Query* query, const char* queryString, Jit ++u_sess->mot_cxt.jit_context_count; AddJitSourceContext(jitSource, jitContext); // register for cleanup due to DDL jitContext->m_jitSource = jitSource; + jitContext->m_queryString = jitSource->_query_string; // update statistics MOT_LOG_TRACE("Registered JIT context %p in JIT source %p for cleanup", jitContext, jitSource); JitStatisticsProvider& instance = JitStatisticsProvider::GetInstance(); @@ -331,7 +337,7 @@ extern int JitExecQuery( // make sure we can execute (guard against crash due to logical error) #ifdef MOT_JIT_DEBUG - MOT_LOG_DEBUG("Executing JIT context %p with query: %s", jitContext, jitContext->_queryString); + MOT_LOG_DEBUG("Executing JIT context %p with query: %s", jitContext, jitContext->m_queryString); #endif if (!jitContext->m_llvmFunction && !jitContext->m_tvmFunction) { MOT_REPORT_ERROR(MOT_ERROR_INVALID_ARG, @@ -371,12 +377,12 @@ extern int JitExecQuery( #ifdef MOT_JIT_DEBUG // in trace log-level we raise the log level to DEBUG on first few executions only bool firstExec = false; - if ((++jitContext->_exec_count <= 10) && MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_TRACE)) { + if ((++jitContext->m_execCount <= 2) && MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_TRACE)) { MOT_LOG_TRACE("Executing JIT context %p for the %dth time: %s", jitContext, - jitContext->_exec_count, - jitContext->_queryString); - MOT::SetLogComponentLogLevel("LiteExec", MOT::LogLevel::LL_DEBUG); + jitContext->m_execCount, + jitContext->m_queryString); + MOT::SetLogComponentLogLevel("JitExec", MOT::LogLevel::LL_DEBUG); firstExec = true; } #endif @@ -384,7 +390,7 @@ extern int JitExecQuery( // invoke the jitted function if (jitContext->m_llvmFunction != nullptr) { #ifdef MOT_JIT_DEBUG - MOT_LOG_DEBUG("Executing LLVM-jitted function %p: %s", jitContext->m_llvmFunction, jitContext->_queryString); + MOT_LOG_DEBUG("Executing LLVM-jitted function %p: %s", jitContext->m_llvmFunction, jitContext->m_queryString); #endif result = ((JitFunc)jitContext->m_llvmFunction)(jitContext->m_table, jitContext->m_index, @@ -401,14 +407,14 @@ extern int JitExecQuery( jitContext->m_innerEndIteratorKey); } else { #ifdef MOT_JIT_DEBUG - MOT_LOG_DEBUG("Executing TVM-jitted function %p: %s", jitContext->m_tvmFunction, jitContext->_queryString); + MOT_LOG_DEBUG("Executing TVM-jitted function %p: %s", jitContext->m_tvmFunction, jitContext->m_queryString); #endif result = JitExecTvmQuery(jitContext, params, slot, tuplesProcessed, scanEnded); } #ifdef MOT_JIT_DEBUG if (firstExec) { - MOT::SetLogComponentLogLevel("LiteExec", MOT::LogLevel::LL_TRACE); + MOT::SetLogComponentLogLevel("JitExec", MOT::LogLevel::LL_TRACE); } #endif diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_explain.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_explain.cpp index 24217657b2282a3534485c53289d5e29b8954c52..810bcad351ea386e6b8218c2ef3c48c406709e71 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_explain.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_explain.cpp @@ -32,10 +32,14 @@ namespace JitExec { DECLARE_LOGGER(JitExplain, JitExec) // Forward declarations -static void ExplainExpr(Query* query, Expr* expr); +static void ExplainExpr(Query* query, JitPlan* plan, JitExpr* jitExpr); +static void ExplainPointQueryPlan(Query* query, JitPointQueryPlan* plan, bool isSubQuery = false); +static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool isSubQuery = false); -static void ExplainConstExpr(Const* constExpr) +static void ExplainConstExpr(JitConstExpr* expr) { + MOT_ASSERT(expr->_source_expr->type == T_Const); + Const* constExpr = (Const*)expr->_source_expr; switch (constExpr->consttype) { case BOOLOID: MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[bool] %u", (unsigned)DatumGetBool(constExpr->constvalue)); @@ -131,54 +135,72 @@ static void ExplainRealColumnName(const Query* query, int tableRefId, int column MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "UnknownColumn"); } -static void ExplainVarExpr(Query* query, const Var* varExpr) +static void ExplainVarExpr(Query* query, JitVarExpr* expr) { - int columnId = varExpr->varattno; - int tableRefId = varExpr->varno; - ExplainRealColumnName(query, tableRefId, columnId); -} - -static void ExplainParamExpr(const Param* paramExpr) -{ - MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "$%d", paramExpr->paramid); + MOT_ASSERT((expr->_source_expr->type == T_Var) || (expr->_source_expr->type == T_RelabelType)); + Var* varExpr = nullptr; + if (expr->_source_expr->type == T_Var) { + varExpr = (Var*)expr->_source_expr; + } else if (expr->_source_expr->type == T_RelabelType) { + RelabelType* relabelType = (RelabelType*)expr->_source_expr; + Expr* subExpr = relabelType->arg; + if (subExpr->type == T_Var) { + varExpr = (Var*)subExpr; + } + } + if (varExpr != nullptr) { + int columnId = varExpr->varattno; + int tableRefId = varExpr->varno; + ExplainRealColumnName(query, tableRefId, columnId); + } else { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[var]"); + } } -static void ExplainRelabelExpr(Query* query, RelabelType* relabelType) +static void ExplainParamExpr(JitParamExpr* expr) { - Expr* expr = (Expr*)relabelType->arg; - if (expr->type == T_Param) { - ExplainParamExpr((Param*)expr); - } else if (expr->type == T_Var) { - ExplainVarExpr(query, (Var*)expr); + MOT_ASSERT((expr->_source_expr->type == T_Param) || (expr->_source_expr->type == T_RelabelType)); + Param* paramExpr = nullptr; + if (expr->_source_expr->type == T_Param) { + paramExpr = (Param*)expr->_source_expr; + } else if (expr->_source_expr->type == T_RelabelType) { + RelabelType* relabelType = (RelabelType*)expr->_source_expr; + Expr* subExpr = relabelType->arg; + if (subExpr->type == T_Param) { + paramExpr = (Param*)subExpr; + } + } + if (paramExpr != nullptr) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "$%d", paramExpr->paramid); } else { - MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "RelabelExpr"); + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[param]"); } } #define APPLY_UNARY_OPERATOR(funcid, name) \ case funcid: \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, #name "("); \ - ExplainExpr(query, args[0]); \ + ExplainExpr(query, plan, expr->_args[0]); \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); \ break; #define APPLY_BINARY_OPERATOR(funcid, name) \ case funcid: \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, #name "("); \ - ExplainExpr(query, args[0]); \ + ExplainExpr(query, plan, expr->_args[0]); \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); \ - ExplainExpr(query, args[1]); \ + ExplainExpr(query, plan, expr->_args[1]); \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); \ break; #define APPLY_TERNARY_OPERATOR(funcid, name) \ case funcid: \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, #name "("); \ - ExplainExpr(query, args[0]); \ + ExplainExpr(query, plan, expr->_args[0]); \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); \ - ExplainExpr(query, args[1]); \ + ExplainExpr(query, plan, expr->_args[1]); \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); \ - ExplainExpr(query, args[2]); \ + ExplainExpr(query, plan, expr->_args[2]); \ MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); \ break; @@ -186,85 +208,89 @@ static void ExplainRelabelExpr(Query* query, RelabelType* relabelType) #define APPLY_BINARY_CAST_OPERATOR(funcid, name) APPLY_BINARY_OPERATOR(funcid, name) #define APPLY_TERNARY_CAST_OPERATOR(funcid, name) APPLY_TERNARY_OPERATOR(funcid, name) -static void ExplainOpExpr(Query* query, const OpExpr* opExpr) +static void ExplainOpExpr(Query* query, JitPlan* plan, JitOpExpr* expr) { - Expr* args[3] = {nullptr, nullptr, nullptr}; - int argNum = 0; - - // process operator arguments (each one is an expression by itself) - ListCell* lc = nullptr; - - foreach (lc, opExpr->args) { - args[argNum] = (Expr*)lfirst(lc); - if (++argNum == 3) { - break; - } - } - // explain the operator - switch (opExpr->opfuncid) { + switch (expr->_op_func_id) { APPLY_OPERATORS() default: - MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[op_%u]", opExpr->opfuncid); + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[op_%u]", expr->_op_func_id); break; } } -static void ExplainFuncExpr(Query* query, const FuncExpr* funcExpr) +static void ExplainFuncExpr(Query* query, JitPlan* plan, JitFuncExpr* expr) { - Expr* args[3] = {nullptr, nullptr, nullptr}; - int argNum = 0; - - // process operator arguments (each one is an expression by itself) - ListCell* lc = nullptr; - - foreach (lc, funcExpr->args) { - args[argNum] = (Expr*)lfirst(lc); - if (++argNum == 3) { - break; - } - } - // explain the function - switch (funcExpr->funcid) { + switch (expr->_func_id) { APPLY_OPERATORS() default: - MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[func_%d]", funcExpr->funcid); + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[func_%d]", expr->_func_id); break; } } -static void ExplainExpr(Query* query, Expr* expr) +#undef APPLY_UNARY_OPERATOR +#undef APPLY_BINARY_OPERATOR +#undef APPLY_TERNARY_OPERATOR +#undef APPLY_UNARY_CAST_OPERATOR +#undef APPLY_BINARY_CAST_OPERATOR +#undef APPLY_TERNARY_CAST_OPERATOR + +static void ExplainSubLinkExpr(Query* query, JitPlan* plan, JitSubLinkExpr* subLinkExpr) +{ + // currently we support only one sub-query (so we don't use sub-query plan index) + if ((plan != nullptr) && (plan->_plan_type == JIT_PLAN_COMPOUND)) { + JitCompoundPlan* compoundPlan = (JitCompoundPlan*)plan; + SubLink* subLink = (SubLink*)subLinkExpr->_source_expr; + Query* subQuery = (Query*)subLink->subselect; + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "["); + JitPlan* subQueryPlan = compoundPlan->_sub_query_plans[subLinkExpr->_sub_query_index]; + if (subQueryPlan->_plan_type == JIT_PLAN_POINT_QUERY) { + ExplainPointQueryPlan(subQuery, (JitPointQueryPlan*)subQueryPlan, true); + } else if (subQueryPlan->_plan_type == JIT_PLAN_RANGE_SCAN) { + ExplainRangeSelectPlan(subQuery, (JitRangeSelectPlan*)subQueryPlan, true); + } else { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "sub-query"); + } + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "]"); + } else { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[sub-query]"); + } +} + +static void ExplainExpr(Query* query, JitPlan* plan, JitExpr* expr) { - switch (expr->type) { - case T_Const: - ExplainConstExpr((Const*)expr); + switch (expr->_expr_type) { + case JIT_EXPR_TYPE_CONST: + ExplainConstExpr((JitConstExpr*)expr); break; - case T_Var: - ExplainVarExpr(query, (Var*)expr); + case JIT_EXPR_TYPE_VAR: + ExplainVarExpr(query, (JitVarExpr*)expr); break; - case T_Param: - ExplainParamExpr((Param*)expr); + case JIT_EXPR_TYPE_PARAM: + ExplainParamExpr((JitParamExpr*)expr); break; - case T_OpExpr: - ExplainOpExpr(query, (OpExpr*)expr); + case JIT_EXPR_TYPE_OP: + ExplainOpExpr(query, plan, (JitOpExpr*)expr); break; - case T_FuncExpr: - ExplainFuncExpr(query, (FuncExpr*)expr); + case JIT_EXPR_TYPE_FUNC: + ExplainFuncExpr(query, plan, (JitFuncExpr*)expr); break; - case T_RelabelType: - ExplainRelabelExpr(query, (RelabelType*)expr); + case JIT_EXPR_TYPE_SUBLINK: + ExplainSubLinkExpr(query, plan, (JitSubLinkExpr*)expr); break; default: MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "[expr]"); + break; } } @@ -286,23 +312,31 @@ static const char* JitWhereOperatorClassToString(JitWhereOperatorClass opClass) } } -static void ExplainFilterArray(Query* query, int indent, JitFilterArray* filterArray) +static void ExplainFilterArray( + Query* query, JitPlan* plan, int indent, JitFilterArray* filterArray, bool isSubQuery = false) { - MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sFILTER ON (", indent, ""); + if (!isSubQuery) { + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sFILTER ON (", indent, ""); + } else { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " FILTER ON ("); + } for (int i = 0; i < filterArray->_filter_count; ++i) { - ExplainExpr(query, filterArray->_scan_filters[i]._lhs_operand->_source_expr); + ExplainExpr(query, plan, filterArray->_scan_filters[i]._lhs_operand); JitWhereOperatorClass opClass = ClassifyWhereOperator(filterArray->_scan_filters[i]._filter_op); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " %s ", JitWhereOperatorClassToString(opClass)); - ExplainExpr(query, filterArray->_scan_filters[i]._rhs_operand->_source_expr); + ExplainExpr(query, plan, filterArray->_scan_filters[i]._rhs_operand); if (i < (filterArray->_filter_count - 1)) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " AND "); } } MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); - MOT_LOG_END(MOT::LogLevel::LL_TRACE); + if (!isSubQuery) { + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } } -static void ExplainExprArray(Query* query, JitColumnExprArray* exprArray, const char* sep, bool forSelect = false) +static void ExplainExprArray( + Query* query, JitPlan* plan, JitColumnExprArray* exprArray, const char* sep, bool forSelect = false) { for (int i = 0; i < exprArray->_count; ++i) { if (!forSelect) { @@ -310,35 +344,35 @@ static void ExplainExprArray(Query* query, JitColumnExprArray* exprArray, const "%s = ", exprArray->_exprs[i]._table->GetFieldName(exprArray->_exprs[i]._table_column_id)); } - ExplainExpr(query, exprArray->_exprs[i]._expr->_source_expr); + ExplainExpr(query, plan, exprArray->_exprs[i]._expr); if (i < (exprArray->_count - 1)) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, sep); } } } -static void ExplainInsertExprArray(Query* query, int indent, JitColumnExprArray* exprArray) +static void ExplainInsertExprArray(Query* query, JitPlan* plan, int indent, JitColumnExprArray* exprArray) { MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sVALUES (", indent, ""); - ExplainExprArray(query, exprArray, ", "); + ExplainExprArray(query, plan, exprArray, ", "); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); MOT_LOG_END(MOT::LogLevel::LL_TRACE); } -static void ExplainUpdateExprArray(Query* query, int indent, JitColumnExprArray* exprArray) +static void ExplainUpdateExprArray(Query* query, JitPlan* plan, int indent, JitColumnExprArray* exprArray) { MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sSET (", indent, ""); - ExplainExprArray(query, exprArray, ", "); + ExplainExprArray(query, plan, exprArray, ", "); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); MOT_LOG_END(MOT::LogLevel::LL_TRACE); } -static void ExplainSelectExprArray(Query* query, JitSelectExprArray* exprArray) +static void ExplainSelectExprArray(Query* query, JitPlan* plan, JitSelectExprArray* exprArray) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "("); for (int i = 0; i < exprArray->_count; ++i) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%%%d = ", exprArray->_exprs[i]._tuple_column_id); - ExplainExpr(query, exprArray->_exprs[i]._column_expr->_source_expr); + ExplainExpr(query, plan, (JitExpr*)exprArray->_exprs[i]._column_expr); if (i < (exprArray->_count - 1)) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); } @@ -346,58 +380,76 @@ static void ExplainSelectExprArray(Query* query, JitSelectExprArray* exprArray) MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); } -static void ExplainSearchExprArray(Query* query, int indent, JitColumnExprArray* exprArray) +static void ExplainSearchExprArray( + Query* query, JitPlan* plan, int indent, JitColumnExprArray* exprArray, bool isSubQuery) { - MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sWHERE (", indent, ""); - ExplainExprArray(query, exprArray, " AND "); + if (!isSubQuery) { + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sWHERE (", indent, ""); + } else { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " WHERE ("); + } + ExplainExprArray(query, plan, exprArray, " AND ", false); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); - MOT_LOG_END(MOT::LogLevel::LL_TRACE); + if (!isSubQuery) { + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } } static void ExplainInsertPlan(Query* query, JitInsertPlan* plan) { MOT_LOG_TRACE("[Plan] INSERT into table %s", plan->_table->GetTableName().c_str()); - ExplainInsertExprArray(query, 2, &plan->_insert_exprs); + ExplainInsertExprArray(query, (JitPlan*)plan, 2, &plan->_insert_exprs); } -static void ExplainUpdateQueryPlan(Query* query, int indent, JitUpdatePlan* plan) +static void ExplainUpdateQueryPlan(Query* query, JitUpdatePlan* plan, int indent) { MOT_LOG_TRACE("%*sUPDATE table %s:", indent, "", plan->_query._table->GetTableName().c_str()); - ExplainUpdateExprArray(query, indent + 2, &plan->_update_exprs); + ExplainUpdateExprArray(query, (JitPlan*)plan, indent + 2, &plan->_update_exprs); } -static void ExplainDeleteQueryPlan(int indent, const JitDeletePlan* plan) +static void ExplainDeleteQueryPlan(JitDeletePlan* plan, int indent) { MOT_LOG_TRACE("%*sDELETE from table %s:", indent, "", plan->_query._table->GetTableName().c_str()); } -static void ExplainSelectQueryPlan(Query* query, int indent, JitSelectPlan* plan) +static void ExplainSelectQueryPlan(Query* query, JitSelectPlan* plan, int indent, bool isSubQuery) { - MOT_LOG_BEGIN( - MOT::LogLevel::LL_TRACE, "%*sSELECT from table %s:", indent, "", plan->_query._table->GetTableName().c_str()); - ExplainSelectExprArray(query, &plan->_select_exprs); - MOT_LOG_END(MOT::LogLevel::LL_TRACE); + if (isSubQuery) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " SELECT from table %s:", plan->_query._table->GetTableName().c_str()); + } else { + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, + "%*sSELECT from table %s:", + indent, + "", + plan->_query._table->GetTableName().c_str()); + } + ExplainSelectExprArray(query, (JitPlan*)plan, &plan->_select_exprs); + if (!isSubQuery) { + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } } -static void ExplainPointQueryPlan(Query* query, JitPointQueryPlan* plan) +static void ExplainPointQueryPlan(Query* query, JitPointQueryPlan* plan, bool isSubQuery /* = false */) { - MOT_LOG_TRACE("[Plan] Point Query", plan->_query._table->GetTableName().c_str()); + if (!isSubQuery) { + MOT_LOG_TRACE("[Plan] Point Query"); + } int indent = 0; if (plan->_query._filters._filter_count > 0) { - ExplainFilterArray(query, indent, &plan->_query._filters); + ExplainFilterArray(query, (JitPlan*)plan, indent, &plan->_query._filters, isSubQuery); indent += 2; } switch (plan->_command_type) { case JIT_COMMAND_UPDATE: - ExplainUpdateQueryPlan(query, indent + 2, (JitUpdatePlan*)plan); + ExplainUpdateQueryPlan(query, (JitUpdatePlan*)plan, indent + 2); break; case JIT_COMMAND_DELETE: - ExplainDeleteQueryPlan(indent + 2, (JitDeletePlan*)plan); + ExplainDeleteQueryPlan((JitDeletePlan*)plan, indent + 2); break; case JIT_COMMAND_SELECT: - ExplainSelectQueryPlan(query, indent + 2, (JitSelectPlan*)plan); + ExplainSelectQueryPlan(query, (JitSelectPlan*)plan, indent + 2, isSubQuery); break; default: @@ -405,10 +457,10 @@ static void ExplainPointQueryPlan(Query* query, JitPointQueryPlan* plan) return; } - ExplainSearchExprArray(query, indent + 4, &plan->_query._search_exprs); + ExplainSearchExprArray(query, (JitPlan*)plan, indent + 4, &plan->_query._search_exprs, isSubQuery); } -static void ExplainIndexExprArray(Query* query, JitIndexScan* indexScan, int count) +static void ExplainIndexExprArray(Query* query, JitPlan* plan, JitIndexScan* indexScan, int count) { for (int i = 0; i < count; ++i) { if (indexScan->_search_exprs._exprs[i]._join_expr) { @@ -417,7 +469,7 @@ static void ExplainIndexExprArray(Query* query, JitIndexScan* indexScan, int cou MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%s = ", indexScan->_table->GetFieldName(indexScan->_search_exprs._exprs[i]._table_column_id)); - ExplainExpr(query, indexScan->_search_exprs._exprs[i]._expr->_source_expr); + ExplainExpr(query, plan, indexScan->_search_exprs._exprs[i]._expr); if (indexScan->_search_exprs._exprs[i]._join_expr) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); } @@ -427,29 +479,30 @@ static void ExplainIndexExprArray(Query* query, JitIndexScan* indexScan, int cou } } -static void ExplainIndexOpenExpr(Query* query, JitIndexScan* indexScan, int index, JitWhereOperatorClass opClass) +static void ExplainIndexOpenExpr( + Query* query, JitPlan* plan, JitIndexScan* indexScan, int index, JitWhereOperatorClass opClass) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%s", indexScan->_table->GetFieldName(indexScan->_search_exprs._exprs[index]._table_column_id)); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " %s ", JitWhereOperatorClassToString(opClass)); - ExplainExpr(query, indexScan->_search_exprs._exprs[index]._expr->_source_expr); + ExplainExpr(query, plan, indexScan->_search_exprs._exprs[index]._expr); } -static void ExplainIndexExprArray(Query* query, JitIndexScan* indexScan) +static void ExplainIndexExprArray(Query* query, JitPlan* plan, JitIndexScan* indexScan) { if ((indexScan->_scan_type == JIT_INDEX_SCAN_CLOSED) || (indexScan->_scan_type == JIT_INDEX_SCAN_POINT)) { - ExplainIndexExprArray(query, indexScan, indexScan->_search_exprs._count); + ExplainIndexExprArray(query, plan, indexScan, indexScan->_search_exprs._count); } else if (indexScan->_scan_type == JIT_INDEX_SCAN_SEMI_OPEN) { - ExplainIndexExprArray(query, indexScan, indexScan->_search_exprs._count - 1); + ExplainIndexExprArray(query, plan, indexScan, indexScan->_search_exprs._count - 1); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " AND "); - ExplainIndexOpenExpr(query, indexScan, indexScan->_search_exprs._count - 1, indexScan->_last_dim_op1); + ExplainIndexOpenExpr(query, plan, indexScan, indexScan->_search_exprs._count - 1, indexScan->_last_dim_op1); } else if (indexScan->_scan_type == JIT_INDEX_SCAN_OPEN) { - ExplainIndexExprArray(query, indexScan, indexScan->_search_exprs._count - 2); + ExplainIndexExprArray(query, plan, indexScan, indexScan->_search_exprs._count - 2); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " AND "); - ExplainIndexOpenExpr(query, indexScan, indexScan->_search_exprs._count - 2, indexScan->_last_dim_op1); + ExplainIndexOpenExpr(query, plan, indexScan, indexScan->_search_exprs._count - 2, indexScan->_last_dim_op1); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " AND "); - ExplainIndexOpenExpr(query, indexScan, indexScan->_search_exprs._count - 1, indexScan->_last_dim_op2); + ExplainIndexOpenExpr(query, plan, indexScan, indexScan->_search_exprs._count - 1, indexScan->_last_dim_op2); } } @@ -494,33 +547,46 @@ static const char* JitIndexScanDirectionToString(JitIndexScanDirection scanDirec } } -static void ExplainIndexScan(Query* query, int indent, JitIndexScan* indexScan, const char* scanName = "") +static void ExplainIndexScan(Query* query, JitPlan* plan, int indent, JitIndexScan* indexScan, + const char* scanName = "", bool isSubQuery = false) { if (indexScan->_filters._filter_count > 0) { - ExplainFilterArray(query, indent, &indexScan->_filters); + ExplainFilterArray(query, plan, indent, &indexScan->_filters, isSubQuery); indent += 2; } MOT::Index* index = indexScan->_table->GetIndex(indexScan->_index_id); - MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, - "%*s%sSCAN %s index %s (%s, %s) ON (", - indent, - "", - scanName, - index->GetName().c_str(), - JitQuerySortOrderToString(indexScan->_sort_order), - JitIndexScanTypeToString(indexScan->_scan_type), - JitIndexScanDirectionToString(indexScan->_scan_direction)); - - ExplainIndexExprArray(query, indexScan); + if (isSubQuery) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, + "%s SCAN %s index %s (%s, %s) ON (", + scanName, + index->GetName().c_str(), + JitQuerySortOrderToString(indexScan->_sort_order), + JitIndexScanTypeToString(indexScan->_scan_type), + JitIndexScanDirectionToString(indexScan->_scan_direction)); + } else { + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, + "%*s%s SCAN %s index %s (%s, %s) ON (", + indent, + "", + scanName, + index->GetName().c_str(), + JitQuerySortOrderToString(indexScan->_sort_order), + JitIndexScanTypeToString(indexScan->_scan_type), + JitIndexScanDirectionToString(indexScan->_scan_direction)); + } + + ExplainIndexExprArray(query, plan, indexScan); MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); - MOT_LOG_END(MOT::LogLevel::LL_TRACE); + if (!isSubQuery) { + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } } static void ExplainRangeUpdatePlan(Query* query, JitRangeUpdatePlan* plan) { MOT_LOG_TRACE("[Plan] Range UPDATE table %s:", plan->_index_scan._table->GetTableName().c_str()); - ExplainUpdateExprArray(query, 2, &plan->_update_exprs); - ExplainIndexScan(query, 2, &plan->_index_scan); + ExplainUpdateExprArray(query, (JitPlan*)plan, 2, &plan->_update_exprs); + ExplainIndexScan(query, (JitPlan*)plan, 2, &plan->_index_scan); } static const char* JitAggregateOperatorToString(JitAggregateOperator aggregateOp) @@ -541,14 +607,21 @@ static const char* JitAggregateOperatorToString(JitAggregateOperator aggregateOp } } -static void ExplainAggregateOperator(int indent, const JitAggregate* aggregate) +static void ExplainAggregateOperator(int indent, const JitAggregate* aggregate, bool isSubQuery = false) { - MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, - "%*s%s [op %d](", - indent, - "", - JitAggregateOperatorToString(aggregate->_aggreaget_op), - aggregate->_func_id); + if (isSubQuery) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, + "%s [op %d](", + JitAggregateOperatorToString(aggregate->_aggreaget_op), + aggregate->_func_id); + } else { + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, + "%*s%s [op %d](", + indent, + "", + JitAggregateOperatorToString(aggregate->_aggreaget_op), + aggregate->_func_id); + } if (aggregate->_distinct) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "DISTINCT("); } @@ -559,29 +632,45 @@ static void ExplainAggregateOperator(int indent, const JitAggregate* aggregate) if (aggregate->_distinct) { MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); } - MOT_LOG_END(MOT::LogLevel::LL_TRACE); + if (!isSubQuery) { + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } } -static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan) +static void ExplainRangeSelectPlan(Query* query, JitRangeSelectPlan* plan, bool isSubQuery /* = false */) { - MOT_LOG_TRACE("[Plan] Range SELECT from table %s:", plan->_index_scan._table->GetTableName().c_str()); + if (isSubQuery) { + MOT_LOG_APPEND( + MOT::LogLevel::LL_TRACE, "Range SELECT from table %s:", plan->_index_scan._table->GetTableName().c_str()); + } else { + MOT_LOG_TRACE("[Plan] Range SELECT from table %s:", plan->_index_scan._table->GetTableName().c_str()); + } int indent = 0; if (plan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) { indent += 2; - ExplainAggregateOperator(indent, &plan->_aggregate); + ExplainAggregateOperator(indent, &plan->_aggregate, isSubQuery); } if (plan->_limit_count > 0) { - indent += 2; - MOT_LOG_TRACE("%*sLIMIT %d", indent, "", plan->_limit_count); + if (isSubQuery) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " LIMIT %d", plan->_limit_count); + } else { + indent += 2; + MOT_LOG_TRACE("%*sLIMIT %d", indent, "", plan->_limit_count); + } } if (plan->_aggregate._aggreaget_op == JIT_AGGREGATE_NONE) { - indent += 2; - MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sSELECT", indent, ""); - ExplainSelectExprArray(query, &plan->_select_exprs); - MOT_LOG_END(MOT::LogLevel::LL_TRACE); + if (isSubQuery) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, " SELECT"); + ExplainSelectExprArray(query, (JitPlan*)plan, &plan->_select_exprs); + } else { + indent += 2; + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sSELECT", indent, ""); + ExplainSelectExprArray(query, (JitPlan*)plan, &plan->_select_exprs); + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } } - ExplainIndexScan(query, indent + 2, &plan->_index_scan); + ExplainIndexScan(query, (JitPlan*)plan, indent + 2, &plan->_index_scan, "", isSubQuery); } static void ExplainRangeScanPlan(Query* query, JitRangeScanPlan* plan) @@ -626,15 +715,30 @@ static void ExplainJoinPlan(Query* query, JitJoinPlan* plan) } else { indent += 2; MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, "%*sSELECT", indent, ""); - ExplainSelectExprArray(query, &plan->_select_exprs); + ExplainSelectExprArray(query, (JitPlan*)plan, &plan->_select_exprs); MOT_LOG_END(MOT::LogLevel::LL_TRACE); } if (plan->_limit_count > 0) { indent += 2; MOT_LOG_TRACE("%*sLIMIT %d", indent, "", plan->_limit_count); } - ExplainIndexScan(query, indent + 2, &plan->_outer_scan, "OUTER "); - ExplainIndexScan(query, indent + 2, &plan->_inner_scan, "INNER "); + ExplainIndexScan(query, (JitPlan*)plan, indent + 2, &plan->_outer_scan, "OUTER "); + ExplainIndexScan(query, (JitPlan*)plan, indent + 2, &plan->_inner_scan, "INNER "); +} + +static void ExplainCompoundPlan(Query* query, JitCompoundPlan* plan) +{ + MOT_LOG_TRACE("[Plan] Compound Query on table %s", plan->_outer_query_plan->_query._table->GetTableName().c_str()); + int indent = 0; + if (plan->_outer_query_plan->_query._filters._filter_count > 0) { + ExplainFilterArray(query, (JitPlan*)plan, indent, &plan->_outer_query_plan->_query._filters, false); + indent += 2; + } + if (plan->_command_type == JIT_COMMAND_SELECT) { + ExplainSelectQueryPlan(query, (JitSelectPlan*)plan->_outer_query_plan, indent + 2, false); + } + + ExplainSearchExprArray(query, (JitPlan*)plan, indent + 4, &plan->_outer_query_plan->_query._search_exprs, false); } extern void JitExplainPlan(Query* query, JitPlan* plan) @@ -657,6 +761,10 @@ extern void JitExplainPlan(Query* query, JitPlan* plan) ExplainJoinPlan(query, (JitJoinPlan*)plan); break; + case JIT_PLAN_COMPOUND: + ExplainCompoundPlan(query, (JitCompoundPlan*)plan); + break; + case JIT_PLAN_INVALID: default: break; diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.cpp index d8f428e4ff55eb61c7e58bd9cdde5905b552afdf..cf9eeed924d2216e207f7f7d01692f54778a4379 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.cpp @@ -1356,4 +1356,42 @@ void writeTupleDatum(TupleTableSlot* slot, int tuple_colid, Datum datum) slot->tts_values[tuple_colid], slot->tts_isnull[tuple_colid]); } + +Datum SelectSubQueryResult(int subQueryIndex) +{ + JitExec::JitContext* jitContext = u_sess->mot_cxt.jit_context; + return readTupleDatum(jitContext->m_subQueryData[subQueryIndex].m_slot, 0, 0); +} + +void CopyAggregateToSubQueryResult(int subQueryIndex) +{ + MOT_LOG_DEBUG("Copying aggregate datum to sub-query %d slot", subQueryIndex); + JitExec::JitContext* jitContext = u_sess->mot_cxt.jit_context; + writeTupleDatum(jitContext->m_subQueryData[subQueryIndex].m_slot, 0, jitContext->m_aggValue); +} + +TupleTableSlot* GetSubQuerySlot(int subQueryIndex) +{ + return u_sess->mot_cxt.jit_context->m_subQueryData[subQueryIndex].m_slot; +} + +MOT::Table* GetSubQueryTable(int subQueryIndex) +{ + return u_sess->mot_cxt.jit_context->m_subQueryData[subQueryIndex].m_table; +} + +MOT::Index* GetSubQueryIndex(int subQueryIndex) +{ + return u_sess->mot_cxt.jit_context->m_subQueryData[subQueryIndex].m_index; +} + +MOT::Key* GetSubQuerySearchKey(int subQueryIndex) +{ + return u_sess->mot_cxt.jit_context->m_subQueryData[subQueryIndex].m_searchKey; +} + +MOT::Key* GetSubQueryEndIteratorKey(int subQueryIndex) +{ + return u_sess->mot_cxt.jit_context->m_subQueryData[subQueryIndex].m_endIteratorKey; +} } // extern "C" diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.h b/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.h index 4cf3f462a3d0df419401e09a882c2b05cd73c8fe..15f402c442c99bc6be14d69482d3592cfb448f15 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_helpers.h @@ -395,10 +395,10 @@ void destroyStateIterators(int inner_scan); /** * @brief Sets the stateful range scan ended flag. - * @param scan_ended Non-zero if the stateful range scan ended. - * @param inner_scan Specifies whether this is an inner scan iterator in a JOIN query. + * @param scanEnded Non-zero if the stateful range scan ended. + * @param innerScan Specifies whether this is an inner scan iterator in a JOIN query. */ -void setStateScanEndFlag(int scan_ended, int inner_scan); +void setStateScanEndFlag(int scanEnded, int innerScan); /** * @brief Retrieves the value of the stateful range scan ended flag. @@ -501,10 +501,10 @@ void destroyDistinctSet(int element_type); /** * @brief Resets a tuple datum to zero value. * @param slot The tuple. - * @param tuple_colid The zero-based column index of the tuple in which to store the zero value. - * @param zero_type The Oid of the zero type. + * @param tupleColumnId The zero-based column index of the tuple in which to store the zero value. + * @param zeroType The Oid of the zero type. */ -void resetTupleDatum(TupleTableSlot* slot, int tuple_colid, int zero_type); +void resetTupleDatum(TupleTableSlot* slot, int tupleColumnId, int zeroType); /** * @brief Reads a tuple datum. @@ -523,6 +523,33 @@ Datum readTupleDatum(TupleTableSlot* slot, int tuple_colid, int arg_pos); */ void writeTupleDatum(TupleTableSlot* slot, int tuple_colid, Datum datum); +/** + * @brief Reads the datum result of a sub-query. + * @param subQueryIndex The sub-query index. + * @return The sub-query result. + */ +Datum SelectSubQueryResult(int subQueryIndex); + +/** + * @brief Copies the aggregate result to a sub-query slot. + * @param subQueryIndex The sub-query index. + */ +void CopyAggregateToSubQueryResult(int subQueryIndex); + +/** @brief Retrieves the result slot of a sub-query (LLVM only). */ +TupleTableSlot* GetSubQuerySlot(int subQueryIndex); + +/** @brief Retrieves the table of a sub-query (LLVM only). */ +MOT::Table* GetSubQueryTable(int subQueryIndex); + +/** @brief Retrieves the index of a sub-query (LLVM only). */ +MOT::Index* GetSubQueryIndex(int subQueryIndex); + +/** @brief Retrieves the search-key of a sub-query (LLVM only). */ +MOT::Key* GetSubQuerySearchKey(int subQueryIndex); + +/** @brief Retrieves the end-iterator key of a sub-query (LLVM only). */ +MOT::Key* GetSubQueryEndIteratorKey(int subQueryIndex); } // extern "C" #endif diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp index 13bfef0208abcc26615b285eb2f2b035efdd4b9f..52fe6d0dce904c193ceb54fbc16eb77fe2349b18 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_llvm_exec.cpp @@ -69,6 +69,7 @@ using namespace dorado; // forward declarations struct JitLlvmCodeGenContext; +static void DestroyCodeGenContext(JitLlvmCodeGenContext* ctx); static bool ProcessJoinOpExpr( JitLlvmCodeGenContext* ctx, const OpExpr* op_expr, int* column_count, int* column_array, int* max_arg); static bool ProcessJoinBoolExpr( @@ -198,6 +199,15 @@ struct JitLlvmCodeGenContext { llvm::Constant* readTupleDatumFunc; llvm::Constant* writeTupleDatumFunc; + llvm::Constant* selectSubQueryResultFunc; + llvm::Constant* copyAggregateToSubQueryResultFunc; + + llvm::Constant* GetSubQuerySlotFunc; + llvm::Constant* GetSubQueryTableFunc; + llvm::Constant* GetSubQueryIndexFunc; + llvm::Constant* GetSubQuerySearchKeyFunc; + llvm::Constant* GetSubQueryEndIteratorKeyFunc; + // builtins #define APPLY_UNARY_OPERATOR(funcid, name) llvm::Constant* _builtin_##name; #define APPLY_BINARY_OPERATOR(funcid, name) llvm::Constant* _builtin_##name; @@ -233,9 +243,21 @@ struct JitLlvmCodeGenContext { llvm::Value* inner_key_value; llvm::Value* inner_end_iterator_key_value; + // sub-query data access (see JitContext::SubQueryData) + struct SubQueryData { + llvm::Value* m_slot; + llvm::Value* m_table; + llvm::Value* m_index; + llvm::Value* m_searchKey; + llvm::Value* m_endIteratorKey; + }; + uint64_t m_subQueryCount; + SubQueryData* m_subQueryData; + // compile context TableInfo _table_info; TableInfo _inner_table_info; + TableInfo* m_subQueryTableInfo; GsCodeGen* _code_gen; GsCodeGen::LlvmBuilder* _builder; @@ -243,8 +265,8 @@ struct JitLlvmCodeGenContext { }; /** @brief Gets a key from the execution context. */ -static llvm::Value* getExecContextKey( - JitLlvmCodeGenContext* ctx, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) +static llvm::Value* getExecContextKey(JitLlvmCodeGenContext* ctx, JitRangeIteratorType range_itr_type, + JitRangeScanType range_scan_type, int subQueryIndex) { llvm::Value* key = nullptr; if (range_scan_type == JIT_RANGE_SCAN_INNER) { @@ -253,16 +275,35 @@ static llvm::Value* getExecContextKey( } else { key = ctx->inner_key_value; } - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { if (range_itr_type == JIT_RANGE_ITERATOR_END) { key = ctx->end_iterator_key_value; } else { key = ctx->key_value; } + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + if (range_itr_type == JIT_RANGE_ITERATOR_END) { + key = ctx->m_subQueryData[subQueryIndex].m_endIteratorKey; + } else { + key = ctx->m_subQueryData[subQueryIndex].m_searchKey; + } } return key; } +llvm::Value* getExecContextIndex(JitLlvmCodeGenContext* ctx, JitRangeScanType rangeScanType, int subQueryIndex) +{ + llvm::Value* indexValue = nullptr; + if (rangeScanType == JIT_RANGE_SCAN_INNER) { + indexValue = ctx->inner_index_value; + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { + indexValue = ctx->index_value; + } else if (rangeScanType == JIT_RANGE_SCAN_SUB_QUERY) { + indexValue = ctx->m_subQueryData[subQueryIndex].m_index; + } + return indexValue; +} + /*--------------------------- Define LLVM Helper Prototypes ---------------------------*/ static llvm::Constant* defineFunction(llvm::Module* module, llvm::Type* ret_type, const char* name, ...) @@ -774,6 +815,47 @@ static void defineWriteTupleDatum(JitLlvmCodeGenContext* ctx, llvm::Module* modu nullptr); } +static void DefineSelectSubQueryResultFunc(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->selectSubQueryResultFunc = defineFunction(module, ctx->DATUM_T, "SelectSubQueryResult", ctx->INT32_T, nullptr); +} + +static void DefineCopyAggregateToSubQueryResultFunc(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->copyAggregateToSubQueryResultFunc = + defineFunction(module, ctx->VOID_T, "CopyAggregateToSubQueryResult", ctx->INT32_T, nullptr); +} + +static void DefineGetSubQuerySlot(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->GetSubQuerySlotFunc = + defineFunction(module, ctx->TupleTableSlotType->getPointerTo(), "GetSubQuerySlot", ctx->INT32_T, nullptr); +} + +static void DefineGetSubQueryTable(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->GetSubQueryTableFunc = + defineFunction(module, ctx->TableType->getPointerTo(), "GetSubQueryTable", ctx->INT32_T, nullptr); +} + +static void DefineGetSubQueryIndex(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->GetSubQueryIndexFunc = + defineFunction(module, ctx->IndexType->getPointerTo(), "GetSubQueryIndex", ctx->INT32_T, nullptr); +} + +static void DefineGetSubQuerySearchKey(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->GetSubQuerySearchKeyFunc = + defineFunction(module, ctx->KeyType->getPointerTo(), "GetSubQuerySearchKey", ctx->INT32_T, nullptr); +} + +static void DefineGetSubQueryEndIteratorKey(JitLlvmCodeGenContext* ctx, llvm::Module* module) +{ + ctx->GetSubQueryEndIteratorKeyFunc = + defineFunction(module, ctx->KeyType->getPointerTo(), "GetSubQueryEndIteratorKey", ctx->INT32_T, nullptr); +} + /*--------------------------- End of LLVM Helper Prototypes ---------------------------*/ /** @brief Define all LLVM prototypes. */ static void InitCodeGenContextFuncs(JitLlvmCodeGenContext* ctx) @@ -859,6 +941,15 @@ static void InitCodeGenContextFuncs(JitLlvmCodeGenContext* ctx) defineResetTupleDatum(ctx, module); defineReadTupleDatum(ctx, module); defineWriteTupleDatum(ctx, module); + + DefineSelectSubQueryResultFunc(ctx, module); + DefineCopyAggregateToSubQueryResultFunc(ctx, module); + + DefineGetSubQuerySlot(ctx, module); + DefineGetSubQueryTable(ctx, module); + DefineGetSubQueryIndex(ctx, module); + DefineGetSubQuerySearchKey(ctx, module); + DefineGetSubQueryEndIteratorKey(ctx, module); } #define APPLY_UNARY_OPERATOR(funcid, name) \ @@ -982,14 +1073,96 @@ static bool InitCodeGenContext(JitLlvmCodeGenContext* ctx, GsCodeGen* code_gen, return true; } +/** @brief Initializes a context for compilation. */ +static bool InitCompoundCodeGenContext(JitLlvmCodeGenContext* ctx, GsCodeGen* code_gen, GsCodeGen::LlvmBuilder* builder, + MOT::Table* table, MOT::Index* index, JitCompoundPlan* plan) +{ + // execute normal initialization + if (!InitCodeGenContext(ctx, code_gen, builder, table, index)) { + return false; + } + + // prepare sub-query table info + ctx->m_subQueryCount = plan->_sub_query_count; + uint32_t allocSize = sizeof(TableInfo) * ctx->m_subQueryCount; + ctx->m_subQueryTableInfo = (TableInfo*)MOT::MemSessionAlloc(allocSize); + if (ctx->m_subQueryTableInfo == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "JIT Compile", + "Failed to allocate %u bytes for %u sub-query table information objects in code-generation context", + allocSize, + (unsigned)ctx->m_subQueryCount); + DestroyTableInfo(&ctx->_table_info); + return false; + } + + // initialize sub-query table info + bool result = true; + for (uint32_t i = 0; i < ctx->m_subQueryCount; ++i) { + JitPlan* subPlan = plan->_sub_query_plans[i]; + MOT::Table* subTable = nullptr; + MOT::Index* subIndex = nullptr; + if (subPlan->_plan_type == JIT_PLAN_POINT_QUERY) { + subTable = ((JitSelectPlan*)subPlan)->_query._table; + subIndex = subTable->GetPrimaryIndex(); + } else if (subPlan->_plan_type == JIT_PLAN_RANGE_SCAN) { + subTable = ((JitRangeSelectPlan*)subPlan)->_index_scan._table; + subIndex = subTable->GetIndex(((JitRangeSelectPlan*)subPlan)->_index_scan._index_id); + } else { + MOT_REPORT_ERROR( + MOT_ERROR_INTERNAL, "JIT Compile", "Invalid sub-plan %u type: %d", i, (int)subPlan->_plan_type); + result = false; + } + if (result && !InitTableInfo(&ctx->m_subQueryTableInfo[i], subTable, subIndex)) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "JIT Compile", + "Failed to initialize sub-query table information for code-generation context"); + result = false; + } + if (!result) { + for (uint32_t j = 0; j < i; ++j) { + DestroyTableInfo(&ctx->m_subQueryTableInfo[j]); + } + MOT::MemSessionFree(ctx->m_subQueryTableInfo); + ctx->m_subQueryTableInfo = nullptr; + DestroyTableInfo(&ctx->_table_info); + return false; + } + } + + // prepare sub-query data array (for sub-query runtime context) + allocSize = sizeof(JitLlvmCodeGenContext::SubQueryData) * ctx->m_subQueryCount; + ctx->m_subQueryData = (JitLlvmCodeGenContext::SubQueryData*)MOT::MemSessionAlloc(allocSize); + if (ctx->m_subQueryData == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "JIT Compile", + "Failed to allocate %u bytes for %u sub-query data items in code-generation context", + allocSize, + (unsigned)ctx->m_subQueryCount); + DestroyCodeGenContext(ctx); + } + errno_t erc = memset_s(ctx->m_subQueryData, allocSize, 0, allocSize); + securec_check(erc, "\0", "\0"); + + return true; +} + /** @brief Destroys a code generation context. */ static void DestroyCodeGenContext(JitLlvmCodeGenContext* ctx) { DestroyTableInfo(&ctx->_table_info); DestroyTableInfo(&ctx->_inner_table_info); + for (uint32_t i = 0; i < ctx->m_subQueryCount; ++i) { + DestroyTableInfo(&ctx->m_subQueryTableInfo[i]); + } + if (ctx->m_subQueryData != nullptr) { + MOT::MemSessionFree(ctx->m_subQueryData); + ctx->m_subQueryData = nullptr; + } if (ctx->_code_gen != nullptr) { ctx->_code_gen->releaseResource(); delete ctx->_code_gen; + ctx->_code_gen = nullptr; } } @@ -1022,20 +1195,30 @@ static void AddInitKey(JitLlvmCodeGenContext* ctx, llvm::Value* key, llvm::Value } /** @brief Adds a call to initSearchKey(key, index). */ -static void AddInitSearchKey(JitLlvmCodeGenContext* ctx, JitRangeScanType range_scan_type) +static void AddInitSearchKey(JitLlvmCodeGenContext* ctx, JitRangeScanType rangeScanType, int subQueryIndex) { - if (range_scan_type == JIT_RANGE_SCAN_INNER) { + if (rangeScanType == JIT_RANGE_SCAN_INNER) { AddInitKey(ctx, ctx->inner_key_value, ctx->inner_index_value); - } else { + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { AddInitKey(ctx, ctx->key_value, ctx->index_value); + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { + AddInitKey(ctx, ctx->m_subQueryData[subQueryIndex].m_searchKey, ctx->m_subQueryData[subQueryIndex].m_index); } } /** @brief Adds a call to getColumnAt(table, colid). */ -static llvm::Value* AddGetColumnAt(JitLlvmCodeGenContext* ctx, int colid, JitRangeScanType range_scan_type) +static llvm::Value* AddGetColumnAt( + JitLlvmCodeGenContext* ctx, int colid, JitRangeScanType range_scan_type, int subQueryIndex = -1) { llvm::ConstantInt* colid_value = llvm::ConstantInt::get(ctx->INT32_T, colid, true); - llvm::Value* table = (range_scan_type == JIT_RANGE_SCAN_INNER) ? ctx->inner_table_value : ctx->table_value; + llvm::Value* table = nullptr; + if (range_scan_type == JIT_RANGE_SCAN_INNER) { + table = ctx->inner_table_value; + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { + table = ctx->table_value; + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + table = ctx->m_subQueryData[subQueryIndex].m_table; + } return AddFunctionCall(ctx, ctx->getColumnAtFunc, table, colid_value, nullptr); } @@ -1084,23 +1267,25 @@ static llvm::Value* AddWriteDatumColumn( /** @brief Adds a call to buildDatumKey(column, key, value, index_colid, offset, value). */ static void AddBuildDatumKey(JitLlvmCodeGenContext* ctx, llvm::Value* column, int index_colid, llvm::Value* value, - int value_type, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) + int value_type, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, int subQueryIndex = -1) { int offset = -1; int size = -1; - int inner_scan = (range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; - if (inner_scan) { + if (range_scan_type == JIT_RANGE_SCAN_INNER) { offset = ctx->_inner_table_info.m_indexColumnOffsets[index_colid]; size = ctx->_inner_table_info.m_index->GetLengthKeyFields()[index_colid]; - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { offset = ctx->_table_info.m_indexColumnOffsets[index_colid]; size = ctx->_table_info.m_index->GetLengthKeyFields()[index_colid]; + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + offset = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets[index_colid]; + size = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields()[index_colid]; } llvm::ConstantInt* colid_value = llvm::ConstantInt::get(ctx->INT32_T, index_colid, true); llvm::ConstantInt* offset_value = llvm::ConstantInt::get(ctx->INT32_T, offset, true); llvm::ConstantInt* value_type_value = llvm::ConstantInt::get(ctx->INT32_T, value_type, true); llvm::ConstantInt* size_value = llvm::ConstantInt::get(ctx->INT32_T, size, true); - llvm::Value* key_value = getExecContextKey(ctx, range_itr_type, range_scan_type); + llvm::Value* key_value = getExecContextKey(ctx, range_itr_type, range_scan_type, subQueryIndex); AddFunctionCall(ctx, ctx->buildDatumKeyFunc, column, @@ -1134,15 +1319,19 @@ static llvm::Value* AddWriteRow(JitLlvmCodeGenContext* ctx, llvm::Value* row) /** @brief Adds a call to searchRow(table, key, access_mode). */ static llvm::Value* AddSearchRow( - JitLlvmCodeGenContext* ctx, MOT::AccessType access_mode, JitRangeScanType range_scan_type) + JitLlvmCodeGenContext* ctx, MOT::AccessType access_mode, JitRangeScanType range_scan_type, int subQueryIndex) { llvm::Value* row = nullptr; llvm::ConstantInt* access_mode_value = llvm::ConstantInt::get(ctx->INT32_T, access_mode, true); if (range_scan_type == JIT_RANGE_SCAN_INNER) { row = AddFunctionCall( ctx, ctx->searchRowFunc, ctx->inner_table_value, ctx->inner_key_value, access_mode_value, nullptr); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { row = AddFunctionCall(ctx, ctx->searchRowFunc, ctx->table_value, ctx->key_value, access_mode_value, nullptr); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitLlvmCodeGenContext::SubQueryData* subQueryData = &ctx->m_subQueryData[subQueryIndex]; + row = AddFunctionCall( + ctx, ctx->searchRowFunc, subQueryData->m_table, subQueryData->m_searchKey, access_mode_value, nullptr); } return row; } @@ -1189,13 +1378,13 @@ static void AddExecStoreVirtualTuple(JitLlvmCodeGenContext* ctx) } /** @brief Adds a call to selectColumn(table, row, slot, colid, column_count). */ -static bool AddSelectColumn( - JitLlvmCodeGenContext* ctx, llvm::Value* row, int table_colid, int tuple_colid, JitRangeScanType range_scan_type) +static bool AddSelectColumn(JitLlvmCodeGenContext* ctx, llvm::Value* row, int tableColumnId, int tupleColumnId, + JitRangeScanType rangeScanType, int subQueryIndex) { - llvm::ConstantInt* table_colid_value = llvm::ConstantInt::get(ctx->INT32_T, table_colid, true); - llvm::ConstantInt* tuple_colid_value = llvm::ConstantInt::get(ctx->INT32_T, tuple_colid, true); + llvm::ConstantInt* table_colid_value = llvm::ConstantInt::get(ctx->INT32_T, tableColumnId, true); + llvm::ConstantInt* tuple_colid_value = llvm::ConstantInt::get(ctx->INT32_T, tupleColumnId, true); llvm::Value* value = nullptr; - if (range_scan_type == JIT_RANGE_SCAN_INNER) { + if (rangeScanType == JIT_RANGE_SCAN_INNER) { value = AddFunctionCall(ctx, ctx->selectColumnFunc, ctx->inner_table_value, @@ -1204,7 +1393,7 @@ static bool AddSelectColumn( table_colid_value, tuple_colid_value, nullptr); - } else { + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { value = AddFunctionCall(ctx, ctx->selectColumnFunc, ctx->table_value, @@ -1213,6 +1402,16 @@ static bool AddSelectColumn( table_colid_value, tuple_colid_value, nullptr); + } else if (rangeScanType == JIT_RANGE_SCAN_SUB_QUERY) { + JitLlvmCodeGenContext::SubQueryData* subQueryData = &ctx->m_subQueryData[subQueryIndex]; + value = AddFunctionCall(ctx, + ctx->selectColumnFunc, + subQueryData->m_table, + row, + subQueryData->m_slot, + table_colid_value, + tuple_colid_value, + nullptr); } if (value == nullptr) { @@ -1236,45 +1435,53 @@ static void AddSetScanEnded(JitLlvmCodeGenContext* ctx, int result) } /** @brief Adds a call to copyKey(index, key, end_iterator_key). */ -static void AddCopyKey(JitLlvmCodeGenContext* ctx, JitRangeScanType range_scan_type) +static void AddCopyKey(JitLlvmCodeGenContext* ctx, JitRangeScanType rangeScanType, int subQueryIndex) { - if (range_scan_type == JIT_RANGE_SCAN_INNER) { + if (rangeScanType == JIT_RANGE_SCAN_INNER) { AddFunctionCall(ctx, ctx->copyKeyFunc, ctx->inner_index_value, ctx->inner_key_value, ctx->inner_end_iterator_key_value, nullptr); - } else { + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { AddFunctionCall(ctx, ctx->copyKeyFunc, ctx->index_value, ctx->key_value, ctx->end_iterator_key_value, nullptr); + } else if (rangeScanType == JIT_RANGE_SCAN_SUB_QUERY) { + JitLlvmCodeGenContext::SubQueryData* subQueryData = &ctx->m_subQueryData[subQueryIndex]; + AddFunctionCall(ctx, + ctx->copyKeyFunc, + subQueryData->m_index, + subQueryData->m_searchKey, + subQueryData->m_endIteratorKey, + nullptr); } } /** @brief Adds a call to FillKeyPattern(key, pattern, offset, size) or FillKeyPattern(end_iterator_key, pattern, * offset, size). */ static void AddFillKeyPattern(JitLlvmCodeGenContext* ctx, unsigned char pattern, int offset, int size, - JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) + JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, int subQueryIndex) { llvm::ConstantInt* pattern_value = llvm::ConstantInt::get(ctx->INT8_T, pattern, true); llvm::ConstantInt* offset_value = llvm::ConstantInt::get(ctx->INT32_T, offset, true); llvm::ConstantInt* size_value = llvm::ConstantInt::get(ctx->INT32_T, size, true); - llvm::Value* key_value = getExecContextKey(ctx, range_itr_type, range_scan_type); + llvm::Value* key_value = getExecContextKey(ctx, range_itr_type, range_scan_type, subQueryIndex); AddFunctionCall(ctx, ctx->fillKeyPatternFunc, key_value, pattern_value, offset_value, size_value, nullptr); } /** @brief Adds a call to adjustKey(key, index, pattern) or adjustKey(end_iterator_key, index, pattern). */ static void AddAdjustKey(JitLlvmCodeGenContext* ctx, unsigned char pattern, JitRangeIteratorType range_itr_type, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex) { llvm::ConstantInt* pattern_value = llvm::ConstantInt::get(ctx->INT8_T, pattern, true); - llvm::Value* key_value = getExecContextKey(ctx, range_itr_type, range_scan_type); - llvm::Value* index_value = (range_scan_type == JIT_RANGE_SCAN_INNER) ? ctx->inner_index_value : ctx->index_value; + llvm::Value* key_value = getExecContextKey(ctx, range_itr_type, range_scan_type, subQueryIndex); + llvm::Value* index_value = getExecContextIndex(ctx, range_scan_type, subQueryIndex); AddFunctionCall(ctx, ctx->adjustKeyFunc, key_value, index_value, pattern_value, nullptr); } /** @brief Adds a call to searchIterator(index, key). */ static llvm::Value* AddSearchIterator(JitLlvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type) + JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type, int subQueryIndex) { llvm::Value* itr = nullptr; uint64_t forward_scan = (index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; @@ -1289,7 +1496,7 @@ static llvm::Value* AddSearchIterator(JitLlvmCodeGenContext* ctx, JitIndexScanDi forward_iterator_value, include_bound_value, nullptr); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { itr = AddFunctionCall(ctx, ctx->searchIteratorFunc, ctx->index_value, @@ -1297,13 +1504,22 @@ static llvm::Value* AddSearchIterator(JitLlvmCodeGenContext* ctx, JitIndexScanDi forward_iterator_value, include_bound_value, nullptr); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitLlvmCodeGenContext::SubQueryData* subQueryData = &ctx->m_subQueryData[subQueryIndex]; + itr = AddFunctionCall(ctx, + ctx->searchIteratorFunc, + subQueryData->m_index, + subQueryData->m_searchKey, + forward_iterator_value, + include_bound_value, + nullptr); } return itr; } /** @brief Adds a call to createEndIterator(index, end_iterator_key). */ static llvm::Value* AddCreateEndIterator(JitLlvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type) + JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type, int subQueryIndex = -1) { llvm::Value* itr = nullptr; uint64_t forward_scan = (index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; @@ -1318,7 +1534,7 @@ static llvm::Value* AddCreateEndIterator(JitLlvmCodeGenContext* ctx, JitIndexSca forward_scan_value, include_bound_value, nullptr); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { itr = AddFunctionCall(ctx, ctx->createEndIteratorFunc, ctx->index_value, @@ -1326,29 +1542,39 @@ static llvm::Value* AddCreateEndIterator(JitLlvmCodeGenContext* ctx, JitIndexSca forward_scan_value, include_bound_value, nullptr); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitLlvmCodeGenContext::SubQueryData* subQueryData = &ctx->m_subQueryData[subQueryIndex]; + itr = AddFunctionCall(ctx, + ctx->createEndIteratorFunc, + subQueryData->m_index, + subQueryData->m_endIteratorKey, + forward_scan_value, + include_bound_value, + nullptr); } return itr; } /** @brief Adds a call to isScanEnd(index, iterator, end_iterator). */ static llvm::Value* AddIsScanEnd(JitLlvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitLlvmRuntimeCursor* cursor, JitRangeScanType range_scan_type) + JitLlvmRuntimeCursor* cursor, JitRangeScanType range_scan_type, int subQueryIndex = -1) { uint64_t forward_scan = (index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; llvm::ConstantInt* forward_scan_value = llvm::ConstantInt::get(ctx->INT32_T, forward_scan, true); - llvm::Value* index_value = (range_scan_type == JIT_RANGE_SCAN_INNER) ? ctx->inner_index_value : ctx->index_value; + llvm::Value* index_value = getExecContextIndex(ctx, range_scan_type, subQueryIndex); return AddFunctionCall( ctx, ctx->isScanEndFunc, index_value, cursor->begin_itr, cursor->end_itr, forward_scan_value, nullptr); } /** @brief Adds a cal to getRowFromIterator(index, iterator, end_iterator). */ static llvm::Value* AddGetRowFromIterator(JitLlvmCodeGenContext* ctx, MOT::AccessType access_mode, - JitIndexScanDirection index_scan_direction, JitLlvmRuntimeCursor* cursor, JitRangeScanType range_scan_type) + JitIndexScanDirection index_scan_direction, JitLlvmRuntimeCursor* cursor, JitRangeScanType range_scan_type, + int subQueryIndex) { uint64_t forward_scan = (index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; llvm::ConstantInt* access_mode_value = llvm::ConstantInt::get(ctx->INT32_T, access_mode, true); llvm::ConstantInt* forward_scan_value = llvm::ConstantInt::get(ctx->INT32_T, forward_scan, true); - llvm::Value* index_value = (range_scan_type == JIT_RANGE_SCAN_INNER) ? ctx->inner_index_value : ctx->index_value; + llvm::Value* index_value = getExecContextIndex(ctx, range_scan_type, subQueryIndex); return AddFunctionCall(ctx, ctx->getRowFromIteratorFunc, index_value, @@ -1574,6 +1800,48 @@ static void AddWriteTupleDatum(JitLlvmCodeGenContext* ctx, int tuple_colid, llvm AddFunctionCall(ctx, ctx->writeTupleDatumFunc, ctx->slot_value, tuple_colid_value, value, nullptr); } +static llvm::Value* AddSelectSubQueryResult(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + return AddFunctionCall(ctx, ctx->selectSubQueryResultFunc, subQueryIndexValue, nullptr); +} + +static void AddCopyAggregateToSubQueryResult(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + AddFunctionCall(ctx, ctx->copyAggregateToSubQueryResultFunc, subQueryIndexValue, nullptr); +} + +static llvm::Value* AddGetSubQuerySlot(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + return AddFunctionCall(ctx, ctx->GetSubQuerySlotFunc, subQueryIndexValue, nullptr); +} + +static llvm::Value* AddGetSubQueryTable(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + return AddFunctionCall(ctx, ctx->GetSubQueryTableFunc, subQueryIndexValue, nullptr); +} + +static llvm::Value* AddGetSubQueryIndex(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + return AddFunctionCall(ctx, ctx->GetSubQueryIndexFunc, subQueryIndexValue, nullptr); +} + +static llvm::Value* AddGetSubQuerySearchKey(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + return AddFunctionCall(ctx, ctx->GetSubQuerySearchKeyFunc, subQueryIndexValue, nullptr); +} + +static llvm::Value* AddGetSubQueryEndIteratorKey(JitLlvmCodeGenContext* ctx, int subQueryIndex) +{ + llvm::ConstantInt* subQueryIndexValue = llvm::ConstantInt::get(ctx->INT32_T, subQueryIndex, true); + return AddFunctionCall(ctx, ctx->GetSubQueryEndIteratorKeyFunc, subQueryIndexValue, nullptr); +} + /** @brief Adds a call to issueDebugLog(function, msg). */ #ifdef MOT_JIT_DEBUG static void IssueDebugLogImpl(JitLlvmCodeGenContext* ctx, const char* function, const char* msg) @@ -1778,7 +2046,7 @@ static void CreateJittedFunction(JitLlvmCodeGenContext* ctx, const char* functio fn_prototype.addArgument(GsCodeGen::NamedVariable("inner_table", ctx->TableType->getPointerTo())); fn_prototype.addArgument(GsCodeGen::NamedVariable("inner_index", ctx->IndexType->getPointerTo())); fn_prototype.addArgument(GsCodeGen::NamedVariable("inner_key", ctx->KeyType->getPointerTo())); - fn_prototype.addArgument(GsCodeGen::NamedVariable("innerm_endIteratorKey", ctx->KeyType->getPointerTo())); + fn_prototype.addArgument(GsCodeGen::NamedVariable("inner_end_iterator_key", ctx->KeyType->getPointerTo())); ctx->m_jittedQuery = fn_prototype.generatePrototype(ctx->_builder, &llvmargs[0]); @@ -1798,6 +2066,14 @@ static void CreateJittedFunction(JitLlvmCodeGenContext* ctx, const char* functio ctx->inner_key_value = llvmargs[arg_index++]; ctx->inner_end_iterator_key_value = llvmargs[arg_index++]; + for (uint32_t i = 0; i < ctx->m_subQueryCount; ++i) { + ctx->m_subQueryData[i].m_slot = AddGetSubQuerySlot(ctx, i); + ctx->m_subQueryData[i].m_table = AddGetSubQueryTable(ctx, i); + ctx->m_subQueryData[i].m_index = AddGetSubQueryIndex(ctx, i); + ctx->m_subQueryData[i].m_searchKey = AddGetSubQuerySearchKey(ctx, i); + ctx->m_subQueryData[i].m_endIteratorKey = AddGetSubQueryEndIteratorKey(ctx, i); + } + IssueDebugLog("Starting execution of jitted function"); } @@ -1830,10 +2106,10 @@ static llvm::Value* buildCreateNewRow(JitLlvmCodeGenContext* ctx) /** @brief Adds code to search for a row by a key. */ static llvm::Value* buildSearchRow( - JitLlvmCodeGenContext* ctx, MOT::AccessType access_type, JitRangeScanType range_scan_type) + JitLlvmCodeGenContext* ctx, MOT::AccessType access_type, JitRangeScanType range_scan_type, int subQueryIndex = -1) { IssueDebugLog("Searching row"); - llvm::Value* row = AddSearchRow(ctx, access_type, range_scan_type); + llvm::Value* row = AddSearchRow(ctx, access_type, range_scan_type, subQueryIndex); JIT_IF_BEGIN(check_row_found) JIT_IF_EVAL_NOT(row) @@ -1922,11 +2198,11 @@ static void buildDeleteRow(JitLlvmCodeGenContext* ctx) /** @brief Adds code to search for an iterator. */ static llvm::Value* buildSearchIterator(JitLlvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type) + JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type, int subQueryIndex = -1) { // search the row, execute: IndexIterator* itr = searchIterator(table, key); IssueDebugLog("Searching range start"); - llvm::Value* itr = AddSearchIterator(ctx, index_scan_direction, range_bound_mode, range_scan_type); + llvm::Value* itr = AddSearchIterator(ctx, index_scan_direction, range_bound_mode, range_scan_type, subQueryIndex); JIT_IF_BEGIN(check_itr_found) JIT_IF_EVAL_NOT(itr) @@ -1941,10 +2217,11 @@ static llvm::Value* buildSearchIterator(JitLlvmCodeGenContext* ctx, JitIndexScan /** @brief Adds code to get row from iterator. */ static llvm::Value* buildGetRowFromIterator(JitLlvmCodeGenContext* ctx, llvm::BasicBlock* endLoopBlock, MOT::AccessType access_mode, JitIndexScanDirection index_scan_direction, JitLlvmRuntimeCursor* cursor, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex = -1) { IssueDebugLog("Retrieving row from iterator"); - llvm::Value* row = AddGetRowFromIterator(ctx, access_mode, index_scan_direction, cursor, range_scan_type); + llvm::Value* row = + AddGetRowFromIterator(ctx, access_mode, index_scan_direction, cursor, range_scan_type, subQueryIndex); JIT_IF_BEGIN(check_itr_row_found) JIT_IF_EVAL_NOT(row) @@ -2401,6 +2678,11 @@ static llvm::Value* ProcessFuncExpr(JitLlvmCodeGenContext* ctx, llvm::Value* row #undef APPLY_BINARY_CAST_OPERATOR #undef APPLY_TERNARY_CAST_OPERATOR +static llvm::Value* ProcessSubLinkExpr(JitLlvmCodeGenContext* ctx, llvm::Value* row, JitSubLinkExpr* expr, int* max_arg) +{ + return AddSelectSubQueryResult(ctx, expr->_sub_query_index); +} + static llvm::Value* ProcessExpr(JitLlvmCodeGenContext* ctx, llvm::Value* row, JitExpr* expr, int* max_arg) { llvm::Value* result = nullptr; @@ -2415,6 +2697,8 @@ static llvm::Value* ProcessExpr(JitLlvmCodeGenContext* ctx, llvm::Value* row, Ji result = ProcessOpExpr(ctx, row, (JitOpExpr*)expr, max_arg); } else if (expr->_expr_type == JIT_EXPR_TYPE_FUNC) { result = ProcessFuncExpr(ctx, row, (JitFuncExpr*)expr, max_arg); + } else if (expr->_expr_type == JIT_EXPR_TYPE_SUBLINK) { + result = ProcessSubLinkExpr(ctx, row, (JitSubLinkExpr*)expr, max_arg); } else { MOT_LOG_TRACE( "Failed to generate jitted code for query: unsupported target expression type: %d", (int)expr->_expr_type); @@ -2438,7 +2722,7 @@ static bool _arm_compile_lock_ready = false; extern bool InitArmCompileLock() { bool result = true; - if (__sync_bool_compare_and_swap(&_arm_compile_lock_initialized, 0, 1)) { + if (MOT_ATOMIC_CAS(_arm_compile_lock_initialized, 0, 1)) { int res = pthread_spin_init(&_arm_compile_lock, 0); if (res != 0) { MOT_REPORT_SYSTEM_ERROR_CODE( @@ -2461,6 +2745,9 @@ extern void DestroyArmCompileLock() if (res != 0) { MOT_REPORT_SYSTEM_ERROR_CODE( res, pthread_spin_init, "Initialize LLVM", "Failed to destroy compile spin-lock for ARM platform"); + } else { + _arm_compile_lock_ready = false; + MOT_ATOMIC_STORE(_arm_compile_lock_initialized, 0); } } } @@ -2614,7 +2901,7 @@ static JitContext* FinalizeCodegen(JitLlvmCodeGenContext* ctx, int max_arg, JitC } static bool buildScanExpression(JitLlvmCodeGenContext* ctx, JitColumnExpr* expr, int* max_arg, - JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, llvm::Value* outer_row) + JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, llvm::Value* outer_row, int subQueryIndex) { llvm::Value* value = ProcessExpr(ctx, outer_row, expr->_expr, max_arg); if (value == nullptr) { @@ -2623,31 +2910,35 @@ static bool buildScanExpression(JitLlvmCodeGenContext* ctx, JitColumnExpr* expr, } else { llvm::Value* column = AddGetColumnAt(ctx, expr->_table_column_id, - range_scan_type); // no need to translate to zero-based index (first column is null bits) + range_scan_type, // no need to translate to zero-based index (first column is null bits) + subQueryIndex); int index_colid = -1; if (range_scan_type == JIT_RANGE_SCAN_INNER) { index_colid = ctx->_inner_table_info.m_columnMap[expr->_table_column_id]; - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { index_colid = ctx->_table_info.m_columnMap[expr->_table_column_id]; + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index_colid = ctx->m_subQueryTableInfo[subQueryIndex].m_columnMap[expr->_table_column_id]; } - AddBuildDatumKey(ctx, column, index_colid, value, expr->_column_type, range_itr_type, range_scan_type); + AddBuildDatumKey( + ctx, column, index_colid, value, expr->_column_type, range_itr_type, range_scan_type, subQueryIndex); } return true; } -static bool buildPointScan(JitLlvmCodeGenContext* ctx, JitColumnExprArray* expr_array, int* max_arg, - JitRangeScanType range_scan_type, llvm::Value* outer_row, int expr_count = 0) +static bool buildPointScan(JitLlvmCodeGenContext* ctx, JitColumnExprArray* exprArray, int* maxArg, + JitRangeScanType rangeScanType, llvm::Value* outerRow, int exprCount = 0, int subQueryIndex = -1) { - if (expr_count == 0) { - expr_count = expr_array->_count; + if (exprCount == 0) { + exprCount = exprArray->_count; } - AddInitSearchKey(ctx, range_scan_type); - for (int i = 0; i < expr_count; ++i) { - JitColumnExpr* expr = &expr_array->_exprs[i]; + AddInitSearchKey(ctx, rangeScanType, subQueryIndex); + for (int i = 0; i < exprCount; ++i) { + JitColumnExpr* expr = &exprArray->_exprs[i]; // validate the expression refers to the right table (in search expressions array, all expressions refer to the // same table) - if (range_scan_type == JIT_RANGE_SCAN_INNER) { + if (rangeScanType == JIT_RANGE_SCAN_INNER) { if (expr->_table != ctx->_inner_table_info.m_table) { MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, "Generate LLVM JIT Code", @@ -2656,7 +2947,7 @@ static bool buildPointScan(JitLlvmCodeGenContext* ctx, JitColumnExprArray* expr_ expr->_table->GetTableName().c_str()); return false; } - } else { + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { if (expr->_table != ctx->_table_info.m_table) { MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, "Generate LLVM JIT Code", @@ -2665,10 +2956,19 @@ static bool buildPointScan(JitLlvmCodeGenContext* ctx, JitColumnExprArray* expr_ expr->_table->GetTableName().c_str()); return false; } + } else if (rangeScanType == JIT_RANGE_SCAN_SUB_QUERY) { + if (expr->_table != ctx->m_subQueryTableInfo[subQueryIndex].m_table) { + MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, + "Generate TVM JIT Code", + "Invalid expression table (expected sub-query table %s, got %s)", + ctx->m_subQueryTableInfo[subQueryIndex].m_table->GetTableName().c_str(), + expr->_table->GetTableName().c_str()); + return false; + } } // prepare the sub-expression - if (!buildScanExpression(ctx, expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row)) { + if (!buildScanExpression(ctx, expr, maxArg, JIT_RANGE_ITERATOR_START, rangeScanType, outerRow, subQueryIndex)) { return false; } } @@ -2700,7 +3000,7 @@ static bool writeRowColumns( } static bool selectRowColumns(JitLlvmCodeGenContext* ctx, llvm::Value* row, JitSelectExprArray* expr_array, int* max_arg, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex = -1) { bool result = true; for (int i = 0; i < expr_array->_count; ++i) { @@ -2710,12 +3010,17 @@ static bool selectRowColumns(JitLlvmCodeGenContext* ctx, llvm::Value* row, JitSe if (expr->_column_expr->_table != ctx->_inner_table_info.m_table) { continue; } - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { if (expr->_column_expr->_table != ctx->_table_info.m_table) { continue; } + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + if (expr->_column_expr->_table != ctx->m_subQueryTableInfo[subQueryIndex].m_table) { + continue; + } } - result = AddSelectColumn(ctx, row, expr->_column_expr->_column_id, expr->_tuple_column_id, range_scan_type); + result = AddSelectColumn( + ctx, row, expr->_column_expr->_column_id, expr->_tuple_column_id, range_scan_type, subQueryIndex); if (!result) { break; } @@ -2725,12 +3030,13 @@ static bool selectRowColumns(JitLlvmCodeGenContext* ctx, llvm::Value* row, JitSe } static bool buildClosedRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, - JitRangeScanType range_scan_type, llvm::Value* outer_row) + JitRangeScanType range_scan_type, llvm::Value* outer_row, int subQueryIndex) { // a closed range scan starts just like a point scan (with not enough search expressions) and then adds key patterns - bool result = buildPointScan(ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row); + bool result = + buildPointScan(ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row, 0, subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, range_scan_type, subQueryIndex); // now fill each key with the right pattern for the missing pkey columns in the where clause bool ascending = (index_scan->_sort_order == JIT_QUERY_SORT_ASCENDING); @@ -2742,10 +3048,14 @@ static bool buildClosedRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index index_column_offsets = ctx->_inner_table_info.m_indexColumnOffsets; key_length = ctx->_inner_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_inner_table_info.m_index->GetNumFields(); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { index_column_offsets = ctx->_table_info.m_indexColumnOffsets; key_length = ctx->_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_table_info.m_index->GetNumFields(); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index_column_offsets = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets; + key_length = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields(); + index_column_count = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetNumFields(); } int first_zero_column = index_scan->_column_count; @@ -2754,130 +3064,154 @@ static bool buildClosedRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index int size = key_length[i]; MOT_LOG_DEBUG( "Filling begin/end iterator pattern for missing pkey fields at offset %d, size %d", offset, size); - AddFillKeyPattern(ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - AddFillKeyPattern(ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + AddFillKeyPattern( + ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type, subQueryIndex); + AddFillKeyPattern( + ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type, subQueryIndex); } AddAdjustKey(ctx, ascending ? 0x00 : 0xFF, JIT_RANGE_ITERATOR_START, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); AddAdjustKey(ctx, ascending ? 0xFF : 0x00, JIT_RANGE_ITERATOR_END, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); } return result; } -static bool buildSemiOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, - JitRangeScanType range_scan_type, JitRangeBoundMode* begin_range_bound, JitRangeBoundMode* end_range_bound, - llvm::Value* outer_row) +static bool buildSemiOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* indexScan, int* maxArg, + JitRangeScanType rangeScanType, JitRangeBoundMode* beginRangeBound, JitRangeBoundMode* endRangeBound, + llvm::Value* outerRow, int subQueryIndex) { // an open range scan starts just like a point scan (with not enough search expressions) and then adds key patterns // we do not use the last search expression - bool result = buildPointScan( - ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row, index_scan->_search_exprs._count - 1); + bool result = buildPointScan(ctx, + &indexScan->_search_exprs, + maxArg, + rangeScanType, + outerRow, + indexScan->_search_exprs._count - 1, + subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, rangeScanType, subQueryIndex); // now fill each key with the right pattern for the missing pkey columns in the where clause - bool ascending = (index_scan->_sort_order == JIT_QUERY_SORT_ASCENDING); + bool ascending = (indexScan->_sort_order == JIT_QUERY_SORT_ASCENDING); int* index_column_offsets = nullptr; const uint16_t* key_length = nullptr; int index_column_count = 0; - if (range_scan_type == JIT_RANGE_SCAN_INNER) { + if (rangeScanType == JIT_RANGE_SCAN_INNER) { index_column_offsets = ctx->_inner_table_info.m_indexColumnOffsets; key_length = ctx->_inner_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_inner_table_info.m_index->GetNumFields(); - } else { + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { index_column_offsets = ctx->_table_info.m_indexColumnOffsets; key_length = ctx->_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_table_info.m_index->GetNumFields(); + } else if (rangeScanType == JIT_RANGE_SCAN_SUB_QUERY) { + index_column_offsets = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets; + key_length = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields(); + index_column_count = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetNumFields(); } // prepare offset and size for last column in search - int last_dim_column = index_scan->_column_count - 1; + int last_dim_column = indexScan->_column_count - 1; int offset = index_column_offsets[last_dim_column]; int size = key_length[last_dim_column]; // now we fill the last dimension (override extra work of point scan above) - int last_expr_index = index_scan->_search_exprs._count - 1; - JitColumnExpr* last_expr = &index_scan->_search_exprs._exprs[last_expr_index]; + int last_expr_index = indexScan->_search_exprs._count - 1; + JitColumnExpr* last_expr = &indexScan->_search_exprs._exprs[last_expr_index]; if (ascending) { - if ((index_scan->_last_dim_op1 == JIT_WOC_LESS_THAN) || - (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS)) { + if ((indexScan->_last_dim_op1 == JIT_WOC_LESS_THAN) || (indexScan->_last_dim_op1 == JIT_WOC_LESS_EQUALS)) { // this is an upper bound operator on an ascending semi-open scan so we fill the begin key with zeros, // and the end key with the value - AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, outer_row); - *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; - *end_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE - : JIT_RANGE_BOUND_EXCLUDE; + AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_START, rangeScanType, subQueryIndex); + buildScanExpression( + ctx, last_expr, maxArg, JIT_RANGE_ITERATOR_END, rangeScanType, outerRow, subQueryIndex); + *beginRangeBound = JIT_RANGE_BOUND_INCLUDE; + *endRangeBound = (indexScan->_last_dim_op1 == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE + : JIT_RANGE_BOUND_EXCLUDE; } else { // this is a lower bound operator on an ascending semi-open scan so we fill the begin key with the // value, and the end key with 0xFF - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row); - AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); - *begin_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE - : JIT_RANGE_BOUND_EXCLUDE; - *end_range_bound = JIT_RANGE_BOUND_INCLUDE; + buildScanExpression( + ctx, last_expr, maxArg, JIT_RANGE_ITERATOR_START, rangeScanType, outerRow, subQueryIndex); + AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_END, rangeScanType, subQueryIndex); + *beginRangeBound = (indexScan->_last_dim_op1 == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE + : JIT_RANGE_BOUND_EXCLUDE; + *endRangeBound = JIT_RANGE_BOUND_INCLUDE; } } else { - if ((index_scan->_last_dim_op1 == JIT_WOC_LESS_THAN) || - (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS)) { + if ((indexScan->_last_dim_op1 == JIT_WOC_LESS_THAN) || (indexScan->_last_dim_op1 == JIT_WOC_LESS_EQUALS)) { // this is an upper bound operator on a descending semi-open scan so we fill the begin key with value, // and the end key with zeroes - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row); - AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); - *begin_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE - : JIT_RANGE_BOUND_EXCLUDE; - *end_range_bound = JIT_RANGE_BOUND_INCLUDE; + buildScanExpression( + ctx, last_expr, maxArg, JIT_RANGE_ITERATOR_START, rangeScanType, outerRow, subQueryIndex); + AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_END, rangeScanType, subQueryIndex); + *beginRangeBound = (indexScan->_last_dim_op1 == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE + : JIT_RANGE_BOUND_EXCLUDE; + *endRangeBound = JIT_RANGE_BOUND_INCLUDE; } else { // this is a lower bound operator on a descending semi-open scan so we fill the begin key with 0xFF, and // the end key with the value - AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, outer_row); - *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; - *end_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE - : JIT_RANGE_BOUND_EXCLUDE; + AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_START, rangeScanType, subQueryIndex); + buildScanExpression( + ctx, last_expr, maxArg, JIT_RANGE_ITERATOR_END, rangeScanType, outerRow, subQueryIndex); + *beginRangeBound = JIT_RANGE_BOUND_INCLUDE; + *endRangeBound = (indexScan->_last_dim_op1 == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE + : JIT_RANGE_BOUND_EXCLUDE; } } // now fill the rest as usual - int first_zero_column = index_scan->_column_count; + int first_zero_column = indexScan->_column_count; for (int i = first_zero_column; i < index_column_count; ++i) { int offset = index_column_offsets[i]; int size = key_length[i]; MOT_LOG_DEBUG( "Filling begin/end iterator pattern for missing pkey fields at offset %d, size %d", offset, size); - AddFillKeyPattern(ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - AddFillKeyPattern(ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + AddFillKeyPattern( + ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, rangeScanType, subQueryIndex); + AddFillKeyPattern( + ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, rangeScanType, subQueryIndex); } AddAdjustKey(ctx, ascending ? 0x00 : 0xFF, JIT_RANGE_ITERATOR_START, - range_scan_type); // currently this is relevant only for secondary index searches + rangeScanType, // currently this is relevant only for secondary index searches + subQueryIndex); AddAdjustKey(ctx, ascending ? 0xFF : 0x00, JIT_RANGE_ITERATOR_END, - range_scan_type); // currently this is relevant only for secondary index searches + rangeScanType, // currently this is relevant only for secondary index searches + subQueryIndex); } return result; } static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, JitRangeScanType range_scan_type, JitRangeBoundMode* begin_range_bound, JitRangeBoundMode* end_range_bound, - llvm::Value* outer_row) + llvm::Value* outer_row, int subQueryIndex) { // an open range scan starts just like a point scan (with not enough search expressions) and then adds key patterns // we do not use the last two expressions - bool result = buildPointScan( - ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row, index_scan->_search_exprs._count - 2); + bool result = buildPointScan(ctx, + &index_scan->_search_exprs, + max_arg, + range_scan_type, + outer_row, + index_scan->_search_exprs._count - 2, + subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, range_scan_type, subQueryIndex); // now fill each key with the right pattern for the missing pkey columns in the where clause bool ascending = (index_scan->_sort_order == JIT_QUERY_SORT_ASCENDING); @@ -2889,10 +3223,14 @@ static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_s index_column_offsets = ctx->_inner_table_info.m_indexColumnOffsets; key_length = ctx->_inner_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_inner_table_info.m_index->GetNumFields(); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { index_column_offsets = ctx->_table_info.m_indexColumnOffsets; key_length = ctx->_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_table_info.m_index->GetNumFields(); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index_column_offsets = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets; + key_length = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields(); + index_column_count = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetNumFields(); } // now we fill the last dimension (override extra work of point scan above) @@ -2911,13 +3249,15 @@ static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_s max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // lower bound on begin iterator key + outer_row, // lower bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, before_last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // upper bound on end iterator key + outer_row, // upper bound on end iterator key + subQueryIndex); *begin_range_bound = (last_dim_op == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -2931,13 +3271,15 @@ static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_s max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // lower bound on begin iterator key + outer_row, // lower bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // upper bound on end iterator key + outer_row, // upper bound on end iterator key + subQueryIndex); *begin_range_bound = (before_last_dim_op == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -2953,13 +3295,15 @@ static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_s max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // upper bound on begin iterator key + outer_row, // upper bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // lower bound on end iterator key + outer_row, // lower bound on end iterator key + subQueryIndex); *begin_range_bound = (before_last_dim_op == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -2973,13 +3317,15 @@ static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_s max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // upper bound on begin iterator key + outer_row, // upper bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, before_last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // lower bound on end iterator key + outer_row, // lower bound on end iterator key + subQueryIndex); *begin_range_bound = (last_dim_op == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -2994,48 +3340,52 @@ static bool buildOpenRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_s int size = key_length[i]; MOT_LOG_DEBUG( "Filling begin/end iterator pattern for missing pkey fields at offset %d, size %d", offset, size); - AddFillKeyPattern(ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - AddFillKeyPattern(ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + AddFillKeyPattern( + ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type, subQueryIndex); + AddFillKeyPattern( + ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type, subQueryIndex); } AddAdjustKey(ctx, ascending ? 0x00 : 0xFF, JIT_RANGE_ITERATOR_START, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); AddAdjustKey(ctx, ascending ? 0xFF : 0x00, JIT_RANGE_ITERATOR_END, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); } return result; } static bool buildRangeScan(JitLlvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, JitRangeScanType range_scan_type, JitRangeBoundMode* begin_range_bound, JitRangeBoundMode* end_range_bound, - llvm::Value* outer_row) + llvm::Value* outer_row, int subQueryIndex = -1) { bool result = false; // if this is a point scan we generate two identical keys for the iterators if (index_scan->_scan_type == JIT_INDEX_SCAN_POINT) { - result = buildPointScan(ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row); + result = buildPointScan(ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row, subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, range_scan_type, subQueryIndex); *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; *end_range_bound = JIT_RANGE_BOUND_INCLUDE; } } else if (index_scan->_scan_type == JIT_INDEX_SCAN_CLOSED) { - result = buildClosedRangeScan(ctx, index_scan, max_arg, range_scan_type, outer_row); + result = buildClosedRangeScan(ctx, index_scan, max_arg, range_scan_type, outer_row, subQueryIndex); if (result) { *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; *end_range_bound = JIT_RANGE_BOUND_INCLUDE; } } else if (index_scan->_scan_type == JIT_INDEX_SCAN_SEMI_OPEN) { result = buildSemiOpenRangeScan( - ctx, index_scan, max_arg, range_scan_type, begin_range_bound, end_range_bound, outer_row); + ctx, index_scan, max_arg, range_scan_type, begin_range_bound, end_range_bound, outer_row, subQueryIndex); } else if (index_scan->_scan_type == JIT_INDEX_SCAN_OPEN) { result = buildOpenRangeScan( - ctx, index_scan, max_arg, range_scan_type, begin_range_bound, end_range_bound, outer_row); + ctx, index_scan, max_arg, range_scan_type, begin_range_bound, end_range_bound, outer_row, subQueryIndex); } return result; } @@ -3187,22 +3537,25 @@ static llvm::Value* buildPrepareStateScanRow(JitLlvmCodeGenContext* ctx, JitInde return row; } -static JitLlvmRuntimeCursor buildRangeCursor(JitLlvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, - JitRangeScanType range_scan_type, JitIndexScanDirection index_scan_direction, llvm::Value* outer_row) +static JitLlvmRuntimeCursor buildRangeCursor(JitLlvmCodeGenContext* ctx, JitIndexScan* indexScan, int* maxArg, + JitRangeScanType rangeScanType, JitIndexScanDirection indexScanDirection, llvm::Value* outerRow, + int subQueryIndex = -1) { JitLlvmRuntimeCursor result = {nullptr, nullptr}; - JitRangeBoundMode begin_range_bound = JIT_RANGE_BOUND_NONE; - JitRangeBoundMode end_range_bound = JIT_RANGE_BOUND_NONE; - if (!buildRangeScan(ctx, index_scan, max_arg, range_scan_type, &begin_range_bound, &end_range_bound, outer_row)) { + JitRangeBoundMode beginRangeBound = JIT_RANGE_BOUND_NONE; + JitRangeBoundMode endRangeBound = JIT_RANGE_BOUND_NONE; + if (!buildRangeScan( + ctx, indexScan, maxArg, rangeScanType, &beginRangeBound, &endRangeBound, outerRow, subQueryIndex)) { MOT_LOG_TRACE( "Failed to generate jitted code for aggregate range JOIN query: unsupported %s-loop WHERE clause type", - outer_row ? "inner" : "outer"); + outerRow ? "inner" : "outer"); return result; } // build range iterators - result.begin_itr = buildSearchIterator(ctx, index_scan_direction, begin_range_bound, range_scan_type); - result.end_itr = AddCreateEndIterator(ctx, index_scan_direction, end_range_bound, range_scan_type); // forward scan + result.begin_itr = buildSearchIterator(ctx, indexScanDirection, beginRangeBound, rangeScanType, subQueryIndex); + result.end_itr = + AddCreateEndIterator(ctx, indexScanDirection, endRangeBound, rangeScanType, subQueryIndex); // forward scan return result; } @@ -4268,12 +4621,12 @@ static JitContext* JitAggregateRangeSelectCodegen( // begin the WHERE clause int max_arg = 0; - JitIndexScanDirection index_scan_direction = JIT_INDEX_SCAN_FORWARD; + JitIndexScanDirection indexScanDirection = JIT_INDEX_SCAN_FORWARD; // build range iterators MOT_LOG_DEBUG("Generating range cursor for range SELECT query"); JitLlvmRuntimeCursor cursor = - buildRangeCursor(ctx, &plan->_index_scan, &max_arg, JIT_RANGE_SCAN_MAIN, index_scan_direction, nullptr); + buildRangeCursor(ctx, &plan->_index_scan, &max_arg, JIT_RANGE_SCAN_MAIN, indexScanDirection, nullptr); if (cursor.begin_itr == nullptr) { MOT_LOG_TRACE("Failed to generate jitted code for aggregate range SELECT query: unsupported WHERE clause type"); DestroyCodeGenContext(ctx); @@ -4281,7 +4634,7 @@ static JitContext* JitAggregateRangeSelectCodegen( } JIT_WHILE_BEGIN(cursor_aggregate_loop) - llvm::Value* res = AddIsScanEnd(ctx, index_scan_direction, &cursor, JIT_RANGE_SCAN_MAIN); + llvm::Value* res = AddIsScanEnd(ctx, indexScanDirection, &cursor, JIT_RANGE_SCAN_MAIN); JIT_WHILE_EVAL_NOT(res) llvm::Value* row = buildGetRowFromIterator( ctx, JIT_WHILE_POST_BLOCK(), access_mode, JIT_INDEX_SCAN_FORWARD, &cursor, JIT_RANGE_SCAN_MAIN); @@ -4630,7 +4983,7 @@ static JitContext* JitPointInnerJoinCodegen(const Query* query, const char* quer // if a limit clause exists, then increment limit counter and check if reached limit buildCheckLimit(ctx, plan->_limit_count); - // execute *tp_processed = rows_processed + // generate code for setting output parameter tp_processed value to rows_processed AddSetTpProcessed(ctx); // return success from calling function @@ -4740,18 +5093,18 @@ static JitContext* JitAggregateRangeJoinCodegen(Query* query, const char* query_ { MOT_LOG_DEBUG("Generating code for MOT aggregate range JOIN at thread %p", (void*)pthread_self()); - GsCodeGen* code_gen = SetupCodegenEnv(); - if (code_gen == nullptr) { + GsCodeGen* codeGen = SetupCodegenEnv(); + if (codeGen == nullptr) { return nullptr; } - GsCodeGen::LlvmBuilder builder(code_gen->context()); + GsCodeGen::LlvmBuilder builder(codeGen->context()); JitLlvmCodeGenContext cg_ctx = {0}; MOT::Table* outer_table = plan->_outer_scan._table; MOT::Index* outer_index = outer_table->GetIndex(plan->_outer_scan._index_id); MOT::Table* inner_table = plan->_inner_scan._table; MOT::Index* inner_index = inner_table->GetIndex(plan->_inner_scan._index_id); - if (!InitCodeGenContext(&cg_ctx, code_gen, &builder, outer_table, outer_index, inner_table, inner_index)) { + if (!InitCodeGenContext(&cg_ctx, codeGen, &builder, outer_table, outer_index, inner_table, inner_index)) { return nullptr; } JitLlvmCodeGenContext* ctx = &cg_ctx; @@ -4771,7 +5124,7 @@ static JitContext* JitAggregateRangeJoinCodegen(Query* query, const char* query_ AddResetStateLimitCounter(ctx); // pay attention: aggregated range scan is not stateful, since we scan all tuples in one call - MOT::AccessType access_mode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; + MOT::AccessType accessMode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; // begin the WHERE clause int max_arg = 0; @@ -4792,7 +5145,7 @@ static JitContext* JitAggregateRangeJoinCodegen(Query* query, const char* query_ llvm::Value* res = AddIsScanEnd(ctx, JIT_INDEX_SCAN_FORWARD, &outer_cursor, JIT_RANGE_SCAN_MAIN); JIT_WHILE_EVAL_NOT(res) llvm::Value* outer_row = buildGetRowFromIterator( - ctx, JIT_WHILE_POST_BLOCK(), access_mode, JIT_INDEX_SCAN_FORWARD, &outer_cursor, JIT_RANGE_SCAN_MAIN); + ctx, JIT_WHILE_POST_BLOCK(), accessMode, JIT_INDEX_SCAN_FORWARD, &outer_cursor, JIT_RANGE_SCAN_MAIN); // check for additional filters, if not try to fetch next row if (!buildFilterRow(ctx, outer_row, &plan->_outer_scan._filters, &max_arg, JIT_WHILE_COND_BLOCK())) { @@ -4821,7 +5174,7 @@ static JitContext* JitAggregateRangeJoinCodegen(Query* query, const char* query_ llvm::Value* res = AddIsScanEnd(ctx, JIT_INDEX_SCAN_FORWARD, &inner_cursor, JIT_RANGE_SCAN_INNER); JIT_WHILE_EVAL_NOT(res) llvm::Value* inner_row = buildGetRowFromIterator( - ctx, JIT_WHILE_POST_BLOCK(), access_mode, JIT_INDEX_SCAN_FORWARD, &inner_cursor, JIT_RANGE_SCAN_INNER); + ctx, JIT_WHILE_POST_BLOCK(), accessMode, JIT_INDEX_SCAN_FORWARD, &inner_cursor, JIT_RANGE_SCAN_INNER); // check for additional filters, if not try to fetch next row if (!buildFilterRow(ctx, inner_row, &plan->_inner_scan._filters, &max_arg, JIT_WHILE_COND_BLOCK())) { @@ -4845,8 +5198,8 @@ static JitContext* JitAggregateRangeJoinCodegen(Query* query, const char* query_ if (plan->_limit_count > 0) { AddIncrementStateLimitCounter(ctx); JIT_IF_BEGIN(limit_count_reached) - llvm::Value* current_limit_count = AddGetStateLimitCounter(ctx); - JIT_IF_EVAL_CMP(current_limit_count, JIT_CONST(plan->_limit_count), JIT_ICMP_EQ); + llvm::Value* currentLimitCount = AddGetStateLimitCounter(ctx); + JIT_IF_EVAL_CMP(currentLimitCount, JIT_CONST(plan->_limit_count), JIT_ICMP_EQ); IssueDebugLog("Reached limit specified in limit clause, raising internal state scan end flag"); AddDestroyCursor(ctx, &outer_cursor); AddDestroyCursor(ctx, &inner_cursor); @@ -4926,6 +5279,269 @@ static JitContext* JitJoinCodegen(Query* query, const char* query_string, JitJoi return jit_context; } +static bool JitSubSelectCodegen(JitLlvmCodeGenContext* ctx, JitCompoundPlan* plan, int subQueryIndex) +{ + MOT_LOG_DEBUG("Generating code for MOT sub-select at thread %p", (intptr_t)pthread_self()); + IssueDebugLog("Executing simple SELECT sub-query"); + + // get the sub-query plan + JitSelectPlan* subPlan = (JitSelectPlan*)plan->_sub_query_plans[subQueryIndex]; + + // begin the WHERE clause + int max_arg = 0; + if (!buildPointScan( + ctx, &subPlan->_query._search_exprs, &max_arg, JIT_RANGE_SCAN_SUB_QUERY, nullptr, 0, subQueryIndex)) { + MOT_LOG_TRACE("Failed to generate jitted code for SELECT sub-query: unsupported WHERE clause type"); + return false; + } + + // fetch row for read + llvm::Value* row = buildSearchRow(ctx, MOT::AccessType::RD, JIT_RANGE_SCAN_SUB_QUERY, subQueryIndex); + + // check for additional filters + if (!buildFilterRow(ctx, row, &subPlan->_query._filters, &max_arg, nullptr)) { + MOT_LOG_TRACE("Failed to generate jitted code for SELECT sub-query: unsupported filter"); + return false; + } + + // now begin selecting columns into result + IssueDebugLog("Selecting column into result"); + if (!selectRowColumns(ctx, row, &subPlan->_select_exprs, &max_arg, JIT_RANGE_SCAN_SUB_QUERY, subQueryIndex)) { + MOT_LOG_TRACE("Failed to generate jitted code for SELECT sub-query: failed to process target entry"); + return false; + } + + return true; +} + +/** @brief Generates code for range SELECT sub-query with aggregator. */ +static bool JitSubAggregateRangeSelectCodegen(JitLlvmCodeGenContext* ctx, JitCompoundPlan* plan, int subQueryIndex) +{ + MOT_LOG_DEBUG("Generating code for MOT aggregate range sub-select at thread %p", (intptr_t)pthread_self()); + IssueDebugLog("Executing aggregated range select sub-query"); + + // get the sub-query plan + JitRangeSelectPlan* subPlan = (JitRangeSelectPlan*)plan->_sub_query_plans[subQueryIndex]; + + // prepare for aggregation + prepareAggregate(ctx, &subPlan->_aggregate); + AddResetStateLimitCounter(ctx); + + // pay attention: aggregated range scan is not stateful, since we scan all tuples in one call + MOT::AccessType access_mode = MOT::AccessType::RD; + + // begin the WHERE clause + int max_arg = 0; + JitIndexScanDirection index_scan_direction = JIT_INDEX_SCAN_FORWARD; + + // build range iterators + MOT_LOG_DEBUG("Generating range cursor for range SELECT sub-query"); + JitLlvmRuntimeCursor cursor = buildRangeCursor( + ctx, &subPlan->_index_scan, &max_arg, JIT_RANGE_SCAN_SUB_QUERY, index_scan_direction, nullptr, subQueryIndex); + if (cursor.begin_itr == nullptr) { + MOT_LOG_TRACE( + "Failed to generate jitted code for aggregate range SELECT sub-query: unsupported WHERE clause type"); + return false; + } + + JIT_WHILE_BEGIN(cursor_aggregate_loop) + llvm::Value* res = AddIsScanEnd(ctx, index_scan_direction, &cursor, JIT_RANGE_SCAN_SUB_QUERY, subQueryIndex); + JIT_WHILE_EVAL_NOT(res) + llvm::Value* row = buildGetRowFromIterator(ctx, + JIT_WHILE_POST_BLOCK(), + access_mode, + JIT_INDEX_SCAN_FORWARD, + &cursor, + JIT_RANGE_SCAN_SUB_QUERY, + subQueryIndex); + + // check for additional filters, if not try to fetch next row + if (!buildFilterRow(ctx, row, &subPlan->_index_scan._filters, &max_arg, JIT_WHILE_COND_BLOCK())) { + MOT_LOG_TRACE("Failed to generate jitted code for aggregate range SELECT sub-query: unsupported filter"); + DestroyCodeGenContext(ctx); + return false; + } + + // aggregate into tuple (we use tuple's resno column as aggregated sum instead of defining local variable) + // if row disqualified due to DISTINCT operator then go back to loop test block + buildAggregateRow(ctx, &subPlan->_aggregate, row, JIT_WHILE_COND_BLOCK()); + + // if a limit clause exists, then increment limit counter and check if reached limit + if (subPlan->_limit_count > 0) { + AddIncrementStateLimitCounter(ctx); + JIT_IF_BEGIN(limit_count_reached) + llvm::Value* current_limit_count = AddGetStateLimitCounter(ctx); + JIT_IF_EVAL_CMP(current_limit_count, JIT_CONST(subPlan->_limit_count), JIT_ICMP_EQ); + IssueDebugLog("Reached limit specified in limit clause, raising internal state scan end flag"); + JIT_WHILE_BREAK() // break from loop + JIT_IF_END() + } + JIT_WHILE_END() + + // cleanup + IssueDebugLog("Reached end of aggregate range select sub-query loop"); + AddDestroyCursor(ctx, &cursor); + + // wrap up aggregation and write to result tuple (even though this is unfitting to outer query tuple...) + buildAggregateResult(ctx, &subPlan->_aggregate); + + // coy aggregate result from outer query result tuple into sub-query result tuple + AddCopyAggregateToSubQueryResult(ctx, subQueryIndex); + + return true; +} + +static bool JitSubQueryCodeGen(JitLlvmCodeGenContext* ctx, JitCompoundPlan* plan, int subQueryIndex) +{ + bool result = false; + JitPlan* subPlan = plan->_sub_query_plans[subQueryIndex]; + if (subPlan->_plan_type == JIT_PLAN_POINT_QUERY) { + result = JitSubSelectCodegen(ctx, plan, subQueryIndex); + } else if (subPlan->_plan_type == JIT_PLAN_RANGE_SCAN) { + result = JitSubAggregateRangeSelectCodegen(ctx, plan, subQueryIndex); + } else { + MOT_REPORT_ERROR(MOT_ERROR_INVALID_ARG, + "Generate JIT Code", + "Cannot generate JIT code for sub-query plan: Invalid plan type %d", + (int)subPlan->_plan_type); + } + return result; +} + +static JitContext* JitCompoundOuterSelectCodegen( + JitLlvmCodeGenContext* ctx, Query* query, const char* queryString, JitSelectPlan* plan) +{ + // begin the WHERE clause + int max_arg = 0; + if (!buildPointScan(ctx, &plan->_query._search_exprs, &max_arg, JIT_RANGE_SCAN_MAIN, nullptr)) { + MOT_LOG_TRACE("Failed to generate jitted code for COMPOUND SELECT query: unsupported WHERE clause type"); + return nullptr; + } + + // fetch row for read + MOT::AccessType access_mode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; + llvm::Value* row = buildSearchRow(ctx, access_mode, JIT_RANGE_SCAN_MAIN); + + // check for additional filters + if (!buildFilterRow(ctx, row, &plan->_query._filters, &max_arg, nullptr)) { + MOT_LOG_TRACE("Failed to generate jitted code for COMPOUND SELECT query: unsupported filter"); + return nullptr; + } + + // now begin selecting columns into result + IssueDebugLog("Selecting columns into result"); + if (!selectRowColumns(ctx, row, &plan->_select_exprs, &max_arg, JIT_RANGE_SCAN_MAIN)) { + MOT_LOG_TRACE("Failed to generate jitted code for COMPOUND SELECT query: failed to process target entry"); + return nullptr; + } + + AddExecStoreVirtualTuple(ctx); + + // update number of rows processed + buildIncrementRowsProcessed(ctx); + + // execute *tp_processed = rows_processed + AddSetTpProcessed(ctx); + + // signal to envelope executor scan ended (this is a point query) + AddSetScanEnded(ctx, 1); + + // return success from calling function + ctx->_builder->CreateRet(llvm::ConstantInt::get(ctx->INT32_T, (int)MOT::RC_OK, true)); + + // wrap up + return FinalizeCodegen(ctx, max_arg, JIT_COMMAND_COMPOUND_SELECT); +} + +static JitContext* JitCompoundOuterCodegen( + JitLlvmCodeGenContext* ctx, Query* query, const char* query_string, JitCompoundPlan* plan) +{ + JitContext* jitContext = nullptr; + if (plan->_command_type == JIT_COMMAND_SELECT) { + jitContext = JitCompoundOuterSelectCodegen(ctx, query, query_string, (JitSelectPlan*)plan->_outer_query_plan); + } + // currently other outer query types are not supported + return jitContext; +} + +static JitContext* JitCompoundCodegen(Query* query, const char* query_string, JitCompoundPlan* plan) +{ + // a compound query plan contains one or more sub-queries that evaluate to a datum that next needs to be fed as a + // parameter to the outer query. We are currently imposing the following limitations: + // 1. one sub-query that can only be a MAX aggregate + // 2. outer query must be a simple point select query. + // + // our main strategy is as follows (based on the fact that each sub-query evaluates into a single value) + // 1. for each sub-query: + // 1.1 execute sub-query and put datum result in sub-query result slot, according to sub-query index + // 2. execute the outer query as a simple query + // 3. whenever we encounter a sub-link expression, it is evaluated as an expression that reads the pre-computed + // sub-query result in step 1.1, according to sub-query index + MOT_LOG_DEBUG("Generating code for MOT compound select at thread %p", (intptr_t)pthread_self()); + + // prepare code generation context + GsCodeGen* code_gen = SetupCodegenEnv(); + if (code_gen == nullptr) { + return nullptr; + } + GsCodeGen::LlvmBuilder builder(code_gen->context()); + + JitLlvmCodeGenContext cg_ctx = {0}; + MOT::Table* table = plan->_outer_query_plan->_query._table; + if (!InitCompoundCodeGenContext(&cg_ctx, code_gen, &builder, table, table->GetPrimaryIndex(), plan)) { + return nullptr; + } + JitLlvmCodeGenContext* ctx = &cg_ctx; + + // prepare the jitted function (declare, get arguments into context and define locals) + CreateJittedFunction(ctx, "MotJittedCompoundSelect"); + IssueDebugLog("Starting execution of jitted COMPOUND SELECT"); + + // initialize rows_processed local variable (required for sub-queries) + buildResetRowsProcessed(ctx); + + // generate code for sub-query execution + uint32_t subQueryCount = 0; + for (int i = 0; i < plan->_outer_query_plan->_query._search_exprs._count; ++i) { + if (plan->_outer_query_plan->_query._search_exprs._exprs[i]._expr->_expr_type == JIT_EXPR_TYPE_SUBLINK) { + JitSubLinkExpr* subLinkExpr = + (JitSubLinkExpr*)plan->_outer_query_plan->_query._search_exprs._exprs[i]._expr; + if (!JitSubQueryCodeGen(ctx, plan, subLinkExpr->_sub_query_index)) { + MOT_LOG_TRACE( + "Failed to generate jitted code for COMPOUND SELECT query: Failed to generate code for sub-query"); + DestroyCodeGenContext(ctx); + return nullptr; + } + ++subQueryCount; + } + } + + // clear tuple early, so that we will have a null datum in case outer query finds nothing + AddExecClearTuple(ctx); + + // generate code for the outer query + JitContext* jitContext = JitCompoundOuterCodegen(ctx, query, query_string, plan); + if (jitContext == nullptr) { + MOT_LOG_TRACE("Failed to generate code for outer query in compound select"); + DestroyCodeGenContext(ctx); + return nullptr; + } + + // prepare sub-query data in resulting JIT context (for later execution) + MOT_ASSERT(subQueryCount > 0); + MOT_ASSERT(subQueryCount == plan->_sub_query_count); + if ((subQueryCount > 0) && !PrepareSubQueryData(jitContext, plan)) { + MOT_LOG_TRACE("Failed to prepare tuple table slot array for sub-queries in JIT context object"); + DestroyJitContext(jitContext); + jitContext = nullptr; + } + + // cleanup + DestroyCodeGenContext(ctx); + + return jitContext; +} + static JitContext* JitRangeScanCodegen(Query* query, const char* query_string, JitRangeScanPlan* plan) { JitContext* jit_context = nullptr; @@ -5011,6 +5627,10 @@ extern JitContext* JitCodegenLlvmQuery(Query* query, const char* query_string, J jit_context = JitJoinCodegen(query, query_string, (JitJoinPlan*)plan); break; + case JIT_PLAN_COMPOUND: + jit_context = JitCompoundCodegen(query, query_string, (JitCompoundPlan*)plan); + break; + default: MOT_REPORT_ERROR( MOT_ERROR_INTERNAL, "Generate JIT Code", "Invalid JIT plan type %d", (int)plan->_plan_type); diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_plan.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_plan.cpp index 2c6d8ddb452b98f246c167d961eaf75cf268fde0..d5e8948918cd1c703a4cde38bfea2c51f72f8132 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_plan.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_plan.cpp @@ -55,13 +55,13 @@ public: virtual ~ExpressionVisitor() {} - virtual bool onFilterExpr(int filter_op, int filter_op_funcid, Expr* lhs, Expr* rhs) + virtual bool OnFilterExpr(int filterOp, int filterOpFuncId, Expr* lhs, Expr* rhs) { return true; } - virtual bool onExpression(Expr* expr, int column_type, int table_column_id, MOT::Table* table, - JitWhereOperatorClass op_class, bool join_expr) + virtual bool OnExpression( + Expr* expr, int columnType, int tableColumnId, MOT::Table* table, JitWhereOperatorClass opClass, bool joinExpr) { return true; } @@ -78,10 +78,10 @@ public: _count = nullptr; } - virtual bool onExpression(Expr* expr, int column_type, int table_column_id, MOT::Table* table, - JitWhereOperatorClass op_class, bool join_expr) + virtual bool OnExpression( + Expr* expr, int columnType, int tableColumnId, MOT::Table* table, JitWhereOperatorClass opClass, bool joinExpr) { - if (op_class != JIT_WOC_EQUALS) { + if (opClass != JIT_WOC_EQUALS) { MOT_LOG_TRACE("ExpressionCounter::onExpression(): Skipping non-equals operator"); return true; // this is not an error condition } @@ -107,24 +107,24 @@ public: _expr_count = nullptr; } - virtual bool onExpression(Expr* expr, int column_type, int table_column_id, MOT::Table* table, - JitWhereOperatorClass op_class, bool join_expr) + virtual bool OnExpression( + Expr* expr, int columnType, int tableColumnId, MOT::Table* table, JitWhereOperatorClass opClass, bool joinExpr) { - if (op_class != JIT_WOC_EQUALS) { + if (opClass != JIT_WOC_EQUALS) { MOT_LOG_TRACE("ExpressionCollector::onExpression(): Skipping non-equals operator"); return true; // this is not an error condition } else if (*_expr_count < _expr_array->_count) { JitExpr* jit_expr = parseExpr(_query, expr, 0, 0); if (jit_expr == nullptr) { MOT_LOG_TRACE("ExpressionCollector::onExpression(): Failed to parse expression %d", *_expr_count); - cleanup(); + Cleanup(); return false; } - _expr_array->_exprs[*_expr_count]._table_column_id = table_column_id; + _expr_array->_exprs[*_expr_count]._table_column_id = tableColumnId; _expr_array->_exprs[*_expr_count]._table = table; _expr_array->_exprs[*_expr_count]._expr = jit_expr; - _expr_array->_exprs[*_expr_count]._column_type = column_type; - _expr_array->_exprs[*_expr_count]._join_expr = join_expr; + _expr_array->_exprs[*_expr_count]._column_type = columnType; + _expr_array->_exprs[*_expr_count]._join_expr = joinExpr; ++(*_expr_count); return true; } else { @@ -139,7 +139,7 @@ private: JitColumnExprArray* _expr_array; int* _expr_count; - void cleanup() + void Cleanup() { for (int i = 0; i < *_expr_count; ++i) { freeExpr(_expr_array->_exprs[*_expr_count]._expr); @@ -187,7 +187,7 @@ public: _index_scan = nullptr; } - inline bool init() + inline bool Init() { bool result = false; _max_index_ops = _index->GetNumFields() + 1; @@ -205,8 +205,8 @@ public: return result; } - virtual bool onExpression(Expr* expr, int column_type, int table_column_id, MOT::Table* table, - JitWhereOperatorClass op_class, bool join_expr) + virtual bool OnExpression( + Expr* expr, int columnType, int tableColumnId, MOT::Table* table, JitWhereOperatorClass opClass, bool joinExpr) { if (_index_op_count >= _index_scan->_search_exprs._count) { MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, @@ -225,23 +225,23 @@ public: if (jit_expr == nullptr) { MOT_LOG_TRACE( "RangeScanExpressionCollector::onExpression(): Failed to parse expression %d", _index_op_count); - cleanup(); + Cleanup(); return false; } - _index_scan->_search_exprs._exprs[_index_op_count]._table_column_id = table_column_id; + _index_scan->_search_exprs._exprs[_index_op_count]._table_column_id = tableColumnId; _index_scan->_search_exprs._exprs[_index_op_count]._table = table; _index_scan->_search_exprs._exprs[_index_op_count]._expr = jit_expr; - _index_scan->_search_exprs._exprs[_index_op_count]._column_type = column_type; - _index_scan->_search_exprs._exprs[_index_op_count]._join_expr = join_expr; + _index_scan->_search_exprs._exprs[_index_op_count]._column_type = columnType; + _index_scan->_search_exprs._exprs[_index_op_count]._join_expr = joinExpr; _index_scan->_search_exprs._count++; - _index_ops[_index_op_count]._index_column_id = MapTableColumnToIndex(_table, _index, table_column_id); - _index_ops[_index_op_count]._op_class = op_class; + _index_ops[_index_op_count]._index_column_id = MapTableColumnToIndex(_table, _index, tableColumnId); + _index_ops[_index_op_count]._op_class = opClass; ++_index_op_count; return true; } } - void evaluateScanType() + void EvaluateScanType() { _index_scan->_scan_type = JIT_INDEX_SCAN_TYPE_INVALID; JitIndexScanType scan_type = JIT_INDEX_SCAN_TYPE_INVALID; @@ -249,7 +249,7 @@ public: // if two expressions refer to the same column, we regard one of them as filter // if an expression is removed from index scan, it will automatically be collected as filter // (see pkey_exprs argument in @ref visitSearchOpExpression) - if (!removeDuplicates()) { + if (!RemoveDuplicates()) { MOT_LOG_TRACE("RangeScanExpressionCollector(): Disqualifying query - failed to remove duplicates"); return; } @@ -264,7 +264,7 @@ public: // first step: sort in-place all collected operators if (_index_op_count > 1) { - std::sort(&_index_ops[0], &_index_ops[_index_op_count - 1], indexOpCmp); + std::sort(&_index_ops[0], &_index_ops[_index_op_count - 1], IndexOpCmp); } // now verify all but last two are equals operator @@ -314,7 +314,7 @@ public: } // final step: verify we have no holes in the columns according to the expected scan type - if (!scanHasHoles(scan_type)) { + if (!ScanHasHoles(scan_type)) { _index_scan->_scan_type = scan_type; _index_scan->_column_count = column_count; _index_scan->_search_exprs._count = _index_op_count; // update real number of participating expressions @@ -322,7 +322,7 @@ public: } private: - void cleanup() + void Cleanup() { for (int i = 0; i < _index_op_count; ++i) { freeExpr(_index_scan->_search_exprs._exprs[i]._expr); @@ -331,16 +331,16 @@ private: _index_op_count = 0; } - bool removeDuplicates() + bool RemoveDuplicates() { - int result = removeSingleDuplicate(); + int result = RemoveSingleDuplicate(); while (result > 0) { - result = removeSingleDuplicate(); + result = RemoveSingleDuplicate(); } return (result == 0); } - int removeSingleDuplicate() + int RemoveSingleDuplicate() { // scan and stop after first removal for (int i = 1; i < _index_op_count; ++i) { @@ -399,7 +399,7 @@ private: return 0; } - static int intCmp(int lhs, int rhs) + static int IntCmp(int lhs, int rhs) { int result = 0; if (lhs < rhs) { @@ -410,17 +410,17 @@ private: return result; } - static bool indexOpCmp(const IndexOpClass& lhs, const IndexOpClass& rhs) + static bool IndexOpCmp(const IndexOpClass& lhs, const IndexOpClass& rhs) { - int result = intCmp(lhs._index_column_id, rhs._index_column_id); + int result = IntCmp(lhs._index_column_id, rhs._index_column_id); if (result == 0) { // make sure equals appears before other operators in case column id is equal - result = intCmp(lhs._op_class, rhs._op_class); + result = IntCmp(lhs._op_class, rhs._op_class); } return result < 0; } - bool scanHasHoles(JitIndexScanType scan_type) const + bool ScanHasHoles(JitIndexScanType scan_type) const { MOT_ASSERT(_index_op_count >= 1); @@ -479,7 +479,7 @@ public: _count = nullptr; } - virtual bool onFilterExpr(int filter_op, int filter_op_funcid, Expr* lhs, Expr* rhs) + virtual bool OnFilterExpr(int filterOp, int filterOpFuncId, Expr* lhs, Expr* rhs) { ++(*_count); return true; @@ -508,13 +508,13 @@ public: _filter_count = nullptr; } - virtual bool onFilterExpr(int filter_op, int filter_op_funcid, Expr* lhs, Expr* rhs) + virtual bool OnFilterExpr(int filterOp, int filterOpFuncId, Expr* lhs, Expr* rhs) { JitExpr* jit_lhs = parseExpr(_query, lhs, 0, 0); if (jit_lhs == nullptr) { MOT_LOG_TRACE("FilterCollector::onFilterExpr(): Failed to parse LHS expression in filter expression %d", *_filter_count); - cleanup(); + Cleanup(); return false; } JitExpr* jit_rhs = parseExpr(_query, rhs, 1, 0); @@ -522,12 +522,12 @@ public: MOT_LOG_TRACE("FilterCollector::onFilterExpr(): Failed to parse RHS expression in filter expression %d", *_filter_count); freeExpr(jit_lhs); - cleanup(); + Cleanup(); return false; } if (*_filter_count < _filter_array->_filter_count) { - _filter_array->_scan_filters[*_filter_count]._filter_op = filter_op; - _filter_array->_scan_filters[*_filter_count]._filter_op_funcid = filter_op_funcid; + _filter_array->_scan_filters[*_filter_count]._filter_op = filterOp; + _filter_array->_scan_filters[*_filter_count]._filter_op_funcid = filterOpFuncId; _filter_array->_scan_filters[*_filter_count]._lhs_operand = jit_lhs; _filter_array->_scan_filters[*_filter_count]._rhs_operand = jit_rhs; ++(*_filter_count); @@ -540,7 +540,7 @@ public: } private: - void cleanup() + void Cleanup() { for (int i = 0; i < *_filter_count; ++i) { freeExpr(_filter_array->_scan_filters[*_filter_count]._lhs_operand); @@ -765,6 +765,44 @@ static JitExpr* parseFuncExpr(Query* query, const FuncExpr* func_expr, int arg_p return (JitExpr*)result; } +static JitExpr* ParseSubLink(Query* query, const SubLink* subLink, int argPos, int depth) +{ + Query* subQuery = (Query*)subLink->subselect; + + // get the result type + int resultType = 0; + TargetEntry* targetEntry = (TargetEntry*)linitial(subQuery->targetList); + if (targetEntry->expr->type == T_Var) { + resultType = ((Var*)targetEntry->expr)->vartype; + } else if (targetEntry->expr->type == T_Aggref) { + resultType = ((Aggref*)targetEntry->expr)->aggtype; + } else { + MOT_LOG_TRACE("Disqualifying sub-link expression: unexpected target entry expression type: %d", + (int)targetEntry->expr->type); + return nullptr; + } + + if (!IsTypeSupported(resultType)) { + MOT_LOG_TRACE("Disqualifying sub-link expression: result type %d is unsupported", resultType); + return nullptr; + } + + size_t alloc_size = sizeof(JitSubLinkExpr); + JitSubLinkExpr* result = (JitSubLinkExpr*)MOT::MemSessionAlloc(alloc_size); + if (result == nullptr) { + MOT_REPORT_ERROR( + MOT_ERROR_OOM, "Prepare JIT Plan", "Failed to allocate %u bytes for sub-link expression", alloc_size); + } else { + result->_expr_type = JIT_EXPR_TYPE_SUBLINK; + result->_source_expr = (Expr*)subLink; + result->_result_type = resultType; + result->_arg_pos = argPos; + result->_sub_query_index = 0; // currently the only valid value for a single sub-query + } + + return (JitExpr*)result; +} + static JitExpr* parseExpr(Query* query, Expr* expr, int arg_pos, int depth) { JitExpr* result = nullptr; @@ -786,6 +824,8 @@ static JitExpr* parseExpr(Query* query, Expr* expr, int arg_pos, int depth) result = parseOpExpr(query, (OpExpr*)expr, arg_pos, depth); } else if (expr->type == T_FuncExpr) { result = parseFuncExpr(query, (FuncExpr*)expr, arg_pos, depth); + } else if (expr->type == T_SubLink) { + result = ParseSubLink(query, (SubLink*)expr, arg_pos, depth); } else { MOT_LOG_TRACE("Disqualifying expression: unsupported target expression type %d", (int)expr->type); } @@ -1137,7 +1177,7 @@ static bool visitSearchOpExpression(Query* query, MOT::Table* table, MOT::Index* op_expr->opresulttype); } else { MOT_LOG_TRACE("visitSearchOpExpression(): Collecting filter expression %p", op_expr); - if (!visitor->onFilterExpr(op_expr->opno, op_expr->opfuncid, lhs, rhs)) { + if (!visitor->OnFilterExpr(op_expr->opno, op_expr->opfuncid, lhs, rhs)) { MOT_LOG_TRACE("visitSearchOpExpression(): Expression collection failed"); return false; } @@ -1227,7 +1267,7 @@ static bool visitSearchOpExpression(Query* query, MOT::Table* table, MOT::Index* colid, index_colid, table->GetFieldName(colid)); - return visitor->onExpression(expr, vartype, colid, table, ClassifyWhereOperator(op_expr->opno), join_expr); + return visitor->OnExpression(expr, vartype, colid, table, ClassifyWhereOperator(op_expr->opno), join_expr); } if (join_expr) { // it is possible to see another table's column but not ours in implicit JOIN statements @@ -1289,8 +1329,13 @@ static bool getSearchExpressions(Query* query, MOT::Table* table, MOT::Index* in use_join_clause ? "yes" : "no"); ExpressionCollector expr_collector(query, search_exprs, count); Node* quals = query->jointree->quals; - bool result = - visitSearchExpressions(query, table, index, (Expr*)&quals[0], include_pkey, &expr_collector, use_join_clause); + bool result = true; + if (quals == nullptr) { + *count = 0; + } else { + result = visitSearchExpressions( + query, table, index, (Expr*)&quals[0], include_pkey, &expr_collector, use_join_clause); + } if (!result) { MOT_LOG_TRACE("Failed to get search expressions"); } else { @@ -1335,10 +1380,14 @@ static bool getRangeSearchExpressions( joinClauseTypeToString(join_clause_type)); bool result = false; RangeScanExpressionCollector expr_collector(query, table, index, index_scan); - if (!expr_collector.init()) { + if (!expr_collector.Init()) { MOT_LOG_TRACE("Failed to initialize range search expression collector"); } else { Node* quals = query->jointree->quals; + if (quals == nullptr) { + MOT_LOG_TRACE("No range search expressions collected - empty WHEER clause"); + return true; + } if (!visitSearchExpressions( query, table, index, (Expr*)&quals[0], true, &expr_collector, join_clause_type == JoinClauseImplicit)) { MOT_LOG_TRACE("Failed to collect range search expressions"); @@ -1356,7 +1405,7 @@ static bool getRangeSearchExpressions( } } } - expr_collector.evaluateScanType(); + expr_collector.EvaluateScanType(); result = true; } } @@ -1455,12 +1504,29 @@ static bool getSelectExpressions(Query* query, JitSelectExprArray* select_exprs) // and have an EQUALS operator static bool countWhereClauseEqualsLeaves(Query* query, MOT::Table* table, MOT::Index* index, int* count) { - MOT_LOG_TRACE("Counting WHERE clause leaf nodes with EQUALS operator for table %s and index %s", - table->GetTableName().c_str(), - index->GetName().c_str()); + if (MOT::CheckLogLevelInline(MOT::LogLevel::LL_TRACE, LOGGER_LEVEL)) { + MOT_LOG_BEGIN(MOT::LogLevel::LL_TRACE, + "Counting WHERE clause leaf nodes with EQUALS operator for table %s and index %s(", + table->GetTableName().c_str(), + index->GetName().c_str()); + for (int i = 0; i < index->GetNumFields(); ++i) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, "%s", table->GetFieldName(index->GetColumnKeyFields()[i])); + if ((i + 1) < index->GetNumFields()) { + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ", "); + } + } + MOT_LOG_APPEND(MOT::LogLevel::LL_TRACE, ")"); + MOT_LOG_END(MOT::LogLevel::LL_TRACE); + } + ExpressionCounter expr_counter(count); Node* quals = query->jointree->quals; - bool result = visitSearchExpressions(query, table, index, (Expr*)&quals[0], true, &expr_counter, false); + bool result = true; + if (quals == nullptr) { // no WHERE clause + *count = 0; + } else { + result = visitSearchExpressions(query, table, index, (Expr*)&quals[0], true, &expr_counter, false); + } if (!result) { MOT_LOG_TRACE("Failed to count WHERE clause EQUALS leaf nodes"); } else { @@ -1481,10 +1547,9 @@ static bool countWhereClauseEqualsLeaves(Query* query, MOT::Table* table, MOT::I return false; \ } -static bool checkQueryAttributes(const Query* query, bool allow_sorting, bool allow_aggregate) +static bool CheckQueryAttributes(const Query* query, bool allowSorting, bool allowAggregate, bool allowSublink) { checkJittableAttribute(query, hasWindowFuncs); - checkJittableAttribute(query, hasSubLinks); checkJittableAttribute(query, hasDistinctOn); checkJittableAttribute(query, hasRecursive); checkJittableAttribute(query, hasModifyingCTE); @@ -1498,14 +1563,18 @@ static bool checkQueryAttributes(const Query* query, bool allow_sorting, bool al checkJittableClause(query, setOperations); checkJittableClause(query, constraintDeps); - if (!allow_sorting) { + if (!allowSorting) { checkJittableClause(query, sortClause); } - if (!allow_aggregate) { + if (!allowAggregate) { checkJittableAttribute(query, hasAggs); } + if (!allowSublink) { + checkJittableAttribute(query, hasSubLinks); + } + return true; } @@ -1683,8 +1752,13 @@ static bool countFilters(Query* query, MOT::Table* table, MOT::Index* index, int MOT_LOG_TRACE("Counting filters for table %s, index %s", table->GetTableName().c_str(), index->GetName().c_str()); FilterCounter filter_counter(count); Node* quals = query->jointree->quals; - bool result = - visitSearchExpressions(query, table, index, (Expr*)&quals[0], false, &filter_counter, false, pkey_exprs); + bool result = true; + if (quals == nullptr) { + *count = 0; + } else { + result = + visitSearchExpressions(query, table, index, (Expr*)&quals[0], false, &filter_counter, false, pkey_exprs); + } if (!result) { MOT_LOG_TRACE("Failed to count number of filters"); } else { @@ -1729,8 +1803,13 @@ static bool getFilters(Query* query, MOT::Table* table, MOT::Index* index, JitFi MOT_LOG_TRACE("Retrieving filters for table %s, index %s", table->GetTableName().c_str(), index->GetName().c_str()); FilterCollector filter_collector(query, filter_array, count); Node* quals = query->jointree->quals; - bool result = - visitSearchExpressions(query, table, index, (Expr*)&quals[0], false, &filter_collector, false, pkey_exprs); + bool result = true; + if (quals == nullptr) { + *count = 0; + } else { + result = + visitSearchExpressions(query, table, index, (Expr*)&quals[0], false, &filter_collector, false, pkey_exprs); + } if (!result) { MOT_LOG_TRACE("Failed to retrieve filters"); } else { @@ -2403,8 +2482,7 @@ static JitPlan* JitPrepareRangeSelectPlan(Query* query, MOT::Table* table, JoinC // the limit count and aggregation can be inferred regardless of plan int limit_count = 0; - JitAggregate aggregate; - aggregate._aggreaget_op = JIT_AGGREGATE_NONE; + JitAggregate aggregate = {JIT_AGGREGATE_NONE, 0, 0, nullptr, 0, 0, 0, false}; if (!getLimitCount(query, &limit_count) || !getAggregateOperator(query, &aggregate)) { MOT_LOG_TRACE( "JitPrepareRangeSelectPlan(): Disqualifying query - unsupported scan limit count or aggregate operation"); @@ -2488,7 +2566,7 @@ static JitPlan* JitPrepareSimplePlan(Query* query) // if this is an insert command then generate an insert plan if (query->commandType == CMD_INSERT) { - if (!checkQueryAttributes(query, false, false)) { + if (!CheckQueryAttributes(query, false, false, false)) { MOT_LOG_TRACE("JitPrepareSimplePlan(): Disqualifying INSERT query - Invalid query attributes"); } else { plan = JitPrepareInsertPlan(query, table); @@ -2503,7 +2581,7 @@ static JitPlan* JitPrepareSimplePlan(Query* query) MOT_LOG_TRACE("JitPrepareSimplePlan(): Failed to determine if this is a point query"); } else if (count == index->GetNumFields()) { // a point query // point query does not expect sort clause or aggregate clause - if (!checkQueryAttributes(query, false, false)) { + if (!CheckQueryAttributes(query, false, false, false)) { MOT_LOG_TRACE("JitPrepareSimplePlan(): Disqualifying point query - Invalid query attributes"); } else if (query->commandType == CMD_UPDATE) { plan = JitPrepareUpdatePlan(query, table); @@ -2519,16 +2597,16 @@ static JitPlan* JitPrepareSimplePlan(Query* query) } } else { if (query->commandType == CMD_UPDATE) { - if (!checkQueryAttributes( - query, false, false)) { // range update does not expect sort clause or aggregate clause + if (!CheckQueryAttributes( + query, false, false, false)) { // range update does not expect sort clause or aggregate clause MOT_LOG_TRACE( "JitPrepareSimplePlan(): Disqualifying range update query - Invalid query attributes"); } else { plan = JitPrepareRangeUpdatePlan(query, table); } } else if (query->commandType == CMD_SELECT) { - if (!checkQueryAttributes( - query, true, true)) { // range select can specify sort clause or aggregate clause + if (!CheckQueryAttributes( + query, true, true, false)) { // range select can specify sort clause or aggregate clause MOT_LOG_TRACE( "JitPrepareSimplePlan(): Disqualifying range select query - Invalid query attributes"); } else { @@ -2792,8 +2870,8 @@ static JitPlan* JitPrepareJoinPlan(Query* query) JitPlan* plan = nullptr; MOT_LOG_TRACE("Preparing JOIN plan"); - if (!checkQueryAttributes( - query, false, true)) { // we do not support join query with ORDER BY clause, but we can aggregate + if (!CheckQueryAttributes( + query, false, true, false)) { // we do not support join query with ORDER BY clause, but we can aggregate MOT_LOG_TRACE("JitPrepareJoinPlan(): Disqualifying join query - Invalid query attributes"); } else { // we deal differently with explicit and implicit joins, since the parsed query looks much different @@ -2810,6 +2888,319 @@ static JitPlan* JitPrepareJoinPlan(Query* query) return plan; } +// Expression visitor that fetches a single sub-link +class SubLinkFetcher : public ExpressionVisitor { +public: + explicit SubLinkFetcher() : _subLink(nullptr), _count(0) + {} + + ~SubLinkFetcher() final + {} + + inline SubLink* GetSubLink() + { + return _subLink; + } + + virtual bool OnExpression( + Expr* expr, int columnType, int tableColumnId, MOT::Table* table, JitWhereOperatorClass opClass, bool joinExpr) + { + if (opClass != JIT_WOC_EQUALS) { + MOT_LOG_TRACE("SubLinkFetcher::onExpression(): Skipping non-equals operator"); + return true; // this is not an error condition + } + if (expr->type == T_SubLink) { + if (++_count > 1) { + MOT_LOG_TRACE("SubLinkFetcher::onExpression(): encountered more than one sub-link"); + return false; // already have a sub-link, we disqualify query + } + SubLink* subLink = (SubLink*)expr; + if (subLink->subLinkType != EXPR_SUBLINK) { + MOT_LOG_TRACE("SubLinkFetcher::onExpression(): unsupported sub-link type"); + return false; // unsupported sub-link type, we disqualify query + } + if (subLink->testexpr != nullptr) { + MOT_LOG_TRACE("SubLinkFetcher::onExpression(): unsupported sub-link outer test expression"); + return false; // unsupported sub-link type, we disqualify query + } + MOT_ASSERT(_subLink == nullptr); + _subLink = subLink; + } + return true; + } + +private: + SubLink* _subLink; + int _count; +}; + +static SubLink* GetSingleSubLink(Query* query, MOT::Table* table) +{ + SubLink* result = nullptr; + Node* quals = query->jointree->quals; + if (quals != nullptr) { + SubLinkFetcher subLinkFetcher; + MOT::Index* index = table->GetPrimaryIndex(); + bool result = visitSearchExpressions(query, table, index, (Expr*)&quals[0], true, &subLinkFetcher, false); + if (!result) { + MOT_LOG_TRACE("Failed to fetch WHERE clause single sub-link node"); + } + result = subLinkFetcher.GetSubLink(); + } + return result; +} + +#ifdef JIT_SUPPORT_FOR_POINT_SUB_QUERY +static bool IsPointQuery(Query* query) +{ + bool result = false; + + MOT::Table* table = GetTableFromQuery(query); + if (table == nullptr) { + MOT_LOG_TRACE("IsPointQuery(): Failed to retrieve table from query"); + return false; + } + + // count all equals operators that relate to the index (disregard other filters) + MOT::Index* index = table->GetPrimaryIndex(); + int count = 0; + if (!countWhereClauseEqualsLeaves(query, table, index, &count)) { + MOT_LOG_TRACE("IsPointQuery(): Failed to determine if this is a point query"); + } else if (count == index->GetNumFields()) { // a point query + // point query does not expect sort clause or aggregate clause + if (!CheckQueryAttributes(query, false, false, false)) { + MOT_LOG_TRACE("JitPrepareSimplePlan(): Disqualifying point query - Invalid query attributes"); + } else { + result = true; + } + } + + return result; +} + +static bool IsSingleColumnResult(Query* query) +{ + bool result = false; + + if (list_length(query->targetList) == 1) { + result = true; + } + + return result; +} +#endif + +static bool IsAggregate(Query* query) +{ + bool result = false; + + // we expect to see single target entry whose expression is AggRef + if (list_length(query->targetList) == 1) { + TargetEntry* targetEntry = (TargetEntry*)linitial(query->targetList); + if (targetEntry->expr->type == T_Aggref) { + Aggref* aggref = (Aggref*)targetEntry->expr; + if (aggref->aggfnoid == INT4LARGERFUNCOID) { // only MAX of int4 is currently supported + result = true; + } + } + } + + return result; +} + +static bool IsSingleResultPlan(JitPlan* plan) +{ + bool result = false; + if (plan->_plan_type == JIT_PLAN_POINT_QUERY) { + JitPointQueryPlan* pointQueryPlan = (JitPointQueryPlan*)plan; + if (pointQueryPlan->_command_type == JIT_COMMAND_SELECT) { + result = true; + } + } else if (plan->_plan_type == JIT_PLAN_RANGE_SCAN) { + JitRangeScanPlan* rangeScanPlan = (JitRangeScanPlan*)plan; + if (rangeScanPlan->_command_type == JIT_COMMAND_SELECT) { + JitRangeSelectPlan* rangeSelectPlan = (JitRangeSelectPlan*)rangeScanPlan; + if (rangeSelectPlan->_index_scan._scan_type == JIT_INDEX_SCAN_POINT) { + result = true; + } else if (rangeSelectPlan->_limit_count == 1) { + result = true; + } else if (rangeSelectPlan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) { + result = true; + } + } + } + return result; +} + +static bool IsValidCompoundScan(JitSelectPlan* outerQueryPlan, JitPlan* subQueryPlan) +{ + int subLinkCount = 0; + for (int i = 0; i < outerQueryPlan->_query._search_exprs._count; ++i) { + if (outerQueryPlan->_query._search_exprs._exprs[i]._expr->_expr_type == JIT_EXPR_TYPE_SUBLINK) { + if (++subLinkCount > 1) { + MOT_LOG_TRACE("Invalid compound scan with more than one sub-link"); + return false; + } + if (outerQueryPlan->_query._search_exprs._exprs[i]._expr->_source_expr->type != T_SubLink) { + MOT_LOG_TRACE("Invalid compound scan with inconsistent sub-link: source expression is not a sub-link"); + return false; + } + JitSubLinkExpr* subLinkExpr = (JitSubLinkExpr*)outerQueryPlan->_query._search_exprs._exprs[i]._expr; + if (subLinkExpr->_sub_query_index != 0) { // we support only a single sub-query currently + MOT_LOG_TRACE("Invalid compound scan sub-link: sub-query plan index is invalid"); + return false; + } + } + } + return true; +} + +static JitPlan* JitPrepareCompoundPlan(Query* query, Query* subQuery) +{ + JitPlan* plan = nullptr; + MOT_LOG_TRACE("Preparing a compound plan"); + + RangeTblEntry* rte = (RangeTblEntry*)linitial(query->rtable); + RangeTblEntry* subQueryRte = (RangeTblEntry*)linitial(subQuery->rtable); + + MOT::Table* table = MOT::GetTableManager()->GetTableByExternal(rte->relid); + MOT::Table* subQueryTable = MOT::GetTableManager()->GetTableByExternal(subQueryRte->relid); + + MOT_LOG_TRACE("Preparing a compound plan on tables: %s, %s", + table->GetTableName().c_str(), + subQueryTable->GetTableName().c_str()); + + // prepare the sub-query plan (we know already it yields only a single value) + JitPlan* sub_query_plan = JitPrepareSimplePlan(subQuery); + if (sub_query_plan == nullptr) { + MOT_LOG_TRACE("Failed to prepare a scan plan for sub-query on table %s", subQueryTable->GetTableName().c_str()); + return nullptr; + } + + // verify plan yields a single result + if (!IsSingleResultPlan(sub_query_plan)) { + MOT_LOG_TRACE("Disqualifying sub-query plan: yielding more than one result"); + return nullptr; + } + + // now prepare the outer query plan (knowing that one column points to sub-query) + JitSelectPlan* outerQueryPlan = (JitSelectPlan*)JitPrepareSelectPlan(query, table); + if (outerQueryPlan == nullptr) { + MOT_LOG_TRACE("Failed to prepare a plan for outer query on table %s", table->GetTableName().c_str()); + JitDestroyPlan(sub_query_plan); + return nullptr; + } + + if (sub_query_plan != nullptr && outerQueryPlan != nullptr) { + MOT_LOG_TRACE("Found Compound sub-query plan for table %s", subQueryTable->GetTableName().c_str()); + JitExplainPlan(subQuery, sub_query_plan); + MOT_LOG_TRACE("Found Compound outer query plan for table %s", table->GetTableName().c_str()); + JitExplainPlan(query, (JitPlan*)outerQueryPlan); + + // verify that the outer query plan has proper reference to sub-query plan + if (!IsValidCompoundScan(outerQueryPlan, sub_query_plan)) { + MOT_LOG_TRACE("Invalid compound scan"); + JitDestroyPlan(sub_query_plan); + JitDestroyPlan((JitPlan*)outerQueryPlan); + return nullptr; + } + + // now prepare the final compound plan + size_t allocSize = sizeof(JitCompoundPlan); + JitCompoundPlan* compoundPlan = (JitCompoundPlan*)MOT::MemSessionAlloc(allocSize); + if (compoundPlan == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "Prepare JIT COMPOUND plan", + "Failed to allocate %u bytes for compound plan", + (unsigned)allocSize); + JitDestroyPlan(sub_query_plan); + JitDestroyPlan((JitPlan*)outerQueryPlan); + } else { + errno_t erc = memset_s(compoundPlan, allocSize, 0, allocSize); + securec_check(erc, "\0", "\0"); + compoundPlan->_plan_type = JIT_PLAN_COMPOUND; + compoundPlan->_command_type = JIT_COMMAND_SELECT; + compoundPlan->_sub_query_count = 1; // we support currently only one sub-query + allocSize = sizeof(JitPlan*) * compoundPlan->_sub_query_count; + compoundPlan->_sub_query_plans = (JitPlan**)MOT::MemSessionAlloc(allocSize); + if (compoundPlan->_sub_query_plans == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "Prepare JIT COMPOUND plan", + "Failed to allocate %u bytes for sub-query plans", + (unsigned)allocSize); + JitDestroyPlan(sub_query_plan); + JitDestroyPlan((JitPlan*)outerQueryPlan); + MOT::MemSessionFree(compoundPlan); + } else { + compoundPlan->_sub_query_plans[0] = sub_query_plan; + compoundPlan->_outer_query_plan = (JitPointQueryPlan*)outerQueryPlan; + + plan = (JitPlan*)compoundPlan; + } + } + } + + return plan; +} + +static JitPlan* JitPrepareCompoundPlan(Query* query) +{ + JitPlan* plan = nullptr; + MOT_LOG_TRACE("Preparing COMPOUND query"); + + // we do not support compound query with ORDER BY clause, but we can aggregate + if (!CheckQueryAttributes(query, false, true, true)) { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Disqualifying compound query - Invalid query attributes"); + return nullptr; + } + + // we need to verify the outer query is a point query, and that only one dimension is depending on a sub-query + // which by itself is a point query or an aggregate + MOT::Table* table = GetTableFromQuery(query); + if (table == nullptr) { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Failed to retrieve table from query"); + return nullptr; + } + + // count all equals operators that relate to the index (disregard other filters) + MOT::Index* index = table->GetPrimaryIndex(); + int count = 0; + if (!countWhereClauseEqualsLeaves(query, table, index, &count)) { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Failed to determine if this is a point query"); + } else if (count == index->GetNumFields()) { // a point query + // now verify that only one dimension has a sub-link + SubLink* subLink = GetSingleSubLink(query, table); + if (subLink == nullptr) { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Disqualifying query with unsupported sub-link specification"); + } else { + Query* subQuery = (Query*)subLink->subselect; + // sub-query can have aggregate, but no sub-query or ORDER BY clause + if (!CheckQueryAttributes(subQuery, false, true, false)) { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Disqualifying sub-query - Invalid query attributes"); + return nullptr; + } + // sub-query must be a SELECT command + if (query->commandType != CMD_SELECT) { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Disqualifying sub-query - Invalid command type %d", + (int)query->commandType); + return nullptr; + } + // final test: verify that sub-link is a point query or aggregate (so it yields a single result) +#ifdef JIT_SUPPORT_FOR_POINT_SUB_QUERY + if ((IsPointQuery(subQuery) && IsSingleColumnResult(subQuery)) || IsAggregate(subQuery)) { +#else + if (IsAggregate(subQuery)) { +#endif + plan = JitPrepareCompoundPlan(query, subQuery); + } else { + MOT_LOG_TRACE("JitPrepareCompoundPlan(): Disqualifying non-point and non-aggregate sub-link query"); + } + } + } + + return plan; +} + extern JitPlan* JitPreparePlan(Query* query, const char* query_string) { JitPlan* plan = nullptr; @@ -2818,6 +3209,11 @@ extern JitPlan* JitPreparePlan(Query* query, const char* query_string) // we start by checking the number of tables involved if (list_length(query->rtable) == 1) { plan = JitPrepareSimplePlan(query); + // special case: a sub-query that evaluates to point query or single value aggregate, which in turn + // is used in a point-select outer query + if ((plan == nullptr) && query->hasSubLinks && (query->commandType == CMD_SELECT)) { + plan = JitPrepareCompoundPlan(query); + } } else { plan = JitPrepareJoinPlan(query); } @@ -2832,13 +3228,34 @@ extern bool JitPlanHasDistinct(JitPlan* plan) if (plan->_plan_type == JIT_PLAN_RANGE_SCAN) { if (((JitRangeScanPlan*)plan)->_command_type == JIT_COMMAND_SELECT) { JitRangeSelectPlan* select_plan = (JitRangeSelectPlan*)plan; - if (select_plan->_aggregate._distinct) { + if ((select_plan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) && select_plan->_aggregate._distinct) { result = true; } } } else if (plan->_plan_type == JIT_PLAN_JOIN) { JitJoinPlan* join_plan = (JitJoinPlan*)plan; - if (join_plan->_aggregate._distinct) { + if ((join_plan->_aggregate._aggreaget_op != JIT_AGGREGATE_NONE) && join_plan->_aggregate._distinct) { + result = true; + } + } + + return result; +} + +extern bool JitPlanHasSort(JitPlan* plan) +{ + bool result = false; + + if (plan->_plan_type == JIT_PLAN_RANGE_SCAN) { + if (((JitRangeScanPlan*)plan)->_command_type == JIT_COMMAND_SELECT) { + JitRangeSelectPlan* select_plan = (JitRangeSelectPlan*)plan; + if (select_plan->_index_scan._sort_order != JIT_QUERY_SORT_INVALID) { + result = true; + } + } + } else if (plan->_plan_type == JIT_PLAN_JOIN) { + JitJoinPlan* join_plan = (JitJoinPlan*)plan; + if (join_plan->_outer_scan._sort_order != JIT_QUERY_SORT_INVALID) { result = true; } } @@ -2903,6 +3320,17 @@ static void JitDestroyJoinPlan(JitJoinPlan* plan) MOT::MemSessionFree(plan); } +static void JitDestroyCompoundPlan(JitCompoundPlan* plan) +{ + for (uint32_t i = 0; i < plan->_sub_query_count; ++i) { + JitDestroyPlan(plan->_sub_query_plans[i]); + } + MOT::MemSessionFree(plan->_sub_query_plans); + + JitDestroyPointQueryPlan(plan->_outer_query_plan); + MOT::MemSessionFree(plan); +} + extern void JitDestroyPlan(JitPlan* plan) { if (plan != nullptr) { @@ -2923,6 +3351,10 @@ extern void JitDestroyPlan(JitPlan* plan) JitDestroyJoinPlan((JitJoinPlan*)plan); break; + case JIT_PLAN_COMPOUND: + JitDestroyCompoundPlan((JitCompoundPlan*)plan); + break; + case JIT_PLAN_INVALID: default: break; diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_plan.h b/src/gausskernel/storage/mot/jit_exec/src/jit_plan.h index f414cef18f153eb24a7e6742fb282374b1648613..8b800e2ae5eca12c25fdc0e5cb6acd88261f8a58 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_plan.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_plan.h @@ -99,7 +99,10 @@ enum JitPlanType { JIT_PLAN_RANGE_SCAN, /** @var Plan for a nested loop join. */ - JIT_PLAN_JOIN + JIT_PLAN_JOIN, + + /** @var Plan for a query with sub-queries. */ + JIT_PLAN_COMPOUND }; /** @enum Expression types. */ @@ -120,7 +123,10 @@ enum JitExprType { JIT_EXPR_TYPE_OP, /** @var Function expression type. */ - JIT_EXPR_TYPE_FUNC + JIT_EXPR_TYPE_FUNC, + + /** @var Sub-link expression type (for a sub-query). */ + JIT_EXPR_TYPE_SUBLINK }; /** @enum Index scan types. */ @@ -148,7 +154,7 @@ struct JitExpr { /** @var The original expression in the parsed query (required for convenient filter collection). */ Expr* _source_expr; - /** @var The column type. */ + /** @var The expression result type. */ int _result_type; /** @var The position of the expression in the arg-is-null array. */ @@ -222,7 +228,7 @@ struct JitOpExpr { /** @var The original expression in the parsed query (required for convenient filter collection). */ Expr* _source_expr; - /** @var The column type. */ + /** @var The expression result type. */ int _result_type; /** @var The position of the expression in the arg-is-null array. */ @@ -248,7 +254,7 @@ struct JitFuncExpr { /** @var The original expression in the parsed query (required for convenient filter collection). */ Expr* _source_expr; - /** @var The column type. */ + /** @var The expression result type. */ int _result_type; /** @var The position of the expression in the arg-is-null array. */ @@ -264,6 +270,23 @@ struct JitFuncExpr { int _arg_count; }; +struct JitSubLinkExpr { + /** @var The expression type (always @ref JIT_EXPR_TYPE_SUBLINK). */ + JitExprType _expr_type; + + /** @var The original expression in the parsed query (required for extracting the sub-query). */ + Expr* _source_expr; + + /** @var The sub-query result type. */ + int _result_type; + + /** @var The position of the expression in the arg-is-null array. */ + int _arg_pos; + + /** @var The position of the sub-query plan in the sub-query plan array of the containing compound plan. */ + int _sub_query_index; +}; + /** @struct An expression tied to a table column. */ struct JitColumnExpr { /** @var The expression. */ @@ -519,7 +542,7 @@ struct JitRangeUpdatePlan { /** @var The type of plan being used (always @ref JIT_PLAN_RANGE_SCAN). */ JitPlanType _plan_type; - /** @var The command type being used (always @ref JIT_COMMAND_RANGE_UPDATE). */ + /** @var The command type being used (always @ref JIT_COMMAND_UPDATE). */ JitCommandType _command_type; /** @var Defines how to make the scan. */ @@ -534,7 +557,7 @@ struct JitRangeSelectPlan { /** @var The type of plan being used (always @ref JIT_PLAN_RANGE_SCAN). */ JitPlanType _plan_type; - /** @var The command type being used (always @ref JIT_COMMAND_RANGE_SELECT). */ + /** @var The command type being used (always @ref JIT_COMMAND_SELECT). */ JitCommandType _command_type; /** @var Defines how to make the scan. */ @@ -577,6 +600,24 @@ struct JitJoinPlan { JitAggregate _aggregate; }; +/** @strut Plan for compound point query with a single sub-query. */ +struct JitCompoundPlan { + /** @var The type of plan being used (always @ref JIT_PLAN_COMPOUND). */ + JitPlanType _plan_type; // always JIT_PLAN_COMPOUND + + /** @var The command type being used (currently always @ref JIT_COMMAND_SELECT). */ + JitCommandType _command_type; + + /** @var The outer point query plan (currently only one column refers to a sub-query). */ + JitPointQueryPlan* _outer_query_plan; + + /** @var The number of sub-queries (currently always limited to 1 by planning phase). */ + uint32_t _sub_query_count; + + /** @var The sub-query plans (each one must evaluate to a single value, whether by point, aggregate or limit 1). */ + JitPlan** _sub_query_plans; +}; + /** @define A special constant denoting a plan is not needed since jitted query has already been generated. */ #define MOT_READY_JIT_PLAN ((JitPlan*)-1) @@ -591,6 +632,9 @@ extern JitPlan* JitPreparePlan(Query* query, const char* queryString); /** @brief Queries whether a plan has a DISTINCT operator. */ extern bool JitPlanHasDistinct(JitPlan* plan); +/** @brief Queries whether a plan has an ORDER BY specifier. */ +extern bool JitPlanHasSort(JitPlan* plan); + /** * @brief Explains how a plan is to be executed. * @param query The parsed SQL query for which the jitted plan is to be explained. diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_source.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_source.cpp index c0e0b4ec14217ae79b7ab7a2301cd89d82a4e205..23423d6617abbedbece0ea71d734933ae39c10ae 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_source.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_source.cpp @@ -28,6 +28,7 @@ #include "utils/memutils.h" #include "jit_statistics.h" #include "debug_utils.h" +#include "mm_global_api.h" namespace JitExec { DECLARE_LOGGER(JitSource, JitExec); @@ -191,10 +192,14 @@ static char* CloneQueryString(const char* queryString) { char* newQueryString = NULL; if (queryString != nullptr) { - MemoryContext oldContext = CurrentMemoryContext; - CurrentMemoryContext = g_instance.instance_context; - newQueryString = pstrdup(queryString); - CurrentMemoryContext = oldContext; + size_t len = strlen(queryString); + if (len > 0) { + newQueryString = (char*)MOT::MemGlobalAlloc(len + 1); + if (newQueryString != nullptr) { + errno_t erc = strcpy_s(newQueryString, len + 1, queryString); + securec_check(erc, "\0", "\0"); + } + } } return newQueryString; } @@ -202,10 +207,7 @@ static char* CloneQueryString(const char* queryString) static void FreeQueryString(char* queryString) { if (queryString != nullptr) { - MemoryContext oldContext = CurrentMemoryContext; - CurrentMemoryContext = g_instance.instance_context; - pfree(queryString); - CurrentMemoryContext = oldContext; + MOT::MemGlobalFree(queryString); } } @@ -224,11 +226,7 @@ static char* ReallocQueryString(char* oldQueryString, const char* newQueryString strncpy_s(oldQueryString, oldLength, newQueryString, newLength + 1); // copy terminating null too securec_check(erc, "\0", "\0"); } else { - MemoryContext oldContext = CurrentMemoryContext; - CurrentMemoryContext = g_instance.instance_context; - pfree(oldQueryString); - oldQueryString = pstrdup(newQueryString); - CurrentMemoryContext = oldContext; + newQueryString = (char*)MOT::MemGlobalRealloc(oldQueryString, newLength, MOT::MEM_REALLOC_COPY_ZERO); } } return oldQueryString; @@ -351,6 +349,7 @@ static void JitSourcePurgeContextList(JitSource* jitSource, uint64_t relationId) static void RemoveJitSourceContextImpl(JitSource* jitSource, JitContext* jitContext) { + MOT_LOG_TRACE("Removing JIT context %p from source %p", jitContext, jitSource); JitContext* prev = nullptr; JitContext* curr = jitSource->m_contextList; while ((curr != nullptr) && (jitContext != curr)) { @@ -358,12 +357,15 @@ static void RemoveJitSourceContextImpl(JitSource* jitSource, JitContext* jitCont curr = curr->m_nextInSource; } if (curr != nullptr) { + MOT_LOG_TRACE("JIT context %p found in source %p, now removing", jitContext, jitSource); if (prev != nullptr) { prev->m_nextInSource = curr->m_nextInSource; } else { // curr is head MOT_ASSERT(curr == jitSource->m_contextList); jitSource->m_contextList = curr->m_nextInSource; } + } else { + MOT_LOG_WARN("Cannot remove JIT context %p from source %p: context not found", jitContext, jitSource); } } diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_source_pool.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_source_pool.cpp index e7cdbd2b69c51011a126d2503670b2b61fda7c61..099031a5ec718b17ab849aeba27d5decfda396cc 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_source_pool.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_source_pool.cpp @@ -28,6 +28,7 @@ #include "jit_source_pool.h" #include "utilities.h" +#include "mm_global_api.h" namespace JitExec { DECLARE_LOGGER(JitSourcePool, JitExec) @@ -57,15 +58,14 @@ struct __attribute__((packed)) JitSourcePool { }; // Globals -static JitSourcePool g_jitSourcePool __attribute__((aligned(64))); +static JitSourcePool g_jitSourcePool __attribute__((aligned(64))) = {0}; // forward declarations static void FreeJitSourceArray(uint32_t count); extern bool InitJitSourcePool(uint32_t poolSize) { - bool result = false; - + MOT_ASSERT(g_jitSourcePool.m_sourcePool == nullptr); errno_t erc = memset_s((void*)&g_jitSourcePool, sizeof(JitSourcePool), 0, sizeof(JitSourcePool)); securec_check(erc, "\0", "\0"); int res = pthread_spin_init(&g_jitSourcePool.m_lock, 0); @@ -78,12 +78,12 @@ extern bool InitJitSourcePool(uint32_t poolSize) } size_t allocSize = sizeof(JitSource) * poolSize; - res = posix_memalign((void**)&g_jitSourcePool.m_sourcePool, 64, allocSize); - if (res != 0) { - MOT_REPORT_SYSTEM_ERROR_CODE(res, - posix_memalign, + g_jitSourcePool.m_sourcePool = (JitSource*)MOT::MemGlobalAllocAligned(allocSize, L1_CACHE_LINE); + if (g_jitSourcePool.m_sourcePool == nullptr) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, "JIT Source Pool Initialization", - "Failed to allocate 64-byte aligned %u bytes for global JIT Source pool", + "Failed to allocate %u JIT source objects (64-byte aligned %u bytes) for global JIT source pool", + poolSize, allocSize); pthread_spin_destroy(&g_jitSourcePool.m_lock); return false; @@ -91,43 +91,38 @@ extern bool InitJitSourcePool(uint32_t poolSize) erc = memset_s(g_jitSourcePool.m_sourcePool, allocSize, 0, allocSize); securec_check(erc, "\0", "\0"); - if (g_jitSourcePool.m_sourcePool == NULL) { - pthread_spin_destroy(&g_jitSourcePool.m_lock); - MOT_REPORT_ERROR( - MOT_ERROR_OOM, "JIT Source Pool Initialization", "Failed to allocate %u JIT source objects", poolSize); - } else { - // we need now to construct each object - for (uint32_t i = 0; i < poolSize; ++i) { - JitSource* jitSource = &g_jitSourcePool.m_sourcePool[i]; - if (!InitJitSource(jitSource, "")) { - MOT_REPORT_ERROR( - MOT_ERROR_INTERNAL, "JIT Source Pool Initialization", "Failed to initialize JIT source %u", i); - // cleanup - FreeJitSourceArray(i); - pthread_spin_destroy(&g_jitSourcePool.m_lock); - return false; - } + // we need now to construct each object + for (uint32_t i = 0; i < poolSize; ++i) { + JitSource* jitSource = &g_jitSourcePool.m_sourcePool[i]; + if (!InitJitSource(jitSource, "")) { + MOT_REPORT_ERROR( + MOT_ERROR_INTERNAL, "JIT Source Pool Initialization", "Failed to initialize JIT source %u", i); + // cleanup + FreeJitSourceArray(i); + pthread_spin_destroy(&g_jitSourcePool.m_lock); + return false; } + } - // fill the free list - result = true; - g_jitSourcePool.m_poolSize = poolSize; - for (uint32_t i = 0; i < g_jitSourcePool.m_poolSize; ++i) { - JitSource* jitSource = &g_jitSourcePool.m_sourcePool[i]; - jitSource->_next = g_jitSourcePool.m_freeSourceList; - g_jitSourcePool.m_freeSourceList = jitSource; - } - g_jitSourcePool.m_freeSourceCount = g_jitSourcePool.m_poolSize; + // fill the free list + g_jitSourcePool.m_poolSize = poolSize; + for (uint32_t i = 0; i < g_jitSourcePool.m_poolSize; ++i) { + JitSource* jitSource = &g_jitSourcePool.m_sourcePool[i]; + jitSource->_next = g_jitSourcePool.m_freeSourceList; + g_jitSourcePool.m_freeSourceList = jitSource; } - return result; + g_jitSourcePool.m_freeSourceCount = g_jitSourcePool.m_poolSize; + + return true; } extern void DestroyJitSourcePool() { - if (g_jitSourcePool.m_sourcePool == NULL) + if (g_jitSourcePool.m_sourcePool == nullptr) { return; + } - FreeJitSourceArray(0); + FreeJitSourceArray(g_jitSourcePool.m_poolSize); int res = pthread_spin_destroy(&g_jitSourcePool.m_lock); if (res != 0) { @@ -137,9 +132,9 @@ extern void DestroyJitSourcePool() "Failed to destroy spin lock for global JIT source pool"); } - g_jitSourcePool.m_sourcePool = NULL; + g_jitSourcePool.m_sourcePool = nullptr; g_jitSourcePool.m_poolSize = 0; - g_jitSourcePool.m_freeSourceList = NULL; + g_jitSourcePool.m_freeSourceList = nullptr; g_jitSourcePool.m_freeSourceCount = 0; } @@ -209,13 +204,10 @@ extern void FreePooledJitSource(JitSource* jitSource) static void FreeJitSourceArray(uint32_t count) { - if (count == 0) { - count = g_jitSourcePool.m_poolSize; - } for (uint32_t i = 0; i < count; ++i) { DestroyJitSource(&g_jitSourcePool.m_sourcePool[i]); } - free(g_jitSourcePool.m_sourcePool); - g_jitSourcePool.m_sourcePool = NULL; + MOT::MemGlobalFree(g_jitSourcePool.m_sourcePool); + g_jitSourcePool.m_sourcePool = nullptr; } } // namespace JitExec diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.cpp index 0d3bdc4a2a931d7b89d115434364113f4434566a..b5ccc358a9d19f6dbe6fcdb3a6cf5f33fecb5711 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.cpp @@ -91,28 +91,28 @@ extern uint64_t getRegisterValue(ExecContext* exec_context, int register_ref) return result; } -uint64_t Instruction::exec(ExecContext* exec_context) +uint64_t Instruction::Exec(ExecContext* exec_context) { #ifdef MOT_JIT_DEBUG if (MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_DEBUG)) { MOT_LOG_DEBUG("Executing instruction:"); - dump(); + Dump(); fprintf(stderr, "\n"); } #endif - uint64_t value = execImpl(exec_context); + uint64_t value = ExecImpl(exec_context); if (_type == Regular) { setRegisterValue(exec_context, _register_ref, value); } return value; } -void Instruction::dump() +void Instruction::Dump() { if (_register_ref != -1) { fprintf(stderr, "%%%d = ", _register_ref); } - dumpImpl(); + DumpImpl(); } Datum ConstExpression::eval(ExecContext* exec_context) @@ -144,44 +144,44 @@ void ParamExpression::dump() fprintf(stderr, "getDatumParam(%%params, param_id=%d, arg_pos=%d)", _param_id, _arg_pos); } -uint64_t RegisterRefInstruction::exec(ExecContext* exec_context) +uint64_t RegisterRefInstruction::Exec(ExecContext* exec_context) { - return getRegisterValue(exec_context, getRegisterRef()); + return getRegisterValue(exec_context, GetRegisterRef()); } -void RegisterRefInstruction::dump() +void RegisterRefInstruction::Dump() { - fprintf(stderr, "%%%d", getRegisterRef()); + fprintf(stderr, "%%%d", GetRegisterRef()); } -uint64_t ReturnInstruction::exec(ExecContext* exec_context) +uint64_t ReturnInstruction::Exec(ExecContext* exec_context) { - return _return_value->exec(exec_context); + return _return_value->Exec(exec_context); } -void ReturnInstruction::dump() +void ReturnInstruction::Dump() { fprintf(stderr, "return "); - _return_value->dump(); + _return_value->Dump(); } -uint64_t ReturnNextInstruction::exec(ExecContext* exec_context) +uint64_t ReturnNextInstruction::Exec(ExecContext* exec_context) { - return _return_value->exec(exec_context); + return _return_value->Exec(exec_context); } -void ReturnNextInstruction::dump() +void ReturnNextInstruction::Dump() { fprintf(stderr, "return next "); - _return_value->dump(); + _return_value->Dump(); } -uint64_t ConstInstruction::exec(ExecContext* exec_context) +uint64_t ConstInstruction::Exec(ExecContext* exec_context) { return _value; } -void ConstInstruction::dump() +void ConstInstruction::Dump() { fprintf(stderr, "%" PRIu64, _value); } @@ -192,33 +192,33 @@ ExpressionInstruction::~ExpressionInstruction() delete _expr; } -uint64_t ExpressionInstruction::execImpl(ExecContext* exec_context) +uint64_t ExpressionInstruction::ExecImpl(ExecContext* exec_context) { return _expr->eval(exec_context); } -void ExpressionInstruction::dumpImpl() +void ExpressionInstruction::DumpImpl() { _expr->dump(); } -uint64_t GetExpressionRCInstruction::execImpl(ExecContext* exec_context) +uint64_t GetExpressionRCInstruction::ExecImpl(ExecContext* exec_context) { return exec_context->_expr_rc; } -void GetExpressionRCInstruction::dumpImpl() +void GetExpressionRCInstruction::DumpImpl() { fprintf(stderr, "getExpressionRC()"); } -uint64_t DebugLogInstruction::exec(ExecContext* exec_context) +uint64_t DebugLogInstruction::Exec(ExecContext* exec_context) { debugLog(_function, _msg); return (uint64_t)MOT::RC_OK; } -void DebugLogInstruction::dump() +void DebugLogInstruction::Dump() { fprintf(stderr, "debugLog(function='%s', msg='%s')", _function, _msg); } @@ -236,7 +236,7 @@ void BasicBlock::addInstruction(Instruction* instruction) _instructions.push_back(instruction); // update predecessors if necessary - if (instruction->getType() == Instruction::Branch) { + if (instruction->GetType() == Instruction::Branch) { AbstractBranchInstruction* branch_instruction = (AbstractBranchInstruction*)instruction; int branch_count = branch_instruction->getBranchCount(); for (int i = 0; i < branch_count; ++i) { @@ -274,7 +274,7 @@ bool BasicBlock::isTrivial() const bool result = false; if (_instructions.size() == 1) { Instruction* instruction = _instructions.front(); - if (instruction->getType() == Instruction::Branch) { + if (instruction->GetType() == Instruction::Branch) { AbstractBranchInstruction* branch_instruction = (AbstractBranchInstruction*)instruction; if (branch_instruction->getBranchType() == AbstractBranchInstruction::Unconditional) { result = true; @@ -290,8 +290,8 @@ BasicBlock* BasicBlock::getNextTrivalBlock() MOT_ASSERT(_instructions.size() == 1); if (_instructions.size() == 1) { Instruction* instruction = _instructions.front(); - MOT_ASSERT(instruction->getType() == Instruction::Branch); - if (instruction->getType() == Instruction::Branch) { + MOT_ASSERT(instruction->GetType() == Instruction::Branch); + if (instruction->GetType() == Instruction::Branch) { AbstractBranchInstruction* branch_instruction = (AbstractBranchInstruction*)instruction; MOT_ASSERT(branch_instruction->getBranchType() == AbstractBranchInstruction::Unconditional); if (branch_instruction->getBranchType() == AbstractBranchInstruction::Unconditional) { @@ -307,7 +307,7 @@ void BasicBlock::replaceTrivialBlockReference(BasicBlock* trivial_block, BasicBl InstructionList::iterator itr = _instructions.begin(); while (itr != _instructions.end()) { Instruction* instruction = *itr; - if (instruction->getType() == Instruction::Branch) { + if (instruction->GetType() == Instruction::Branch) { AbstractBranchInstruction* branch_instruction = (AbstractBranchInstruction*)instruction; branch_instruction->replaceTrivialBlockReference(trivial_block, next_block); } @@ -323,8 +323,8 @@ uint64_t BasicBlock::exec(ExecContext* exec_context) InstructionList::iterator itr = _instructions.begin(); while (itr != _instructions.end()) { Instruction* instruction = *itr; - uint64_t rc = instruction->exec(exec_context); - Instruction::Type itype = instruction->getType(); + uint64_t rc = instruction->Exec(exec_context); + Instruction::Type itype = instruction->GetType(); if (itype == Instruction::Return) { return rc; } @@ -360,10 +360,10 @@ uint64_t BasicBlock::execNext(ExecContext* exec_context) while (_next_instruction != _instructions.end()) { Instruction* instruction = *_next_instruction; ++_next_instruction; - uint64_t rc = instruction->exec(exec_context); + uint64_t rc = instruction->Exec(exec_context); // check instruction type to understand what happened - Instruction::Type itype = instruction->getType(); + Instruction::Type itype = instruction->GetType(); // case 1: function execution terminated if (itype == Instruction::Return) { @@ -396,7 +396,7 @@ bool BasicBlock::endsInBranch() { bool result = false; if (!_instructions.empty()) { - Instruction::Type last_instr_type = _instructions.back()->getType(); + Instruction::Type last_instr_type = _instructions.back()->GetType(); result = (last_instr_type == Instruction::Branch) || (last_instr_type == Instruction::Return); } return result; @@ -456,7 +456,7 @@ void BasicBlock::dumpInstructions() InstructionList::iterator itr = _instructions.begin(); while (itr != _instructions.end()) { fprintf(stderr, " "); - (*itr)->dump(); + (*itr)->Dump(); fprintf(stderr, ";\n"); ++itr; } @@ -470,7 +470,7 @@ bool BasicBlock::hasIllegalInstruction() Instruction* instruction = *itr; if (!isInstructionLegal(instruction)) { MOT_LOG_ERROR("Found illegal instruction:"); - instruction->dump(); + instruction->Dump(); fprintf(stderr, "\n"); return true; } @@ -485,21 +485,21 @@ bool BasicBlock::isInstructionLegal(Instruction* instruction) // otherwise check that all sub-instructions are visible if (MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_TRACE)) { MOT_LOG_TRACE("Checking whether instruction is legal:"); - instruction->dump(); + instruction->Dump(); fprintf(stderr, "\n"); } - if (instruction->getType() == Instruction::RegisterRef) { + if (instruction->GetType() == Instruction::RegisterRef) { BasicBlockList visited_blocks; - if (!isRegisterRefVisible(instruction->getRegisterRef(), &visited_blocks)) { + if (!isRegisterRefVisible(instruction->GetRegisterRef(), &visited_blocks)) { MOT_LOG_ERROR("Register reference instruction is invisible from current block %s:", getName()); - instruction->dump(); + instruction->Dump(); fprintf(stderr, "\n"); return false; } } else if (hasInvisibleRegisterRef(instruction)) { MOT_LOG_ERROR("Found instruction with invisible register ref:"); - instruction->dump(); + instruction->Dump(); fprintf(stderr, "\n"); return false; } @@ -509,17 +509,17 @@ bool BasicBlock::isInstructionLegal(Instruction* instruction) bool BasicBlock::hasInvisibleRegisterRef(Instruction* instruction) { MOT_LOG_TRACE("Checking if instruction contains invisible register reference"); - int sub_inst_count = instruction->getSubInstructionCount(); + int sub_inst_count = instruction->GetSubInstructionCount(); for (int i = 0; i < sub_inst_count; ++i) { - Instruction* sub_instruction = instruction->getSubInstructionAt(i); + Instruction* sub_instruction = instruction->GetSubInstructionAt(i); if (MOT_CHECK_LOG_LEVEL(MOT::LogLevel::LL_TRACE)) { MOT_LOG_TRACE("Checking sub-instruction:") - sub_instruction->dump(); + sub_instruction->Dump(); fprintf(stderr, "\n"); } if (!isInstructionLegal(sub_instruction)) { MOT_LOG_ERROR("Found illegal sub-instruction:"); - sub_instruction->dump(); + sub_instruction->Dump(); fprintf(stderr, "\n"); return true; } @@ -584,17 +584,17 @@ bool BasicBlock::containsRegRefDefinition(int ref_ref_value) return result; } -uint64_t ICmpInstruction::execImpl(ExecContext* exec_context) +uint64_t ICmpInstruction::ExecImpl(ExecContext* exec_context) { - uint64_t lhs_res = _lhs_instruction->exec(exec_context); - uint64_t rhs_res = _rhs_instruction->exec(exec_context); + uint64_t lhs_res = _lhs_instruction->Exec(exec_context); + uint64_t rhs_res = _rhs_instruction->Exec(exec_context); return exec_cmp(lhs_res, rhs_res); } -void ICmpInstruction::dumpImpl() +void ICmpInstruction::DumpImpl() { fprintf(stderr, "icmp "); - _lhs_instruction->dump(); + _lhs_instruction->Dump(); switch (_cmp_op) { case JitExec::JIT_ICMP_EQ: @@ -619,7 +619,7 @@ void ICmpInstruction::dumpImpl() fprintf(stderr, " cmp? "); } - _rhs_instruction->dump(); + _rhs_instruction->Dump(); } int ICmpInstruction::exec_cmp(uint64_t lhs_res, uint64_t rhs_res) @@ -677,10 +677,10 @@ void CondBranchInstruction::replaceTrivialBlockReference(BasicBlock* trivial_blo } } -uint64_t CondBranchInstruction::exec(ExecContext* exec_context) +uint64_t CondBranchInstruction::Exec(ExecContext* exec_context) { BasicBlock* result = NULL; - uint64_t rc = _if_test->exec(exec_context); + uint64_t rc = _if_test->Exec(exec_context); if (rc) { result = _true_branch; } else { @@ -689,10 +689,10 @@ uint64_t CondBranchInstruction::exec(ExecContext* exec_context) return (uint64_t)result; } -void CondBranchInstruction::dump() +void CondBranchInstruction::Dump() { fprintf(stderr, "br "); // format compatible with IR (meaning if non-zero jump to true branch) - _if_test->dump(); + _if_test->Dump(); fprintf(stderr, ", label %%%s, label %%%s", _true_branch->getName(), _false_branch->getName()); } @@ -721,12 +721,12 @@ void BranchInstruction::replaceTrivialBlockReference(BasicBlock* trivial_block, } } -uint64_t BranchInstruction::exec(ExecContext* exec_context) +uint64_t BranchInstruction::Exec(ExecContext* exec_context) { return (uint64_t)_target_branch; } -void BranchInstruction::dump() +void BranchInstruction::Dump() { fprintf(stderr, "br label %%%s", _target_branch->getName()); } @@ -784,8 +784,8 @@ uint64_t Function::execNext(ExecContext* exec_context) void Function::addInstruction(Instruction* instruction) { _all_instructions.push_back(instruction); - if (instruction->getRegisterRef() > _max_register_ref) { - _max_register_ref = instruction->getRegisterRef(); + if (instruction->GetRegisterRef() > _max_register_ref) { + _max_register_ref = instruction->GetRegisterRef(); } } @@ -935,8 +935,8 @@ Function* Builder::createFunction(const char* function_name, const char* query_s Instruction* Builder::addInstruction(Instruction* instruction) { Instruction* result = instruction; - if (instruction->getType() == Instruction::Regular) { - instruction->setRegisterRef(_next_register_ref); + if (instruction->GetType() == Instruction::Regular) { + instruction->SetRegisterRef(_next_register_ref); result = new (std::nothrow) RegisterRefInstruction(_next_register_ref); _current_block->recordRegisterReferenceDefinition(_next_register_ref); // for later validation _current_function->addInstruction(result); // for cleanup only diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h index f24b739febd2bfe8c60b44c1f5b57a7dddd9c822..fd4d362a2f8bfa1218462f6318d1f558a468c52a 100644 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm.h @@ -147,38 +147,38 @@ public: /** * @brief Executes the instruction. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result, or zero if instruction does not return a value. The returned * value is saved in the register associated with the instruction. */ - virtual uint64_t exec(ExecContext* exec_context); + virtual uint64_t Exec(ExecContext* execContext); /** @brief Retrieves the instruction type. */ - inline Type getType() const + inline Type GetType() const { return _type; } /** @brief Dumps the instruction into the standard error stream. */ - virtual void dump(); + virtual void Dump(); /** * @brief Sets the index of the register with which the instruction is associated. - * @param register_ref + * @param registerRef */ - inline void setRegisterRef(int register_ref) + inline void SetRegisterRef(int registerRef) { - _register_ref = register_ref; + _register_ref = registerRef; } /** @brief Retrieves the index of the register with which the instruction is associated. */ - inline int getRegisterRef() const + inline int GetRegisterRef() const { return _register_ref; } /** @brief Retrieves the number of sub-instructions referred to by this instruction. */ - inline int getSubInstructionCount() const + inline int GetSubInstructionCount() const { return _sub_instructions.size(); } @@ -188,7 +188,7 @@ public: * @param index The sub-instruction index. * @return The sub-instruction. */ - inline Instruction* getSubInstructionAt(int index) + inline Instruction* GetSubInstructionAt(int index) { MOT_ASSERT(index < (int)_sub_instructions.size()); return _sub_instructions[index]; @@ -204,17 +204,17 @@ protected: /** * @brief Implements the execution of the instruction. Must be overridden by sub-classes. - * @param exec_context + * @param execContext * @return */ - virtual uint64_t execImpl(ExecContext* exec_context) + virtual uint64_t ExecImpl(ExecContext* execContext) { MOT_ASSERT(false); return 0; } /** @brief Implements dumping the instruction to standard error stream. */ - virtual void dumpImpl() + virtual void DumpImpl() {} /** @@ -223,7 +223,7 @@ protected: * @note Every derived class who refers to sub-instruction must update the @ref Instruction * base-class, otherwise function verification might fail, or result in unexpected runtime behavior. */ - inline void addSubInstruction(Instruction* sub_instruction) + inline void AddSubInstruction(Instruction* sub_instruction) { _sub_instructions.push_back(sub_instruction); } @@ -380,7 +380,7 @@ public: */ explicit RegisterRefInstruction(int register_ref) : Instruction(Instruction::RegisterRef) { - setRegisterRef(register_ref); + SetRegisterRef(register_ref); } /** @brief Destructor. */ @@ -389,15 +389,15 @@ public: /** * @brief Executes the instruction by the retrieving the cached result from the appropriate register. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result. * @note The returned value is NOT saved in any register (as it is by itself being retrieved from * a register). */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dump() override; + void Dump() override; }; /*--------------------------------- ReturnInstruction --------------------------------*/ @@ -411,7 +411,7 @@ public: explicit ReturnInstruction(Instruction* return_value) : Instruction(Instruction::Return), _return_value(return_value) { - addSubInstruction(return_value); + AddSubInstruction(return_value); } /** @brief Destructor. */ @@ -423,16 +423,16 @@ public: /** * @brief Executes the instruction by evaluating the sub-instruction and returning the resulting * value. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result. * @note The returned value is saved in NOT saved in any register, since it is executed only once * (although the underlying sub-instruction could be very well a @ref RegisterRefInstruction * instruction). */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dump() override; + void Dump() override; private: /** @brief The sub-instruction that should be evaluated as the return value. */ @@ -452,7 +452,7 @@ public: */ ReturnNextInstruction(Instruction* return_value) : Instruction(Instruction::ReturnNext), _return_value(return_value) { - addSubInstruction(return_value); + AddSubInstruction(return_value); } /** @brief Destructor. */ @@ -464,16 +464,16 @@ public: /** * @brief Executes the instruction by evaluating the sub-instruction and returning the resulting * value. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result. * @note The returned value is saved in NOT saved in any register, since it is executed only once * (although the underlying sub-instruction could be very well a @ref RegisterRefInstruction * instruction). */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dump() override; + void Dump() override; private: /** @brief The sub-instruction that should be evaluated as the return value. */ @@ -501,14 +501,14 @@ public: /** * @brief Executes the instruction by returning the constant value. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result. * @note The returned value is NOT saved in any register. */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* exec_cContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dump() override; + void Dump() override; private: /** @var The constant value. */ @@ -536,14 +536,14 @@ public: protected: /** * @brief Implements the execution of the instruction by evaluating the sub-expression. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result. * @note The returned value is saved in a register. */ - uint64_t execImpl(ExecContext* exec_context) override; + uint64_t ExecImpl(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dumpImpl() override; + void DumpImpl() override; private: /** @var The sub-expression. */ @@ -572,15 +572,15 @@ protected: /** * @brief Implements the execution of the instruction by retrieving the execution result of the * recently evaluated expression from the execution context. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The execution result. * @note The returned value is saved in a register, since a subsequent expression evaluation will * override the recent expression evaluation execution result in the execution context. */ - uint64_t execImpl(ExecContext* exec_context) override; + uint64_t ExecImpl(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dumpImpl() override; + void DumpImpl() override; }; /*--------------------------------- DebugLogInstruction --------------------------------*/ @@ -605,13 +605,13 @@ public: /** * @brief Executes the instruction by printing the debug message. - * @param exec_context The execution context. + * @param execContext The execution context. * @return Not used. */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dump() override; + void Dump() override; private: /** @brief The issuing function. */ @@ -887,13 +887,13 @@ public: protected: /** * @brief Implements the execution of the instruction. - * @param exec_context The execution context. + * @param execContext The execution context. * @return Non-zero value if the comparison resulted in true, otherwise zero. */ - uint64_t execImpl(ExecContext* exec_context) override; + uint64_t ExecImpl(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dumpImpl() override; + void DumpImpl() override; private: /** @var The left-hand side operand. */ @@ -960,13 +960,13 @@ public: /** * @brief Executes the instruction. Evaluates the condition and returns the next block to execute. - * @param exec_context The execution context. + * @param execContext The execution context. * @return The next block to execute. */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* execContext) override; /** @brief Dumps the instruction to the standard error stream. */ - void dump() override; + void Dump() override; private: /** @var The condition to test. */ @@ -1021,10 +1021,10 @@ public: * @param exec_context The execution context. * @return The next block to execute. */ - uint64_t exec(ExecContext* exec_context) override; + uint64_t Exec(ExecContext* exec_context) override; /** @brief Dumps the block to the standard error stream. */ - void dump() override; + void Dump() override; private: /** @var The next block to execute. */ @@ -1170,13 +1170,13 @@ public: /** * @brief Creates a function. This is the first step to do. - * @param function_name The name of the function. - * @param query_string The string of the query/function it executes. + * @param functionName The name of the function. + * @param queryString The string of the query/function it executes. * @return The resulting object or NULL if allocation failed. * @note The function is initialized with an initial empty entry blocks. New instructions will be * added to the entry block until a new block is started. */ - Function* createFunction(const char* function_name, const char* query_string); + Function* createFunction(const char* functionName, const char* queryString); /** * @brief Adds an instruction to the current block. @@ -1214,13 +1214,13 @@ public: /** * @brief Creates an integer comparison instruction. - * @param lhs_instruction The left-hand side operand. - * @param rhs_instruction The right-hand side operand. - * @param cmp_op The comparison operator. + * @param lhsInstruction The left-hand side operand. + * @param rhsInstruction The right-hand side operand. + * @param cmpOp The comparison operator. * @return The resulting instruction. This is a @ref RegisterRefInstruction to the cached result * of the original instruction. */ - Instruction* CreateICmp(Instruction* lhs_instruction, Instruction* rhs_instruction, JitExec::JitICmpOp cmp_op); + Instruction* CreateICmp(Instruction* lhsInstruction, Instruction* rhsInstruction, JitExec::JitICmpOp cmpOp); /** * @brief Creates an integer EQUALS comparison instruction. diff --git a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp index 480744229f8d5f3c0c19a2d3014af6df486f8fa2..60d15bc3d3e6ca205b27a7b66b4bff1aa4c0119c 100755 --- a/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp +++ b/src/gausskernel/storage/mot/jit_exec/src/jit_tvm_exec.cpp @@ -84,6 +84,12 @@ struct JitTvmCodeGenContext { /** @var Inner table info (in JOIN queries). */ TableInfo m_innerTable_info; + /** @var Sub-query table info (in COMPOUND queries). */ + TableInfo* m_subQueryTableInfo; + + /** @var Sub-query count (in COMPOUND queries). */ + uint64_t m_subQueryCount; + /** @var The builder used for emitting code. */ Builder* _builder; @@ -117,18 +123,80 @@ static bool InitCodeGenContext(JitTvmCodeGenContext* ctx, Builder* builder, MOT: return true; } +/** @brief Initializes a context for compilation. */ +static bool InitCompoundCodeGenContext( + JitTvmCodeGenContext* ctx, Builder* builder, MOT::Table* table, MOT::Index* index, JitCompoundPlan* plan) +{ + // initialize outer query table info + errno_t erc = memset_s(ctx, sizeof(JitTvmCodeGenContext), 0, sizeof(JitTvmCodeGenContext)); + securec_check(erc, "\0", "\0"); + ctx->_builder = builder; + if (!InitTableInfo(&ctx->_table_info, table, index)) { + MOT_REPORT_ERROR( + MOT_ERROR_OOM, "JIT Compile", "Failed to initialize table information for code-generation context"); + return false; + } + ctx->m_subQueryCount = plan->_sub_query_count; + ctx->m_subQueryTableInfo = (TableInfo*)MOT::MemSessionAlloc(sizeof(TableInfo) * ctx->m_subQueryCount); + if (ctx->m_subQueryTableInfo == nullptr) { + MOT_REPORT_ERROR( + MOT_ERROR_OOM, "JIT Compile", "Failed to initialize table information for code-generation context"); + DestroyTableInfo(&ctx->_table_info); + return false; + } + + // initialize sub-query table info + bool result = true; + for (uint32_t i = 0; i < ctx->m_subQueryCount; ++i) { + JitPlan* subPlan = plan->_sub_query_plans[i]; + MOT::Table* subTable = nullptr; + MOT::Index* subIndex = nullptr; + if (subPlan->_plan_type == JIT_PLAN_POINT_QUERY) { + subTable = ((JitSelectPlan*)subPlan)->_query._table; + subIndex = subTable->GetPrimaryIndex(); + } else if (subPlan->_plan_type == JIT_PLAN_RANGE_SCAN) { + subTable = ((JitRangeSelectPlan*)subPlan)->_index_scan._table; + subIndex = subTable->GetIndex(((JitRangeSelectPlan*)subPlan)->_index_scan._index_id); + } else { + MOT_REPORT_ERROR( + MOT_ERROR_INTERNAL, "JIT Compile", "Invalid sub-plan %u type: %d", i, (int)subPlan->_plan_type); + result = false; + } + if (result && !InitTableInfo(&ctx->m_subQueryTableInfo[i], subTable, subIndex)) { + MOT_REPORT_ERROR(MOT_ERROR_OOM, + "JIT Compile", + "Failed to initialize sub-query table information for code-generation context"); + result = false; + } + if (!result) { + for (uint32_t j = 0; j < i; ++j) { + DestroyTableInfo(&ctx->m_subQueryTableInfo[j]); + } + MOT::MemSessionFree(ctx->m_subQueryTableInfo); + ctx->m_subQueryTableInfo = nullptr; + DestroyTableInfo(&ctx->_table_info); + return false; + } + } + + return true; +} + /** @brief Destroys a compilation context. */ static void DestroyCodeGenContext(JitTvmCodeGenContext* ctx) { if (ctx != nullptr) { DestroyTableInfo(&ctx->_table_info); DestroyTableInfo(&ctx->m_innerTable_info); + for (uint32_t i = 0; i < ctx->m_subQueryCount; ++i) { + DestroyTableInfo(&ctx->m_subQueryTableInfo[i]); + } } } /** @brief Gets a key from the execution context. */ static MOT::Key* getExecContextKey( - ExecContext* exec_context, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) + ExecContext* exec_context, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, int subQueryIndex) { MOT::Key* key = nullptr; if (range_scan_type == JIT_RANGE_SCAN_INNER) { @@ -137,12 +205,18 @@ static MOT::Key* getExecContextKey( } else { key = exec_context->_jit_context->m_innerSearchKey; } - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { if (range_itr_type == JIT_RANGE_ITERATOR_END) { key = exec_context->_jit_context->m_endIteratorKey; } else { key = exec_context->_jit_context->m_searchKey; } + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + if (range_itr_type == JIT_RANGE_ITERATOR_END) { + key = exec_context->_jit_context->m_subQueryData[subQueryIndex].m_endIteratorKey; + } else { + key = exec_context->_jit_context->m_subQueryData[subQueryIndex].m_searchKey; + } } return key; } @@ -167,14 +241,14 @@ public: Datum eval(ExecContext* exec_context) final { exec_context->_expr_rc = MOT_NO_ERROR; - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); return readDatumColumn(_table, row, _table_colid, _arg_pos); } void dump() final { (void)fprintf(stderr, "readDatumColumn(%%table, %%row="); - _row_inst->dump(); + _row_inst->Dump(); (void)fprintf(stderr, ", table_colid=%d, arg_pos=%d)", _table_colid, _arg_pos); } @@ -604,12 +678,12 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { return (uint64_t)isSoftMemoryLimitReached(); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "isSoftMemoryLimitReached()"); } @@ -618,70 +692,86 @@ protected: /** InitSearchKeyInstruction */ class InitSearchKeyInstruction : public Instruction { public: - explicit InitSearchKeyInstruction(JitRangeScanType range_scan_type) - : Instruction(Instruction::Void), _range_scan_type(range_scan_type) + explicit InitSearchKeyInstruction(JitRangeScanType range_scan_type, int subQueryIndex) + : Instruction(Instruction::Void), _range_scan_type(range_scan_type), m_subQueryIndex(subQueryIndex) {} ~InitSearchKeyInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { InitKey(exec_context->_jit_context->m_innerSearchKey, exec_context->_jit_context->m_innerIndex); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { InitKey(exec_context->_jit_context->m_searchKey, exec_context->_jit_context->m_index); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitContext::SubQueryData* subQueryData = &exec_context->_jit_context->m_subQueryData[m_subQueryIndex]; + InitKey(subQueryData->m_searchKey, subQueryData->m_index); + } else { + return (uint64_t)MOT::RC_ERROR; } return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, "InitKey(%%inner_search_key, %%inner_index)"); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "InitKey(%%search_key, %%index)"); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf( + stderr, "InitKey(%%sub_query_key[%d], %%sub_query_index[%d])", m_subQueryIndex, m_subQueryIndex); } } private: JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** GetColumnAtInstruction */ class GetColumnAtInstruction : public Instruction { public: - GetColumnAtInstruction(int table_colid, JitRangeScanType range_scan_type) - : _table_colid(table_colid), _range_scan_type(range_scan_type) + GetColumnAtInstruction(int table_colid, JitRangeScanType range_scan_type, int subQueryIndex) + : _table_colid(table_colid), _range_scan_type(range_scan_type), m_subQueryIndex(subQueryIndex) {} ~GetColumnAtInstruction() final {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { MOT::Column* column = nullptr; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { column = getColumnAt(exec_context->_jit_context->m_innerTable, _table_colid); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { column = getColumnAt(exec_context->_jit_context->m_table, _table_colid); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + column = getColumnAt(exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_table, _table_colid); + } else { + return (uint64_t) nullptr; } return (uint64_t)column; } - void dumpImpl() final + void DumpImpl() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, "%%column = %%inner_table->columns[%d]", _table_colid); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "%%column = %%table->columns[%d]", _table_colid); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, "%%column = %%sub_query[%d].table->columns[%d]", m_subQueryIndex, _table_colid); } } private: int _table_colid; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** SetExprArgIsNullInstruction */ @@ -694,13 +784,13 @@ public: ~SetExprArgIsNullInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { setExprArgIsNull(_arg_pos, _is_null); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "setExprArgIsNull(%d, %d)", _arg_pos, _is_null); } @@ -720,12 +810,12 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { return (uint64_t)getExprArgIsNull(_arg_pos); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "getExprArgIsNull(%d)", _arg_pos); } @@ -740,9 +830,9 @@ public: WriteDatumColumnInstruction(Instruction* row_inst, Instruction* column_inst, Instruction* sub_expr) : Instruction(Instruction::Void), _row_inst(row_inst), _column_inst(column_inst), _sub_expr(sub_expr) { - addSubInstruction(row_inst); - addSubInstruction(column_inst); - addSubInstruction(sub_expr); + AddSubInstruction(row_inst); + AddSubInstruction(column_inst); + AddSubInstruction(sub_expr); } ~WriteDatumColumnInstruction() final @@ -751,23 +841,23 @@ public: _column_inst = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - Datum arg = (Datum)_sub_expr->exec(exec_context); - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); - MOT::Column* column = (MOT::Column*)_column_inst->exec(exec_context); + Datum arg = (Datum)_sub_expr->Exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); + MOT::Column* column = (MOT::Column*)_column_inst->Exec(exec_context); writeDatumColumn(row, column, arg); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "writeDatumColumn(%%row="); - _row_inst->dump(); + _row_inst->Dump(); (void)fprintf(stderr, ", %%column="); - _column_inst->dump(); + _column_inst->Dump(); (void)fprintf(stderr, ", "); - _sub_expr->dump(); + _sub_expr->Dump(); (void)fprintf(stderr, ")"); } @@ -781,7 +871,7 @@ private: class BuildDatumKeyInstruction : public Instruction { public: BuildDatumKeyInstruction(Instruction* column_inst, Instruction* sub_expr, int index_colid, int offset, int size, - int value_type, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) + int value_type, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, int subQueryIndex) : Instruction(Instruction::Void), _column_inst(column_inst), _sub_expr(sub_expr), @@ -790,10 +880,11 @@ public: _size(size), _value_type(value_type), _range_itr_type(range_itr_type), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) { - addSubInstruction(_column_inst); - addSubInstruction(_sub_expr); + AddSubInstruction(_column_inst); + AddSubInstruction(_sub_expr); } ~BuildDatumKeyInstruction() final @@ -802,33 +893,39 @@ public: _sub_expr = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - Datum arg = (Datum)_sub_expr->exec(exec_context); - MOT::Column* column = (MOT::Column*)_column_inst->exec(exec_context); - MOT::Key* key = getExecContextKey(exec_context, _range_itr_type, _range_scan_type); + Datum arg = (Datum)_sub_expr->Exec(exec_context); + MOT::Column* column = (MOT::Column*)_column_inst->Exec(exec_context); + MOT::Key* key = getExecContextKey(exec_context, _range_itr_type, _range_scan_type, m_subQueryIndex); buildDatumKey(column, key, arg, _index_colid, _offset, _size, _value_type); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "buildDatumKey(%%column="); - _column_inst->dump(); + _column_inst->Dump(); if (_range_scan_type == JIT_RANGE_SCAN_INNER) { if (_range_itr_type == JIT_RANGE_ITERATOR_END) { - (void)fprintf(stderr, ", %%innerm_endIteratorKey, "); + (void)fprintf(stderr, ", %%inner_end_iterator_key, "); } else { (void)fprintf(stderr, ", %%inner_search_key, "); } - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { if (_range_itr_type == JIT_RANGE_ITERATOR_END) { (void)fprintf(stderr, ", %%end_iterator_key, "); } else { (void)fprintf(stderr, ", %%search_key, "); } + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + if (_range_itr_type == JIT_RANGE_ITERATOR_END) { + (void)fprintf(stderr, ", %%sub_query[%d].end_iterator_key, ", m_subQueryIndex); + } else { + (void)fprintf(stderr, ", %%sub_query[%d].search_key, ", m_subQueryIndex); + } } - _sub_expr->dump(); + _sub_expr->Dump(); (void)fprintf( stderr, ", index_colid=%d, offset=%d, size=%d, value_type=%d)", _index_colid, _offset, _size, _value_type); } @@ -842,6 +939,7 @@ private: int _value_type; JitRangeIteratorType _range_itr_type; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** SetBitInstruction */ @@ -853,13 +951,13 @@ public: ~SetBitInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { setBit(exec_context->_jit_context->m_bitmapSet, _col); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "setBit(%%bitmap_set, col=%d)", _col); } @@ -877,13 +975,13 @@ public: ~ResetBitmapSetInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { resetBitmapSet(exec_context->_jit_context->m_bitmapSet); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "resetBitmapSet(%%bitmap_set)"); } @@ -894,7 +992,7 @@ class WriteRowInstruction : public Instruction { public: explicit WriteRowInstruction(Instruction* row_inst) : _row_inst(row_inst) { - addSubInstruction(_row_inst); + AddSubInstruction(_row_inst); } ~WriteRowInstruction() final @@ -903,16 +1001,16 @@ public: } protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); return (uint64_t)writeRow(row, exec_context->_jit_context->m_bitmapSet); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "writeRow(%%row="); - _row_inst->dump(); + _row_inst->Dump(); (void)fprintf(stderr, ", %%bitmap_set)"); } @@ -923,43 +1021,55 @@ private: /** SearchRowInstruction */ class SearchRowInstruction : public Instruction { public: - SearchRowInstruction(MOT::AccessType access_mode_value, JitRangeScanType range_scan_type) - : _access_mode_value(access_mode_value), _range_scan_type(range_scan_type) + SearchRowInstruction(MOT::AccessType access_mode_value, JitRangeScanType range_scan_type, int subQueryIndex) + : _access_mode_value(access_mode_value), _range_scan_type(range_scan_type), m_subQueryIndex(subQueryIndex) {} ~SearchRowInstruction() final {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { MOT::Row* row = nullptr; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { row = searchRow(exec_context->_jit_context->m_innerTable, exec_context->_jit_context->m_innerSearchKey, _access_mode_value); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { row = searchRow( exec_context->_jit_context->m_table, exec_context->_jit_context->m_searchKey, _access_mode_value); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitContext::SubQueryData* subQueryData = &exec_context->_jit_context->m_subQueryData[m_subQueryIndex]; + row = searchRow(subQueryData->m_table, subQueryData->m_searchKey, _access_mode_value); + } else { + return (uint64_t) nullptr; } return (uint64_t)row; } - void dumpImpl() final + void DumpImpl() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, "%%row = searchRow(%%inner_table, %%inner_search_key, access_mode_value=%d)", (int)_access_mode_value); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf( stderr, "%%row = searchRow(%%table, %%search_key, access_mode_value=%d)", (int)_access_mode_value); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, + "%%row = searchRow(%%sub_query[%d].table, %%sub_query[%d].search_key, access_mode_value=%d)", + m_subQueryIndex, + m_subQueryIndex, + (int)_access_mode_value); } } private: MOT::AccessType _access_mode_value; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class CreateNewRowInstruction */ @@ -972,13 +1082,13 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { MOT::Row* row = createNewRow(exec_context->_jit_context->m_table); return (uint64_t)row; } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "%%row = createNewRow(%%table)"); } @@ -989,7 +1099,7 @@ class InsertRowInstruction : public Instruction { public: explicit InsertRowInstruction(Instruction* row_inst) : _row_inst(row_inst) { - addSubInstruction(_row_inst); + AddSubInstruction(_row_inst); } ~InsertRowInstruction() final @@ -998,16 +1108,16 @@ public: } protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); return (uint64_t)insertRow(exec_context->_jit_context->m_table, row); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "insertRow(%%table, %%row="); - _row_inst->dump(); + _row_inst->Dump(); (void)fprintf(stderr, ")"); } @@ -1024,12 +1134,12 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { return (uint64_t)deleteRow(); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "deleteRow()"); } @@ -1040,7 +1150,7 @@ class SetRowNullBitsInstruction : public Instruction { public: explicit SetRowNullBitsInstruction(Instruction* row_inst) : Instruction(Instruction::Void), _row_inst(row_inst) { - addSubInstruction(_row_inst); + AddSubInstruction(_row_inst); } ~SetRowNullBitsInstruction() final @@ -1048,17 +1158,17 @@ public: _row_inst = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); setRowNullBits(exec_context->_jit_context->m_table, row); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "setRowNullBits(%%table, %%row="); - _row_inst->dump(); + _row_inst->Dump(); (void)fprintf(stderr, ")"); } @@ -1072,7 +1182,7 @@ public: SetExprResultNullBitInstruction(Instruction* row_inst, int table_colid) : _row_inst(row_inst), _table_colid(table_colid) { - addSubInstruction(_row_inst); + AddSubInstruction(_row_inst); } ~SetExprResultNullBitInstruction() final @@ -1081,17 +1191,17 @@ public: } protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { // always performed on main table (there is no inner table in UPDATE command) - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); return (uint64_t)setExprResultNullBit(exec_context->_jit_context->m_table, row, _table_colid); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "setExprResultNullBit(%%table, %%row="); - _row_inst->dump(); + _row_inst->Dump(); (void)fprintf(stderr, ", table_colid=%d)", _table_colid); } @@ -1109,13 +1219,13 @@ public: ~ExecClearTupleInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { execClearTuple(exec_context->_slot); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "execClearTuple(%%slot)"); } @@ -1130,13 +1240,13 @@ public: ~ExecStoreVirtualTupleInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { execStoreVirtualTuple(exec_context->_slot); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "execStoreVirtualTuple(%%slot)"); } @@ -1145,14 +1255,16 @@ public: /** @class SelectColumnInstruction */ class SelectColumnInstruction : public Instruction { public: - SelectColumnInstruction(Instruction* row_inst, int table_colid, int tuple_colid, JitRangeScanType range_scan_type) + SelectColumnInstruction( + Instruction* row_inst, int table_colid, int tuple_colid, JitRangeScanType range_scan_type, int subQueryIndex) : Instruction(Instruction::Void), _row_inst(row_inst), _table_colid(table_colid), _tuple_colid(tuple_colid), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) { - addSubInstruction(_row_inst); + AddSubInstruction(_row_inst); } ~SelectColumnInstruction() final @@ -1160,27 +1272,42 @@ public: _row_inst = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - MOT::Row* row = (MOT::Row*)_row_inst->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row_inst->Exec(exec_context); if (_range_scan_type == JIT_RANGE_SCAN_INNER) { selectColumn( exec_context->_jit_context->m_innerTable, row, exec_context->_slot, _table_colid, _tuple_colid); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { selectColumn(exec_context->_jit_context->m_table, row, exec_context->_slot, _table_colid, _tuple_colid); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitContext::SubQueryData* subQueryData = &exec_context->_jit_context->m_subQueryData[m_subQueryIndex]; + selectColumn(subQueryData->m_table, row, subQueryData->m_slot, _table_colid, _tuple_colid); + } else { + return (uint64_t)MOT::RC_ERROR; } return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, "selectColumn(%%inner_table, %%row="); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "selectColumn(%%table, %%row="); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, "selectColumn(%%sub_query[%d].table, %%row=", m_subQueryIndex); + } + _row_inst->Dump(); + if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, + ", %%sub_query[%d].slot, table_colid=%d, tuple_colid=%d)", + m_subQueryIndex, + _table_colid, + _tuple_colid); + } else { + (void)fprintf(stderr, ", %%slot, table_colid=%d, tuple_colid=%d)", _table_colid, _tuple_colid); } - _row_inst->dump(); - (void)fprintf(stderr, ", %%slot, table_colid=%d, tuple_colid=%d)", _table_colid, _tuple_colid); } private: @@ -1188,6 +1315,7 @@ private: int _table_colid; int _tuple_colid; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @@ -1209,14 +1337,14 @@ public: * @param exec_context The execution context. * @return Not used. */ - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { setTpProcessed(exec_context->_tp_processed, exec_context->_rows_processed); return (uint64_t)MOT::RC_OK; } /** @brief Dumps the instruction to the standard error stream. */ - void dump() final + void Dump() final { (void)fprintf(stderr, "setTpProcessed(%%tp_processed, %%rows_processed)"); } @@ -1245,14 +1373,14 @@ public: * @param exec_context The execution context. * @return Not used. */ - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { setScanEnded(exec_context->_scan_ended, _result); return (uint64_t)MOT::RC_OK; } /** @brief Dumps the instruction to the standard error stream. */ - void dump() final + void Dump() final { (void)fprintf(stderr, "setScanEnded(%%scan_ended, %d)", _result); } @@ -1271,13 +1399,13 @@ public: ~ResetRowsProcessedInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { exec_context->_rows_processed = 0; return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "%%rows_processed = 0"); } @@ -1292,13 +1420,13 @@ public: ~IncrementRowsProcessedInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { ++exec_context->_rows_processed; return 0; } - void dump() final + void Dump() final { (void)fprintf(stderr, "%%rows_processed += 1"); } @@ -1307,93 +1435,116 @@ public: /** @class CopyKeyInstruction */ class CopyKeyInstruction : public Instruction { public: - explicit CopyKeyInstruction(JitRangeScanType range_scan_type) - : Instruction(Instruction::Void), _range_scan_type(range_scan_type) + explicit CopyKeyInstruction(JitRangeScanType range_scan_type, int subQueryIndex) + : Instruction(Instruction::Void), _range_scan_type(range_scan_type), m_subQueryIndex(subQueryIndex) {} ~CopyKeyInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { copyKey(exec_context->_jit_context->m_innerIndex, exec_context->_jit_context->m_innerSearchKey, exec_context->_jit_context->m_innerEndIteratorKey); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { copyKey(exec_context->_jit_context->m_index, exec_context->_jit_context->m_searchKey, exec_context->_jit_context->m_endIteratorKey); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + JitContext::SubQueryData* subQueryData = &exec_context->_jit_context->m_subQueryData[m_subQueryIndex]; + copyKey(subQueryData->m_index, subQueryData->m_searchKey, subQueryData->m_endIteratorKey); } return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { - (void)fprintf(stderr, "copyKey(%%inner_index, %%inner_search_key, %%innerm_endIteratorKey)"); - } else { + (void)fprintf(stderr, "copyKey(%%inner_index, %%inner_search_key, %%inner_end_iterator_key)"); + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "copyKey(%%index, %%search_key, %%end_iterator_key)"); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, + "copyKey(%%sub_query[%d].index, %%sub_query[%d].search_key, %%sub_query[%d].end_iterator_key)", + m_subQueryIndex, + m_subQueryIndex, + m_subQueryIndex); } } private: JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class FillKeyPatternInstruction */ class FillKeyPatternInstruction : public Instruction { public: - FillKeyPatternInstruction( - JitRangeIteratorType itr_type, unsigned char pattern, int offset, int size, JitRangeScanType range_scan_type) + FillKeyPatternInstruction(JitRangeIteratorType itr_type, unsigned char pattern, int offset, int size, + JitRangeScanType range_scan_type, int subQueryIndex) : Instruction(Instruction::Void), _itr_type(itr_type), _pattern(pattern), _offset(offset), _size(size), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) {} ~FillKeyPatternInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - MOT::Key* key = getExecContextKey(exec_context, _itr_type, _range_scan_type); + MOT::Key* key = getExecContextKey(exec_context, _itr_type, _range_scan_type, m_subQueryIndex); FillKeyPattern(key, _pattern, _offset, _size); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { if (_itr_type == JIT_RANGE_ITERATOR_END) { (void)fprintf(stderr, - "FillKeyPattern(%%%s, pattern=0x%X, offset=%d, size=%d)", - "innerm_endIteratorKey", + "FillKeyPattern(%%inner_end_iterator_key, pattern=0x%X, offset=%d, size=%d)", (unsigned)_pattern, _offset, _size); } else { (void)fprintf(stderr, - "FillKeyPattern(%%%s, pattern=0x%X, offset=%d, size=%d)", - "inner_search_key", + "FillKeyPattern(%%inner_search_key, pattern=0x%X, offset=%d, size=%d)", (unsigned)_pattern, _offset, _size); } - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { + if (_itr_type == JIT_RANGE_ITERATOR_END) { + (void)fprintf(stderr, + "FillKeyPattern(%%end_iterator_key, pattern=0x%X, offset=%d, size=%d)", + (unsigned)_pattern, + _offset, + _size); + } else { + (void)fprintf(stderr, + "FillKeyPattern(%%search_key, pattern=0x%X, offset=%d, size=%d)", + (unsigned)_pattern, + _offset, + _size); + } + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { if (_itr_type == JIT_RANGE_ITERATOR_END) { (void)fprintf(stderr, - "FillKeyPattern(%%%s, pattern=0x%X, offset=%d, size=%d)", - "end_iterator_key", + "FillKeyPattern(%%sub_query[%d].end_iterator_key, pattern=0x%X, offset=%d, size=%d)", + m_subQueryIndex, (unsigned)_pattern, _offset, _size); } else { (void)fprintf(stderr, - "FillKeyPattern(%%%s, pattern=0x%X, offset=%d, size=%d)", - "search_key", + "FillKeyPattern(%%sub_query[%d].search_key, pattern=0x%X, offset=%d, size=%d)", + m_subQueryIndex, (unsigned)_pattern, _offset, _size); @@ -1407,44 +1558,67 @@ private: int _offset; int _size; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class AdjustKeyInstruction */ class AdjustKeyInstruction : public Instruction { public: - AdjustKeyInstruction(JitRangeIteratorType itr_type, unsigned char pattern, JitRangeScanType range_scan_type) - : Instruction(Instruction::Void), _itr_type(itr_type), _pattern(pattern), _range_scan_type(range_scan_type) + AdjustKeyInstruction( + JitRangeIteratorType itr_type, unsigned char pattern, JitRangeScanType range_scan_type, int subQueryIndex) + : Instruction(Instruction::Void), + _itr_type(itr_type), + _pattern(pattern), + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) {} ~AdjustKeyInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - MOT::Key* key = getExecContextKey(exec_context, _itr_type, _range_scan_type); - MOT::Index* index = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? exec_context->_jit_context->m_innerIndex - : exec_context->_jit_context->m_index; + MOT::Key* key = getExecContextKey(exec_context, _itr_type, _range_scan_type, m_subQueryIndex); + MOT::Index* index = nullptr; + if (_range_scan_type == JIT_RANGE_SCAN_INNER) { + index = exec_context->_jit_context->m_innerIndex; + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { + index = exec_context->_jit_context->m_index; + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index = exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_index; + } adjustKey(key, index, _pattern); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { if (_range_scan_type == JIT_RANGE_SCAN_INNER) { if (_itr_type == JIT_RANGE_ITERATOR_END) { - (void)fprintf(stderr, - "adjustKey(%%%s, %%inner_index, pattern=0x%X)", - "innerm_endIteratorKey", - (unsigned)_pattern); - } else { (void)fprintf( - stderr, "adjustKey(%%%s, %%inner_index, pattern=0x%X)", "inner_search_key", (unsigned)_pattern); + stderr, "adjustKey(%%inner_end_iterator_key, %%inner_index, pattern=0x%X)", (unsigned)_pattern); + } else { + (void)fprintf(stderr, "adjustKey(%%inner_search_key, %%inner_index, pattern=0x%X)", (unsigned)_pattern); } - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { + if (_itr_type == JIT_RANGE_ITERATOR_END) { + (void)fprintf(stderr, "adjustKey(%%end_iterator_key, %%index, pattern=0x%X)", (unsigned)_pattern); + } else { + (void)fprintf(stderr, "adjustKey(%%search_key, %%index, pattern=0x%X)", (unsigned)_pattern); + } + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { if (_itr_type == JIT_RANGE_ITERATOR_END) { - (void)fprintf(stderr, "adjustKey(%%%s, %%index, pattern=0x%X)", "end_iterator_key", (unsigned)_pattern); + (void)fprintf(stderr, + "adjustKey(%%sub_query[%d].end_iterator_key, %%sub_query[%d].index, pattern=0x%X)", + m_subQueryIndex, + m_subQueryIndex, + (unsigned)_pattern); } else { - (void)fprintf(stderr, "adjustKey(%%%s, %%index, pattern=0x%X)", "search_key", (unsigned)_pattern); + (void)fprintf(stderr, + "adjustKey(%%sub_query[%d].search_key, %%sub_query[%d].index, pattern=0x%X)", + m_subQueryIndex, + m_subQueryIndex, + (unsigned)_pattern); } } } @@ -1453,23 +1627,25 @@ private: JitRangeIteratorType _itr_type; unsigned char _pattern; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class SearchIteratorInstruction */ class SearchIteratorInstruction : public Instruction { public: SearchIteratorInstruction(JitIndexScanDirection index_scan_direction, JitRangeBoundMode range_bound_mode, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex) : _index_scan_direction(index_scan_direction), _range_bound_mode(range_bound_mode), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) {} ~SearchIteratorInstruction() final {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { MOT::IndexIterator* iterator = nullptr; int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; @@ -1479,16 +1655,21 @@ protected: exec_context->_jit_context->m_innerSearchKey, forward_scan, include_bound); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { iterator = searchIterator(exec_context->_jit_context->m_index, exec_context->_jit_context->m_searchKey, forward_scan, include_bound); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + iterator = searchIterator(exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_index, + exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_searchKey, + forward_scan, + include_bound); } return (uint64_t)iterator; } - void dumpImpl() final + void DumpImpl() final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; int include_bound = (_range_bound_mode == JIT_RANGE_BOUND_INCLUDE) ? 1 : 0; @@ -1497,11 +1678,18 @@ protected: "searchIterator(%%inner_index, %%inner_search_key, forward_scan=%d, include_bound=%d)", forward_scan, include_bound); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "searchIterator(%%index, %%search_key, forward_scan=%d, include_bound=%d)", forward_scan, include_bound); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, + "searchIterator(%%sub_query[%d].index, %%sub_query[%d].search_key, forward_scan=%d, include_bound=%d)", + m_subQueryIndex, + m_subQueryIndex, + forward_scan, + include_bound); } } @@ -1509,23 +1697,25 @@ private: JitIndexScanDirection _index_scan_direction; JitRangeBoundMode _range_bound_mode; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class CreateEndIteratorInstruction */ class CreateEndIteratorInstruction : public Instruction { public: CreateEndIteratorInstruction(JitIndexScanDirection index_scan_direction, JitRangeBoundMode range_bound_mode, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex) : _index_scan_direction(index_scan_direction), _range_bound_mode(range_bound_mode), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) {} ~CreateEndIteratorInstruction() final {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { MOT::IndexIterator* iterator = nullptr; int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; @@ -1535,29 +1725,42 @@ protected: exec_context->_jit_context->m_innerEndIteratorKey, forward_scan, include_bound); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { iterator = createEndIterator(exec_context->_jit_context->m_index, exec_context->_jit_context->m_endIteratorKey, forward_scan, include_bound); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + iterator = createEndIterator(exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_index, + exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_endIteratorKey, + forward_scan, + include_bound); } return (uint64_t)iterator; } - void dumpImpl() final + void DumpImpl() final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; int include_bound = (_range_bound_mode == JIT_RANGE_BOUND_INCLUDE) ? 1 : 0; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, - "createEndIterator(%%inner_index, %%innerm_endIteratorKey, forward_scan=%d, include_bound=%d)", + "createEndIterator(%%inner_index, %%inner_end_iterator_key, forward_scan=%d, include_bound=%d)", forward_scan, include_bound); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "createEndIterator(%%index, %%end_iterator_key, forward_scan=%d, include_bound=%d)", forward_scan, include_bound); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, + "createEndIterator(%%sub_query[%d].index, %%sub_query[%d].end_iterator_key, forward_scan=%d, " + "include_bound=%d)", + m_subQueryIndex, + m_subQueryIndex, + forward_scan, + include_bound); } } @@ -1565,20 +1768,22 @@ private: JitIndexScanDirection _index_scan_direction; JitRangeBoundMode _range_bound_mode; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class IsScanEndInstruction */ class IsScanEndInstruction : public Instruction { public: IsScanEndInstruction(JitIndexScanDirection index_scan_direction, Instruction* begin_itr_inst, - Instruction* end_itr_inst, JitRangeScanType range_scan_type) + Instruction* end_itr_inst, JitRangeScanType range_scan_type, int subQueryIndex) : _index_scan_direction(index_scan_direction), _begin_itr_inst(begin_itr_inst), _end_itr_inst(end_itr_inst), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) { - addSubInstruction(_begin_itr_inst); - addSubInstruction(_end_itr_inst); + AddSubInstruction(_begin_itr_inst); + AddSubInstruction(_end_itr_inst); } ~IsScanEndInstruction() final @@ -1588,31 +1793,36 @@ public: } protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { uint64_t result = 0; - MOT::IndexIterator* begin_itr = (MOT::IndexIterator*)_begin_itr_inst->exec(exec_context); - MOT::IndexIterator* end_itr = (MOT::IndexIterator*)_end_itr_inst->exec(exec_context); + MOT::IndexIterator* begin_itr = (MOT::IndexIterator*)_begin_itr_inst->Exec(exec_context); + MOT::IndexIterator* end_itr = (MOT::IndexIterator*)_end_itr_inst->Exec(exec_context); int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { result = isScanEnd(exec_context->_jit_context->m_innerIndex, begin_itr, end_itr, forward_scan); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { result = isScanEnd(exec_context->_jit_context->m_index, begin_itr, end_itr, forward_scan); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + result = isScanEnd( + exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_index, begin_itr, end_itr, forward_scan); } return result; } - void dumpImpl() final + void DumpImpl() final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, "isScanEnd(%%inner_index, %%iterator="); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "isScanEnd(%%index, %%iterator="); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, "isScanEnd(%%sub_query[%d].index, %%iterator=", m_subQueryIndex); } - _begin_itr_inst->dump(); + _begin_itr_inst->Dump(); (void)fprintf(stderr, ", %%end_iterator="); - _end_itr_inst->dump(); + _end_itr_inst->Dump(); (void)fprintf(stderr, ", forward_scan=%d)", forward_scan); } @@ -1621,21 +1831,23 @@ private: Instruction* _begin_itr_inst; Instruction* _end_itr_inst; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class GetRowFromIteratorInstruction */ class GetRowFromIteratorInstruction : public Instruction { public: GetRowFromIteratorInstruction(MOT::AccessType access_mode, JitIndexScanDirection index_scan_direction, - Instruction* begin_itr_inst, Instruction* end_itr_inst, JitRangeScanType range_scan_type) + Instruction* begin_itr_inst, Instruction* end_itr_inst, JitRangeScanType range_scan_type, int subQueryIndex) : _access_mode(access_mode), _index_scan_direction(index_scan_direction), _begin_itr_inst(begin_itr_inst), _end_itr_inst(end_itr_inst), - _range_scan_type(range_scan_type) + _range_scan_type(range_scan_type), + m_subQueryIndex(subQueryIndex) { - addSubInstruction(_begin_itr_inst); - addSubInstruction(_end_itr_inst); + AddSubInstruction(_begin_itr_inst); + AddSubInstruction(_end_itr_inst); } ~GetRowFromIteratorInstruction() final @@ -1645,33 +1857,41 @@ public: } protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { MOT::Row* row = nullptr; - MOT::IndexIterator* begin_itr = (MOT::IndexIterator*)_begin_itr_inst->exec(exec_context); - MOT::IndexIterator* end_itr = (MOT::IndexIterator*)_end_itr_inst->exec(exec_context); + MOT::IndexIterator* begin_itr = (MOT::IndexIterator*)_begin_itr_inst->Exec(exec_context); + MOT::IndexIterator* end_itr = (MOT::IndexIterator*)_end_itr_inst->Exec(exec_context); int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { row = getRowFromIterator( exec_context->_jit_context->m_innerIndex, begin_itr, end_itr, _access_mode, forward_scan); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { row = getRowFromIterator(exec_context->_jit_context->m_index, begin_itr, end_itr, _access_mode, forward_scan); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + row = getRowFromIterator(exec_context->_jit_context->m_subQueryData[m_subQueryIndex].m_index, + begin_itr, + end_itr, + _access_mode, + forward_scan); } return (uint64_t)row; } - void dumpImpl() final + void DumpImpl() final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; if (_range_scan_type == JIT_RANGE_SCAN_INNER) { (void)fprintf(stderr, "%%row = getRowFromIterator(%%inner_index, %%iterator="); - } else { + } else if (_range_scan_type == JIT_RANGE_SCAN_MAIN) { (void)fprintf(stderr, "%%row = getRowFromIterator(%%index, %%iterator="); + } else if (_range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + (void)fprintf(stderr, "%%row = getRowFromIterator(%%sub_query[%d].index, %%iterator=", m_subQueryIndex); } - _begin_itr_inst->dump(); + _begin_itr_inst->Dump(); (void)fprintf(stderr, ", %%end_iterator="); - _end_itr_inst->dump(); + _end_itr_inst->Dump(); (void)fprintf(stderr, ", access_mode=%d, forward_scan=%d)", (int)_access_mode, forward_scan); } @@ -1681,6 +1901,7 @@ private: Instruction* _begin_itr_inst; Instruction* _end_itr_inst; JitRangeScanType _range_scan_type; + int m_subQueryIndex; }; /** @class DestroyIteratorInstruction */ @@ -1688,7 +1909,7 @@ class DestroyIteratorInstruction : public Instruction { public: explicit DestroyIteratorInstruction(Instruction* itr_inst) : Instruction(Instruction::Void), _itr_inst(itr_inst) { - addSubInstruction(_itr_inst); + AddSubInstruction(_itr_inst); } ~DestroyIteratorInstruction() final @@ -1696,17 +1917,17 @@ public: _itr_inst = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - MOT::IndexIterator* itr = (MOT::IndexIterator*)_itr_inst->exec(exec_context); + MOT::IndexIterator* itr = (MOT::IndexIterator*)_itr_inst->Exec(exec_context); destroyIterator(itr); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "destroyIterator(%%iterator="); - _itr_inst->dump(); + _itr_inst->Dump(); (void)fprintf(stderr, ")"); } @@ -1720,7 +1941,7 @@ public: SetStateIteratorInstruction(Instruction* itr, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) : Instruction(Instruction::Void), _itr(itr), _range_itr_type(range_itr_type), _range_scan_type(range_scan_type) { - addSubInstruction(_itr); + AddSubInstruction(_itr); } ~SetStateIteratorInstruction() final @@ -1728,21 +1949,21 @@ public: _itr = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { - MOT::IndexIterator* itr = (MOT::IndexIterator*)_itr->exec(exec_context); + MOT::IndexIterator* itr = (MOT::IndexIterator*)_itr->Exec(exec_context); int begin_itr = (_range_itr_type == JIT_RANGE_ITERATOR_START) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; setStateIterator(itr, begin_itr, inner_scan); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { int begin_itr = (_range_itr_type == JIT_RANGE_ITERATOR_START) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "setStateIterator("); - _itr->dump(); + _itr->Dump(); (void)fprintf(stderr, ", begin_itr=%d, inner_scan=%d)", begin_itr, inner_scan); } @@ -1763,14 +1984,14 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int begin_itr = (_range_itr_type == JIT_RANGE_ITERATOR_START) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; return (uint64_t)getStateIterator(begin_itr, inner_scan); } - void dumpImpl() final + void DumpImpl() final { int begin_itr = (_range_itr_type == JIT_RANGE_ITERATOR_START) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; @@ -1793,14 +2014,14 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int begin_itr = (_range_itr_type == JIT_RANGE_ITERATOR_START) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; return (uint64_t)isStateIteratorNull(begin_itr, inner_scan); } - void dumpImpl() final + void DumpImpl() final { int begin_itr = (_range_itr_type == JIT_RANGE_ITERATOR_START) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; @@ -1823,14 +2044,14 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; return (uint64_t)isStateScanEnd(forward_scan, inner_scan); } - void dumpImpl() final + void DumpImpl() final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; @@ -1854,7 +2075,7 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; @@ -1862,7 +2083,7 @@ protected: return (uint64_t)row; } - void dumpImpl() final + void DumpImpl() final { int forward_scan = (_index_scan_direction == JIT_INDEX_SCAN_FORWARD) ? 1 : 0; int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; @@ -1889,14 +2110,14 @@ public: ~DestroyStateIteratorsInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; destroyStateIterators(inner_scan); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "destroyStateIterators(inner_scan=%d)", inner_scan); @@ -1916,14 +2137,14 @@ public: ~SetStateScanEndFlagInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; setStateScanEndFlag(_scan_ended, inner_scan); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "setStateScanEndFlag(scan_ended=%d, inner_scan=%d)", _scan_ended, inner_scan); @@ -1944,13 +2165,13 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; return (uint64_t)getStateScanEndFlag(inner_scan); } - void dumpImpl() final + void DumpImpl() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "getStateScanEndFlag(inner_scan=%d)", inner_scan); @@ -1969,14 +2190,14 @@ public: ~ResetStateRowInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; resetStateRow(inner_scan); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "resetStateRow(inner_scan=%d)", inner_scan); @@ -1991,7 +2212,7 @@ public: SetStateRowInstruction(Instruction* row, JitRangeScanType range_scan_type) : Instruction(Instruction::Void), _row(row), _range_scan_type(range_scan_type) { - addSubInstruction(_row); + AddSubInstruction(_row); } ~SetStateRowInstruction() final @@ -1999,19 +2220,19 @@ public: _row = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; - MOT::Row* row = (MOT::Row*)_row->exec(exec_context); + MOT::Row* row = (MOT::Row*)_row->Exec(exec_context); setStateRow(row, inner_scan); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "setStateRow(row="); - _row->dump(); + _row->Dump(); (void)fprintf(stderr, ", inner_scan=%d)", inner_scan); } @@ -2029,13 +2250,13 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; return (uint64_t)getStateRow(inner_scan); } - void dumpImpl() final + void DumpImpl() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "getStateRow(inner_scan=%d)", inner_scan); @@ -2053,13 +2274,13 @@ public: ~CopyOuterStateRowInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { copyOuterStateRow(); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "copyOuterStateRow()"); } @@ -2074,12 +2295,12 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { return (uint64_t)getOuterStateRowCopy(); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "getOuterStateRowCopy()"); } @@ -2094,13 +2315,13 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; return (uint64_t)isStateRowNull(inner_scan); } - void dumpImpl() final + void DumpImpl() final { int inner_scan = (_range_scan_type == JIT_RANGE_SCAN_INNER) ? 1 : 0; (void)fprintf(stderr, "isStateRowNull(inner_scan=%d)", inner_scan); @@ -2119,13 +2340,13 @@ public: ~ResetStateLimitCounterInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { resetStateLimitCounter(); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "resetStateLimitCounter()"); } @@ -2140,13 +2361,13 @@ public: ~IncrementStateLimitCounterInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { incrementStateLimitCounter(); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "incrementStateLimitCounter()"); } @@ -2162,13 +2383,13 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { uint64_t value = getStateLimitCounter(); return (uint64_t)value; } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "getStateLimitCounter()"); } @@ -2184,13 +2405,13 @@ public: ~PrepareAvgArrayInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { prepareAvgArray(_element_type, _element_count); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "prepareAvgArray(element_type=%d, element_count=%d)", _element_type, _element_count); } @@ -2231,14 +2452,14 @@ public: _avg_array = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { Datum avg_array = _avg_array->eval(exec_context); saveAvgArray(avg_array); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "saveAvgArray(avg_array="); _avg_array->dump(); @@ -2259,12 +2480,12 @@ public: {} protected: - Datum execImpl(ExecContext* exec_context) final + Datum ExecImpl(ExecContext* exec_context) final { return (uint64_t)computeAvgFromArray(_element_type); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "computeAvgFromArray(element_type=%d)", _element_type); } @@ -2282,13 +2503,13 @@ public: ~ResetAggValueInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { resetAggValue(_element_type); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "resetAggValue(element_type=%d)", _element_type); } @@ -2328,14 +2549,14 @@ public: _value = nullptr; } - Datum exec(ExecContext* exec_context) final + Datum Exec(ExecContext* exec_context) final { Datum value = (Datum)_value->eval(exec_context); setAggValue(value); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "setAggValue(value="); _value->dump(); @@ -2355,13 +2576,13 @@ public: ~ResetAggMaxMinNullInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { resetAggMaxMinNull(); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "resetAggMaxMinNull()"); } @@ -2376,13 +2597,13 @@ public: ~SetAggMaxMinNotNullInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { setAggMaxMinNotNull(); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "setAggMaxMinNotNull()"); } @@ -2398,12 +2619,12 @@ public: {} protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { return (uint64_t)getAggMaxMinIsNull(); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "getAggMaxMinIsNull()"); } @@ -2419,13 +2640,13 @@ public: ~PrepareDistinctSetInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { prepareDistinctSet(_element_type); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "prepareDistinctSet(element_type=%d)", _element_type); } @@ -2446,13 +2667,13 @@ public: } protected: - uint64_t execImpl(ExecContext* exec_context) final + uint64_t ExecImpl(ExecContext* exec_context) final { Datum value = (Datum)_value->eval(exec_context); return (uint64_t)insertDistinctItem(_element_type, value); } - void dumpImpl() final + void DumpImpl() final { (void)fprintf(stderr, "insertDistinctItem(element_type=%d, ", _element_type); _value->dump(); @@ -2474,13 +2695,13 @@ public: ~DestroyDistinctSetInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { destroyDistinctSet(_element_type); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "destroyDistinctSet(element_type=%d)", _element_type); } @@ -2499,13 +2720,13 @@ public: ~ResetTupleDatumInstruction() final {} - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* exec_context) final { resetTupleDatum(exec_context->_slot, _tuple_colid, _zero_type); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "resetTupleDatum(%%slot, tuple_colid=%d, zero_type=%d)", _tuple_colid, _zero_type); } @@ -2547,7 +2768,7 @@ public: WriteTupleDatumInstruction(int tuple_colid, Instruction* value) : Instruction(Instruction::Void), _tuple_colid(tuple_colid), _value(value) { - addSubInstruction(_value); + AddSubInstruction(_value); } ~WriteTupleDatumInstruction() final @@ -2555,17 +2776,17 @@ public: _value = nullptr; } - uint64_t exec(ExecContext* exec_context) final + uint64_t Exec(ExecContext* execContext) final { - Datum datum_value = (Datum)_value->exec(exec_context); - writeTupleDatum(exec_context->_slot, _tuple_colid, datum_value); + Datum datum_value = (Datum)_value->Exec(execContext); + writeTupleDatum(execContext->_slot, _tuple_colid, datum_value); return (uint64_t)MOT::RC_OK; } - void dump() final + void Dump() final { (void)fprintf(stderr, "writeTupleDatum(%%slot, tuple_colid=%d, ", _tuple_colid); - _value->dump(); + _value->Dump(); (void)fprintf(stderr, ")"); } @@ -2574,19 +2795,69 @@ private: Instruction* _value; }; +class SelectSubQueryResultExpression : public Expression { +public: + explicit SelectSubQueryResultExpression(int subQueryIndex) + : Expression(Expression::CannotFail), m_subQueryIndex(subQueryIndex) + {} + + ~SelectSubQueryResultExpression() final + {} + + Datum eval(ExecContext* exec_context) final + { + exec_context->_expr_rc = MOT_NO_ERROR; + return (uint64_t)SelectSubQueryResult(m_subQueryIndex); + } + + void dump() final + { + (void)fprintf(stderr, "SelectSubQueryResult(%%sub_query_index=%d)", m_subQueryIndex); + } + +private: + int m_subQueryIndex; +}; + +class CopyAggregateToSubQueryResultInstruction : public Instruction { +public: + explicit CopyAggregateToSubQueryResultInstruction(int subQueryIndex) + : Instruction(Instruction::Void), m_subQueryIndex(subQueryIndex) + {} + + ~CopyAggregateToSubQueryResultInstruction() final + {} + + uint64_t Exec(ExecContext* exec_context) final + { + CopyAggregateToSubQueryResult(m_subQueryIndex); + return (uint64_t)MOT::RC_OK; + } + + void Dump() final + { + (void)fprintf(stderr, "CopyAggregateToSubQueryResult(%%sub_query_index=%d)", m_subQueryIndex); + } + +private: + int m_subQueryIndex; +}; + static Instruction* AddIsSoftMemoryLimitReached(JitTvmCodeGenContext* ctx) { return ctx->_builder->addInstruction(new (std::nothrow) IsSoftMemoryLimitReachedInstruction()); } -static void AddInitSearchKey(JitTvmCodeGenContext* ctx, JitRangeScanType range_scan_type) +static void AddInitSearchKey(JitTvmCodeGenContext* ctx, JitRangeScanType rangeScanType, int subQueryIndex) { - (void)ctx->_builder->addInstruction(new (std::nothrow) InitSearchKeyInstruction(range_scan_type)); + (void)ctx->_builder->addInstruction(new (std::nothrow) InitSearchKeyInstruction(rangeScanType, subQueryIndex)); } -static Instruction* AddGetColumnAt(JitTvmCodeGenContext* ctx, int colid, JitRangeScanType range_scan_type) +static Instruction* AddGetColumnAt( + JitTvmCodeGenContext* ctx, int colid, JitRangeScanType range_scan_type, int subQueryIndex = -1) { - return ctx->_builder->addInstruction(new (std::nothrow) GetColumnAtInstruction(colid, range_scan_type)); + return ctx->_builder->addInstruction( + new (std::nothrow) GetColumnAtInstruction(colid, range_scan_type, subQueryIndex)); } static Instruction* AddSetExprArgIsNull(JitTvmCodeGenContext* ctx, int arg_pos, int isnull) @@ -2620,19 +2891,23 @@ static Instruction* AddWriteDatumColumn( } static void AddBuildDatumKey(JitTvmCodeGenContext* ctx, Instruction* column_inst, int index_colid, - Instruction* sub_expr, int value_type, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) + Instruction* sub_expr, int value_type, JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, + int subQueryIndex = -1) { int offset = -1; int size = -1; if (range_scan_type == JIT_RANGE_SCAN_INNER) { offset = ctx->m_innerTable_info.m_indexColumnOffsets[index_colid]; size = ctx->m_innerTable_info.m_index->GetLengthKeyFields()[index_colid]; - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { offset = ctx->_table_info.m_indexColumnOffsets[index_colid]; size = ctx->_table_info.m_index->GetLengthKeyFields()[index_colid]; + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + offset = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets[index_colid]; + size = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields()[index_colid]; } (void)ctx->_builder->addInstruction(new (std::nothrow) BuildDatumKeyInstruction( - column_inst, sub_expr, index_colid, offset, size, value_type, range_itr_type, range_scan_type)); + column_inst, sub_expr, index_colid, offset, size, value_type, range_itr_type, range_scan_type, subQueryIndex)); } static void AddSetBit(JitTvmCodeGenContext* ctx, int colid) @@ -2651,9 +2926,10 @@ static Instruction* AddWriteRow(JitTvmCodeGenContext* ctx, Instruction* row_inst } static Instruction* AddSearchRow( - JitTvmCodeGenContext* ctx, MOT::AccessType access_mode_value, JitRangeScanType range_scan_type) + JitTvmCodeGenContext* ctx, MOT::AccessType access_mode_value, JitRangeScanType range_scan_type, int subQueryIndex) { - return ctx->_builder->addInstruction(new (std::nothrow) SearchRowInstruction(access_mode_value, range_scan_type)); + return ctx->_builder->addInstruction( + new (std::nothrow) SearchRowInstruction(access_mode_value, range_scan_type, subQueryIndex)); } static Instruction* AddCreateNewRow(JitTvmCodeGenContext* ctx) @@ -2691,11 +2967,11 @@ static void AddExecStoreVirtualTuple(JitTvmCodeGenContext* ctx) ctx->_builder->addInstruction(new (std::nothrow) ExecStoreVirtualTupleInstruction()); } -static void AddSelectColumn(JitTvmCodeGenContext* ctx, Instruction* row_inst, int table_colid, int tuple_colid, - JitRangeScanType range_scan_type) +static void AddSelectColumn(JitTvmCodeGenContext* ctx, Instruction* rowInst, int tableColumnId, int tupleColumnId, + JitRangeScanType rangeScanType, int subQueryIndex) { - ctx->_builder->addInstruction( - new (std::nothrow) SelectColumnInstruction(row_inst, table_colid, tuple_colid, range_scan_type)); + ctx->_builder->addInstruction(new (std::nothrow) + SelectColumnInstruction(rowInst, tableColumnId, tupleColumnId, rangeScanType, subQueryIndex)); } static void AddSetTpProcessed(JitTvmCodeGenContext* ctx) @@ -2708,51 +2984,52 @@ static void AddSetScanEnded(JitTvmCodeGenContext* ctx, int result) ctx->_builder->addInstruction(new (std::nothrow) SetScanEndedInstruction(result)); } -static void AddCopyKey(JitTvmCodeGenContext* ctx, JitRangeScanType range_scan_type) +static void AddCopyKey(JitTvmCodeGenContext* ctx, JitRangeScanType range_scan_type, int subQueryIndex) { - ctx->_builder->addInstruction(new (std::nothrow) CopyKeyInstruction(range_scan_type)); + ctx->_builder->addInstruction(new (std::nothrow) CopyKeyInstruction(range_scan_type, subQueryIndex)); } static void AddFillKeyPattern(JitTvmCodeGenContext* ctx, unsigned char pattern, int offset, int size, - JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type) + JitRangeIteratorType rangeItrType, JitRangeScanType rangeScanType, int subQueryIndex) { - ctx->_builder->addInstruction( - new (std::nothrow) FillKeyPatternInstruction(range_itr_type, pattern, offset, size, range_scan_type)); + ctx->_builder->addInstruction(new (std::nothrow) + FillKeyPatternInstruction(rangeItrType, pattern, offset, size, rangeScanType, subQueryIndex)); } static void AddAdjustKey(JitTvmCodeGenContext* ctx, unsigned char pattern, JitRangeIteratorType range_itr_type, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex) { (void)ctx->_builder->addInstruction( - new (std::nothrow) AdjustKeyInstruction(range_itr_type, pattern, range_scan_type)); + new (std::nothrow) AdjustKeyInstruction(range_itr_type, pattern, range_scan_type, subQueryIndex)); } static Instruction* AddSearchIterator(JitTvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type) + JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type, int subQueryIndex) { - return ctx->_builder->addInstruction( - new (std::nothrow) SearchIteratorInstruction(index_scan_direction, range_bound_mode, range_scan_type)); + return ctx->_builder->addInstruction(new (std::nothrow) + SearchIteratorInstruction(index_scan_direction, range_bound_mode, range_scan_type, subQueryIndex)); } static Instruction* AddCreateEndIterator(JitTvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type) + JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type, int subQueryIndex = -1) { - return ctx->_builder->addInstruction( - new (std::nothrow) CreateEndIteratorInstruction(index_scan_direction, range_bound_mode, range_scan_type)); + return ctx->_builder->addInstruction(new (std::nothrow) + CreateEndIteratorInstruction(index_scan_direction, range_bound_mode, range_scan_type, subQueryIndex)); } static Instruction* AddIsScanEnd(JitTvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitTvmRuntimeCursor* cursor, JitRangeScanType range_scan_type) + JitTvmRuntimeCursor* cursor, JitRangeScanType range_scan_type, int subQueryIndex = -1) { - return ctx->_builder->addInstruction(new (std::nothrow) - IsScanEndInstruction(index_scan_direction, cursor->begin_itr, cursor->end_itr, range_scan_type)); + return ctx->_builder->addInstruction(new (std::nothrow) IsScanEndInstruction( + index_scan_direction, cursor->begin_itr, cursor->end_itr, range_scan_type, subQueryIndex)); } static Instruction* AddGetRowFromIterator(JitTvmCodeGenContext* ctx, MOT::AccessType access_mode, - JitIndexScanDirection index_scan_direction, JitTvmRuntimeCursor* cursor, JitRangeScanType range_scan_type) + JitIndexScanDirection index_scan_direction, JitTvmRuntimeCursor* cursor, JitRangeScanType range_scan_type, + int subQueryIndex) { return ctx->_builder->addInstruction(new (std::nothrow) GetRowFromIteratorInstruction( - access_mode, index_scan_direction, cursor->begin_itr, cursor->end_itr, range_scan_type)); + access_mode, index_scan_direction, cursor->begin_itr, cursor->end_itr, range_scan_type, subQueryIndex)); } static void AddDestroyIterator(JitTvmCodeGenContext* ctx, Instruction* itr_inst) @@ -2930,6 +3207,16 @@ static void AddWriteTupleDatum(JitTvmCodeGenContext* ctx, int tuple_colid, Instr (void)ctx->_builder->addInstruction(new (std::nothrow) WriteTupleDatumInstruction(tuple_colid, datum_value)); } +static Expression* AddSelectSubQueryResult(JitTvmCodeGenContext* ctx, int subQueryIndex) +{ + return new (std::nothrow) SelectSubQueryResultExpression(subQueryIndex); +} + +static void AddCopyAggregateToSubQueryResult(JitTvmCodeGenContext* ctx, int subQueryIndex) +{ + ctx->_builder->addInstruction(new (std::nothrow) CopyAggregateToSubQueryResultInstruction(subQueryIndex)); +} + #ifdef MOT_JIT_DEBUG static void IssueDebugLogImpl(JitTvmCodeGenContext* ctx, const char* function, const char* msg) { @@ -3167,10 +3454,10 @@ static Instruction* buildCreateNewRow(JitTvmCodeGenContext* ctx) } static Instruction* buildSearchRow( - JitTvmCodeGenContext* ctx, MOT::AccessType access_type, JitRangeScanType range_scan_type) + JitTvmCodeGenContext* ctx, MOT::AccessType access_type, JitRangeScanType range_scan_type, int subQueryIndex = -1) { IssueDebugLog("Searching row"); - Instruction* row = AddSearchRow(ctx, access_type, range_scan_type); + Instruction* row = AddSearchRow(ctx, access_type, range_scan_type, subQueryIndex); JIT_IF_BEGIN(check_row_found) JIT_IF_EVAL_NOT(row) @@ -3261,11 +3548,11 @@ static void buildDeleteRow(JitTvmCodeGenContext* ctx) } static Instruction* buildSearchIterator(JitTvmCodeGenContext* ctx, JitIndexScanDirection index_scan_direction, - JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type) + JitRangeBoundMode range_bound_mode, JitRangeScanType range_scan_type, int subQueryIndex = -1) { // search the row, execute: IndexIterator* itr = searchIterator(table, key); IssueDebugLog("Searching range start"); - Instruction* itr = AddSearchIterator(ctx, index_scan_direction, range_bound_mode, range_scan_type); + Instruction* itr = AddSearchIterator(ctx, index_scan_direction, range_bound_mode, range_scan_type, subQueryIndex); JIT_IF_BEGIN(check_itr_found) JIT_IF_EVAL_NOT(itr) @@ -3279,10 +3566,11 @@ static Instruction* buildSearchIterator(JitTvmCodeGenContext* ctx, JitIndexScanD static Instruction* buildGetRowFromIterator(JitTvmCodeGenContext* ctx, BasicBlock* endLoopBlock, MOT::AccessType access_mode, JitIndexScanDirection index_scan_direction, JitTvmRuntimeCursor* cursor, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex = -1) { IssueDebugLog("Retrieving row from iterator"); - Instruction* row = AddGetRowFromIterator(ctx, access_mode, index_scan_direction, cursor, range_scan_type); + Instruction* row = + AddGetRowFromIterator(ctx, access_mode, index_scan_direction, cursor, range_scan_type, subQueryIndex); JIT_IF_BEGIN(check_itr_row_found) JIT_IF_EVAL_NOT(row) @@ -3737,6 +4025,11 @@ static Expression* ProcessFilterExpr(JitTvmCodeGenContext* ctx, Instruction* row #undef APPLY_BINARY_CAST_OPERATOR #undef APPLY_TERNARY_CAST_OPERATOR +static Expression* ProcessSubLinkExpr(JitTvmCodeGenContext* ctx, Instruction* row, JitSubLinkExpr* expr, int* max_arg) +{ + return AddSelectSubQueryResult(ctx, expr->_sub_query_index); +} + static Expression* ProcessExpr(JitTvmCodeGenContext* ctx, Instruction* row, JitExpr* expr, int* max_arg) { Expression* result = nullptr; @@ -3751,6 +4044,8 @@ static Expression* ProcessExpr(JitTvmCodeGenContext* ctx, Instruction* row, JitE result = ProcessOpExpr(ctx, row, (JitOpExpr*)expr, max_arg); } else if (expr->_expr_type == JIT_EXPR_TYPE_FUNC) { result = ProcessFuncExpr(ctx, row, (JitFuncExpr*)expr, max_arg); + } else if (expr->_expr_type == JIT_EXPR_TYPE_SUBLINK) { + result = ProcessSubLinkExpr(ctx, row, (JitSubLinkExpr*)expr, max_arg); } else { MOT_LOG_TRACE( "Failed to generate jitted code for query: unsupported target expression type: %d", (int)expr->_expr_type); @@ -3797,12 +4092,13 @@ static JitContext* FinalizeCodegen(JitTvmCodeGenContext* ctx, int max_arg, JitCo jit_context->m_innerTable = ctx->m_innerTable_info.m_table; jit_context->m_innerIndex = ctx->m_innerTable_info.m_index; jit_context->m_commandType = command_type; + jit_context->m_subQueryCount = 0; return jit_context; } static bool buildScanExpression(JitTvmCodeGenContext* ctx, JitColumnExpr* expr, int* max_arg, - JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, Instruction* outer_row) + JitRangeIteratorType range_itr_type, JitRangeScanType range_scan_type, Instruction* outer_row, int subQueryIndex) { Expression* value_expr = ProcessExpr(ctx, outer_row, expr->_expr, max_arg); if (value_expr == nullptr) { @@ -3812,25 +4108,29 @@ static bool buildScanExpression(JitTvmCodeGenContext* ctx, JitColumnExpr* expr, Instruction* value = buildExpression(ctx, value_expr); Instruction* column = AddGetColumnAt(ctx, expr->_table_column_id, - range_scan_type); // no need to translate to zero-based index (first column is null bits) + range_scan_type, // no need to translate to zero-based index (first column is null bits) + subQueryIndex); int index_colid = -1; if (range_scan_type == JIT_RANGE_SCAN_INNER) { index_colid = ctx->m_innerTable_info.m_columnMap[expr->_table_column_id]; - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { index_colid = ctx->_table_info.m_columnMap[expr->_table_column_id]; + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index_colid = ctx->m_subQueryTableInfo[subQueryIndex].m_columnMap[expr->_table_column_id]; } - AddBuildDatumKey(ctx, column, index_colid, value, expr->_column_type, range_itr_type, range_scan_type); + AddBuildDatumKey( + ctx, column, index_colid, value, expr->_column_type, range_itr_type, range_scan_type, subQueryIndex); } return true; } static bool buildPointScan(JitTvmCodeGenContext* ctx, JitColumnExprArray* expr_array, int* max_arg, - JitRangeScanType range_scan_type, Instruction* outer_row, int expr_count = 0) + JitRangeScanType range_scan_type, Instruction* outer_row, int expr_count = 0, int subQueryIndex = -1) { if (expr_count == 0) { expr_count = expr_array->_count; } - AddInitSearchKey(ctx, range_scan_type); + AddInitSearchKey(ctx, range_scan_type, subQueryIndex); for (int i = 0; i < expr_count; ++i) { JitColumnExpr* expr = &expr_array->_exprs[i]; @@ -3845,7 +4145,7 @@ static bool buildPointScan(JitTvmCodeGenContext* ctx, JitColumnExprArray* expr_a expr->_table->GetTableName().c_str()); return false; } - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { if (expr->_table != ctx->_table_info.m_table) { MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, "Generate TVM JIT Code", @@ -3854,10 +4154,20 @@ static bool buildPointScan(JitTvmCodeGenContext* ctx, JitColumnExprArray* expr_a expr->_table->GetTableName().c_str()); return false; } + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + if (expr->_table != ctx->m_subQueryTableInfo[subQueryIndex].m_table) { + MOT_REPORT_ERROR(MOT_ERROR_INTERNAL, + "Generate TVM JIT Code", + "Invalid expression table (expected sub-query table %s, got %s)", + ctx->m_subQueryTableInfo[subQueryIndex].m_table->GetTableName().c_str(), + expr->_table->GetTableName().c_str()); + return false; + } } // prepare the sub-expression - if (!buildScanExpression(ctx, expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row)) { + if (!buildScanExpression( + ctx, expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row, subQueryIndex)) { return false; } } @@ -3890,7 +4200,7 @@ static bool writeRowColumns( } static bool selectRowColumns(JitTvmCodeGenContext* ctx, Instruction* row, JitSelectExprArray* expr_array, int* max_arg, - JitRangeScanType range_scan_type) + JitRangeScanType range_scan_type, int subQueryIndex = -1) { for (int i = 0; i < expr_array->_count; ++i) { JitSelectExpr* expr = &expr_array->_exprs[i]; @@ -3899,73 +4209,91 @@ static bool selectRowColumns(JitTvmCodeGenContext* ctx, Instruction* row, JitSel if (expr->_column_expr->_table != ctx->m_innerTable_info.m_table) { continue; } - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { if (expr->_column_expr->_table != ctx->_table_info.m_table) { continue; } + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + if (expr->_column_expr->_table != ctx->m_subQueryTableInfo[subQueryIndex].m_table) { + continue; + } } - AddSelectColumn(ctx, row, expr->_column_expr->_column_id, expr->_tuple_column_id, range_scan_type); + AddSelectColumn( + ctx, row, expr->_column_expr->_column_id, expr->_tuple_column_id, range_scan_type, subQueryIndex); } return true; } -static bool buildClosedRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, - JitRangeScanType range_scan_type, Instruction* outer_row) +static bool buildClosedRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* indexScan, int* maxArg, + JitRangeScanType rangeScanType, Instruction* outerRow, int subQueryIndex) { // a closed range scan starts just like a point scan (with not enough search expressions) and then adds key patterns - bool result = buildPointScan(ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row); + bool result = buildPointScan(ctx, &indexScan->_search_exprs, maxArg, rangeScanType, outerRow, 0, subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, rangeScanType, subQueryIndex); // now fill each key with the right pattern for the missing pkey columns in the where clause - bool ascending = (index_scan->_sort_order == JIT_QUERY_SORT_ASCENDING); + bool ascending = (indexScan->_sort_order == JIT_QUERY_SORT_ASCENDING); int* index_column_offsets = nullptr; const uint16_t* key_length = nullptr; int index_column_count = 0; - if (range_scan_type == JIT_RANGE_SCAN_INNER) { + if (rangeScanType == JIT_RANGE_SCAN_INNER) { index_column_offsets = ctx->m_innerTable_info.m_indexColumnOffsets; key_length = ctx->m_innerTable_info.m_index->GetLengthKeyFields(); index_column_count = ctx->m_innerTable_info.m_index->GetNumFields(); - } else { + } else if (rangeScanType == JIT_RANGE_SCAN_MAIN) { index_column_offsets = ctx->_table_info.m_indexColumnOffsets; key_length = ctx->_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_table_info.m_index->GetNumFields(); + } else if (rangeScanType == JIT_RANGE_SCAN_SUB_QUERY) { + index_column_offsets = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets; + key_length = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields(); + index_column_count = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetNumFields(); } - int first_zero_column = index_scan->_column_count; + int first_zero_column = indexScan->_column_count; for (int i = first_zero_column; i < index_column_count; ++i) { int offset = index_column_offsets[i]; int size = key_length[i]; MOT_LOG_DEBUG( "Filling begin/end iterator pattern for missing pkey fields at offset %d, size %d", offset, size); - AddFillKeyPattern(ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - AddFillKeyPattern(ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + AddFillKeyPattern( + ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, rangeScanType, subQueryIndex); + AddFillKeyPattern( + ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, rangeScanType, subQueryIndex); } AddAdjustKey(ctx, ascending ? 0x00 : 0xFF, JIT_RANGE_ITERATOR_START, - range_scan_type); // currently this is relevant only for secondary index searches + rangeScanType, // currently this is relevant only for secondary index searches + subQueryIndex); AddAdjustKey(ctx, ascending ? 0xFF : 0x00, JIT_RANGE_ITERATOR_END, - range_scan_type); // currently this is relevant only for secondary index searches + rangeScanType, // currently this is relevant only for secondary index searches + subQueryIndex); } return result; } static bool buildSemiOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, JitRangeScanType range_scan_type, JitRangeBoundMode* begin_range_bound, JitRangeBoundMode* end_range_bound, - Instruction* outer_row) + Instruction* outer_row, int subQueryIndex) { // an open range scan starts just like a point scan (with not enough search expressions) and then adds key patterns // we do not use the last search expression - bool result = buildPointScan( - ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row, index_scan->_search_exprs._count - 1); + bool result = buildPointScan(ctx, + &index_scan->_search_exprs, + max_arg, + range_scan_type, + outer_row, + index_scan->_search_exprs._count - 1, + subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, range_scan_type, subQueryIndex); // now fill each key with the right pattern for the missing pkey columns in the where clause bool ascending = (index_scan->_sort_order == JIT_QUERY_SORT_ASCENDING); @@ -3977,10 +4305,14 @@ static bool buildSemiOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* inde index_column_offsets = ctx->m_innerTable_info.m_indexColumnOffsets; key_length = ctx->m_innerTable_info.m_index->GetLengthKeyFields(); index_column_count = ctx->m_innerTable_info.m_index->GetNumFields(); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { index_column_offsets = ctx->_table_info.m_indexColumnOffsets; key_length = ctx->_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_table_info.m_index->GetNumFields(); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index_column_offsets = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets; + key_length = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields(); + index_column_count = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetNumFields(); } // prepare offset and size for last column in search @@ -3996,16 +4328,18 @@ static bool buildSemiOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* inde (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS)) { // this is an upper bound operator on an ascending semi-open scan so we fill the begin key with zeros, // and the end key with the value - AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, outer_row); + AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type, subQueryIndex); + buildScanExpression( + ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, outer_row, subQueryIndex); *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; *end_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; } else { // this is a lower bound operator on an ascending semi-open scan so we fill the begin key with the // value, and the end key with 0xFF - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row); - AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + buildScanExpression( + ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row, subQueryIndex); + AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type, subQueryIndex); *begin_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = JIT_RANGE_BOUND_INCLUDE; @@ -4015,16 +4349,18 @@ static bool buildSemiOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* inde (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS)) { // this is an upper bound operator on a descending semi-open scan so we fill the begin key with value, // and the end key with zeroes - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row); - AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + buildScanExpression( + ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, outer_row, subQueryIndex); + AddFillKeyPattern(ctx, 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type, subQueryIndex); *begin_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = JIT_RANGE_BOUND_INCLUDE; } else { // this is a lower bound operator on a descending semi-open scan so we fill the begin key with 0xFF, and // the end key with the value - AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, outer_row); + AddFillKeyPattern(ctx, 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type, subQueryIndex); + buildScanExpression( + ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, outer_row, subQueryIndex); *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; *end_range_bound = (index_scan->_last_dim_op1 == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; @@ -4039,34 +4375,51 @@ static bool buildSemiOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* inde MOT_LOG_DEBUG("Filling begin/end iterator pattern for missing pkey fields at offset %d, size %d", col_offset, key_len); - AddFillKeyPattern( - ctx, ascending ? 0x00 : 0xFF, col_offset, key_len, JIT_RANGE_ITERATOR_START, range_scan_type); - AddFillKeyPattern( - ctx, ascending ? 0xFF : 0x00, col_offset, key_len, JIT_RANGE_ITERATOR_END, range_scan_type); + AddFillKeyPattern(ctx, + ascending ? 0x00 : 0xFF, + col_offset, + key_len, + JIT_RANGE_ITERATOR_START, + range_scan_type, + subQueryIndex); + AddFillKeyPattern(ctx, + ascending ? 0xFF : 0x00, + col_offset, + key_len, + JIT_RANGE_ITERATOR_END, + range_scan_type, + subQueryIndex); } AddAdjustKey(ctx, ascending ? 0x00 : 0xFF, JIT_RANGE_ITERATOR_START, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); AddAdjustKey(ctx, ascending ? 0xFF : 0x00, JIT_RANGE_ITERATOR_END, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); } return result; } static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, JitRangeScanType range_scan_type, JitRangeBoundMode* begin_range_bound, JitRangeBoundMode* end_range_bound, - Instruction* outer_row) + Instruction* outer_row, int subQueryIndex) { // an open range scan starts just like a point scan (with not enough search expressions) and then adds key patterns // we do not use the last two expressions - bool result = buildPointScan( - ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row, index_scan->_search_exprs._count - 2); + bool result = buildPointScan(ctx, + &index_scan->_search_exprs, + max_arg, + range_scan_type, + outer_row, + index_scan->_search_exprs._count - 2, + subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); + AddCopyKey(ctx, range_scan_type, subQueryIndex); // now fill each key with the right pattern for the missing pkey columns in the where clause bool ascending = (index_scan->_sort_order == JIT_QUERY_SORT_ASCENDING); @@ -4078,10 +4431,14 @@ static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_sc index_column_offsets = ctx->m_innerTable_info.m_indexColumnOffsets; key_length = ctx->m_innerTable_info.m_index->GetLengthKeyFields(); index_column_count = ctx->m_innerTable_info.m_index->GetNumFields(); - } else { + } else if (range_scan_type == JIT_RANGE_SCAN_MAIN) { index_column_offsets = ctx->_table_info.m_indexColumnOffsets; key_length = ctx->_table_info.m_index->GetLengthKeyFields(); index_column_count = ctx->_table_info.m_index->GetNumFields(); + } else if (range_scan_type == JIT_RANGE_SCAN_SUB_QUERY) { + index_column_offsets = ctx->m_subQueryTableInfo[subQueryIndex].m_indexColumnOffsets; + key_length = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetLengthKeyFields(); + index_column_count = ctx->m_subQueryTableInfo[subQueryIndex].m_index->GetNumFields(); } // now we fill the last dimension (override extra work of point scan above) @@ -4100,13 +4457,15 @@ static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_sc max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // lower bound on begin iterator key + outer_row, // lower bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, before_last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // upper bound on end iterator key + outer_row, // upper bound on end iterator key + subQueryIndex); *begin_range_bound = (last_dim_op == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -4120,13 +4479,15 @@ static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_sc max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // lower bound on begin iterator key + outer_row, // lower bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // upper bound on end iterator key + outer_row, // upper bound on end iterator key + subQueryIndex); *begin_range_bound = (before_last_dim_op == JIT_WOC_GREATER_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -4142,13 +4503,15 @@ static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_sc max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // upper bound on begin iterator key + outer_row, // upper bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // lower bound on end iterator key + outer_row, // lower bound on end iterator key + subQueryIndex); *begin_range_bound = (before_last_dim_op == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -4162,13 +4525,15 @@ static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_sc max_arg, JIT_RANGE_ITERATOR_START, range_scan_type, - outer_row); // upper bound on begin iterator key + outer_row, // upper bound on begin iterator key + subQueryIndex); buildScanExpression(ctx, before_last_expr, max_arg, JIT_RANGE_ITERATOR_END, range_scan_type, - outer_row); // lower bound on end iterator key + outer_row, // lower bound on end iterator key + subQueryIndex); *begin_range_bound = (last_dim_op == JIT_WOC_LESS_EQUALS) ? JIT_RANGE_BOUND_INCLUDE : JIT_RANGE_BOUND_EXCLUDE; *end_range_bound = @@ -4183,48 +4548,52 @@ static bool buildOpenRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_sc int size = key_length[i]; MOT_LOG_DEBUG( "Filling begin/end iterator pattern for missing pkey fields at offset %d, size %d", offset, size); - AddFillKeyPattern(ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type); - AddFillKeyPattern(ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type); + AddFillKeyPattern( + ctx, ascending ? 0x00 : 0xFF, offset, size, JIT_RANGE_ITERATOR_START, range_scan_type, subQueryIndex); + AddFillKeyPattern( + ctx, ascending ? 0xFF : 0x00, offset, size, JIT_RANGE_ITERATOR_END, range_scan_type, subQueryIndex); } AddAdjustKey(ctx, ascending ? 0x00 : 0xFF, JIT_RANGE_ITERATOR_START, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); AddAdjustKey(ctx, ascending ? 0xFF : 0x00, JIT_RANGE_ITERATOR_END, - range_scan_type); // currently this is relevant only for secondary index searches + range_scan_type, // currently this is relevant only for secondary index searches + subQueryIndex); } return result; } -static bool buildRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, - JitRangeScanType range_scan_type, JitRangeBoundMode* begin_range_bound, JitRangeBoundMode* end_range_bound, - Instruction* outer_row) +static bool buildRangeScan(JitTvmCodeGenContext* ctx, JitIndexScan* indexScan, int* maxArg, + JitRangeScanType rangeScanType, JitRangeBoundMode* beginRangeBound, JitRangeBoundMode* endRangeBound, + Instruction* outerRow, int subQueryIndex = -1) { bool result = false; // if this is a point scan we generate two identical keys for the iterators - if (index_scan->_scan_type == JIT_INDEX_SCAN_POINT) { - result = buildPointScan(ctx, &index_scan->_search_exprs, max_arg, range_scan_type, outer_row); + if (indexScan->_scan_type == JIT_INDEX_SCAN_POINT) { + result = buildPointScan(ctx, &indexScan->_search_exprs, maxArg, rangeScanType, outerRow, 0, subQueryIndex); if (result) { - AddCopyKey(ctx, range_scan_type); - *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; - *end_range_bound = JIT_RANGE_BOUND_INCLUDE; + AddCopyKey(ctx, rangeScanType, subQueryIndex); + *beginRangeBound = JIT_RANGE_BOUND_INCLUDE; + *endRangeBound = JIT_RANGE_BOUND_INCLUDE; } - } else if (index_scan->_scan_type == JIT_INDEX_SCAN_CLOSED) { - result = buildClosedRangeScan(ctx, index_scan, max_arg, range_scan_type, outer_row); + } else if (indexScan->_scan_type == JIT_INDEX_SCAN_CLOSED) { + result = buildClosedRangeScan(ctx, indexScan, maxArg, rangeScanType, outerRow, subQueryIndex); if (result) { - *begin_range_bound = JIT_RANGE_BOUND_INCLUDE; - *end_range_bound = JIT_RANGE_BOUND_INCLUDE; + *beginRangeBound = JIT_RANGE_BOUND_INCLUDE; + *endRangeBound = JIT_RANGE_BOUND_INCLUDE; } - } else if (index_scan->_scan_type == JIT_INDEX_SCAN_SEMI_OPEN) { + } else if (indexScan->_scan_type == JIT_INDEX_SCAN_SEMI_OPEN) { result = buildSemiOpenRangeScan( - ctx, index_scan, max_arg, range_scan_type, begin_range_bound, end_range_bound, outer_row); - } else if (index_scan->_scan_type == JIT_INDEX_SCAN_OPEN) { + ctx, indexScan, maxArg, rangeScanType, beginRangeBound, endRangeBound, outerRow, subQueryIndex); + } else if (indexScan->_scan_type == JIT_INDEX_SCAN_OPEN) { result = buildOpenRangeScan( - ctx, index_scan, max_arg, range_scan_type, begin_range_bound, end_range_bound, outer_row); + ctx, indexScan, maxArg, rangeScanType, beginRangeBound, endRangeBound, outerRow, subQueryIndex); } return result; } @@ -4367,22 +4736,25 @@ static Instruction* buildPrepareStateScanRow(JitTvmCodeGenContext* ctx, JitIndex return row; } -static JitTvmRuntimeCursor buildRangeCursor(JitTvmCodeGenContext* ctx, JitIndexScan* index_scan, int* max_arg, - JitRangeScanType range_scan_type, JitIndexScanDirection index_scan_direction, Instruction* outer_row) +static JitTvmRuntimeCursor buildRangeCursor(JitTvmCodeGenContext* ctx, JitIndexScan* indexScan, int* maxArg, + JitRangeScanType rangeScanType, JitIndexScanDirection indexScanDirection, Instruction* outerRow, + int subQueryIndex = -1) { JitTvmRuntimeCursor result = {nullptr, nullptr}; - JitRangeBoundMode begin_range_bound = JIT_RANGE_BOUND_NONE; - JitRangeBoundMode end_range_bound = JIT_RANGE_BOUND_NONE; - if (!buildRangeScan(ctx, index_scan, max_arg, range_scan_type, &begin_range_bound, &end_range_bound, outer_row)) { + JitRangeBoundMode beginRangeBound = JIT_RANGE_BOUND_NONE; + JitRangeBoundMode endRangeBound = JIT_RANGE_BOUND_NONE; + if (!buildRangeScan( + ctx, indexScan, maxArg, rangeScanType, &beginRangeBound, &endRangeBound, outerRow, subQueryIndex)) { MOT_LOG_TRACE( "Failed to generate jitted code for aggregate range JOIN query: unsupported %s-loop WHERE clause type", - outer_row ? "inner" : "outer"); + outerRow ? "inner" : "outer"); return result; } // build range iterators - result.begin_itr = buildSearchIterator(ctx, index_scan_direction, begin_range_bound, range_scan_type); - result.end_itr = AddCreateEndIterator(ctx, index_scan_direction, end_range_bound, range_scan_type); // forward scan + result.begin_itr = buildSearchIterator(ctx, indexScanDirection, beginRangeBound, rangeScanType, subQueryIndex); + result.end_itr = + AddCreateEndIterator(ctx, indexScanDirection, endRangeBound, rangeScanType, subQueryIndex); // forward scan return result; } @@ -5578,7 +5950,7 @@ static JitContext* JitPointJoinCodegen(const Query* query, const char* query_str // update number of rows processed buildIncrementRowsProcessed(ctx); - // execute *tp_processed = rows_processed + // generate code for setting output parameter tp_processed value to rows_processed AddSetTpProcessed(ctx); // signal to envelope executor scan ended (this is a point query) @@ -5914,12 +6286,12 @@ static JitContext* JitAggregateRangeJoinCodegen(const Query* query, const char* MOT::AccessType access_mode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; // begin the WHERE clause - int max_arg = 0; + int maxArg = 0; // build range iterators MOT_LOG_DEBUG("Generating outer loop cursor for range JOIN query"); JitTvmRuntimeCursor outer_cursor = - buildRangeCursor(ctx, &plan->_outer_scan, &max_arg, JIT_RANGE_SCAN_MAIN, JIT_INDEX_SCAN_FORWARD, nullptr); + buildRangeCursor(ctx, &plan->_outer_scan, &maxArg, JIT_RANGE_SCAN_MAIN, JIT_INDEX_SCAN_FORWARD, nullptr); if (outer_cursor.begin_itr == nullptr) { MOT_LOG_TRACE( "Failed to generate jitted code for aggregate range JOIN query: unsupported outer-loop WHERE clause type"); @@ -5935,7 +6307,7 @@ static JitContext* JitAggregateRangeJoinCodegen(const Query* query, const char* ctx, JIT_WHILE_POST_BLOCK(), access_mode, JIT_INDEX_SCAN_FORWARD, &outer_cursor, JIT_RANGE_SCAN_MAIN); // check for additional filters, if not try to fetch next row - if (!buildFilterRow(ctx, outer_row, &plan->_outer_scan._filters, &max_arg, JIT_WHILE_COND_BLOCK())) { + if (!buildFilterRow(ctx, outer_row, &plan->_outer_scan._filters, &maxArg, JIT_WHILE_COND_BLOCK())) { MOT_LOG_TRACE("Failed to generate jitted code for aggregate range JOIN query: unsupported outer-loop filter"); DestroyCodeGenContext(ctx); return nullptr; @@ -5949,7 +6321,7 @@ static JitContext* JitAggregateRangeJoinCodegen(const Query* query, const char* // now build the inner loop MOT_LOG_DEBUG("Generating inner loop cursor for range JOIN query"); JitTvmRuntimeCursor inner_cursor = - buildRangeCursor(ctx, &plan->_inner_scan, &max_arg, JIT_RANGE_SCAN_INNER, JIT_INDEX_SCAN_FORWARD, outer_row); + buildRangeCursor(ctx, &plan->_inner_scan, &maxArg, JIT_RANGE_SCAN_INNER, JIT_INDEX_SCAN_FORWARD, outer_row); if (inner_cursor.begin_itr == nullptr) { MOT_LOG_TRACE( "Failed to generate jitted code for aggregate range JOIN query: unsupported inner-loop WHERE clause type"); @@ -5964,7 +6336,7 @@ static JitContext* JitAggregateRangeJoinCodegen(const Query* query, const char* ctx, JIT_WHILE_POST_BLOCK(), access_mode, JIT_INDEX_SCAN_FORWARD, &inner_cursor, JIT_RANGE_SCAN_INNER); // check for additional filters, if not try to fetch next row - if (!buildFilterRow(ctx, inner_row, &plan->_inner_scan._filters, &max_arg, JIT_WHILE_COND_BLOCK())) { + if (!buildFilterRow(ctx, inner_row, &plan->_inner_scan._filters, &maxArg, JIT_WHILE_COND_BLOCK())) { MOT_LOG_TRACE("Failed to generate jitted code for aggregate range JOIN query: unsupported inner-loop filter"); DestroyCodeGenContext(ctx); return nullptr; @@ -5985,8 +6357,8 @@ static JitContext* JitAggregateRangeJoinCodegen(const Query* query, const char* if (plan->_limit_count > 0) { AddIncrementStateLimitCounter(ctx); JIT_IF_BEGIN(limit_count_reached) - Instruction* current_limit_count = AddGetStateLimitCounter(ctx); - JIT_IF_EVAL_CMP(current_limit_count, JIT_CONST(plan->_limit_count), JIT_ICMP_EQ); + Instruction* currentLimitCount = AddGetStateLimitCounter(ctx); + JIT_IF_EVAL_CMP(currentLimitCount, JIT_CONST(plan->_limit_count), JIT_ICMP_EQ); IssueDebugLog("Reached limit specified in limit clause, raising internal state scan end flag"); AddDestroyCursor(ctx, &outer_cursor); AddDestroyCursor(ctx, &inner_cursor); @@ -6021,7 +6393,7 @@ static JitContext* JitAggregateRangeJoinCodegen(const Query* query, const char* builder.CreateRet(builder.CreateConst((uint64_t)MOT::RC_OK)); // wrap up - JitContext* jit_context = FinalizeCodegen(ctx, max_arg, JIT_COMMAND_AGGREGATE_JOIN); + JitContext* jit_context = FinalizeCodegen(ctx, maxArg, JIT_COMMAND_AGGREGATE_JOIN); // cleanup DestroyCodeGenContext(ctx); @@ -6066,6 +6438,263 @@ static JitContext* JitJoinCodegen(Query* query, const char* query_string, JitJoi return jit_context; } +static bool JitSubSelectCodegen(JitTvmCodeGenContext* ctx, JitCompoundPlan* plan, int subQueryIndex) +{ + MOT_LOG_DEBUG("Generating code for MOT sub-select at thread %p", (intptr_t)pthread_self()); + IssueDebugLog("Executing simple SELECT sub-query"); + + // get the sub-query plan + JitSelectPlan* subPlan = (JitSelectPlan*)plan->_sub_query_plans[subQueryIndex]; + + // begin the WHERE clause + int maxArg = 0; + if (!buildPointScan( + ctx, &subPlan->_query._search_exprs, &maxArg, JIT_RANGE_SCAN_SUB_QUERY, nullptr, 0, subQueryIndex)) { + MOT_LOG_TRACE("Failed to generate jitted code for SELECT sub-query: unsupported WHERE clause type"); + return false; + } + + // fetch row for read + Instruction* row = buildSearchRow(ctx, MOT::AccessType::RD, JIT_RANGE_SCAN_SUB_QUERY, subQueryIndex); + + // check for additional filters + if (!buildFilterRow(ctx, row, &subPlan->_query._filters, &maxArg, nullptr)) { + MOT_LOG_TRACE("Failed to generate jitted code for SELECT sub-query: unsupported filter"); + return false; + } + + // now begin selecting columns into result + IssueDebugLog("Selecting column into result"); + if (!selectRowColumns(ctx, row, &subPlan->_select_exprs, &maxArg, JIT_RANGE_SCAN_SUB_QUERY, subQueryIndex)) { + MOT_LOG_TRACE("Failed to generate jitted code for SELECT sub-query: failed to process target entry"); + return false; + } + + return true; +} + +/** @brief Generates code for range SELECT sub-query with aggregator. */ +static bool JitSubAggregateRangeSelectCodegen(JitTvmCodeGenContext* ctx, JitCompoundPlan* plan, int subQueryIndex) +{ + MOT_LOG_DEBUG("Generating code for MOT aggregate range select sub-query at thread %p", (intptr_t)pthread_self()); + IssueDebugLog("Executing aggregated range select sub-query"); + + // get the sub-query plan + JitRangeSelectPlan* subPlan = (JitRangeSelectPlan*)plan->_sub_query_plans[subQueryIndex]; + + // prepare for aggregation + prepareAggregate(ctx, &subPlan->_aggregate); + AddResetStateLimitCounter(ctx); + + // pay attention: aggregated range scan is not stateful, since we scan all tuples in one call + MOT::AccessType accessMode = MOT::AccessType::RD; + + // begin the WHERE clause + int maxArg = 0; + JitIndexScanDirection index_scan_direction = JIT_INDEX_SCAN_FORWARD; + + // build range iterators + MOT_LOG_DEBUG("Generating range cursor for range SELECT sub-query"); + JitTvmRuntimeCursor cursor = buildRangeCursor( + ctx, &subPlan->_index_scan, &maxArg, JIT_RANGE_SCAN_SUB_QUERY, index_scan_direction, nullptr, subQueryIndex); + if (cursor.begin_itr == nullptr) { + MOT_LOG_TRACE( + "Failed to generate jitted code for aggregate range SELECT sub-query: unsupported WHERE clause type"); + return false; + } + + JIT_WHILE_BEGIN(cursor_aggregate_loop) + Instruction* res = AddIsScanEnd(ctx, index_scan_direction, &cursor, JIT_RANGE_SCAN_SUB_QUERY, subQueryIndex); + JIT_WHILE_EVAL_NOT(res) + Instruction* row = buildGetRowFromIterator(ctx, + JIT_WHILE_POST_BLOCK(), + accessMode, + JIT_INDEX_SCAN_FORWARD, + &cursor, + JIT_RANGE_SCAN_SUB_QUERY, + subQueryIndex); + + // check for additional filters, if not try to fetch next row + if (!buildFilterRow(ctx, row, &subPlan->_index_scan._filters, &maxArg, JIT_WHILE_COND_BLOCK())) { + MOT_LOG_TRACE("Failed to generate jitted code for aggregate range SELECT sub-query: unsupported filter"); + return false; + } + + // aggregate into tuple (we use tuple's resno column as aggregated sum instead of defining local variable) + // if row disqualified due to DISTINCT operator then go back to loop test block + buildAggregateRow(ctx, &subPlan->_aggregate, row, JIT_WHILE_COND_BLOCK()); + + // if a limit clause exists, then increment limit counter and check if reached limit + if (subPlan->_limit_count > 0) { + AddIncrementStateLimitCounter(ctx); + JIT_IF_BEGIN(limit_count_reached) + Instruction* current_limit_count = AddGetStateLimitCounter(ctx); + JIT_IF_EVAL_CMP(current_limit_count, JIT_CONST(subPlan->_limit_count), JIT_ICMP_EQ); + IssueDebugLog("Reached limit specified in limit clause, raising internal state scan end flag"); + JIT_WHILE_BREAK() // break from loop + JIT_IF_END() + } + JIT_WHILE_END() + + // cleanup + IssueDebugLog("Reached end of aggregate range select sub-query loop"); + AddDestroyCursor(ctx, &cursor); + + // wrap up aggregation and write to result tuple (even though this is unfitting to outer query tuple...) + buildAggregateResult(ctx, &subPlan->_aggregate); + + // coy aggregate result from outer query result tuple into sub-query result tuple + AddCopyAggregateToSubQueryResult(ctx, subQueryIndex); + + return true; +} + +static bool JitSubQueryCodeGen(JitTvmCodeGenContext* ctx, JitCompoundPlan* plan, int subQueryIndex) +{ + bool result = false; + JitPlan* subPlan = plan->_sub_query_plans[subQueryIndex]; + if (subPlan->_plan_type == JIT_PLAN_POINT_QUERY) { + result = JitSubSelectCodegen(ctx, plan, subQueryIndex); + } else if (subPlan->_plan_type == JIT_PLAN_RANGE_SCAN) { + result = JitSubAggregateRangeSelectCodegen(ctx, plan, subQueryIndex); + } else { + MOT_REPORT_ERROR(MOT_ERROR_INVALID_ARG, + "Generate JIT Code", + "Cannot generate JIT code for sub-query plan: Invalid plan type %d", + (int)subPlan->_plan_type); + } + return result; +} + +static JitContext* JitCompoundOuterSelectCodegen( + JitTvmCodeGenContext* ctx, Query* query, const char* query_string, JitSelectPlan* plan) +{ + // begin the WHERE clause + int max_arg = 0; + if (!buildPointScan(ctx, &plan->_query._search_exprs, &max_arg, JIT_RANGE_SCAN_MAIN, nullptr)) { + MOT_LOG_TRACE("Failed to generate jitted code for COMPOUND SELECT query: unsupported WHERE clause type"); + return nullptr; + } + + // fetch row for read + MOT::AccessType access_mode = query->hasForUpdate ? MOT::AccessType::RD_FOR_UPDATE : MOT::AccessType::RD; + Instruction* row = buildSearchRow(ctx, access_mode, JIT_RANGE_SCAN_MAIN); + + // check for additional filters + if (!buildFilterRow(ctx, row, &plan->_query._filters, &max_arg, nullptr)) { + MOT_LOG_TRACE("Failed to generate jitted code for COMPOUND SELECT query: unsupported filter"); + return nullptr; + } + + // now begin selecting columns into result + IssueDebugLog("Selecting columns into result"); + if (!selectRowColumns(ctx, row, &plan->_select_exprs, &max_arg, JIT_RANGE_SCAN_MAIN)) { + MOT_LOG_TRACE("Failed to generate jitted code for COMPOUND SELECT query: failed to process target entry"); + return nullptr; + } + + AddExecStoreVirtualTuple(ctx); + + // update number of rows processed + buildIncrementRowsProcessed(ctx); + + // execute *tp_processed = rows_processed + AddSetTpProcessed(ctx); + + // signal to envelope executor scan ended (this is a point query) + AddSetScanEnded(ctx, 1); + + // return success from calling function + ctx->_builder->CreateRet(ctx->_builder->CreateConst((uint64_t)MOT::RC_OK)); + + // wrap up + return FinalizeCodegen(ctx, max_arg, JIT_COMMAND_COMPOUND_SELECT); +} + +static JitContext* JitCompoundOuterCodegen( + JitTvmCodeGenContext* ctx, Query* query, const char* queryString, JitCompoundPlan* plan) +{ + JitContext* jitContext = nullptr; + if (plan->_command_type == JIT_COMMAND_SELECT) { + jitContext = JitCompoundOuterSelectCodegen(ctx, query, queryString, (JitSelectPlan*)plan->_outer_query_plan); + } + // currently other outer query types are not supported + return jitContext; +} + +static JitContext* JitCompoundCodegen(Query* query, const char* query_string, JitCompoundPlan* plan) +{ + // a compound query plan contains one or more sub-queries that evaluate to a datum that next needs to be fed as a + // parameter to the outer query. We are currently imposing the following limitations: + // 1. one sub-query that can only be a MAX aggregate + // 2. outer query must be a simple point select query. + // + // our main strategy is as follows (based on the fact that each sub-query evaluates into a single value) + // 1. for each sub-query: + // 1.1 execute sub-query and put datum result in sub-query result slot, according to sub-query index + // 2. execute the outer query as a simple query + // 3. whenever we encounter a sub-link expression, it is evaluated as an expression that reads the pre-computed + // sub-query result in step 1.1, according to sub-query index + MOT_LOG_DEBUG("Generating code for MOT compound select at thread %p", (intptr_t)pthread_self()); + + // prepare code generation context + Builder builder; + JitTvmCodeGenContext cg_ctx = {0}; + MOT::Table* table = plan->_outer_query_plan->_query._table; + if (!InitCompoundCodeGenContext(&cg_ctx, &builder, table, table->GetPrimaryIndex(), plan)) { + return nullptr; + } + JitTvmCodeGenContext* ctx = &cg_ctx; + + // prepare the jitted function (declare, get arguments into context and define locals) + CreateJittedFunction(ctx, "MotJittedCompoundSelect", query_string); + IssueDebugLog("Starting execution of jitted COMPOUND SELECT"); + + // initialize rows_processed local variable + buildResetRowsProcessed(ctx); + + // generate code for sub-query execution + uint32_t subQueryCount = 0; + for (int i = 0; i < plan->_outer_query_plan->_query._search_exprs._count; ++i) { + if (plan->_outer_query_plan->_query._search_exprs._exprs[i]._expr->_expr_type == JIT_EXPR_TYPE_SUBLINK) { + JitSubLinkExpr* subLinkExpr = + (JitSubLinkExpr*)plan->_outer_query_plan->_query._search_exprs._exprs[i]._expr; + if (!JitSubQueryCodeGen(ctx, plan, subLinkExpr->_sub_query_index)) { + MOT_LOG_TRACE( + "Failed to generate jitted code for COMPOUND SELECT query: Failed to generate code for sub-query"); + DestroyCodeGenContext(ctx); + return nullptr; + } + ++subQueryCount; + } + } + + // clear tuple early, so that we will have a null datum in case outer query finds nothing + AddExecClearTuple(ctx); + + // generate code for the outer query + JitContext* jitContext = JitCompoundOuterCodegen(ctx, query, query_string, plan); + if (jitContext == nullptr) { + MOT_LOG_TRACE("Failed to generate code for outer query in compound select"); + DestroyCodeGenContext(ctx); + return nullptr; + } + + // prepare sub-query data in resulting JIT context (for later execution) + MOT_ASSERT(subQueryCount > 0); + MOT_ASSERT(subQueryCount == plan->_sub_query_count); + if ((subQueryCount > 0) && !PrepareSubQueryData(jitContext, plan)) { + MOT_LOG_TRACE("Failed to prepare tuple table slot array for sub-queries in JIT context object"); + DestroyJitContext(jitContext); + jitContext = nullptr; + } + + // cleanup + DestroyCodeGenContext(ctx); + + return jitContext; +} + static JitContext* JitRangeScanCodegen(const Query* query, const char* query_string, JitRangeScanPlan* plan) { JitContext* jit_context = nullptr; @@ -6146,6 +6775,10 @@ extern JitContext* JitCodegenTvmQuery(Query* query, const char* query_string, Ji jit_context = JitJoinCodegen(query, query_string, (JitJoinPlan*)plan); break; + case JIT_PLAN_COMPOUND: + jit_context = JitCompoundCodegen(query, query_string, (JitCompoundPlan*)plan); + break; + default: MOT_REPORT_ERROR( MOT_ERROR_INTERNAL, "Generate JIT Code", "Invalid JIT plan type %d", (int)plan->_plan_type); diff --git a/src/include/storage/mot/jit_def.h b/src/include/storage/mot/jit_def.h index 6a6ec6aec4786c54aa3bb915689ed82b182ca566..a0be3f5c0fe6be5a9966c253950b197c4f68309f 100644 --- a/src/include/storage/mot/jit_def.h +++ b/src/include/storage/mot/jit_def.h @@ -27,7 +27,6 @@ #include - /** @define Impose a hard coded limit on depth of parsed expression. */ #define MOT_JIT_MAX_EXPR_DEPTH 10 @@ -37,7 +36,6 @@ /** @define The maximum number of registers used in a pseudo-function execution. */ #define MOT_JIT_MAX_FUNC_REGISTERS 4096 - namespace JitExec { // uncomment this to debug lite execution @@ -79,7 +77,10 @@ enum JitCommandType : uint8_t { JIT_COMMAND_RANGE_JOIN, /** @var Join aggregate command. */ - JIT_COMMAND_AGGREGATE_JOIN + JIT_COMMAND_AGGREGATE_JOIN, + + /** @var Compound select command (point-select with sub-queries). */ + JIT_COMMAND_COMPOUND_SELECT }; /** @enum JIT context usage constants. */ @@ -142,7 +143,10 @@ enum JitRangeScanType { JIT_RANGE_SCAN_MAIN, /** @var Designates inner loop range scan. Can be specified only on JOIN queries.*/ - JIT_RANGE_SCAN_INNER + JIT_RANGE_SCAN_INNER, + + /** @var Sub-query range scan. */ + JIT_RANGE_SCAN_SUB_QUERY }; /** @enum Range bound mode constants. */ @@ -173,14 +177,13 @@ enum JitRangeIteratorType { enum JitQuerySortOrder { /** @var Invalid query sort order. */ JIT_QUERY_SORT_INVALID, - + /** @var Ascending query sort order. */ JIT_QUERY_SORT_ASCENDING, - + /** @var Descending query sort order. */ JIT_QUERY_SORT_DESCENDING }; - -} // namespace JitExec +} // namespace JitExec #endif