From 5fb8f21f20c397e077b2f7a8f96a7be9819f4883 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Fri, 1 Jun 2018 22:44:58 +0000 Subject: [PATCH 01/17] [TRAFODION-3034] add parser changes --- core/sql/comexe/ComTdbExeUtil.h | 56 +++++++++++++++++++++++++++- core/sql/executor/ExExeUtil.h | 15 ++++++++ core/sql/generator/GenRelExeUtil.cpp | 5 +++ core/sql/optimizer/BindRelExpr.cpp | 16 ++++++-- core/sql/optimizer/RelExeUtil.cpp | 30 +++++++++++++++ core/sql/optimizer/RelExeUtil.h | 29 +++++++++++++- core/sql/parser/ParKeyWords.cpp | 4 +- core/sql/parser/sqlparser.y | 43 ++++++++++++++++++++- 8 files changed, 188 insertions(+), 10 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index 47164608ff..4c6557b63b 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -92,7 +92,8 @@ class ComTdbExeUtil : public ComTdbGenericUtil GET_QID_ = 35, HIVE_TRUNCATE_ = 36, LOB_UPDATE_UTIL_ = 37, - HIVE_QUERY_ = 38 + HIVE_QUERY_ = 38, + CONNECT_BY_ = 39 }; ComTdbExeUtil() @@ -4103,7 +4104,58 @@ class ComTdbExeUtilLobInfo : public ComTdbExeUtil NABoolean tableFormat_; }; -#endif +class ComTdbExeUtilConnectby : public ComTdbExeUtil +{ + friend class ExExeUtilConnectbyTcb; + +public: + ComTdbExeUtilConnectby() + : ComTdbExeUtil() + {} + + ComTdbExeUtilConnectby(char * tableName, + ULng32 tableNameLen + ); + + Long pack(void *); + Lng32 unpack(void *, void * reallocator); + + virtual short getClassSize() {return (short)sizeof(ComTdbExeUtilConnectby);} + + virtual const char *getNodeName() const + { + return "CONNECT_BY"; + }; +}; + +#if 0 +class ExExeUtilConnectbyTcb : public ExExeUtilTcb +{ + //friend class ExExeUtilConnectbyTdb; + +public: + ExExeUtilConnectbyTcb(const ComTdbExeUtil & exe_util_tdb, + ex_globals * glob = 0); + + virtual ~ExExeUtilConnectbyTcb() + {} + + virtual short work(); +}; +#endif +class ExExeUtilConnectbyTdb : public ComTdbExeUtilConnectby +{ +public: + ExExeUtilConnectbyTdb() + {} + virtual ~ExExeUtilConnectbyTdb() + {} + + virtual ex_tcb *build(ex_globals *globals); + +}; + +#endif diff --git a/core/sql/executor/ExExeUtil.h b/core/sql/executor/ExExeUtil.h index a3f197de8d..0e5f7d0ea2 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4308,6 +4308,21 @@ class ExExeUtilLobInfoTablePrivateState : public ex_tcb_private_state protected: }; +class ExExeUtilConnectbyTcb : public ExExeUtilTcb +{ + friend class ExExeUtilConnectbyTdb; + +public: + ExExeUtilConnectbyTcb(const ComTdbExeUtil & exe_util_tdb, + ex_globals * glob = 0); + + virtual ~ExExeUtilConnectbyTcb() + {} + + virtual short work(); + +}; + #endif diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 570c3e56fb..b1b83bbc27 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5331,6 +5331,11 @@ short ExeUtilOrcFastAggr::codeGen(Generator * generator) +short ExeUtilConnectby::codeGen(Generator * generator) +{ + return 0; +} + ///////////////////////////////////////////////////////// // // ExeUtilHbaseLoad::codeGen() diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index d5e874bec3..02db28e644 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -4587,11 +4587,19 @@ RelRoot * RelRoot::transformGroupByWithOrdinalPhase2(BindWA *bindWA) // make sure child of root is a groupby node or a sequence node // whose child is a group by node - if (child(0)->getOperatorType() != REL_GROUPBY && - (child(0)->getOperatorType() != REL_SEQUENCE || - (child(0)->child(0) && child(0)->child(0)->getOperatorType()!=REL_GROUPBY))) + if(child(0)) +{ + if (child(0)->getOperatorType() != REL_GROUPBY) + { + + if (child(0)->getOperatorType() != REL_SEQUENCE ) return this; + if (child(0)->child(0) ) + if (child(0)->child(0) && child(0)->child(0)->getOperatorType()!=REL_GROUPBY) + return this; + } +} + else return this; - GroupByAgg * grby; RelSequence * seqNode=NULL; diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index 5d143a2a12..e1b12fa92f 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6174,6 +6174,36 @@ RelExpr * ExeUtilMetadataUpgrade::copyTopNode(RelExpr *derivedNode, CollHeap* ou return ExeUtilExpr::copyTopNode(result, outHeap); } + +RelExpr * ExeUtilConnectby::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap) +{ + ExeUtilConnectby* result; + if (derivedNode == NULL) + result = new (outHeap) + ExeUtilConnectby(getTableName(), + NULL, CharInfo::UnknownCharSet, outHeap); + else + result = (ExeUtilConnectby*) derivedNode; + return ExeUtilExpr::copyTopNode(result, outHeap); +} + +RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) +{ + if (nodeIsBound()) { + bindWA->getCurrentScope()->setRETDesc(getRETDesc()); + return this; + } + return NULL; +} +const NAString ExeUtilConnectby::getText() const +{ + NAString result(CmpCommon::statementHeap()); + + result = "CONNECT BY STATEMENT"; + + return result; +} + // ----------------------------------------------------------------------- // Member functions for class ExeUtilHbaseLoad // ----------------------------------------------------------------------- diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 73d6ed7a00..08090509f9 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -513,7 +513,8 @@ class ExeUtilExpr : public GenericUtilExpr GET_QID_ = 38, HIVE_TRUNCATE_ = 39, LOB_UPDATE_UTIL_ = 40, - HIVE_QUERY_ = 41 + HIVE_QUERY_ = 41, + CONNECT_BY_ = 42 }; ExeUtilExpr(ExeUtilType type, @@ -1079,6 +1080,32 @@ class ExeUtilFastDelete : public ExeUtilExpr NAList lobNumArray_; // array of shorts. Each short is the lob num }; +class ExeUtilConnectby : public ExeUtilExpr +{ +public: + ExeUtilConnectby( const CorrName &TableName, + char * stmtText, + CharInfo::CharSet stmtTextCharSet, + CollHeap *oHeap = CmpCommon::statementHeap()) + : ExeUtilExpr(CONNECT_BY_, TableName, NULL, NULL, + stmtText, stmtTextCharSet, oHeap) + {} + virtual const NAString getText() const; + + virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL, + CollHeap* outHeap = 0); + + virtual RelExpr * bindNode(BindWA *bindWAPtr); + + virtual short codeGen(Generator*); + +private: + //connect by + //start with + //table + int fake_; +}; + class ExeUtilHiveTruncate : public ExeUtilExpr { public: diff --git a/core/sql/parser/ParKeyWords.cpp b/core/sql/parser/ParKeyWords.cpp index a21345831c..293d39a0e0 100644 --- a/core/sql/parser/ParKeyWords.cpp +++ b/core/sql/parser/ParKeyWords.cpp @@ -231,7 +231,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("CONDITION_NUMBER", TOK_CONDITION_NUMBER, NONRESTOKEN_), ParKeyWord("CONFIG", TOK_CONFIG, NONRESTOKEN_), ParKeyWord("CONFLICT", TOK_CONFLICT, SECOND_|NONRESTOKEN_), - ParKeyWord("CONNECT", IDENTIFIER, ANS_|RESWORD_), + ParKeyWord("CONNECT", TOK_CONNECT, ANS_|NONRESTOKEN_), // ParKeyWord("CONNECTION", IDENTIFIER, ANS_|RESWORD_), ParKeyWord("CONNECTION_NAME", TOK_CONNECTION_NAME, NONRESTOKEN_), ParKeyWord("CONSTRAINT", TOK_CONSTRAINT, ANS_|RESWORD_), @@ -814,7 +814,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("PREPARE", TOK_PREPARE, ANS_|RESWORD_), ParKeyWord("PRESERVE", TOK_PRESERVE, ANS_|RESWORD_), ParKeyWord("PRIMARY", TOK_PRIMARY, FIRST_|ANS_|RESWORD_), - ParKeyWord("PRIOR", IDENTIFIER, ANS_|RESWORD_), + ParKeyWord("PRIOR", TOK_PRIOR, ANS_), ParKeyWord("PRIORITY", TOK_PRIORITY, NONRESTOKEN_), ParKeyWord("PRIORITY_DELTA", TOK_PRIORITY_DELTA, NONRESTOKEN_), ParKeyWord("PRIVATE", TOK_PRIVATE, NONRESTOKEN_), diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 455447ec1d..972854fde6 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -931,6 +931,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_PREFER_FOR_SCAN_KEY %token TOK_PREPARE %token TOK_PRESERVE /* TD extension that HP wants to ignore */ +%token TOK_PRIOR %token TOK_PRIORITY %token TOK_PRIORITY_DELTA %token TOK_PROCEDURE @@ -1237,6 +1238,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_COMPONENTS %token TOK_COMPRESSION %token TOK_CONFIG /* Tandem extension */ +%token TOK_CONNECT /* Tandem extension */ %token TOK_CONSTRAINT %token TOK_CONSTRAINTS %token TOK_COPY @@ -2125,6 +2127,9 @@ static void enableMakeQuotedStringISO88591Mechanism() %type rel_subquery %type row_subquery %type predicate +%type connectby_expression +%type connect_by +%type startwith %type dml_column_reference %type null_predicate %type scan_key_hint @@ -13091,6 +13096,19 @@ list_of_values : '(' insert_value_expression_list ')' // end of fix: left recursion for insert statement values. +connectby_expression: TOK_PRIOR qualified_name '=' qualified_name + { + } + | qualified_name '=' TOK_PRIOR qualified_name + { + } +connect_by : TOK_CONNECT TOK_BY connectby_expression + { + } +startwith : empty | + TOK_START TOK_WITH + { + } table_expression : from_clause where_clause sample_clause cond_transpose_clause_list sequence_by_clause @@ -13630,7 +13648,18 @@ query_specification :select_token set_quantifier query_spec_body ((RelRoot*)$$)->setAnalyzeOnly(); } - +/* +query_specification : select_token select_list from_clause connect_by + { + CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; + NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & + , PARSERHEAP() // in - NAMemory * + ); + ExeUtilConnectby *euc = new (PARSERHEAP()) ExeUtilConnectby(CorrName( ((Scan*)$3)->getTableName(), PARSERHEAP()), NULL, + stmtCharSet,PARSERHEAP()); + $$ = finalize(euc); + } +*/ query_specification : exe_util_maintain_object { RelRoot *root = new (PARSERHEAP()) @@ -13781,6 +13810,18 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ AssignmentHostVars->clear(); $$ = temp; } + | query_select_list from_clause connect_by +{ + CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; + NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & + , PARSERHEAP() // in - NAMemory * + ); + ExeUtilConnectby *euc = new (PARSERHEAP()) ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), NULL, + stmtCharSet,PARSERHEAP()); + RelRoot *temp = new (PARSERHEAP()) + RelRoot(euc, REL_ROOT , $1); + $$ = temp; +} //++ MV OZ // type item From b29f4ddb417b087a3c888b17e9fae2ee6b060828 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Tue, 17 Jul 2018 09:21:17 +0000 Subject: [PATCH 02/17] basic work finish --- core/sql/bin/SqlciErrors.txt | 1 + core/sql/comexe/ComTdb.cpp | 7 +- core/sql/comexe/ComTdb.h | 1 + core/sql/comexe/ComTdbExeUtil.cpp | 53 ++ core/sql/comexe/ComTdbExeUtil.h | 55 +- core/sql/executor/ExComTdb.cpp | 7 + core/sql/executor/ExExeUtil.h | 43 +- core/sql/executor/ExExeUtilConnectby.cpp | 628 +++++++++++++++++++++++ core/sql/generator/GenRelExeUtil.cpp | 159 ++++++ core/sql/nskgmake/executor/Makefile | 1 + core/sql/optimizer/BindRelExpr.cpp | 86 ++++ core/sql/optimizer/ItemLog.h | 6 + core/sql/optimizer/NormRelExpr.cpp | 11 + core/sql/optimizer/RelExeUtil.cpp | 25 +- core/sql/optimizer/RelExeUtil.h | 28 +- core/sql/optimizer/RelExpr.cpp | 34 ++ core/sql/optimizer/RelExpr.h | 22 +- core/sql/optimizer/RelScan.h | 18 + core/sql/parser/sqlparser.y | 68 +-- 19 files changed, 1192 insertions(+), 61 deletions(-) create mode 100644 core/sql/executor/ExExeUtilConnectby.cpp diff --git a/core/sql/bin/SqlciErrors.txt b/core/sql/bin/SqlciErrors.txt index 8146be4013..cb1cfb34fa 100644 --- a/core/sql/bin/SqlciErrors.txt +++ b/core/sql/bin/SqlciErrors.txt @@ -1513,6 +1513,7 @@ $1~String1 -------------------------------- 8034 ZZZZZ 99999 ADVANCED MAJOR DBADMIN Column $0~String0 of object $1~string1 does not have a default clause but it is missing in database. This indicates inconsistent data. 8035 ZZZZZ 99999 ADVANCED MAJOR DBADMIN Truncation of hive table failed. $0~String0 8036 ZZZZZ 99999 ADVANCED MINOR LOGONLY Error while creating the error logging file or logging the error row to file $0~String0: Details :$1~String1 +8041 ZZZZZ 99999 BEGINNER MAJOR DBADMIN Loop detected in connect by execution. 8100 ZZZZZ 99999 BEGINNER MINOR LOGONLY Define $1~string0 does not exist 8101 23000 99999 BEGINNER MAJOR DBADMIN The operation is prevented by check constraint $0~ConstraintName on table $1~TableName. 8102 23000 99999 BEGINNER MAJOR DBADMIN The operation is prevented by a unique constraint. diff --git a/core/sql/comexe/ComTdb.cpp b/core/sql/comexe/ComTdb.cpp index 2578c46b41..6a0e3237cd 100644 --- a/core/sql/comexe/ComTdb.cpp +++ b/core/sql/comexe/ComTdb.cpp @@ -374,7 +374,12 @@ char *ComTdb::findVTblPtrCom(short classID) GetVTblPtr(vtblptr,ComTdbCompoundStmt); break; } - + case ex_CONNECT_BY: + { + GetVTblPtr(vtblptr,ComTdbExeUtilConnectby); + break; + } + case ex_TUPLE: { GetVTblPtr(vtblptr,ComTdbTuple); diff --git a/core/sql/comexe/ComTdb.h b/core/sql/comexe/ComTdb.h index 1b90b907d8..0a26bfb837 100644 --- a/core/sql/comexe/ComTdb.h +++ b/core/sql/comexe/ComTdb.h @@ -291,6 +291,7 @@ class ComTdb : public NAVersionedObject ex_HIVE_TRUNCATE = 153, ex_LOB_UPDATE_UTIL = 154, ex_HIVE_QUERY = 155, + ex_CONNECT_BY= 156, ex_LAST = 9999 // not used }; diff --git a/core/sql/comexe/ComTdbExeUtil.cpp b/core/sql/comexe/ComTdbExeUtil.cpp index adb0390679..44c8647362 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -74,6 +74,7 @@ ComTdbExeUtil::ComTdbExeUtil(Lng32 type, child_(NULL), scanExpr_(scan_expr), flags_(0), + oriQuery_(query), explOptionsStr_(NULL) { setNodeType(ComTdb::ex_EXE_UTIL); @@ -3166,3 +3167,55 @@ Lng32 ComTdbExeUtilLobInfo::unpack(void * base, void * reallocator) return -1; return ComTdbExeUtil::unpack(base, reallocator); } + +ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, + ULng32 querylen, + Int16 querycharset, + char * tableName, + char * stmtName, + ex_expr * input_expr, + ULng32 input_rowlen, + ex_expr * output_expr, + ULng32 output_rowlen, + ex_cri_desc * work_cri_desc, + const unsigned short work_atp_index, + Lng32 colDescSize, + Lng32 outputRowSize, + ex_cri_desc * given_cri_desc, + ex_cri_desc * returned_cri_desc, + queue_index down, + queue_index up, + Lng32 num_buffers, + ULng32 buffer_size, + ExCriDescPtr workCriDesc + ) + : ComTdbExeUtil(ComTdbExeUtil::CONNECT_BY_, + query, querylen, querycharset, + tableName, strlen(tableName), + input_expr, input_rowlen, + output_expr, output_rowlen, + NULL, + work_cri_desc, work_atp_index, + given_cri_desc, returned_cri_desc, + down, up, + num_buffers, buffer_size), + flags_(0), + workCriDesc_(workCriDesc), + tupleLen_(outputRowSize) +{ + setNodeType(ComTdb::ex_CONNECT_BY); + connTableName_ = tableName; + oriQuery_ = query; +} + +Long ComTdbExeUtilConnectby::pack(void * space) +{ + workCriDesc_.pack(space); + return ComTdbExeUtil::pack(space); +} + +Lng32 ComTdbExeUtilConnectby::unpack(void * base, void * reallocator) +{ + if(workCriDesc_.unpack(base, reallocator)) return -1; + return ComTdbExeUtil::unpack(base, reallocator); +} diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index 4c6557b63b..db4d6e4e37 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -201,6 +201,7 @@ class ComTdbExeUtil : public ComTdbGenericUtil void setNEOCatalogName(char * catalog) { NEOCatalogName_ = catalog; } void setType(ExeUtilType type) { type_ = type; } + char * oriQuery_; protected: Lng32 type_; // 00-03 @@ -4111,13 +4112,30 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil friend class ExExeUtilConnectbyTcb; public: - ComTdbExeUtilConnectby() - : ComTdbExeUtil() - {} + ComTdbExeUtilConnectby(char * query, + ULng32 querylen, + Int16 querycharset, + char * tableName, + char * stmtName, + ex_expr * input_expr, + ULng32 input_rowlen, + ex_expr * output_expr, + ULng32 output_rowlen, + ex_cri_desc * work_cri_desc, + const unsigned short work_atp_index, + Lng32 colDescSize, + Lng32 outputRowSize, + ex_cri_desc * given_cri_desc, + ex_cri_desc * returned_cri_desc, + queue_index down, + queue_index up, + Lng32 num_buffers, + ULng32 buffer_size, + ExCriDescPtr workCriDesc + ); - ComTdbExeUtilConnectby(char * tableName, - ULng32 tableNameLen - ); + ComTdbExeUtilConnectby() + : ComTdbExeUtil() { hasStartWith_ = TRUE; } Long pack(void *); Lng32 unpack(void *, void * reallocator); @@ -4128,24 +4146,17 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil { return "CONNECT_BY"; }; + UInt16 sourceDataTuppIndex_; + NAString parentColName_; + NAString childColName_; + NAString connTableName_; + NABoolean hasStartWith_; +private: + ExCriDescPtr workCriDesc_; + Int32 flags_; + Int32 tupleLen_; }; -#if 0 -class ExExeUtilConnectbyTcb : public ExExeUtilTcb -{ - //friend class ExExeUtilConnectbyTdb; - -public: - ExExeUtilConnectbyTcb(const ComTdbExeUtil & exe_util_tdb, - ex_globals * glob = 0); - - virtual ~ExExeUtilConnectbyTcb() - {} - - virtual short work(); - -}; -#endif class ExExeUtilConnectbyTdb : public ComTdbExeUtilConnectby { public: diff --git a/core/sql/executor/ExComTdb.cpp b/core/sql/executor/ExComTdb.cpp index 3766b3dd6d..18384e872a 100644 --- a/core/sql/executor/ExComTdb.cpp +++ b/core/sql/executor/ExComTdb.cpp @@ -573,6 +573,13 @@ case ex_LOB_INFO: break; } + case ex_CONNECT_BY: + { + GetVTblPtr(vtblptr,ExExeUtilConnectbyTdb); + + break; + } + default: ex_assert(0, "findVTblPtrExe(): Cannot find entry of this ClassId"); break; diff --git a/core/sql/executor/ExExeUtil.h b/core/sql/executor/ExExeUtil.h index 0e5f7d0ea2..03e97ce7d2 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4263,6 +4263,7 @@ class ExExeUtilLobInfoTableTcb : public ExExeUtilTcb DONE_ }; Step step_; + char * data_; protected: Int64 getEmbeddedNumValue(char* &sep, char endChar, @@ -4313,14 +4314,54 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb friend class ExExeUtilConnectbyTdb; public: - ExExeUtilConnectbyTcb(const ComTdbExeUtil & exe_util_tdb, + ExExeUtilConnectbyTcb(const ComTdbExeUtilConnectby &exe_util_tdb, ex_globals * glob = 0); virtual ~ExExeUtilConnectbyTcb() {} virtual short work(); + virtual ex_tcb_private_state * allocatePstates( + Lng32 &numElems, // inout, desired/actual elements + Lng32 &pstateLength); // out, length of one element + enum Step + { + INITIAL_, + EVAL_INPUT_, + EVAL_START_WITH_, + DO_CONNECT_BY_, + POPULATE_CONNECT_BUF_, + EVAL_EXPR_, + RETURN_CONNECT_BUF_, + NEXT_LEVEL_, + ERROR_, + DONE_ + }; + Step step_; + ExExeUtilConnectbyTdb& exeUtilTdb() const + {return (ExExeUtilConnectbyTdb&) tdb;}; + short emitRows(Queue *q, ExpTupleDesc * tDesc) ; + short emitRow(ExpTupleDesc * tDesc, int level) ; + short emitOneRow(ExpTupleDesc * tDesc, int level) ; + +protected: + ExExeUtilConnectbyTcb *tcb_; + +private: + tupp tuppData_; + char * data_; +}; + +class ExExeUtilConnectbyTdbState : public ex_tcb_private_state +{ + friend class ExExeUtilConnectbyTcb; + + public: + ExExeUtilConnectbyTdbState(); + ~ExExeUtilConnectbyTdbState(); +protected: + ExExeUtilConnectbyTcb::Step step_; }; #endif diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp new file mode 100644 index 0000000000..7e72bb1808 --- /dev/null +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -0,0 +1,628 @@ +/********************************************************************** +// @@@ START COPYRIGHT @@@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// +// @@@ END COPYRIGHT @@@ +**********************************************************************/ + +/* -*-C++-*- + ***************************************************************************** + * + * File: ExExeUtilConnectby.cpp + * Description: + * + * + * Language: C++ + * + * + * + * + ***************************************************************************** + */ + +#include +using std::cerr; +using std::endl; + +#include +using std::ofstream; + +#include + +#include "ComCextdecs.h" +#include "cli_stdh.h" +#include "ex_stdh.h" +#include "sql_id.h" +#include "ex_transaction.h" +#include "ComTdb.h" +#include "ex_tcb.h" +#include "ComSqlId.h" + +#include "ExExeUtil.h" +#include "ex_exe_stmt_globals.h" +#include "exp_expr.h" +#include "exp_clause_derived.h" +#include "ComRtUtils.h" +#include "ExStats.h" +#include "ExpLOB.h" +#include "ExpLOBenums.h" +#include "ExpLOBinterface.h" +#include "ExpLOBexternal.h" +#include "str.h" +#include "ExpHbaseInterface.h" +#include "ExHbaseAccess.h" +#include "ExpErrorEnums.h" +#include "HdfsClient_JNI.h" + + +class connectByStackItem +{ +public: + connectByStackItem() {} + ~connectByStackItem() {} + char * seedValue; + int len; + int level; + int type; +}; + +class rootItem +{ +public: + rootItem() {} + ~rootItem() {} + int rootId; + Queue * qptr; +}; + +ExExeUtilConnectbyTcb::ExExeUtilConnectbyTcb( + const ComTdbExeUtilConnectby & exe_util_tdb, + ex_globals * glob) +: ExExeUtilTcb( exe_util_tdb, NULL, glob), + step_(INITIAL_) +{ + Space * space = (glob ? glob->getSpace() : 0); + CollHeap * heap = (glob ? glob->getDefaultHeap() : 0); + qparent_.down->allocatePstate(this); + pool_->get_free_tuple(tuppData_, exe_util_tdb.tupleLen_); + data_ = tuppData_.getDataPointer(); + //pool_->get_free_tuple(workAtp_->getTupp(2), 0); + + +} + +ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( + Lng32 &numElems, // inout, desired/actual elements + Lng32 &pstateLength) // out, length of one element +{ + PstateAllocator pa; + + return pa.allocatePstates(this, numElems, pstateLength); +} + +short ExExeUtilConnectbyTcb::emitRows(Queue *q, ExpTupleDesc * tDesc) +{ + short retcode = 0, rc =0; + char * ptr; + Lng32 len; + + q->position(); +#if 1 + for (Lng32 idx = 0; idx < q->numEntries(); idx++) + { + OutputInfo * vi = (OutputInfo*)q->getNext(); + + if (vi == NULL) break; + for (UInt32 i = 1; i < tDesc->numAttrs() ; i++) + { + // OutputInfo * vi = (OutputInfo*)q->getNext(); + + char * src = (char*)vi->get(i); + Attributes * attr = tDesc->getAttr(i); + short srcType; + Lng32 srcLen; + short valIsNull = 0; + if(attr->getDatatype() < REC_MAX_CHARACTER) + srcType = REC_BYTE_F_ASCII; + else + srcType = attr->getDatatype(); + srcLen = attr->getLength(); + if(src == NULL) valIsNull = 1; +#if 1 + if (attr->getNullFlag()) + { + // target is nullable + if (attr->getNullIndicatorLength() == 2) + { + // set the 2 byte NULL indicator to -1 + *(short *) (&data_[attr->getNullIndOffset()]) = + valIsNull; + } + else + { + ex_assert(attr->getNullIndicatorLength() == 4, + "NULL indicator must be 2 or 4 bytes"); + *(Lng32 *) (&data_[attr->getNullIndOffset()]) = + valIsNull; + } + } + else + ex_assert(!valIsNull, + "NULL source for NOT NULL stats column"); +#endif + if (!valIsNull) + { + // str_cpy_all(src,&data_[attr->getOffset()],attr->getLength() ); +#if 1 + if ( + ::convDoIt(src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + 0, 0, NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } +#endif + } + } +#endif + + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); + } + + return retcode; +} + +short ExExeUtilConnectbyTcb::emitOneRow(ExpTupleDesc * tDesc, int level) +{ + short retcode = 0, rc = 0; + char * ptr; + Lng32 len; + ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_OK; + UInt32 rowLen = exeUtilTdb().outputRowlen_; //TODO + ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); + + cliInterface()->getPtrAndLen(1, ptr, len); //start from second column + //setup ATP + workAtp_->getTupp(exeUtilTdb().sourceDataTuppIndex_) + .setDataPointer(data_); + workAtp_->getTupp(2) + .setDataPointer(ptr); + + evalRetCode = (exeUtilTdb().outputExpr())->eval(pentry_down->getAtp(), workAtp_, NULL, + exeUtilTdb().tupleLen_, &rowLen); + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); + return retcode; +} + +short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level) +{ + short retcode = 0, rc =0; + char * ptr; + Lng32 len; + short nullInd = 0; + short *ind ; + ind = &nullInd; + + for (UInt32 i = 1; i < tDesc->numAttrs() ; i++) + { + cliInterface()->getPtrAndLen(i+1, ptr, len,&ind); + char * src = ptr; + Attributes * attr = tDesc->getAttr(i); + short srcType = 0; + Lng32 srcLen; + short valIsNull = 0; + srcType = attr->getDatatype(); + srcLen = len; + if (len == 0 ) valIsNull = -1; + + if (attr->getNullFlag()) + { + // target is nullable + if (attr->getNullIndicatorLength() == 2) + { + // set the 2 byte NULL indicator to -1 + *(short *) (&data_[attr->getNullIndOffset()]) = + valIsNull; + } + else + { + ex_assert(attr->getNullIndicatorLength() == 4, + "NULL indicator must be 2 or 4 bytes"); + *(Lng32 *) (&data_[attr->getNullIndOffset()]) = + valIsNull; + } + } + else + ex_assert(!valIsNull, + "NULL source for NOT NULL stats column"); + UInt32 vcActualLen = 0; + + if (!valIsNull) + { + if (attr->getVCIndicatorLength() > 0) + { + ::convDoIt(src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + (char*) &vcActualLen, sizeof(vcActualLen), NULL); + attr->setVarLength(vcActualLen,&data_[attr->getVCLenIndOffset()]); + } + else + ::convDoIt(src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + NULL, 0, NULL); + + } + } +#if 0 + short srcType = REC_BIN32_UNSIGNED; + Lng32 srcLen = 4; + int src = level; + Attributes * attr = tDesc->getAttr(tDesc->numAttrs() - 1); + if ( + ::convDoIt((char*)&src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + 0, 0, NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } +#endif + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); + return retcode; +} + +void releaseCurrentQueue(Queue * q, CollHeap * h) +{ + for(int i = 0; i < q->numEntries(); i++) + { + connectByStackItem *entry = (connectByStackItem *)q->get(i); + NADELETEBASIC(entry->seedValue,h); + } +} + +short haveDupSeed(Queue * q , connectByStackItem *it, int len, int level) +{ + + for(int i = 0; i < q->numEntries(); i++) + { + connectByStackItem *entry = (connectByStackItem *)q->get(i); + if(memcmp(entry->seedValue,it->seedValue, len) == 0) + { + if(entry->level < level) + return 1; + else + return -1; + } + } + return 0; +} + +short ExExeUtilConnectbyTcb::work() +{ + short retcode = 0; + char q1[1024], q2[1024]; + void* uppderid = NULL; + char * ptr; + Lng32 len; + short rc; + NAString nq11, nq21; + memset(q1, 0, 1024); + memset(q2, 0, 1024); + int matchRowNum = 0; + + int currLevel = 1; + int resultSize = 0; + // if no parent request, return + if (qparent_.down->isEmpty()) + return WORK_OK; + + // if no room in up queue, won't be able to return data/status. + // Come back later. + if (qparent_.up->isFull()) + return WORK_OK; + + ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); + ex_queue_entry * up_entry = qparent_.up->getTailEntry(); + ex_tcb_private_state * pstate = pentry_down->pstate; + char * stmtStr = exeUtilTdb().oriQuery_; + if(stmtStr && exeUtilTdb().hasStartWith_ == TRUE) + { + NAString nq1=stmtStr; + UInt32 pos = nq1.index(" from ", 0, NAString::ignoreCase); + sprintf(q1,"SELECT %s , * , 0" ,(exeUtilTdb().parentColName_).data()); + nq11 = q1; + nq11.append((char*)&(nq1.data()[pos])); + nq11.append(" START ;"); + } + else + { + NAString nq1=stmtStr; + UInt32 pos = nq1.index(" from ", 0, NAString::ignoreCase); + sprintf(q1,"SELECT %s , * , 0 FROM %s WHERE %s is null ;" ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().connTableName_).data(), (exeUtilTdb().childColName_).data()); + nq11 = q1; + } + + ExpTupleDesc * tDesc = exeUtilTdb().workCriDesc_->getTupleDescriptor( exeUtilTdb().sourceDataTuppIndex_); + + int isVarchar = 0; + char * dp ; + Queue * seedQueue = NULL; + Queue * currQueue = new(getHeap()) Queue(getHeap()) ; + Queue * tmpQueue = new(getHeap()) Queue(getHeap());; + tupp p; + Lng32 fsDatatype = 0; + Lng32 length; + Lng32 indOffset = 0; + Lng32 varOffset = 0; + + while (1) + { + ex_queue_entry *pentry_down = qparent_.down->getHeadEntry(); + switch (step_) + { + case INITIAL_: + + step_ = EVAL_START_WITH_; + break; + case EVAL_START_WITH_: + { + short rc = 0; + //get the stmt + retcode = cliInterface()->fetchRowsPrologue(nq11.data(), FALSE, FALSE); + while ((rc >= 0) && + (rc != 100)) + { + rc = cliInterface()->fetch(); + if (rc < 0) + { + cliInterface()->fetchRowsEpilogue(0, TRUE); + return rc; + } + + if (rc == 100) + continue; + + connectByStackItem *it = new connectByStackItem(); + cliInterface()->getPtrAndLen(1, ptr, len); + cliInterface()->getAttributes(1, FALSE, + fsDatatype, length, + &indOffset, &varOffset); + + char *tmp = new(getHeap()) char[len]; + memcpy(tmp,ptr,len); + it->seedValue = tmp; + it->level = currLevel; + it->type = fsDatatype; + it->len = len; + if(haveDupSeed(currQueue, it, len, currLevel) == 0) { + emitRow(tDesc, currLevel); matchRowNum++; + currQueue->insert(it); + } + } + cliInterface()->fetchRowsEpilogue(0, FALSE); + step_ = DO_CONNECT_BY_; + } + break; + case DO_CONNECT_BY_: + { + int seedNum = currQueue->numEntries(); + int loopDetected = 0; + + currQueue->position(); + resultSize = 0; + for(int i=0; i< seedNum; i++) { + + NAString nq2=stmtStr; + sprintf(q2,"SELECT %s , * , %d FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), currLevel,(exeUtilTdb().connTableName_).data()); + nq21 = q2; + nq21.append((exeUtilTdb().childColName_).data()); + nq21.append(" in ( "); + int sybnum = 0; + + for(int batchIdx = 0; batchIdx < 10 && i < seedNum; batchIdx ++) + { + connectByStackItem * vi = (connectByStackItem*)currQueue->get(i); + int tmpLevel = vi->level; + i++; + if( tmpLevel == currLevel) { + sybnum++; + uppderid = ((connectByStackItem*)vi)->seedValue; + char tmpbuf[128]; + char tmpbuf1[128]; + memset(tmpbuf,0,128); + memset(tmpbuf1,0,128); + switch(vi->type) //TODO: more types to support + { + case REC_BYTE_F_ASCII: + case REC_BYTE_V_ASCII: + strcpy(tmpbuf, " '"); + strncpy(tmpbuf1,(char*)uppderid, vi->len); + strcat(tmpbuf,tmpbuf1); + strcat(tmpbuf,"'"); + break; + default: + sprintf(tmpbuf, "%d ", *(int*)uppderid); + } + nq21.append(tmpbuf); + if( i == seedNum || batchIdx ==10) continue; + else + nq21.append(" , "); + } //if( tmpLevel == currLevel) + + }//for(int batchIdx = 0; batchIdx < 10 && i < seedNum; batchIdx ++) + + nq21.append(" );"); + if(sybnum == 0 ) //end + { + step_ = NEXT_LEVEL_; + break; + } + retcode = cliInterface()->fetchRowsPrologue(nq21.data(), FALSE, FALSE); + + rc = 0; + while ((rc >= 0) && + (rc != 100)) + { + rc = cliInterface()->fetch(); + if (rc < 0) + { + cliInterface()->fetchRowsEpilogue(0, TRUE); + return rc; + } + if (rc == 100) + continue; + resultSize++; + cliInterface()->getPtrAndLen(1, ptr, len); + connectByStackItem *it = new connectByStackItem(); + char *tmp = new(getHeap()) char[len]; + memcpy(tmp,ptr,len); + it->seedValue = tmp; + it->level = currLevel + 1; + it->type = fsDatatype; + it->len = len; + short rc1 = haveDupSeed(currQueue, it, len, currLevel) ; //loop detection + if(rc1 == 1) + { + loopDetected = 1; + step_ = ERROR_; + break; + } + + if(rc1 == 0) { + emitRow(tDesc, currLevel+1); matchRowNum++; + tmpQueue->insert(it); + }//if(haveDupSeed(currQueue, it, len, currLevel) == 0) + }// while ((rc >= 0) + cliInterface()->fetchRowsEpilogue(0, FALSE); + }//for(int i=0; i< seedNum; i++) + //insert tmpQueue into currQueue + for(int i = 0; i < tmpQueue->numEntries(); i++) + currQueue->insert(tmpQueue->get(i)); + NADELETE(tmpQueue, Queue, getHeap()); + tmpQueue = new(getHeap()) Queue(getHeap()); + + if( loopDetected == 1) + { + step_ = ERROR_; + break; + } + if(resultSize == 0) + step_ = DONE_; + else + step_ = NEXT_LEVEL_; + } + break; + case NEXT_LEVEL_: + { + currLevel++; + step_ = DO_CONNECT_BY_; + } + break; + case ERROR_: + { + if (qparent_.up->isFull()) + return WORK_OK; + + // Return EOF. + ex_queue_entry * up_entry = qparent_.up->getTailEntry(); + + up_entry->upState.parentIndex = + pentry_down->downState.parentIndex; + + up_entry->upState.setMatchNo(0); + up_entry->upState.status = ex_queue::Q_SQLERROR; + ComDiagsArea * diagsArea = NULL; + ExRaiseSqlError(getHeap(), &diagsArea, + (ExeErrorCode)(8041)); + up_entry->setDiagsArea(diagsArea); + //ComDiagsArea *diagsArea = up_entry->getDiagsArea(); + + if (diagsArea == NULL) + diagsArea = + ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); + else + diagsArea->incrRefCount (); // setDiagsArea call below will decr ref count + + if (getDiagsArea()) + diagsArea->mergeAfter(*getDiagsArea()); + + // insert into parent + qparent_.up->insert(); + + step_ = DONE_; + } + break; + case DONE_: + if (qparent_.up->isFull()) + return WORK_OK; + + step_ = INITIAL_; + // Return EOF. + up_entry = qparent_.up->getTailEntry(); + up_entry->upState.parentIndex = + pentry_down->downState.parentIndex; + + up_entry->upState.setMatchNo(matchRowNum); + up_entry->upState.status = ex_queue::Q_NO_DATA; + + // insert into parent + qparent_.up->insert(); + + qparent_.down->removeHead(); + + //release the currentQueue + releaseCurrentQueue(currQueue, getHeap()); + NADELETE(currQueue, Queue, getHeap()); + return WORK_OK; + break; + } + } + + return WORK_OK; +} + +ex_tcb * ExExeUtilConnectbyTdb::build(ex_globals * glob ) +{ + ExExeUtilConnectbyTcb * exe_util_tcb; + + exe_util_tcb = new(glob->getSpace()) ExExeUtilConnectbyTcb(*this, glob); + + exe_util_tcb->registerSubtasks(); + + return (exe_util_tcb); +} + +ExExeUtilConnectbyTdbState::ExExeUtilConnectbyTdbState() +{ + +} +ExExeUtilConnectbyTdbState::~ExExeUtilConnectbyTdbState() +{} + diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index b1b83bbc27..7c6a7a1684 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -83,6 +83,7 @@ #include "ComSqlId.h" #include "MVInfo.h" #include "StmtDDLCreateTable.h" +#include "CmpSeabaseDDL.h" // need for authorization checks #include "ComUser.h" @@ -5330,9 +5331,167 @@ short ExeUtilOrcFastAggr::codeGen(Generator * generator) } +const char * ExeUtilConnectby::getVirtualTableName() +{ + Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); + NAString tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); + NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); + return tbl.data(); +} + +TrafDesc *ExeUtilConnectby::createVirtualTableDesc() +{ + CmpSeabaseDDL cmpSBD((NAHeap *)CmpCommon::statementHeap()); + NAString cat; + NAString sch; + NAString tbl; + Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); + cat= (scanNode->getTableName()).getQualifiedNameObj().getCatalogName(); + sch= (scanNode->getTableName()).getQualifiedNameObj().getSchemaName(); + tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); + NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); + tblDesc_ = cmpSBD.getSeabaseTableDesc(cat,sch,tbl,COM_BASE_TABLE_OBJECT); + //add LEVEL column + TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; + tblDesc_->tableDesc()->colcount++; + //go to the last entry + int i = 0; + int tmpOffset = 0; + while(column_desc->next) { i++; column_desc = column_desc->next; } + tmpOffset = column_desc->columnsDesc()->offset + 4; + TrafDesc * col_desc = TrafMakeColumnDesc( + tableName.data(), + "LEVEL", //info->colName, + i, + REC_BIN32_UNSIGNED, + 4, + tmpOffset, + FALSE, + SQLCHARSETCODE_UNKNOWN, + NULL); + column_desc->next = col_desc; + col_desc->columnsDesc()->colclass='S'; + return tblDesc_; +} + +int ExeUtilConnectby::createAsciiColAndCastExpr2(Generator * generator, + ItemExpr * colNode, + const NAType &givenType, + ItemExpr *&asciiValue, + ItemExpr *&castValue, + NABoolean alignedFormat) +{ + asciiValue = NULL; + castValue = NULL; + CollHeap * h = generator->wHeap(); + + // if this is an upshifted datatype, remove the upshift attr. + // We dont want to upshift data during retrievals or while building keys. + // Data is only upshifted during insert or updates. + const NAType * newGivenType = &givenType; + if (newGivenType->getTypeQualifier() == NA_CHARACTER_TYPE && + ((CharType *)newGivenType)->isUpshifted()) + { + newGivenType = newGivenType->newCopy(h); + ((CharType*)newGivenType)->setUpshifted(FALSE); + } + + NABoolean encodingNeeded = FALSE; + asciiValue = new (h) NATypeToItem(newGivenType->newCopy(h)); + castValue = new(h) Cast(asciiValue, newGivenType); + + if ((!alignedFormat) && HbaseAccess::isEncodingNeededForSerialization(colNode)) + { + castValue = new(generator->wHeap()) CompDecode(castValue, + newGivenType->newCopy(h), + FALSE, TRUE); + } + + return 1; +} short ExeUtilConnectby::codeGen(Generator * generator) { + ExpGenerator * expGen = generator->getExpGenerator(); + Space * space = generator->getSpace(); + + ex_cri_desc * givenDesc + = generator->getCriDesc(Generator::DOWN); + ex_cri_desc * returnedDesc + = new(space) ex_cri_desc(givenDesc->noTuples() + 1, space); + ex_cri_desc * workCriDesc = new(space) ex_cri_desc(4, space); + const Int32 work_atp = 1; + const Int32 fetchSourceAtpIndex = 2; + const Int32 outputAtpIndex = 3; + + Attributes ** attrs = + new(generator->wHeap()) + Attributes * [getVirtualTableDesc()->getColumnList().entries()]; + + for (CollIndex i = 0; i < getVirtualTableDesc()->getColumnList().entries(); i++) + { + ItemExpr * col_node + = (((getVirtualTableDesc()->getColumnList())[i]).getValueDesc())-> + getItemExpr(); + + attrs[i] = (generator->addMapInfo(col_node->getValueId(), 0))-> + getAttr(); + } + + ExpTupleDesc *tupleDesc = 0; + ULng32 tupleLength = 0; + + ExpTupleDesc::TupleDataFormat tupleFormat = ExpTupleDesc::SQLARK_EXPLODED_FORMAT; + + expGen->processAttributes(getVirtualTableDesc()->getColumnList().entries(), + attrs, tupleFormat, + tupleLength, + work_atp, outputAtpIndex, + &tupleDesc, ExpTupleDesc::LONG_FORMAT); + + // add this descriptor to the work cri descriptor. + workCriDesc->setTupleDescriptor(outputAtpIndex , tupleDesc); + + Int32 theAtpIndex = returnedDesc->noTuples()-1; + expGen->assignAtpAndAtpIndex(getVirtualTableDesc()->getColumnList(), + 0, theAtpIndex); + + TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; + Lng32 colDescSize = column_desc->columnsDesc()->length; + + char * stmtText = getStmtText(); + char *tblnm = (char*)getTableName().getQualifiedNameObj().getObjectName().data(); + + ComTdbExeUtilConnectby * exe_util_tdb = new(space) + ComTdbExeUtilConnectby (stmtText , (stmtText ? strlen(stmtText) : 0), getStmtTextCharSet(), tblnm , NULL, + 0 , 0, + 0,0, //This is the output expression, used in parent to apply on the output + workCriDesc , 1, + colDescSize, + tupleLength, + givenDesc, + returnedDesc, + (queue_index)8, + (queue_index)1024, + 10, + 32000, + workCriDesc + ); + exe_util_tdb->sourceDataTuppIndex_ = outputAtpIndex; + exe_util_tdb->parentColName_ = parentColName_; + exe_util_tdb->childColName_ = childColName_; + exe_util_tdb->hasStartWith_ = hasStartWith_; + generator->initTdbFields(exe_util_tdb); + + if (!generator->explainDisabled()) + { + generator->setExplainTuple(addExplainInfo(exe_util_tdb, 0, 0, generator)); + } + generator->setCriDesc(givenDesc, Generator::DOWN); + generator->setCriDesc(returnedDesc, Generator::UP); + + generator->setGenObj(this, exe_util_tdb); + return 0; } diff --git a/core/sql/nskgmake/executor/Makefile b/core/sql/nskgmake/executor/Makefile index 691c1d2b5e..66b1d8c37a 100755 --- a/core/sql/nskgmake/executor/Makefile +++ b/core/sql/nskgmake/executor/Makefile @@ -64,6 +64,7 @@ CPPSRC := Allocator.cpp \ ExComTdb.cpp \ ExDupSqlBuffer.cpp \ ExExeUtilAll.cpp \ + ExExeUtilConnectby.cpp \ ExExplain.cpp \ ExFirstN.cpp \ ExHbaseAccess.cpp \ diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index 02db28e644..548a730467 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -2505,6 +2505,61 @@ RelExpr *RelExpr::bindSelf(BindWA *bindWA) bindWA->predsOfViewWithCheckOption() += selectionPred(); } + ItemExpr *startWithTree = removeStartWithTree(); + if (startWithTree) { + bindWA->getCurrentScope()->context()->inWhereClause() = TRUE; + startWithTree->convertToValueIdSet(getStartWith(), bindWA, ITM_AND); + bindWA->getCurrentScope()->context()->inWhereClause() = FALSE; + + if (bindWA->errStatus()) return this; + + // If this is an embedded insert, then subquery predicates are not + // allowed. + // For example: To handle this query and issue an error stating + // subqueries are not allowed in embedded inserts + // + // select a from (insert into t901t01 values(22,22,222))t(a,b,c) + // where t.a IN (select m from t901t03 where t901t03.m = 77); + + if (getGroupAttr()->isEmbeddedInsert()) + { + if (!getStartWith().isEmpty() && getStartWith().containsSubquery()) + { + *CmpCommon::diags() << DgSqlCode(-4337); + bindWA->setErrStatus(); + return this; + } + } + } + + ItemExpr *connectByTree = removeConnectByTree(); + if (connectByTree) { + + bindWA->getCurrentScope()->context()->inWhereClause() = TRUE; + connectByTree->convertToValueIdSet(getConnectBy(), bindWA, ITM_AND); + bindWA->getCurrentScope()->context()->inWhereClause() = FALSE; + + if (bindWA->errStatus()) return this; + + // If this is an embedded insert, then subquery predicates are not + // allowed. + // For example: To handle this query and issue an error stating + // subqueries are not allowed in embedded inserts + // + // select a from (insert into t901t01 values(22,22,222))t(a,b,c) + // where t.a IN (select m from t901t03 where t901t03.m = 77); + + if (getGroupAttr()->isEmbeddedInsert()) + { + if (!getConnectBy().isEmpty() && getConnectBy().containsSubquery()) + { + *CmpCommon::diags() << DgSqlCode(-4337); + bindWA->setErrStatus(); + return this; + } + } + } + // ++MV // Bind the uniqueColumnsTree expression. // @@ -8219,6 +8274,7 @@ RelExpr *Scan::bindNode(BindWA *bindWA) // RelExpr *boundExpr = bindSelf(bindWA); if (bindWA->errStatus()) return this; + // // Assign the set of columns that belong to the table to be scanned // as the output values that can be produced by this scan. @@ -8373,7 +8429,37 @@ RelExpr *Scan::bindNode(BindWA *bindWA) ); } } + for (ValueId exprId = getConnectBy().init(); getConnectBy().next(exprId); getConnectBy().advance(exprId)) + { + if(exprId.getItemExpr()->getOperatorType() == ITM_EQUAL) + { + if( ((BiRelat*)exprId.getItemExpr())->getPrior() == 1) + { + //right child is the PRIOR column + ItemExpr * c = exprId.getItemExpr()->child(0); + NAString unparsed(CmpCommon::statementHeap()); + c->unparse(unparsed); + setPriorColName((char*)unparsed.data()); + ItemExpr * cc = exprId.getItemExpr()->child(1); + NAString unparsedc(CmpCommon::statementHeap()); + cc->unparse(unparsedc); + setPriorChildColName((char*)unparsedc.data()); + } + if( ((BiRelat*)exprId.getItemExpr())->getPrior() == 2) + { + //left child is the PRIOR column + ItemExpr * c = exprId.getItemExpr()->child(1); + NAString unparsed(CmpCommon::statementHeap()); + c->unparse(unparsed); + setPriorColName((char*)unparsed.data()); + ItemExpr * cc = exprId.getItemExpr()->child(0); + NAString unparsedc(CmpCommon::statementHeap()); + cc->unparse(unparsedc); + setPriorChildColName((char*)unparsedc.data()); + } + } + } return boundExpr; } // Scan::bindNode() diff --git a/core/sql/optimizer/ItemLog.h b/core/sql/optimizer/ItemLog.h index a6597f5371..f1c598125d 100644 --- a/core/sql/optimizer/ItemLog.h +++ b/core/sql/optimizer/ItemLog.h @@ -345,6 +345,7 @@ class BiRelat : public ItemExpr outerNullFilteringDetected_ (FALSE), innerNullFilteringDetected_ (FALSE), rollupColumnNum_(-1), + prior_(0), flags_(0) { #ifndef NDEBUG @@ -611,6 +612,9 @@ class BiRelat : public ItemExpr void setAddedForLikePred(NABoolean v) { (v ? flags_ |= FOR_LIKE : flags_ &= ~FOR_LIKE); } + void setPrior(Int8 v) { prior_ = v; } + Int8 getPrior() { return prior_; } + private: // helper to change literals of a cacheable query into input parameters @@ -728,6 +732,8 @@ class BiRelat : public ItemExpr // Used to return the rollup groups. Int16 rollupColumnNum_; + Int8 prior_; //0 left , 1 right + UInt32 flags_; }; // class BiRelat diff --git a/core/sql/optimizer/NormRelExpr.cpp b/core/sql/optimizer/NormRelExpr.cpp index 974c055b71..cd505d1fba 100644 --- a/core/sql/optimizer/NormRelExpr.cpp +++ b/core/sql/optimizer/NormRelExpr.cpp @@ -6065,6 +6065,17 @@ RelExpr * Scan::normalizeNode } } + //check connect by phase + if( getConnectByPhase() == 1 ) // This is start with + { + selectionPred().clear(); + selectionPred() += getStartWith(); + } + if( getConnectByPhase() == 2 ) // This is start with + { + selectionPred().clear(); + selectionPred() += getConnectBy(); + } // the following block of code can transform an OR predicate into // semijoin(Scan, TupleList) // where the Scan is this scan node. diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index e1b12fa92f..0308d3526c 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6181,9 +6181,13 @@ RelExpr * ExeUtilConnectby::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap) if (derivedNode == NULL) result = new (outHeap) ExeUtilConnectby(getTableName(), - NULL, CharInfo::UnknownCharSet, outHeap); + NULL, CharInfo::UnknownCharSet, NULL,outHeap); else result = (ExeUtilConnectby*) derivedNode; + result->tblDesc_ = tblDesc_; + result->connectByTree_ = connectByTree_; + result->connectByTree_ = connectByTree_; + result->hasStartWith_ = hasStartWith_; return ExeUtilExpr::copyTopNode(result, outHeap); } @@ -6193,13 +6197,28 @@ RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) bindWA->getCurrentScope()->setRETDesc(getRETDesc()); return this; } - return NULL; + RelExpr * boundExpr = NULL; + bindChildren(bindWA); + boundExpr = ExeUtilExpr::bindNode(bindWA); + Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); + parentColName_=scanNode->getPirorColName(); + childColName_=scanNode->getPirorChildColName(); + if (bindWA->errStatus()) + return NULL; + return boundExpr; + } + +RelExpr * ExeUtilConnectby::normalizeNode(NormWA & normWARef) +{ + return RelExpr::normalizeNode(normWARef); +} + const NAString ExeUtilConnectby::getText() const { NAString result(CmpCommon::statementHeap()); - result = "CONNECT BY STATEMENT"; + result = "CONNECT_BY_STATEMENT"; return result; } diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 08090509f9..c91b7ccc93 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1086,25 +1086,47 @@ class ExeUtilConnectby : public ExeUtilExpr ExeUtilConnectby( const CorrName &TableName, char * stmtText, CharInfo::CharSet stmtTextCharSet, + RelExpr * scan, CollHeap *oHeap = CmpCommon::statementHeap()) - : ExeUtilExpr(CONNECT_BY_, TableName, NULL, NULL, + : ExeUtilExpr(CONNECT_BY_, TableName, NULL, scan, stmtText, stmtTextCharSet, oHeap) - {} + { + hasStartWith_ = TRUE; + } virtual const NAString getText() const; virtual RelExpr * copyTopNode(RelExpr *derivedNode = NULL, CollHeap* outHeap = 0); virtual RelExpr * bindNode(BindWA *bindWAPtr); + virtual RelExpr * normalizeNode(NormWA & normWARef); + virtual Int32 getArity() const { return (child(0) ? 1 : 0); } + virtual NABoolean producesOutput() { return TRUE; } virtual short codeGen(Generator*); + + virtual TrafDesc * createVirtualTableDesc(); + + virtual const char * getVirtualTableName(); + + int createAsciiColAndCastExpr2(Generator * generator, + ItemExpr * colNode, + const NAType &givenType, + ItemExpr *&asciiValue, + ItemExpr *&castValue, + NABoolean alignedFormat); + TrafDesc * tblDesc_; + ItemExpr * connectByTree_; + NAString parentColName_; + NAString childColName_; + NABoolean hasStartWith_; private: //connect by //start with //table int fake_; -}; +}; class ExeUtilHiveTruncate : public ExeUtilExpr { diff --git a/core/sql/optimizer/RelExpr.cpp b/core/sql/optimizer/RelExpr.cpp index ea4495a68c..ec61d19f04 100644 --- a/core/sql/optimizer/RelExpr.cpp +++ b/core/sql/optimizer/RelExpr.cpp @@ -250,6 +250,8 @@ RelExpr::RelExpr(OperatorTypeEnum otype, CollHeap *outHeap) : ExprNode(otype) ,selection_(NULL) + ,startWith_(NULL) + ,connectBy_(NULL) ,RETDesc_(NULL) ,groupAttr_(NULL) ,groupId_(INVALID_GROUP_ID) @@ -307,6 +309,10 @@ RelExpr::~RelExpr() // these data structures are always owned by the tree delete selection_; + if(startWith_) + delete startWith_; + if(connectBy_) + delete connectBy_; // delete all children, if this is a standalone query // (NOTE: can't use the virtual function getArity() in a destructor!!!) @@ -484,6 +490,20 @@ void RelExpr::addSelPredTree(ItemExpr *selpred) selection_ = sel.getPtr(); } // RelExpr::addSelPredTree() +void RelExpr::addStartWithExprTree(ItemExpr *predExpr) +{ + ExprValueId sel = startWith_; + ItemExprTreeAsList(&sel, ITM_AND).insert(predExpr); + startWith_= sel.getPtr(); +} + +void RelExpr::addConnectByExprTree(ItemExpr *predExpr) +{ + ExprValueId sel = connectBy_; + ItemExprTreeAsList(&sel, ITM_AND).insert(predExpr); + connectBy_ = sel.getPtr(); +} + ItemExpr * RelExpr::removeSelPredTree() { ItemExpr * result = selection_; @@ -491,6 +511,20 @@ ItemExpr * RelExpr::removeSelPredTree() return result; } // RelExpr::removeSelPredTree() +ItemExpr * RelExpr::removeConnectByTree() +{ + ItemExpr * result = connectBy_; + connectBy_ = NULL; + return result; +} // RelExpr::removeConnectByTree() + +ItemExpr * RelExpr::removeStartWithTree() +{ + ItemExpr * result = startWith_; + startWith_ = NULL; + return result; +} // RelExpr::removeStartWithTree() + //++ MV - void RelExpr::addUniqueColumnsTree(ItemExpr *uniqueColumnsTree) { diff --git a/core/sql/optimizer/RelExpr.h b/core/sql/optimizer/RelExpr.h index 44ed08663d..79e561294b 100644 --- a/core/sql/optimizer/RelExpr.h +++ b/core/sql/optimizer/RelExpr.h @@ -385,13 +385,27 @@ class RelExpr : public ExprNode // add a new selection predicate (new pred = child pred AND existing pred) void addSelPredTree(ItemExpr *selpred); + void addConnectByExprTree(ItemExpr *selpred); + void addStartWithExprTree(ItemExpr *selpred); + // remove the selection predicate tree from this node and return its pointer ItemExpr * removeSelPredTree(); + ItemExpr * removeConnectByTree(); + ItemExpr * removeStartWithTree(); // non-destructive read of the selection predicates ItemExpr * selPredTree() const { return selection_; } const ItemExpr * getSelPredTree() const { return selection_; } + ItemExpr * startWithPredTree() const { return startWith_; } + const ItemExpr * getStartWithPredTree() const { return startWith_; } + + ItemExpr * connectByPredTree() const { return connectBy_; } + const ItemExpr * getConnectByPredTree() const { return connectBy_; } + + ValueIdSet & getStartWith() { return startPred_; } + ValueIdSet & getConnectBy() { return connectByPred_; } + // return a (short-lived) read/write reference to the selection predicates ValueIdSet & selectionPred() { CMPASSERT(NOT isCutOp()); return predicates_; } @@ -525,7 +539,7 @@ class RelExpr : public ExprNode // QSTUFF // -------------------------------------------------------------------- - // normalizeNode() performs predicate pushdown and also ensures + // normalizeNode() performs predicate pushdown and also ensuresL // that the characteristic input as well as characteristic output // values are both "minimal". // -------------------------------------------------------------------- @@ -1448,6 +1462,12 @@ class RelExpr : public ExprNode ItemExpr * selection_; // generated by the parser ValueIdSet predicates_; // predicates represented as a set + ItemExpr * startWith_ ; + ValueIdSet startPred_; + + ItemExpr * connectBy_; + ValueIdSet connectByPred_; + // A descriptor for the table derived from the RelExpr. RETDesc * RETDesc_; diff --git a/core/sql/optimizer/RelScan.h b/core/sql/optimizer/RelScan.h index c026914a45..075ab54847 100644 --- a/core/sql/optimizer/RelScan.h +++ b/core/sql/optimizer/RelScan.h @@ -235,6 +235,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(oHeap), hbaseAccessOptions_(NULL), + connectByPhase_(0), commonSubExpr_(NULL) {} @@ -263,6 +264,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(CmpCommon::statementHeap()), hbaseAccessOptions_(NULL), + connectByPhase_(0), commonSubExpr_(NULL) {} @@ -294,6 +296,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(oHeap), hbaseAccessOptions_(NULL), + connectByPhase_(0), commonSubExpr_(NULL) {} @@ -323,6 +326,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), hbaseAccessOptions_(NULL), matchingMVs_(CmpCommon::statementHeap()), + connectByPhase_(0), commonSubExpr_(NULL) {} @@ -633,6 +637,14 @@ class Scan : public RelExpr CommonSubExprRef *getCommonSubExpr() const { return commonSubExpr_; } void setCommonSubExpr(CommonSubExprRef *cse) { commonSubExpr_ = cse; } + void setConnectByPhase(char v) { connectByPhase_ = v; } + char getConnectByPhase() { return connectByPhase_; } + + NAString getPirorColName() { return priorColName_; } + NAString getPirorChildColName() { return priorChildColName_; } + void setPriorColName(char * v) { priorColName_ = v; } + void setPriorChildColName(char * v) { priorChildColName_ = v; } + protected: // Find the most promising index from the LIST, for index joins @@ -781,6 +793,12 @@ class Scan : public RelExpr // pointer to the common subexpression, if this is a scan of a // materialized common subexpr CommonSubExprRef *commonSubExpr_; + + char connectByPhase_ ; + + NAString priorColName_; + NAString priorChildColName_; + }; // ----------------------------------------------------------------------- diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 972854fde6..95f50aaf49 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -1177,6 +1177,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_WHENEVER %token TOK_WHERE %token TOK_WITH +%token TOK_WITH1 %token TOK_SLEEP %token TOK_UUID_SHORT %token TOK_UNIX_TIMESTAMP @@ -2127,7 +2128,6 @@ static void enableMakeQuotedStringISO88591Mechanism() %type rel_subquery %type row_subquery %type predicate -%type connectby_expression %type connect_by %type startwith %type dml_column_reference @@ -13096,18 +13096,13 @@ list_of_values : '(' insert_value_expression_list ')' // end of fix: left recursion for insert statement values. -connectby_expression: TOK_PRIOR qualified_name '=' qualified_name +connect_by : TOK_CONNECT TOK_BY comparison_predicate { + $$ = $3; } - | qualified_name '=' TOK_PRIOR qualified_name - { - } -connect_by : TOK_CONNECT TOK_BY connectby_expression - { - } -startwith : empty | - TOK_START TOK_WITH +startwith : empty { $$ = NULL; }| TOK_START TOK_WITH comparison_predicate { + $$ = $3; } table_expression : from_clause where_clause sample_clause @@ -13648,18 +13643,6 @@ query_specification :select_token set_quantifier query_spec_body ((RelRoot*)$$)->setAnalyzeOnly(); } -/* -query_specification : select_token select_list from_clause connect_by - { - CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; - NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & - , PARSERHEAP() // in - NAMemory * - ); - ExeUtilConnectby *euc = new (PARSERHEAP()) ExeUtilConnectby(CorrName( ((Scan*)$3)->getTableName(), PARSERHEAP()), NULL, - stmtCharSet,PARSERHEAP()); - $$ = finalize(euc); - } -*/ query_specification : exe_util_maintain_object { RelRoot *root = new (PARSERHEAP()) @@ -13779,6 +13762,15 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ $$=temp; } + | query_select_list from_clause startwith connect_by where_clause access_type optional_lock_mode TOK_START + { + RelRoot *temp= new (PARSERHEAP()) + RelRoot($2, $6, $7, REL_ROOT, $1); + $2->addConnectByExprTree($4); + $2->addStartWithExprTree($3); + ((Scan*)$2)->setConnectByPhase(1); + $$=temp; + } | query_select_list into_clause table_expression access_type optional_lock_mode { // use a compute node to attach select list @@ -13810,17 +13802,29 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ AssignmentHostVars->clear(); $$ = temp; } - | query_select_list from_clause connect_by -{ - CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; - NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & + |query_select_list from_clause startwith connect_by where_clause access_type optional_lock_mode + { + CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; + NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & , PARSERHEAP() // in - NAMemory * ); - ExeUtilConnectby *euc = new (PARSERHEAP()) ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), NULL, - stmtCharSet,PARSERHEAP()); + //remove ';' + UInt32 pos = + stmt->index(";", 0, NAString::ignoreCase); + stmt->remove(pos); + + ExeUtilConnectby *euc = new (PARSERHEAP()) + ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), (char*) stmt->data(), + stmtCharSet, $2,PARSERHEAP()); + + $2->addConnectByExprTree($4); + $2->addStartWithExprTree($3); RelRoot *temp = new (PARSERHEAP()) RelRoot(euc, REL_ROOT , $1); - $$ = temp; + euc->connectByTree_ = $4; + if($3 == NULL) + euc->hasStartWith_ = FALSE; + $$ = temp; } //++ MV OZ @@ -19047,6 +19051,10 @@ comparison_predicate : { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } | row_subquery comparison_operator value_expression_list_paren { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } + | TOK_PRIOR value_expression comparison_operator value_expression + { $$ = new (PARSERHEAP()) BiRelat($3, $2, $4); ((BiRelat*)$$)->setPrior(1);} + | value_expression comparison_operator TOK_PRIOR value_expression + { $$ = new (PARSERHEAP()) BiRelat($2, $1, $4); ((BiRelat*)$$)->setPrior(2);} // BEGIN rules added for UDF /* COMMENTED OUT FOR R2.5. CAUSES GRAMMAR CONFLICTS. @@ -34101,7 +34109,7 @@ nonreserved_word : TOK_ABORT | TOK_SP_RESULT_SET | TOK_SQL_WARNING | TOK_SQLROW - | TOK_START /* used in nist618 for column name */ +// | TOK_START /* used in nist618 for column name */ | TOK_STATE /* used internally? qat tests */ | TOK_STATEMENT | TOK_STATIC From 88e8b20d91ed7093ea06448a64bcdc3090d91ba9 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sat, 21 Jul 2018 09:56:44 +0000 Subject: [PATCH 03/17] fix parser, add loop detection --- core/sql/comexe/ComTdbExeUtil.h | 1 + core/sql/executor/ExExeUtil.h | 3 +- core/sql/executor/ExExeUtilConnectby.cpp | 111 ++++++++++++++++------- core/sql/generator/GenRelExeUtil.cpp | 1 + core/sql/optimizer/ItemLog.h | 22 ++++- core/sql/optimizer/RelExeUtil.h | 1 + core/sql/optimizer/RelScan.h | 3 + core/sql/parser/ParKeyWords.cpp | 3 +- core/sql/parser/sqlparser.y | 105 +++++++++++++++------ core/sql/parser/ulexer.cpp | 7 ++ 10 files changed, 189 insertions(+), 68 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index db4d6e4e37..a1218ff364 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -4150,6 +4150,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil NAString parentColName_; NAString childColName_; NAString connTableName_; + NAString startWithExprString_; NABoolean hasStartWith_; private: ExCriDescPtr workCriDesc_; diff --git a/core/sql/executor/ExExeUtil.h b/core/sql/executor/ExExeUtil.h index 03e97ce7d2..7cc5c036be 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4330,10 +4330,9 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb EVAL_INPUT_, EVAL_START_WITH_, DO_CONNECT_BY_, - POPULATE_CONNECT_BUF_, EVAL_EXPR_, - RETURN_CONNECT_BUF_, NEXT_LEVEL_, + NEXT_ROOT_, ERROR_, DONE_ }; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 7e72bb1808..f5c44fe20a 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -103,8 +103,6 @@ ExExeUtilConnectbyTcb::ExExeUtilConnectbyTcb( pool_->get_free_tuple(tuppData_, exe_util_tdb.tupleLen_); data_ = tuppData_.getDataPointer(); //pool_->get_free_tuple(workAtp_->getTupp(2), 0); - - } ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( @@ -168,7 +166,7 @@ short ExExeUtilConnectbyTcb::emitRows(Queue *q, ExpTupleDesc * tDesc) #endif if (!valIsNull) { - // str_cpy_all(src,&data_[attr->getOffset()],attr->getLength() ); + #if 1 if ( ::convDoIt(src, srcLen, srcType, 0, 0, @@ -323,18 +321,27 @@ short haveDupSeed(Queue * q , connectByStackItem *it, int len, int level) } return 0; } + +Queue * getCurrQueue(int id, Queue *q) +{ + for(int i = 0; i < q->numEntries(); i++) + { + rootItem * ri = (rootItem*) q->get(i); + if(ri->rootId == id) return ri->qptr; + } + return NULL; +} short ExExeUtilConnectbyTcb::work() { short retcode = 0; - char q1[1024], q2[1024]; + char q1[2048]; //TODO: the max len of supported query len void* uppderid = NULL; char * ptr; Lng32 len; short rc; NAString nq11, nq21; - memset(q1, 0, 1024); - memset(q2, 0, 1024); + memset(q1, 0, sizeof(q1)); int matchRowNum = 0; int currLevel = 1; @@ -356,10 +363,8 @@ short ExExeUtilConnectbyTcb::work() { NAString nq1=stmtStr; UInt32 pos = nq1.index(" from ", 0, NAString::ignoreCase); - sprintf(q1,"SELECT %s , * , 0" ,(exeUtilTdb().parentColName_).data()); + sprintf(q1,"SELECT %s , * , 0 FROM %s WHERE %s ;" ,(exeUtilTdb().parentColName_).data() , (exeUtilTdb().connTableName_).data() ,(exeUtilTdb().startWithExprString_).data() ); nq11 = q1; - nq11.append((char*)&(nq1.data()[pos])); - nq11.append(" START ;"); } else { @@ -371,17 +376,16 @@ short ExExeUtilConnectbyTcb::work() ExpTupleDesc * tDesc = exeUtilTdb().workCriDesc_->getTupleDescriptor( exeUtilTdb().sourceDataTuppIndex_); - int isVarchar = 0; - char * dp ; - Queue * seedQueue = NULL; - Queue * currQueue = new(getHeap()) Queue(getHeap()) ; + Queue * seedQueue = new(getHeap()) Queue(getHeap()) ; + Queue * currQueue = NULL ; Queue * tmpQueue = new(getHeap()) Queue(getHeap());; tupp p; Lng32 fsDatatype = 0; - Lng32 length; + Lng32 length = 0; Lng32 indOffset = 0; Lng32 varOffset = 0; - + int currRootId = 0; + while (1) { ex_queue_entry *pentry_down = qparent_.down->getHeadEntry(); @@ -394,6 +398,8 @@ short ExExeUtilConnectbyTcb::work() case EVAL_START_WITH_: { short rc = 0; + int rootId = 0; + //get the stmt retcode = cliInterface()->fetchRowsPrologue(nq11.data(), FALSE, FALSE); while ((rc >= 0) && @@ -414,7 +420,14 @@ short ExExeUtilConnectbyTcb::work() cliInterface()->getAttributes(1, FALSE, fsDatatype, length, &indOffset, &varOffset); - + currQueue = new(getHeap()) Queue(getHeap()) ; + rootItem * ri= new(getHeap()) rootItem(); + ri->rootId = rootId; + rootId++; + ri->qptr = currQueue; + seedQueue->insert(ri); + + char *tmp = new(getHeap()) char[len]; memcpy(tmp,ptr,len); it->seedValue = tmp; @@ -434,14 +447,14 @@ short ExExeUtilConnectbyTcb::work() { int seedNum = currQueue->numEntries(); int loopDetected = 0; - + currQueue->position(); resultSize = 0; + for(int i=0; i< seedNum; i++) { - NAString nq2=stmtStr; - sprintf(q2,"SELECT %s , * , %d FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), currLevel,(exeUtilTdb().connTableName_).data()); - nq21 = q2; + sprintf(q1,"SELECT %s , *, %d FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), currLevel,(exeUtilTdb().connTableName_).data()); + nq21 = q1; nq21.append((exeUtilTdb().childColName_).data()); nq21.append(" in ( "); int sybnum = 0; @@ -458,18 +471,16 @@ short ExExeUtilConnectbyTcb::work() char tmpbuf1[128]; memset(tmpbuf,0,128); memset(tmpbuf1,0,128); - switch(vi->type) //TODO: more types to support - { - case REC_BYTE_F_ASCII: - case REC_BYTE_V_ASCII: - strcpy(tmpbuf, " '"); + if(vi->type >= REC_MIN_NUMERIC && vi->type <= REC_MAX_NUMERIC) + sprintf(tmpbuf, "%d ", *(int*)uppderid); + else + { + strcpy(tmpbuf, " '"); strncpy(tmpbuf1,(char*)uppderid, vi->len); strcat(tmpbuf,tmpbuf1); strcat(tmpbuf,"'"); - break; - default: - sprintf(tmpbuf, "%d ", *(int*)uppderid); - } + } + nq21.append(tmpbuf); if( i == seedNum || batchIdx ==10) continue; else @@ -479,6 +490,7 @@ short ExExeUtilConnectbyTcb::work() }//for(int batchIdx = 0; batchIdx < 10 && i < seedNum; batchIdx ++) nq21.append(" );"); + if(sybnum == 0 ) //end { step_ = NEXT_LEVEL_; @@ -511,6 +523,13 @@ short ExExeUtilConnectbyTcb::work() if(rc1 == 1) { loopDetected = 1; + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8041); step_ = ERROR_; break; } @@ -534,7 +553,7 @@ short ExExeUtilConnectbyTcb::work() break; } if(resultSize == 0) - step_ = DONE_; + step_ = NEXT_ROOT_; else step_ = NEXT_LEVEL_; } @@ -545,11 +564,28 @@ short ExExeUtilConnectbyTcb::work() step_ = DO_CONNECT_BY_; } break; + case NEXT_ROOT_: + { + currRootId++; + currLevel = 1; + currQueue = getCurrQueue(currRootId, seedQueue); + if(currQueue == NULL) step_ = DONE_; + else + step_ = DO_CONNECT_BY_; + } + break; case ERROR_: { - if (qparent_.up->isFull()) - return WORK_OK; + //if (qparent_.up->isFull()) + //return WORK_OK; + if (handleError()) + return WORK_OK; + + //getDiagsArea()->clear(); + + step_ = DONE_; +#if 0 // Return EOF. ex_queue_entry * up_entry = qparent_.up->getTailEntry(); @@ -575,7 +611,7 @@ short ExExeUtilConnectbyTcb::work() // insert into parent qparent_.up->insert(); - +#endif step_ = DONE_; } break; @@ -598,8 +634,13 @@ short ExExeUtilConnectbyTcb::work() qparent_.down->removeHead(); //release the currentQueue - releaseCurrentQueue(currQueue, getHeap()); - NADELETE(currQueue, Queue, getHeap()); + for(int i = 0; i< currRootId ; i++) + { + currQueue = getCurrQueue( i, seedQueue); + releaseCurrentQueue(currQueue, getHeap()); + NADELETE(currQueue, Queue, getHeap()); + } + NADELETE(seedQueue, Queue, getHeap()); return WORK_OK; break; } diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 7c6a7a1684..baae5d05e8 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5481,6 +5481,7 @@ short ExeUtilConnectby::codeGen(Generator * generator) exe_util_tdb->parentColName_ = parentColName_; exe_util_tdb->childColName_ = childColName_; exe_util_tdb->hasStartWith_ = hasStartWith_; + exe_util_tdb->startWithExprString_ = startWithExprString_; generator->initTdbFields(exe_util_tdb); if (!generator->explainDisabled()) diff --git a/core/sql/optimizer/ItemLog.h b/core/sql/optimizer/ItemLog.h index f1c598125d..d84d6490dc 100644 --- a/core/sql/optimizer/ItemLog.h +++ b/core/sql/optimizer/ItemLog.h @@ -732,12 +732,32 @@ class BiRelat : public ItemExpr // Used to return the rollup groups. Int16 rollupColumnNum_; - Int8 prior_; //0 left , 1 right + Int8 prior_; UInt32 flags_; }; // class BiRelat +class BiConnectBy :public BiRelat { +public: + BiConnectBy( BiRelat * start, + BiRelat * conn) + :BiRelat(ITM_EQUAL, NULL, NULL) + { + startWith_ = start; + connectBy_ = conn; + } + virtual ~BiConnectBy() {} + + BiRelat * getStartWith() {return startWith_; } + BiRelat * getConnectBy() {return connectBy_; } + NAString startWithString_; + +private: + BiRelat * startWith_; + BiRelat * connectBy_; +}; + class KeyRangeCompare : public BiRelat { diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index c91b7ccc93..e4f60dd92c 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1120,6 +1120,7 @@ class ExeUtilConnectby : public ExeUtilExpr ItemExpr * connectByTree_; NAString parentColName_; NAString childColName_; + NAString startWithExprString_; NABoolean hasStartWith_; private: //connect by diff --git a/core/sql/optimizer/RelScan.h b/core/sql/optimizer/RelScan.h index 075ab54847..0a46a3cca9 100644 --- a/core/sql/optimizer/RelScan.h +++ b/core/sql/optimizer/RelScan.h @@ -642,8 +642,10 @@ class Scan : public RelExpr NAString getPirorColName() { return priorColName_; } NAString getPirorChildColName() { return priorChildColName_; } + NAString getStartWithExpr() { return startWithExpr_; } void setPriorColName(char * v) { priorColName_ = v; } void setPriorChildColName(char * v) { priorChildColName_ = v; } + void setStartWithExpr(const char *v) { startWithExpr_ = v; } protected: @@ -798,6 +800,7 @@ class Scan : public RelExpr NAString priorColName_; NAString priorChildColName_; + NAString startWithExpr_; }; diff --git a/core/sql/parser/ParKeyWords.cpp b/core/sql/parser/ParKeyWords.cpp index 293d39a0e0..2046c61394 100644 --- a/core/sql/parser/ParKeyWords.cpp +++ b/core/sql/parser/ParKeyWords.cpp @@ -709,6 +709,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("NEXT", TOK_NEXT, ANS_|RESWORD_), ParKeyWord("NEXT_DAY", TOK_NEXT_DAY, NONRESTOKEN_), ParKeyWord("NO", TOK_NO, FIRST_|ANS_|RESWORD_), + ParKeyWord("NOCYCLE", TOK_NOCYCLE, FIRST_|ANS_|RESWORD_), ParKeyWord("NODELETE", TOK_NODELETE, FLAGSNONE_), ParKeyWord("NODES", TOK_NODES, NONRESTOKEN_), ParKeyWord("NOLOG", TOK_NOLOG, NONRESTOKEN_), @@ -1043,7 +1044,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("SQL_VARCHAR", TOK_VARCHAR, COMPAQ_|RESWORD_), ParKeyWord("SQL_WARNING", TOK_SQL_WARNING, NONRESTOKEN_), ParKeyWord("SQRT", TOK_SQRT, NONRESTOKEN_), - ParKeyWord("START", TOK_START, COMPAQ_|NONRESWORD_), + ParKeyWord("START", TOK_START, FIRST_|COMPAQ_|NONRESWORD_), // used in nist618 test ParKeyWord("STATE", TOK_STATE, COMPAQ_|NONRESWORD_), // used in QAT tests diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 95f50aaf49..f8837eac6f 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -475,6 +475,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_END_HINT %token TOK_BALANCE %token TOK_NOT_BETWEEN +%token TOK_NOCYCLE %token TOK_BETWEEN %token TOK_BIT %token TOK_BITAND @@ -1533,7 +1534,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_SPECIFICTYPE %token TOK_START %token TOK_STATE - +%token TOK_START_WITH %token TOK_TERMINATE %token TOK_THAN %token TOK_TREAT @@ -2084,6 +2085,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %type table_value_constructor %type table_expression %type from_clause +%type startwith_clause %type join_specification %type join_condition %type where_clause @@ -2128,8 +2130,8 @@ static void enableMakeQuotedStringISO88591Mechanism() %type rel_subquery %type row_subquery %type predicate -%type connect_by -%type startwith +//%type connect_by +//%type startwith %type dml_column_reference %type null_predicate %type scan_key_hint @@ -9406,18 +9408,18 @@ sequence_generator_option : start_with_option | datatype_option /* type pElemDDL */ -start_with_option : TOK_START TOK_WITH sg_sign NUMERIC_LITERAL_EXACT_NO_SCALE +start_with_option : TOK_START_WITH sg_sign NUMERIC_LITERAL_EXACT_NO_SCALE { // Validate that the value is not larger than // the maximum allowed for a LARGEINT. - NABoolean result = validateSGOption(TRUE, FALSE,(char *)$4->data(), "START WITH", "SEQUENCE"); + NABoolean result = validateSGOption(TRUE, FALSE,(char *)$3->data(), "START WITH", "SEQUENCE"); if (result == FALSE) YYERROR; - Int64 value = atoInt64($4->data()); - if (NOT $3) + Int64 value = atoInt64($3->data()); + if (NOT $2) value = -value; $$ = new (PARSERHEAP()) @@ -13095,15 +13097,6 @@ list_of_values : '(' insert_value_expression_list ')' } // end of fix: left recursion for insert statement values. - -connect_by : TOK_CONNECT TOK_BY comparison_predicate - { - $$ = $3; - } -startwith : empty { $$ = NULL; }| TOK_START TOK_WITH comparison_predicate - { - $$ = $3; - } table_expression : from_clause where_clause sample_clause cond_transpose_clause_list sequence_by_clause @@ -13204,13 +13197,42 @@ table_expression : from_clause where_clause sample_clause SqlParser_CurrentParser->topHasOlapFunctions()); SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); } + | from_clause startwith_clause where_clause + { + $$ = + getTableExpressionRelExpr($1, + $3, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + FALSE, + SqlParser_CurrentParser->topHasOlapFunctions()); + SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); + $$->addStartWithExprTree(((BiConnectBy*)$2)->getStartWith()); + $$->addConnectByExprTree(((BiConnectBy*)$2)->getConnectBy()); + ((Scan*)$$)->setStartWithExpr( ((BiConnectBy*)$2)->startWithString_.data()); + } /* type relx */ from_clause : TOK_FROM global_hint table_reference { $$ = $3; } | from_clause ',' table_reference { $$ = new (PARSERHEAP()) Join($1, $3, REL_JOIN); - } + } + +startwith_clause :TOK_START_WITH predicate TOK_CONNECT TOK_BY predicate + { + $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$5); + //save the predicate text + $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); + } + | TOK_CONNECT TOK_BY predicate + { + $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$3); + } /* type item */ join_specification : join_condition @@ -13743,6 +13765,7 @@ set_quantifier : { $$ = FALSE; /* by default, set quantifier is ALL */ /* type relx */ query_spec_body : query_select_list table_expression access_type optional_lock_mode { + if($2->getConnectByPredTree() == NULL) { // use a compute node to attach select list RelRoot *temp= new (PARSERHEAP()) RelRoot($2, $3, $4, REL_ROOT, $1); @@ -13761,16 +13784,38 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ SqlParser_CurrentParser->popHasTDFunctions(); $$=temp; + } + else + { + CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; + NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & + , PARSERHEAP() // in - NAMemory * + ); + //remove ';' + UInt32 pos = + stmt->index(";", 0, NAString::ignoreCase); + stmt->remove(pos); + + ExeUtilConnectby *euc = new (PARSERHEAP()) + ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), (char*) stmt->data(), + stmtCharSet, $2,PARSERHEAP()); + + RelRoot *temp = new (PARSERHEAP()) + RelRoot(euc, REL_ROOT , $1); + + if($2->getStartWithPredTree() == NULL) + { + euc->hasStartWith_ = FALSE; + } + else + { + euc->hasStartWith_ = TRUE; + euc->startWithExprString_ = ((Scan*)$2)->getStartWithExpr(); + } + $$ = temp; + } } - | query_select_list from_clause startwith connect_by where_clause access_type optional_lock_mode TOK_START - { - RelRoot *temp= new (PARSERHEAP()) - RelRoot($2, $6, $7, REL_ROOT, $1); - $2->addConnectByExprTree($4); - $2->addStartWithExprTree($3); - ((Scan*)$2)->setConnectByPhase(1); - $$=temp; - } + | query_select_list into_clause table_expression access_type optional_lock_mode { // use a compute node to attach select list @@ -13802,6 +13847,7 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ AssignmentHostVars->clear(); $$ = temp; } +/* |query_select_list from_clause startwith connect_by where_clause access_type optional_lock_mode { CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; @@ -13826,6 +13872,7 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ euc->hasStartWith_ = FALSE; $$ = temp; } +*/ //++ MV OZ // type item @@ -19051,7 +19098,7 @@ comparison_predicate : { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } | row_subquery comparison_operator value_expression_list_paren { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } - | TOK_PRIOR value_expression comparison_operator value_expression + | TOK_PRIOR value_expression comparison_operator value_expression { $$ = new (PARSERHEAP()) BiRelat($3, $2, $4); ((BiRelat*)$$)->setPrior(1);} | value_expression comparison_operator TOK_PRIOR value_expression { $$ = new (PARSERHEAP()) BiRelat($2, $1, $4); ((BiRelat*)$$)->setPrior(2);} @@ -24678,7 +24725,7 @@ param_name : IDENTIFIER temp.toUpper(); $$ = new (PARSERHEAP())ElemDDLParamName(temp); } - | nonreserved_func_word + | nonreserved_func_word { NAString temp = *(unicodeToChar (ToTokvalPlusYYText(&$1)->yytext, @@ -34109,7 +34156,7 @@ nonreserved_word : TOK_ABORT | TOK_SP_RESULT_SET | TOK_SQL_WARNING | TOK_SQLROW -// | TOK_START /* used in nist618 for column name */ + | TOK_START /* used in nist618 for column name */ | TOK_STATE /* used internally? qat tests */ | TOK_STATEMENT | TOK_STATIC diff --git a/core/sql/parser/ulexer.cpp b/core/sql/parser/ulexer.cpp index 8fc8df4e87..be99b4a1ad 100644 --- a/core/sql/parser/ulexer.cpp +++ b/core/sql/parser/ulexer.cpp @@ -3138,6 +3138,13 @@ Int32 yyULexer::yylex(YYSTYPE *lvalp) return anSQLMXKeyword(keyWordEntry1->getTokenCode(), lvalp); } break; + case TOK_START: + return eitherCompoundOrSimpleKeyword( + keyWordEntry2->getTokenCode() == TOK_WITH, + TOK_START_WITH, + keyWordEntry1->getTokenCode(), + end1, holdChar1, lvalp); + break; case TOK_UNION: return eitherCompoundOrSimpleKeyword (keyWordEntry2->getTokenCode() == TOK_JOIN, From 9fb3a5943f6440540b4894bc554d94b317fd9ece Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Mon, 23 Jul 2018 05:28:08 +0000 Subject: [PATCH 04/17] refactor the code, next need to add CQD and where clause support --- core/sql/bin/SqlciErrors.txt | 4 +- core/sql/comexe/ComTdbExeUtil.cpp | 2 - core/sql/comexe/ComTdbExeUtil.h | 4 +- core/sql/common/OperTypeEnum.h | 2 + core/sql/executor/ExExeUtil.h | 6 +- core/sql/executor/ExExeUtilConnectby.cpp | 128 +++++++++++------------ core/sql/generator/GenRelExeUtil.cpp | 46 +++++++- core/sql/optimizer/BindRelExpr.cpp | 35 +------ core/sql/optimizer/ItemLog.h | 26 ++--- core/sql/optimizer/ItemOther.h | 29 +++++ core/sql/optimizer/NormRelExpr.cpp | 11 -- core/sql/optimizer/RelExeUtil.cpp | 5 +- core/sql/optimizer/RelExeUtil.h | 2 + core/sql/optimizer/RelExpr.cpp | 34 ------ core/sql/optimizer/RelExpr.h | 15 --- core/sql/optimizer/RelScan.h | 41 ++++---- core/sql/parser/sqlparser.y | 43 ++++++-- 17 files changed, 217 insertions(+), 216 deletions(-) diff --git a/core/sql/bin/SqlciErrors.txt b/core/sql/bin/SqlciErrors.txt index cb1cfb34fa..137c611d96 100644 --- a/core/sql/bin/SqlciErrors.txt +++ b/core/sql/bin/SqlciErrors.txt @@ -1513,7 +1513,9 @@ $1~String1 -------------------------------- 8034 ZZZZZ 99999 ADVANCED MAJOR DBADMIN Column $0~String0 of object $1~string1 does not have a default clause but it is missing in database. This indicates inconsistent data. 8035 ZZZZZ 99999 ADVANCED MAJOR DBADMIN Truncation of hive table failed. $0~String0 8036 ZZZZZ 99999 ADVANCED MINOR LOGONLY Error while creating the error logging file or logging the error row to file $0~String0: Details :$1~String1 -8041 ZZZZZ 99999 BEGINNER MAJOR DBADMIN Loop detected in connect by execution. +8037 ZZZZZ 99999 BEGINNER MAJOR DBADMIN Loop detected in connect by execution. +8038 ZZZZZ 99999 BEGINNER MAJOR DBADMIN Exceed max recursive running depth. +8039 ZZZZZ 99999 BEGINNER MAJOR DBADMIN Exceed max connect by memory size. 8100 ZZZZZ 99999 BEGINNER MINOR LOGONLY Define $1~string0 does not exist 8101 23000 99999 BEGINNER MAJOR DBADMIN The operation is prevented by check constraint $0~ConstraintName on table $1~TableName. 8102 23000 99999 BEGINNER MAJOR DBADMIN The operation is prevented by a unique constraint. diff --git a/core/sql/comexe/ComTdbExeUtil.cpp b/core/sql/comexe/ComTdbExeUtil.cpp index 44c8647362..95e407a811 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -74,7 +74,6 @@ ComTdbExeUtil::ComTdbExeUtil(Lng32 type, child_(NULL), scanExpr_(scan_expr), flags_(0), - oriQuery_(query), explOptionsStr_(NULL) { setNodeType(ComTdb::ex_EXE_UTIL); @@ -3205,7 +3204,6 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, { setNodeType(ComTdb::ex_CONNECT_BY); connTableName_ = tableName; - oriQuery_ = query; } Long ComTdbExeUtilConnectby::pack(void * space) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index a1218ff364..a46ae08e88 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -201,7 +201,6 @@ class ComTdbExeUtil : public ComTdbGenericUtil void setNEOCatalogName(char * catalog) { NEOCatalogName_ = catalog; } void setType(ExeUtilType type) { type_ = type; } - char * oriQuery_; protected: Lng32 type_; // 00-03 @@ -4135,7 +4134,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil ); ComTdbExeUtilConnectby() - : ComTdbExeUtil() { hasStartWith_ = TRUE; } + : ComTdbExeUtil() { hasStartWith_ = TRUE; noCycle_ = FALSE; } Long pack(void *); Lng32 unpack(void *, void * reallocator); @@ -4152,6 +4151,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil NAString connTableName_; NAString startWithExprString_; NABoolean hasStartWith_; + NABoolean noCycle_; private: ExCriDescPtr workCriDesc_; Int32 flags_; diff --git a/core/sql/common/OperTypeEnum.h b/core/sql/common/OperTypeEnum.h index 404c704157..b9644162a4 100644 --- a/core/sql/common/OperTypeEnum.h +++ b/core/sql/common/OperTypeEnum.h @@ -676,6 +676,8 @@ enum OperatorTypeEnum { ITM_GREATEST = 2385, ITM_LEAST = 2386, + ITM_CONNECT_BY = 2387, + ITM_UNIQUE_EXECUTE_ID = 2391, ITM_GET_TRIGGERS_STATUS = 2392, ITM_GET_BIT_VALUE_AT = 2393, diff --git a/core/sql/executor/ExExeUtil.h b/core/sql/executor/ExExeUtil.h index 7cc5c036be..b590e8eca7 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4330,7 +4330,7 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb EVAL_INPUT_, EVAL_START_WITH_, DO_CONNECT_BY_, - EVAL_EXPR_, + EVAL_OUTPUT_EXPR_, NEXT_LEVEL_, NEXT_ROOT_, ERROR_, @@ -4340,9 +4340,7 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb ExExeUtilConnectbyTdb& exeUtilTdb() const {return (ExExeUtilConnectbyTdb&) tdb;}; - short emitRows(Queue *q, ExpTupleDesc * tDesc) ; - short emitRow(ExpTupleDesc * tDesc, int level) ; - short emitOneRow(ExpTupleDesc * tDesc, int level) ; + short emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle) ; protected: ExExeUtilConnectbyTcb *tcb_; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index f5c44fe20a..35b4cc9ba7 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -113,7 +113,7 @@ ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( return pa.allocatePstates(this, numElems, pstateLength); } - +#if 0 short ExExeUtilConnectbyTcb::emitRows(Queue *q, ExpTupleDesc * tDesc) { short retcode = 0, rc =0; @@ -211,8 +211,8 @@ short ExExeUtilConnectbyTcb::emitOneRow(ExpTupleDesc * tDesc, int level) retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); return retcode; } - -short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level) +#endif +short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle) { short retcode = 0, rc =0; char * ptr; @@ -221,7 +221,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level) short *ind ; ind = &nullInd; - for (UInt32 i = 1; i < tDesc->numAttrs() ; i++) + for (UInt32 i = 1; i < tDesc->numAttrs() - 2 ; i++) { cliInterface()->getPtrAndLen(i+1, ptr, len,&ind); char * src = ptr; @@ -275,23 +275,40 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level) } } -#if 0 + +#if 1 short srcType = REC_BIN32_UNSIGNED; Lng32 srcLen = 4; - int src = level; + int src = isleaf; Attributes * attr = tDesc->getAttr(tDesc->numAttrs() - 1); if ( ::convDoIt((char*)&src, srcLen, srcType, 0, 0, - &data_[attr->getOffset()], - attr->getLength(), - attr->getDatatype(),0,0, - 0, 0, NULL) != ex_expr::EXPR_OK) + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + 0, 0, NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } + + src = iscycle; + attr = tDesc->getAttr(tDesc->numAttrs() - 2); + if ( + ::convDoIt((char*)&src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + 0, 0, NULL) != ex_expr::EXPR_OK) { ex_assert( - 0, - "Error from ExStatsTcb::work::convDoIt."); + 0, + "Error from ExStatsTcb::work::convDoIt."); } #endif + + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); return retcode; } @@ -345,7 +362,8 @@ short ExExeUtilConnectbyTcb::work() int matchRowNum = 0; int currLevel = 1; - int resultSize = 0; + int resultSize = 0; //the number q2 returned, 0 means reach the leaf + // if no parent request, return if (qparent_.down->isEmpty()) return WORK_OK; @@ -358,19 +376,15 @@ short ExExeUtilConnectbyTcb::work() ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); ex_queue_entry * up_entry = qparent_.up->getTailEntry(); ex_tcb_private_state * pstate = pentry_down->pstate; - char * stmtStr = exeUtilTdb().oriQuery_; - if(stmtStr && exeUtilTdb().hasStartWith_ == TRUE) + + if(exeUtilTdb().hasStartWith_ == TRUE) { - NAString nq1=stmtStr; - UInt32 pos = nq1.index(" from ", 0, NAString::ignoreCase); - sprintf(q1,"SELECT %s , * , 0 FROM %s WHERE %s ;" ,(exeUtilTdb().parentColName_).data() , (exeUtilTdb().connTableName_).data() ,(exeUtilTdb().startWithExprString_).data() ); + sprintf(q1,"SELECT %s , * , cast( 0 as INT) FROM %s WHERE %s ;" ,(exeUtilTdb().parentColName_).data() , (exeUtilTdb().connTableName_).data() ,(exeUtilTdb().startWithExprString_).data() ); nq11 = q1; } else { - NAString nq1=stmtStr; - UInt32 pos = nq1.index(" from ", 0, NAString::ignoreCase); - sprintf(q1,"SELECT %s , * , 0 FROM %s WHERE %s is null ;" ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().connTableName_).data(), (exeUtilTdb().childColName_).data()); + sprintf(q1,"SELECT %s , * , cast(0 as INT) FROM %s WHERE %s is null ;" ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().connTableName_).data(), (exeUtilTdb().childColName_).data()); nq11 = q1; } @@ -392,7 +406,6 @@ short ExExeUtilConnectbyTcb::work() switch (step_) { case INITIAL_: - step_ = EVAL_START_WITH_; break; case EVAL_START_WITH_: @@ -435,7 +448,7 @@ short ExExeUtilConnectbyTcb::work() it->type = fsDatatype; it->len = len; if(haveDupSeed(currQueue, it, len, currLevel) == 0) { - emitRow(tDesc, currLevel); matchRowNum++; + emitRow(tDesc, currLevel, 0, 0); matchRowNum++; currQueue->insert(it); } } @@ -453,7 +466,7 @@ short ExExeUtilConnectbyTcb::work() for(int i=0; i< seedNum; i++) { - sprintf(q1,"SELECT %s , *, %d FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), currLevel,(exeUtilTdb().connTableName_).data()); + sprintf(q1,"SELECT %s , *, cast( %d as INT) FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), currLevel,(exeUtilTdb().connTableName_).data()); nq21 = q1; nq21.append((exeUtilTdb().childColName_).data()); nq21.append(" in ( "); @@ -522,22 +535,27 @@ short ExExeUtilConnectbyTcb::work() short rc1 = haveDupSeed(currQueue, it, len, currLevel) ; //loop detection if(rc1 == 1) { - loopDetected = 1; - ComDiagsArea * diags = getDiagsArea(); - if(diags == NULL) - { - setDiagsArea(ComDiagsArea::allocate(getHeap())); - diags = getDiagsArea(); - } - *diags << DgSqlCode(-8041); - step_ = ERROR_; - break; + loopDetected = 1; + if(exeUtilTdb().noCycle_ == FALSE) { + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8037); + step_ = ERROR_; + } + else + emitRow(tDesc, currLevel+1, 0, 1); + } if(rc1 == 0) { - emitRow(tDesc, currLevel+1); matchRowNum++; + emitRow(tDesc, currLevel+1, 0, 0); matchRowNum++; tmpQueue->insert(it); }//if(haveDupSeed(currQueue, it, len, currLevel) == 0) + }// while ((rc >= 0) cliInterface()->fetchRowsEpilogue(0, FALSE); }//for(int i=0; i< seedNum; i++) @@ -549,7 +567,12 @@ short ExExeUtilConnectbyTcb::work() if( loopDetected == 1) { - step_ = ERROR_; + if( exeUtilTdb().noCycle_ == TRUE) + { + step_ = NEXT_ROOT_; + } + else + step_ = ERROR_; break; } if(resultSize == 0) @@ -577,41 +600,14 @@ short ExExeUtilConnectbyTcb::work() case ERROR_: { - //if (qparent_.up->isFull()) - //return WORK_OK; + if (qparent_.up->isFull()) + return WORK_OK; if (handleError()) return WORK_OK; - //getDiagsArea()->clear(); step_ = DONE_; -#if 0 - // Return EOF. - ex_queue_entry * up_entry = qparent_.up->getTailEntry(); - - up_entry->upState.parentIndex = - pentry_down->downState.parentIndex; - - up_entry->upState.setMatchNo(0); - up_entry->upState.status = ex_queue::Q_SQLERROR; - ComDiagsArea * diagsArea = NULL; - ExRaiseSqlError(getHeap(), &diagsArea, - (ExeErrorCode)(8041)); - up_entry->setDiagsArea(diagsArea); - //ComDiagsArea *diagsArea = up_entry->getDiagsArea(); - - if (diagsArea == NULL) - diagsArea = - ComDiagsArea::allocate(this->getGlobals()->getDefaultHeap()); - else - diagsArea->incrRefCount (); // setDiagsArea call below will decr ref count - - if (getDiagsArea()) - diagsArea->mergeAfter(*getDiagsArea()); - - // insert into parent - qparent_.up->insert(); -#endif + step_ = DONE_; } break; diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index baae5d05e8..73063d7815 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5351,6 +5351,7 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); tblDesc_ = cmpSBD.getSeabaseTableDesc(cat,sch,tbl,COM_BASE_TABLE_OBJECT); + //add LEVEL column TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; tblDesc_->tableDesc()->colcount++; @@ -5371,6 +5372,47 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() NULL); column_desc->next = col_desc; col_desc->columnsDesc()->colclass='S'; + + column_desc = tblDesc_->tableDesc()->columns_desc; + tblDesc_->tableDesc()->colcount++; + i =0; + tmpOffset = 0; + while(column_desc->next) { i++; column_desc = column_desc->next; } + + tmpOffset = column_desc->columnsDesc()->offset + 4; + col_desc = TrafMakeColumnDesc( + tableName.data(), + "CONNECT_BY_ISCYCLE", //info->colName, + i, + REC_BIN32_UNSIGNED, + 4, + tmpOffset, + FALSE, + SQLCHARSETCODE_UNKNOWN, + NULL); + column_desc->next = col_desc; + col_desc->columnsDesc()->colclass='S'; + + column_desc = tblDesc_->tableDesc()->columns_desc; + tblDesc_->tableDesc()->colcount++; + i =0; + tmpOffset = 0; + while(column_desc->next) { i++; column_desc = column_desc->next; } + + tmpOffset = column_desc->columnsDesc()->offset + 4; + col_desc = TrafMakeColumnDesc( + tableName.data(), + "CONNECT_BY_ISLEAF", //info->colName, + i, + REC_BIN32_UNSIGNED, + 4, + tmpOffset, + FALSE, + SQLCHARSETCODE_UNKNOWN, + NULL); + column_desc->next = col_desc; + col_desc->columnsDesc()->colclass='S'; + return tblDesc_; } @@ -5477,11 +5519,13 @@ short ExeUtilConnectby::codeGen(Generator * generator) 32000, workCriDesc ); + exe_util_tdb->sourceDataTuppIndex_ = outputAtpIndex; - exe_util_tdb->parentColName_ = parentColName_; + exe_util_tdb->parentColName_ = parentColName_; exe_util_tdb->childColName_ = childColName_; exe_util_tdb->hasStartWith_ = hasStartWith_; exe_util_tdb->startWithExprString_ = startWithExprString_; + exe_util_tdb->noCycle_ = noCycle_; generator->initTdbFields(exe_util_tdb); if (!generator->explainDisabled()) diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index 548a730467..1fbc761823 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -2504,7 +2504,7 @@ RelExpr *RelExpr::bindSelf(BindWA *bindWA) if (bindWA->inViewWithCheckOption()) bindWA->predsOfViewWithCheckOption() += selectionPred(); } - +#if 0 ItemExpr *startWithTree = removeStartWithTree(); if (startWithTree) { bindWA->getCurrentScope()->context()->inWhereClause() = TRUE; @@ -2559,7 +2559,7 @@ RelExpr *RelExpr::bindSelf(BindWA *bindWA) } } } - +#endif // ++MV // Bind the uniqueColumnsTree expression. // @@ -8429,37 +8429,6 @@ RelExpr *Scan::bindNode(BindWA *bindWA) ); } } - for (ValueId exprId = getConnectBy().init(); getConnectBy().next(exprId); getConnectBy().advance(exprId)) - { - - if(exprId.getItemExpr()->getOperatorType() == ITM_EQUAL) - { - if( ((BiRelat*)exprId.getItemExpr())->getPrior() == 1) - { - //right child is the PRIOR column - ItemExpr * c = exprId.getItemExpr()->child(0); - NAString unparsed(CmpCommon::statementHeap()); - c->unparse(unparsed); - setPriorColName((char*)unparsed.data()); - ItemExpr * cc = exprId.getItemExpr()->child(1); - NAString unparsedc(CmpCommon::statementHeap()); - cc->unparse(unparsedc); - setPriorChildColName((char*)unparsedc.data()); - } - if( ((BiRelat*)exprId.getItemExpr())->getPrior() == 2) - { - //left child is the PRIOR column - ItemExpr * c = exprId.getItemExpr()->child(1); - NAString unparsed(CmpCommon::statementHeap()); - c->unparse(unparsed); - setPriorColName((char*)unparsed.data()); - ItemExpr * cc = exprId.getItemExpr()->child(0); - NAString unparsedc(CmpCommon::statementHeap()); - cc->unparse(unparsedc); - setPriorChildColName((char*)unparsedc.data()); - } - } - } return boundExpr; } // Scan::bindNode() diff --git a/core/sql/optimizer/ItemLog.h b/core/sql/optimizer/ItemLog.h index d84d6490dc..20d2082fc1 100644 --- a/core/sql/optimizer/ItemLog.h +++ b/core/sql/optimizer/ItemLog.h @@ -738,24 +738,26 @@ class BiRelat : public ItemExpr }; // class BiRelat -class BiConnectBy :public BiRelat { +class BiConnectByRelat :public BiRelat { public: - BiConnectBy( BiRelat * start, - BiRelat * conn) - :BiRelat(ITM_EQUAL, NULL, NULL) + BiConnectByRelat( OperatorTypeEnum otype, + ItemExpr *child0 = NULL, + ItemExpr *child1 = NULL) + :BiRelat(otype, NULL, NULL) { - startWith_ = start; - connectBy_ = conn; } - virtual ~BiConnectBy() {} - BiRelat * getStartWith() {return startWith_; } - BiRelat * getConnectBy() {return connectBy_; } - NAString startWithString_; + virtual ~BiConnectByRelat() {} + + void setParentColName(char * v) { parentColName_ = v; } + NAString getParentColName () { return parentColName_; } + + void setChildColName(char * v) { childColName_ = v; } + NAString getChildColName() { return childColName_ ; } private: - BiRelat * startWith_; - BiRelat * connectBy_; + NAString parentColName_; + NAString childColName_; }; class KeyRangeCompare : public BiRelat diff --git a/core/sql/optimizer/ItemOther.h b/core/sql/optimizer/ItemOther.h index 4ebdad50fa..44f24468e4 100644 --- a/core/sql/optimizer/ItemOther.h +++ b/core/sql/optimizer/ItemOther.h @@ -1131,6 +1131,35 @@ class VEGReference : public ItemExpr }; // class VEGReference + +class BiConnectBy :public ItemExpr { +public: + BiConnectBy( BiRelat * start, + BiRelat * conn) + : + ItemExpr(ITM_CONNECT_BY), + noCycle_(FALSE) + { + startWith_ = start; + connectBy_ = (BiConnectByRelat*)conn; + } + virtual ~BiConnectBy() {} + + BiRelat * getStartWith() {return startWith_; } + BiConnectByRelat * getConnectBy() {return connectBy_; } + NAString getStartWithString() {return startWithString_; } + void setStartWithString(char *v ) {startWithString_ = v; } + void setNoCycle(NABoolean v) { noCycle_ = v; } + NABoolean getNoCycle() {return noCycle_; } + NAString startWithString_; + +private: + BiRelat * startWith_; + BiConnectByRelat * connectBy_; + NABoolean noCycle_; +}; + + //This RangeSpecRef class is an wrapper for RangeSpec object and also holds a relationship // which needs to be used for traversal and selectivity estimation/generating MDAM Pred for different BiRelational as well. diff --git a/core/sql/optimizer/NormRelExpr.cpp b/core/sql/optimizer/NormRelExpr.cpp index cd505d1fba..974c055b71 100644 --- a/core/sql/optimizer/NormRelExpr.cpp +++ b/core/sql/optimizer/NormRelExpr.cpp @@ -6065,17 +6065,6 @@ RelExpr * Scan::normalizeNode } } - //check connect by phase - if( getConnectByPhase() == 1 ) // This is start with - { - selectionPred().clear(); - selectionPred() += getStartWith(); - } - if( getConnectByPhase() == 2 ) // This is start with - { - selectionPred().clear(); - selectionPred() += getConnectBy(); - } // the following block of code can transform an OR predicate into // semijoin(Scan, TupleList) // where the Scan is this scan node. diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index 0308d3526c..55575de2e1 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6185,8 +6185,6 @@ RelExpr * ExeUtilConnectby::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap) else result = (ExeUtilConnectby*) derivedNode; result->tblDesc_ = tblDesc_; - result->connectByTree_ = connectByTree_; - result->connectByTree_ = connectByTree_; result->hasStartWith_ = hasStartWith_; return ExeUtilExpr::copyTopNode(result, outHeap); } @@ -6201,8 +6199,7 @@ RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) bindChildren(bindWA); boundExpr = ExeUtilExpr::bindNode(bindWA); Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); - parentColName_=scanNode->getPirorColName(); - childColName_=scanNode->getPirorChildColName(); + if (bindWA->errStatus()) return NULL; return boundExpr; diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index e4f60dd92c..cd5889ea54 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1092,6 +1092,7 @@ class ExeUtilConnectby : public ExeUtilExpr stmtText, stmtTextCharSet, oHeap) { hasStartWith_ = TRUE; + noCycle_ = FALSE; } virtual const NAString getText() const; @@ -1122,6 +1123,7 @@ class ExeUtilConnectby : public ExeUtilExpr NAString childColName_; NAString startWithExprString_; NABoolean hasStartWith_; + NABoolean noCycle_; private: //connect by //start with diff --git a/core/sql/optimizer/RelExpr.cpp b/core/sql/optimizer/RelExpr.cpp index ec61d19f04..ea4495a68c 100644 --- a/core/sql/optimizer/RelExpr.cpp +++ b/core/sql/optimizer/RelExpr.cpp @@ -250,8 +250,6 @@ RelExpr::RelExpr(OperatorTypeEnum otype, CollHeap *outHeap) : ExprNode(otype) ,selection_(NULL) - ,startWith_(NULL) - ,connectBy_(NULL) ,RETDesc_(NULL) ,groupAttr_(NULL) ,groupId_(INVALID_GROUP_ID) @@ -309,10 +307,6 @@ RelExpr::~RelExpr() // these data structures are always owned by the tree delete selection_; - if(startWith_) - delete startWith_; - if(connectBy_) - delete connectBy_; // delete all children, if this is a standalone query // (NOTE: can't use the virtual function getArity() in a destructor!!!) @@ -490,20 +484,6 @@ void RelExpr::addSelPredTree(ItemExpr *selpred) selection_ = sel.getPtr(); } // RelExpr::addSelPredTree() -void RelExpr::addStartWithExprTree(ItemExpr *predExpr) -{ - ExprValueId sel = startWith_; - ItemExprTreeAsList(&sel, ITM_AND).insert(predExpr); - startWith_= sel.getPtr(); -} - -void RelExpr::addConnectByExprTree(ItemExpr *predExpr) -{ - ExprValueId sel = connectBy_; - ItemExprTreeAsList(&sel, ITM_AND).insert(predExpr); - connectBy_ = sel.getPtr(); -} - ItemExpr * RelExpr::removeSelPredTree() { ItemExpr * result = selection_; @@ -511,20 +491,6 @@ ItemExpr * RelExpr::removeSelPredTree() return result; } // RelExpr::removeSelPredTree() -ItemExpr * RelExpr::removeConnectByTree() -{ - ItemExpr * result = connectBy_; - connectBy_ = NULL; - return result; -} // RelExpr::removeConnectByTree() - -ItemExpr * RelExpr::removeStartWithTree() -{ - ItemExpr * result = startWith_; - startWith_ = NULL; - return result; -} // RelExpr::removeStartWithTree() - //++ MV - void RelExpr::addUniqueColumnsTree(ItemExpr *uniqueColumnsTree) { diff --git a/core/sql/optimizer/RelExpr.h b/core/sql/optimizer/RelExpr.h index 79e561294b..6c0b9e9cdb 100644 --- a/core/sql/optimizer/RelExpr.h +++ b/core/sql/optimizer/RelExpr.h @@ -397,15 +397,6 @@ class RelExpr : public ExprNode ItemExpr * selPredTree() const { return selection_; } const ItemExpr * getSelPredTree() const { return selection_; } - ItemExpr * startWithPredTree() const { return startWith_; } - const ItemExpr * getStartWithPredTree() const { return startWith_; } - - ItemExpr * connectByPredTree() const { return connectBy_; } - const ItemExpr * getConnectByPredTree() const { return connectBy_; } - - ValueIdSet & getStartWith() { return startPred_; } - ValueIdSet & getConnectBy() { return connectByPred_; } - // return a (short-lived) read/write reference to the selection predicates ValueIdSet & selectionPred() { CMPASSERT(NOT isCutOp()); return predicates_; } @@ -1462,12 +1453,6 @@ class RelExpr : public ExprNode ItemExpr * selection_; // generated by the parser ValueIdSet predicates_; // predicates represented as a set - ItemExpr * startWith_ ; - ValueIdSet startPred_; - - ItemExpr * connectBy_; - ValueIdSet connectByPred_; - // A descriptor for the table derived from the RelExpr. RETDesc * RETDesc_; diff --git a/core/sql/optimizer/RelScan.h b/core/sql/optimizer/RelScan.h index 0a46a3cca9..e51af9bbdf 100644 --- a/core/sql/optimizer/RelScan.h +++ b/core/sql/optimizer/RelScan.h @@ -50,6 +50,7 @@ #include "SchemaDB.h" #include "HbaseSearchSpec.h" #include "OptHints.h" +#include "ItemOther.h" #include "ExpHbaseDefs.h" #include @@ -235,8 +236,8 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(oHeap), hbaseAccessOptions_(NULL), - connectByPhase_(0), - commonSubExpr_(NULL) + commonSubExpr_(NULL), + biConnectBy_(NULL) {} Scan(const CorrName& name, @@ -264,8 +265,8 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(CmpCommon::statementHeap()), hbaseAccessOptions_(NULL), - connectByPhase_(0), - commonSubExpr_(NULL) + commonSubExpr_(NULL), + biConnectBy_(NULL) {} Scan(const CorrName& name, @@ -296,8 +297,8 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(oHeap), hbaseAccessOptions_(NULL), - connectByPhase_(0), - commonSubExpr_(NULL) + commonSubExpr_(NULL), + biConnectBy_(NULL) {} Scan(OperatorTypeEnum otype, @@ -326,8 +327,8 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), hbaseAccessOptions_(NULL), matchingMVs_(CmpCommon::statementHeap()), - connectByPhase_(0), - commonSubExpr_(NULL) + commonSubExpr_(NULL), + biConnectBy_(NULL) {} // virtual destructor @@ -599,6 +600,10 @@ class Scan : public RelExpr void setForceInverseOrder(NABoolean v=TRUE) { (v ? scanFlags_ |= FORCE_INVERSE_ORDER : scanFlags_ &= ~FORCE_INVERSE_ORDER); } + NABoolean hasConnectBy() const { return (scanFlags_ & HAS_CONNECT_BY) != 0; } + void setHasConnectBy(NABoolean v=TRUE) + { (v ? scanFlags_ |= HAS_CONNECT_BY: scanFlags_ &= ~HAS_CONNECT_BY); } + void setExtraOutputColumns(ValueIdSet outputCols) { extraOutputColumns_ = outputCols; } const ValueIdSet& getExtraOutputColumns() const @@ -637,15 +642,8 @@ class Scan : public RelExpr CommonSubExprRef *getCommonSubExpr() const { return commonSubExpr_; } void setCommonSubExpr(CommonSubExprRef *cse) { commonSubExpr_ = cse; } - void setConnectByPhase(char v) { connectByPhase_ = v; } - char getConnectByPhase() { return connectByPhase_; } - - NAString getPirorColName() { return priorColName_; } - NAString getPirorChildColName() { return priorChildColName_; } - NAString getStartWithExpr() { return startWithExpr_; } - void setPriorColName(char * v) { priorColName_ = v; } - void setPriorChildColName(char * v) { priorChildColName_ = v; } - void setStartWithExpr(const char *v) { startWithExpr_ = v; } + void setBiConnectBy(BiConnectBy *b) { biConnectBy_ = b; } + BiConnectBy * getBiConnectBy() {return biConnectBy_; } protected: @@ -693,7 +691,8 @@ class Scan : public RelExpr // operation (ex., UPDATE becomes UPDATE(SCAN) in parser), // then no security check is needed. enum ScanFlags { NO_SECURITY_CHECK = 0x0001, - FORCE_INVERSE_ORDER = 0x0002}; + FORCE_INVERSE_ORDER = 0x0002, + HAS_CONNECT_BY = 0x0004}; Cardinality baseCardinality_; // from table statistics @@ -796,11 +795,7 @@ class Scan : public RelExpr // materialized common subexpr CommonSubExprRef *commonSubExpr_; - char connectByPhase_ ; - - NAString priorColName_; - NAString priorChildColName_; - NAString startWithExpr_; + BiConnectBy * biConnectBy_; }; diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index f8837eac6f..b274f558e6 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -13211,9 +13211,8 @@ table_expression : from_clause where_clause sample_clause FALSE, SqlParser_CurrentParser->topHasOlapFunctions()); SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); - $$->addStartWithExprTree(((BiConnectBy*)$2)->getStartWith()); - $$->addConnectByExprTree(((BiConnectBy*)$2)->getConnectBy()); - ((Scan*)$$)->setStartWithExpr( ((BiConnectBy*)$2)->startWithString_.data()); + ((Scan*)$$)->setBiConnectBy( (BiConnectBy*)$2); + ((Scan*)$$)->setHasConnectBy(TRUE); } /* type relx */ @@ -13229,10 +13228,22 @@ startwith_clause :TOK_START_WITH predicate TOK_CONNECT TOK_BY predicate //save the predicate text $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); } + |TOK_START_WITH predicate TOK_CONNECT TOK_BY TOK_NOCYCLE predicate + { + $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$6); + //save the predicate text + $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); + ((BiConnectBy*)$$)->setNoCycle(TRUE); + } | TOK_CONNECT TOK_BY predicate { $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$3); } + | TOK_CONNECT TOK_BY TOK_NOCYCLE predicate + { + $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$4); + ((BiConnectBy*)$$)->setNoCycle(TRUE); + } /* type item */ join_specification : join_condition @@ -13765,7 +13776,7 @@ set_quantifier : { $$ = FALSE; /* by default, set quantifier is ALL */ /* type relx */ query_spec_body : query_select_list table_expression access_type optional_lock_mode { - if($2->getConnectByPredTree() == NULL) { + if( ! ((Scan *)$2)->hasConnectBy()) { // use a compute node to attach select list RelRoot *temp= new (PARSERHEAP()) RelRoot($2, $3, $4, REL_ROOT, $1); @@ -13803,15 +13814,19 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ RelRoot *temp = new (PARSERHEAP()) RelRoot(euc, REL_ROOT , $1); - if($2->getStartWithPredTree() == NULL) + if( ((Scan*)$2)->getBiConnectBy()->getStartWith() == NULL) { euc->hasStartWith_ = FALSE; } else { euc->hasStartWith_ = TRUE; - euc->startWithExprString_ = ((Scan*)$2)->getStartWithExpr(); + euc->startWithExprString_ = ((Scan*)$2)->getBiConnectBy()->getStartWithString(); } + euc->noCycle_ = ((Scan*)$2)->getBiConnectBy()->getNoCycle(); + euc->parentColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getParentColName(); + euc->childColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getChildColName(); + $$ = temp; } } @@ -19099,9 +19114,21 @@ comparison_predicate : | row_subquery comparison_operator value_expression_list_paren { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } | TOK_PRIOR value_expression comparison_operator value_expression - { $$ = new (PARSERHEAP()) BiRelat($3, $2, $4); ((BiRelat*)$$)->setPrior(1);} + { $$ = new (PARSERHEAP()) BiConnectByRelat($3, $2, $4); + NAString pn, cn; + $2->unparse(pn, PARSER_PHASE, USER_FORMAT); + $4->unparse(cn, PARSER_PHASE, USER_FORMAT); + ( (BiConnectByRelat*)$$)->setParentColName((char*)pn.data()); + ( (BiConnectByRelat*)$$)->setChildColName((char*)cn.data()); + } | value_expression comparison_operator TOK_PRIOR value_expression - { $$ = new (PARSERHEAP()) BiRelat($2, $1, $4); ((BiRelat*)$$)->setPrior(2);} + { $$ = new (PARSERHEAP()) BiConnectByRelat($2, $1, $4); + NAString pn, cn; + $4->unparse(pn, PARSER_PHASE, USER_FORMAT); + $1->unparse(cn, PARSER_PHASE, USER_FORMAT); + ( (BiConnectByRelat*)$$)->setParentColName((char*)pn.data()); + ( (BiConnectByRelat*)$$)->setChildColName((char*)cn.data()); + } // BEGIN rules added for UDF /* COMMENTED OUT FOR R2.5. CAUSES GRAMMAR CONFLICTS. From b875ec3cdaef2c33cc3d127c24e62be478a78781 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Wed, 25 Jul 2018 04:22:21 +0000 Subject: [PATCH 05/17] support where clause, next add CQD to control memory usage --- core/sql/comexe/ComTdbExeUtil.cpp | 9 ++-- core/sql/comexe/ComTdbExeUtil.h | 3 +- core/sql/executor/ExExeUtilConnectby.cpp | 26 +++++++++- core/sql/generator/GenRelExeUtil.cpp | 62 ++++++++++++++++++------ core/sql/optimizer/ItemOther.h | 1 + core/sql/optimizer/RelExeUtil.cpp | 11 ++++- core/sql/optimizer/RelExeUtil.h | 22 +++++++++ core/sql/parser/sqlparser.y | 14 ++++-- 8 files changed, 118 insertions(+), 30 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.cpp b/core/sql/comexe/ComTdbExeUtil.cpp index 95e407a811..b1268338e7 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -3176,6 +3176,7 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, ULng32 input_rowlen, ex_expr * output_expr, ULng32 output_rowlen, + ex_expr * scan_expr, ex_cri_desc * work_cri_desc, const unsigned short work_atp_index, Lng32 colDescSize, @@ -3193,13 +3194,13 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, tableName, strlen(tableName), input_expr, input_rowlen, output_expr, output_rowlen, - NULL, + scan_expr, work_cri_desc, work_atp_index, given_cri_desc, returned_cri_desc, down, up, num_buffers, buffer_size), flags_(0), - workCriDesc_(workCriDesc), + myWorkCriDesc_(workCriDesc), tupleLen_(outputRowSize) { setNodeType(ComTdb::ex_CONNECT_BY); @@ -3208,12 +3209,12 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, Long ComTdbExeUtilConnectby::pack(void * space) { - workCriDesc_.pack(space); + myWorkCriDesc_.pack(space); return ComTdbExeUtil::pack(space); } Lng32 ComTdbExeUtilConnectby::unpack(void * base, void * reallocator) { - if(workCriDesc_.unpack(base, reallocator)) return -1; + if(myWorkCriDesc_.unpack(base, reallocator)) return -1; return ComTdbExeUtil::unpack(base, reallocator); } diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index a46ae08e88..20f053bf83 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -4120,6 +4120,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil ULng32 input_rowlen, ex_expr * output_expr, ULng32 output_rowlen, + ex_expr * scan_expr, ex_cri_desc * work_cri_desc, const unsigned short work_atp_index, Lng32 colDescSize, @@ -4153,7 +4154,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil NABoolean hasStartWith_; NABoolean noCycle_; private: - ExCriDescPtr workCriDesc_; + ExCriDescPtr myWorkCriDesc_; Int32 flags_; Int32 tupleLen_; }; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 35b4cc9ba7..f065f88d78 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -102,7 +102,11 @@ ExExeUtilConnectbyTcb::ExExeUtilConnectbyTcb( qparent_.down->allocatePstate(this); pool_->get_free_tuple(tuppData_, exe_util_tdb.tupleLen_); data_ = tuppData_.getDataPointer(); - //pool_->get_free_tuple(workAtp_->getTupp(2), 0); +// workAtp_ = allocateAtp(exe_util_tdb.workCriDesc_, glob->getSpace()); + +// pool_->get_free_tuple(workAtp_->getTupp(1), 0); +// pool_->get_free_tuple(workAtp_->getTupp(2), 0); + } ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( @@ -308,8 +312,26 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf } #endif + //apply the expression +#if 0 + ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_OK; + UInt32 rowLen = exeUtilTdb().outputRowlen_; //TODO + ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); - retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); + //setup ATP + workAtp_->getTupp(exeUtilTdb().workAtpIndex()) + .setDataPointer(data_); + + evalRetCode = (exeUtilTdb().scanExpr_)->eval(pentry_down->getAtp(), workAtp_, NULL, + exeUtilTdb().tupleLen_, &rowLen); +#endif +#if 1 + ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_TRUE; + if(exeUtilTdb().scanExpr_ ) + evalRetCode = evalScanExpr((char*)data_, exeUtilTdb().tupleLen_, FALSE); +#endif + if (evalRetCode == ex_expr::EXPR_TRUE) + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); return retcode; } diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 73063d7815..3c07359643 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5333,10 +5333,14 @@ short ExeUtilOrcFastAggr::codeGen(Generator * generator) const char * ExeUtilConnectby::getVirtualTableName() { - Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); - NAString tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); - NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); - return tbl.data(); + //Scan * scanNode = (Scan *)scan_; +// Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); +// NAString tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); +// NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); +// return tbl.data(); + //NAString returnNm = "_CONNNEC_BY_"+myTableName_; + return myTableName_.data(); + } TrafDesc *ExeUtilConnectby::createVirtualTableDesc() @@ -5345,13 +5349,16 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() NAString cat; NAString sch; NAString tbl; - Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); - cat= (scanNode->getTableName()).getQualifiedNameObj().getCatalogName(); - sch= (scanNode->getTableName()).getQualifiedNameObj().getSchemaName(); + Scan * scanNode = (Scan *)scan_; + //Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); + cat= "TRAFODION"; //(scanNode->getTableName()).getQualifiedNameObj().getCatalogName(); + sch= "SEABASE"; //(scanNode->getTableName()).getQualifiedNameObj().getSchemaName(); tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); tblDesc_ = cmpSBD.getSeabaseTableDesc(cat,sch,tbl,COM_BASE_TABLE_OBJECT); - + //rename + TrafTableDesc * td = tblDesc_->tableDesc(); + td->tablename = (char*)getVirtualTableName(); //add LEVEL column TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; tblDesc_->tableDesc()->colcount++; @@ -5361,7 +5368,7 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() while(column_desc->next) { i++; column_desc = column_desc->next; } tmpOffset = column_desc->columnsDesc()->offset + 4; TrafDesc * col_desc = TrafMakeColumnDesc( - tableName.data(), + getVirtualTableName(), "LEVEL", //info->colName, i, REC_BIN32_UNSIGNED, @@ -5381,7 +5388,7 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() tmpOffset = column_desc->columnsDesc()->offset + 4; col_desc = TrafMakeColumnDesc( - tableName.data(), + getVirtualTableName(), "CONNECT_BY_ISCYCLE", //info->colName, i, REC_BIN32_UNSIGNED, @@ -5401,7 +5408,7 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() tmpOffset = column_desc->columnsDesc()->offset + 4; col_desc = TrafMakeColumnDesc( - tableName.data(), + getVirtualTableName(), "CONNECT_BY_ISLEAF", //info->colName, i, REC_BIN32_UNSIGNED, @@ -5463,8 +5470,7 @@ short ExeUtilConnectby::codeGen(Generator * generator) = new(space) ex_cri_desc(givenDesc->noTuples() + 1, space); ex_cri_desc * workCriDesc = new(space) ex_cri_desc(4, space); const Int32 work_atp = 1; - const Int32 fetchSourceAtpIndex = 2; - const Int32 outputAtpIndex = 3; + const Int32 outputAtpIndex = 2; Attributes ** attrs = new(generator->wHeap()) @@ -5496,7 +5502,7 @@ short ExeUtilConnectby::codeGen(Generator * generator) Int32 theAtpIndex = returnedDesc->noTuples()-1; expGen->assignAtpAndAtpIndex(getVirtualTableDesc()->getColumnList(), - 0, theAtpIndex); + work_atp, outputAtpIndex); TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; Lng32 colDescSize = column_desc->columnsDesc()->length; @@ -5504,11 +5510,35 @@ short ExeUtilConnectby::codeGen(Generator * generator) char * stmtText = getStmtText(); char *tblnm = (char*)getTableName().getQualifiedNameObj().getObjectName().data(); + ex_expr * selectPred = NULL; +#if 0 + ExpTupleDesc * asciiTupleDesc = 0; + expGen->processValIdList( + getVirtualTableDesc()->getColumnList(), // [IN] ValueIdList + tupleFormat, // [IN] tuple data format + tupleLength, // [OUT] tuple length + work_atp, // [IN] atp number + outputAtpIndex, // [IN] index into atp + &asciiTupleDesc, // [optional OUT] tuple desc + ExpTupleDesc::LONG_FORMAT // [optional IN] desc format + ); +#endif + + if (!selectionPred().isEmpty()) + { + ItemExpr * selPredTree = + selectionPred().rebuildExprTree(ITM_AND,TRUE,TRUE); + expGen->generateExpr(selPredTree->getValueId(), + ex_expr::exp_SCAN_PRED, + &selectPred); + } + ComTdbExeUtilConnectby * exe_util_tdb = new(space) ComTdbExeUtilConnectby (stmtText , (stmtText ? strlen(stmtText) : 0), getStmtTextCharSet(), tblnm , NULL, 0 , 0, - 0,0, //This is the output expression, used in parent to apply on the output - workCriDesc , 1, + 0 , 0, + selectPred, //This is the output expression, used in parent to apply on the output + workCriDesc , outputAtpIndex, colDescSize, tupleLength, givenDesc, diff --git a/core/sql/optimizer/ItemOther.h b/core/sql/optimizer/ItemOther.h index 44f24468e4..0f4eac462a 100644 --- a/core/sql/optimizer/ItemOther.h +++ b/core/sql/optimizer/ItemOther.h @@ -1152,6 +1152,7 @@ class BiConnectBy :public ItemExpr { void setNoCycle(NABoolean v) { noCycle_ = v; } NABoolean getNoCycle() {return noCycle_; } NAString startWithString_; + ItemExpr * where_clause; private: BiRelat * startWith_; diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index 55575de2e1..ccc8acc30b 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6186,6 +6186,13 @@ RelExpr * ExeUtilConnectby::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap) result = (ExeUtilConnectby*) derivedNode; result->tblDesc_ = tblDesc_; result->hasStartWith_ = hasStartWith_; + result->connectByTree_ = connectByTree_; + result->parentColName_ = parentColName_; + result->childColName_ = childColName_; + result->startWithExprString_ = startWithExprString_; + result->noCycle_ = noCycle_; + result->myselection_= myselection_; + result->mypredicates_= mypredicates_; return ExeUtilExpr::copyTopNode(result, outHeap); } @@ -6197,9 +6204,9 @@ RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) } RelExpr * boundExpr = NULL; bindChildren(bindWA); + boundExpr = ExeUtilExpr::bindNode(bindWA); - Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); - + if (bindWA->errStatus()) return NULL; return boundExpr; diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index cd5889ea54..8b6f154c47 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1093,6 +1093,8 @@ class ExeUtilConnectby : public ExeUtilExpr { hasStartWith_ = TRUE; noCycle_ = FALSE; + myselection_ = NULL; + scan_ = scan; } virtual const NAString getText() const; @@ -1109,6 +1111,21 @@ class ExeUtilConnectby : public ExeUtilExpr virtual TrafDesc * createVirtualTableDesc(); virtual const char * getVirtualTableName(); +#if 1 + virtual + void pushdownCoveredExpr(const ValueIdSet & outputExprOnOperator, + const ValueIdSet & newExternalInputs, + ValueIdSet& predOnOperator, + const ValueIdSet * nonPredExprOnOperator = NULL, + Lng32 childId = (-MAX_REL_ARITY) ) { + ValueIdSet emptySet; + RelExpr::pushdownCoveredExpr(outputExprOnOperator, + newExternalInputs, + emptySet, + nonPredExprOnOperator, + 0); + } +#endif int createAsciiColAndCastExpr2(Generator * generator, ItemExpr * colNode, @@ -1124,6 +1141,11 @@ class ExeUtilConnectby : public ExeUtilExpr NAString startWithExprString_; NABoolean hasStartWith_; NABoolean noCycle_; + ItemExpr * myselection_; // generated by the parser + ValueIdSet mypredicates_; // predicates represented as a set + RelExpr * scan_; + NAString myTableName_; + private: //connect by //start with diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index b274f558e6..023dce549d 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -13201,7 +13201,7 @@ table_expression : from_clause where_clause sample_clause { $$ = getTableExpressionRelExpr($1, - $3, + NULL, NULL, NULL, NULL, @@ -13210,10 +13210,10 @@ table_expression : from_clause where_clause sample_clause NULL, FALSE, SqlParser_CurrentParser->topHasOlapFunctions()); - SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); + SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); + ((BiConnectBy*)$2)->where_clause = $3; ((Scan*)$$)->setBiConnectBy( (BiConnectBy*)$2); ((Scan*)$$)->setHasConnectBy(TRUE); - } /* type relx */ from_clause : TOK_FROM global_hint table_reference { $$ = $3; } @@ -13809,8 +13809,8 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ ExeUtilConnectby *euc = new (PARSERHEAP()) ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), (char*) stmt->data(), - stmtCharSet, $2,PARSERHEAP()); - + stmtCharSet, NULL, PARSERHEAP()); + RelRoot *temp = new (PARSERHEAP()) RelRoot(euc, REL_ROOT , $1); @@ -13824,8 +13824,12 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ euc->startWithExprString_ = ((Scan*)$2)->getBiConnectBy()->getStartWithString(); } euc->noCycle_ = ((Scan*)$2)->getBiConnectBy()->getNoCycle(); + euc->scan_ = $2; + euc->myTableName_ = "_CONN_"+((Scan*)$2)->getTableName().getQualifiedNameAsString(); euc->parentColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getParentColName(); euc->childColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getChildColName(); + + euc->addSelPredTree( ((Scan*)$2)->getBiConnectBy()->where_clause ); $$ = temp; } From 1b853c5da8210d77bd8d84dac374e57a67e38bef Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Thu, 26 Jul 2018 05:00:23 +0000 Subject: [PATCH 06/17] support where clause, next add regression test --- core/sql/comexe/ComTdbExeUtil.cpp | 2 ++ core/sql/comexe/ComTdbExeUtil.h | 2 ++ core/sql/executor/ExExeUtilConnectby.cpp | 46 +++++++++++++++++++++--- core/sql/generator/GenRelExeUtil.cpp | 34 ++++-------------- core/sql/optimizer/RelExeUtil.cpp | 9 +++-- core/sql/optimizer/RelExeUtil.h | 8 ++--- core/sql/parser/sqlparser.y | 8 ++--- core/sql/sqlcomp/DefaultConstants.h | 4 ++- core/sql/sqlcomp/nadefaults.cpp | 3 ++ 9 files changed, 74 insertions(+), 42 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.cpp b/core/sql/comexe/ComTdbExeUtil.cpp index b1268338e7..831a94d26b 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -3205,6 +3205,8 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, { setNodeType(ComTdb::ex_CONNECT_BY); connTableName_ = tableName; + maxDeep_ = 200; //by default, max deep of a tree + maxSize_ = 100000; //by default, the max number of rows to return for hierachy query } Long ComTdbExeUtilConnectby::pack(void * space) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index 20f053bf83..2e570c6832 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -4153,6 +4153,8 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil NAString startWithExprString_; NABoolean hasStartWith_; NABoolean noCycle_; + Int32 maxDeep_; + Int32 maxSize_; private: ExCriDescPtr myWorkCriDesc_; Int32 flags_; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index f065f88d78..ec66854f69 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -332,6 +332,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf #endif if (evalRetCode == ex_expr::EXPR_TRUE) retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); + return retcode; } @@ -475,7 +476,21 @@ short ExExeUtilConnectbyTcb::work() } } cliInterface()->fetchRowsEpilogue(0, FALSE); - step_ = DO_CONNECT_BY_; + + if( matchRowNum > exeUtilTdb().maxSize_ ) + { + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8039); + + step_ = ERROR_; + } + else + step_ = DO_CONNECT_BY_; } break; case DO_CONNECT_BY_: @@ -606,7 +621,20 @@ short ExExeUtilConnectbyTcb::work() case NEXT_LEVEL_: { currLevel++; - step_ = DO_CONNECT_BY_; + if( currLevel > exeUtilTdb().maxDeep_ ) + { + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8038); + + step_ = ERROR_; + } + else + step_ = DO_CONNECT_BY_; } break; case NEXT_ROOT_: @@ -637,7 +665,15 @@ short ExExeUtilConnectbyTcb::work() if (qparent_.up->isFull()) return WORK_OK; - step_ = INITIAL_; + step_ = INITIAL_; +#if 1 + retcode = handleDone(); + if (retcode == 1) + return WORK_OK; + + step_ = INITIAL_; +#endif +#if 0 // Return EOF. up_entry = qparent_.up->getTailEntry(); up_entry->upState.parentIndex = @@ -655,11 +691,13 @@ short ExExeUtilConnectbyTcb::work() for(int i = 0; i< currRootId ; i++) { currQueue = getCurrQueue( i, seedQueue); - releaseCurrentQueue(currQueue, getHeap()); + //releaseCurrentQueue(currQueue, getHeap()); NADELETE(currQueue, Queue, getHeap()); } NADELETE(seedQueue, Queue, getHeap()); +#endif return WORK_OK; + break; } } diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 3c07359643..6ed604ba19 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5333,14 +5333,7 @@ short ExeUtilOrcFastAggr::codeGen(Generator * generator) const char * ExeUtilConnectby::getVirtualTableName() { - //Scan * scanNode = (Scan *)scan_; -// Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); -// NAString tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); -// NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); -// return tbl.data(); - //NAString returnNm = "_CONNNEC_BY_"+myTableName_; return myTableName_.data(); - } TrafDesc *ExeUtilConnectby::createVirtualTableDesc() @@ -5349,12 +5342,11 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() NAString cat; NAString sch; NAString tbl; - Scan * scanNode = (Scan *)scan_; - //Scan * scanNode = (Scan *)(child(0)->castToRelExpr()); - cat= "TRAFODION"; //(scanNode->getTableName()).getQualifiedNameObj().getCatalogName(); - sch= "SEABASE"; //(scanNode->getTableName()).getQualifiedNameObj().getSchemaName(); + Scan * scanNode = (Scan*)scan_; + cat= (scanNode->getTableName()).getQualifiedNameObj().getCatalogName(); + sch= (scanNode->getTableName()).getQualifiedNameObj().getSchemaName(); tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); - NAString tableName = (scanNode->getTableName()).getQualifiedNameAsString(); + tblDesc_ = cmpSBD.getSeabaseTableDesc(cat,sch,tbl,COM_BASE_TABLE_OBJECT); //rename TrafTableDesc * td = tblDesc_->tableDesc(); @@ -5511,23 +5503,11 @@ short ExeUtilConnectby::codeGen(Generator * generator) char *tblnm = (char*)getTableName().getQualifiedNameObj().getObjectName().data(); ex_expr * selectPred = NULL; -#if 0 - ExpTupleDesc * asciiTupleDesc = 0; - expGen->processValIdList( - getVirtualTableDesc()->getColumnList(), // [IN] ValueIdList - tupleFormat, // [IN] tuple data format - tupleLength, // [OUT] tuple length - work_atp, // [IN] atp number - outputAtpIndex, // [IN] index into atp - &asciiTupleDesc, // [optional OUT] tuple desc - ExpTupleDesc::LONG_FORMAT // [optional IN] desc format - ); -#endif - if (!selectionPred().isEmpty()) + if (!mypredicates_.isEmpty()) { ItemExpr * selPredTree = - selectionPred().rebuildExprTree(ITM_AND,TRUE,TRUE); + mypredicates_.rebuildExprTree(ITM_AND,TRUE,TRUE); expGen->generateExpr(selPredTree->getValueId(), ex_expr::exp_SCAN_PRED, &selectPred); @@ -5537,7 +5517,7 @@ short ExeUtilConnectby::codeGen(Generator * generator) ComTdbExeUtilConnectby (stmtText , (stmtText ? strlen(stmtText) : 0), getStmtTextCharSet(), tblnm , NULL, 0 , 0, 0 , 0, - selectPred, //This is the output expression, used in parent to apply on the output + selectPred, workCriDesc , outputAtpIndex, colDescSize, tupleLength, diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index ccc8acc30b..6d324bbcf3 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6191,8 +6191,6 @@ RelExpr * ExeUtilConnectby::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap) result->childColName_ = childColName_; result->startWithExprString_ = startWithExprString_; result->noCycle_ = noCycle_; - result->myselection_= myselection_; - result->mypredicates_= mypredicates_; return ExeUtilExpr::copyTopNode(result, outHeap); } @@ -6205,7 +6203,14 @@ RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) RelExpr * boundExpr = NULL; bindChildren(bindWA); + scan_->bindNode(bindWA); boundExpr = ExeUtilExpr::bindNode(bindWA); + + if( myselection_ ) + { + myselection_->bindNode(bindWA); + myselection_->convertToValueIdSet(mypredicates_, bindWA, ITM_AND); + } if (bindWA->errStatus()) return NULL; diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 8b6f154c47..106f89092c 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1093,7 +1093,6 @@ class ExeUtilConnectby : public ExeUtilExpr { hasStartWith_ = TRUE; noCycle_ = FALSE; - myselection_ = NULL; scan_ = scan; } virtual const NAString getText() const; @@ -1111,7 +1110,7 @@ class ExeUtilConnectby : public ExeUtilExpr virtual TrafDesc * createVirtualTableDesc(); virtual const char * getVirtualTableName(); -#if 1 +#if 0 virtual void pushdownCoveredExpr(const ValueIdSet & outputExprOnOperator, const ValueIdSet & newExternalInputs, @@ -1141,11 +1140,12 @@ class ExeUtilConnectby : public ExeUtilExpr NAString startWithExprString_; NABoolean hasStartWith_; NABoolean noCycle_; - ItemExpr * myselection_; // generated by the parser - ValueIdSet mypredicates_; // predicates represented as a set RelExpr * scan_; NAString myTableName_; + ItemExpr * myselection_; + ValueIdSet mypredicates_; + private: //connect by //start with diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 023dce549d..f2e3072918 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -2130,8 +2130,6 @@ static void enableMakeQuotedStringISO88591Mechanism() %type rel_subquery %type row_subquery %type predicate -//%type connect_by -//%type startwith %type dml_column_reference %type null_predicate %type scan_key_hint @@ -13777,6 +13775,7 @@ set_quantifier : { $$ = FALSE; /* by default, set quantifier is ALL */ query_spec_body : query_select_list table_expression access_type optional_lock_mode { if( ! ((Scan *)$2)->hasConnectBy()) { + // use a compute node to attach select list RelRoot *temp= new (PARSERHEAP()) RelRoot($2, $3, $4, REL_ROOT, $1); @@ -13825,11 +13824,12 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ } euc->noCycle_ = ((Scan*)$2)->getBiConnectBy()->getNoCycle(); euc->scan_ = $2; - euc->myTableName_ = "_CONN_"+((Scan*)$2)->getTableName().getQualifiedNameAsString(); + euc->myselection_ = ((Scan*)$2)->getBiConnectBy()->where_clause ; + euc->myTableName_ = "_CONNECTBY_"+((Scan*)$2)->getTableName().getQualifiedNameAsString(); euc->parentColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getParentColName(); euc->childColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getChildColName(); - euc->addSelPredTree( ((Scan*)$2)->getBiConnectBy()->where_clause ); + //euc->addSelPredTree( ((Scan*)$2)->getBiConnectBy()->where_clause ); $$ = temp; } diff --git a/core/sql/sqlcomp/DefaultConstants.h b/core/sql/sqlcomp/DefaultConstants.h index b2b2bb9bef..58213ec6d4 100644 --- a/core/sql/sqlcomp/DefaultConstants.h +++ b/core/sql/sqlcomp/DefaultConstants.h @@ -165,7 +165,6 @@ enum DefaultConstants DP2_CACHE_4096_BLOCKS, - // Constants needed to estimate the cost of communication // between DP2 and exeInDp2: CPUCOST_SCAN_KEY_LENGTH, // key encoding/decoding @@ -3324,6 +3323,9 @@ enum DefaultConstants // both compressed and uncompressed hdfs files HDFS_IO_INTERIM_BYTEARRAY_SIZE_IN_KB, + CONNECTBY_MAX_DEEP, + CONNECTBY_MAX_SIZE, + __NUM_DEFAULT_ATTRIBUTES }; diff --git a/core/sql/sqlcomp/nadefaults.cpp b/core/sql/sqlcomp/nadefaults.cpp index 7e5cfa113c..044cd9d454 100644 --- a/core/sql/sqlcomp/nadefaults.cpp +++ b/core/sql/sqlcomp/nadefaults.cpp @@ -879,6 +879,9 @@ SDDkwd__(CAT_ENABLE_QUERY_INVALIDATION, "ON"), DD_____(COMP_STRING_5, ""), + DDint__(CONNECTBY_MAX_DEEP, "200"), + DDint__(CONNECTBY_MAX_SIZE, "100000"), + DDkwd__(CONSTANT_FOLDING, "OFF"), DDkwd__(COSTING_SHORTCUT_GROUPBY_FIX, "ON"), From f20b63c875f3a56ba3da1a83c2f1e0f255b29b71 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Fri, 27 Jul 2018 12:03:44 +0000 Subject: [PATCH 07/17] support both where clause and order by, next add test cases --- core/sql/executor/ExExeUtilCommon.cpp | 1 + core/sql/executor/ExExeUtilConnectby.cpp | 156 +++-------------------- core/sql/exp/ExpAtp.h | 2 + core/sql/generator/GenRelExeUtil.cpp | 17 ++- core/sql/optimizer/RelExeUtil.cpp | 2 +- core/sql/optimizer/RelExeUtil.h | 2 +- core/sql/parser/sqlparser.y | 4 +- 7 files changed, 34 insertions(+), 150 deletions(-) diff --git a/core/sql/executor/ExExeUtilCommon.cpp b/core/sql/executor/ExExeUtilCommon.cpp index b623ee3d8e..e644baffc9 100644 --- a/core/sql/executor/ExExeUtilCommon.cpp +++ b/core/sql/executor/ExExeUtilCommon.cpp @@ -158,6 +158,7 @@ ExExeUtilTcb::ExExeUtilTcb(const ComTdbExeUtil & exe_util_tdb, if (exe_util_tdb.workCriDesc_) { +printf("LMDBG1: it is at %p, no is %d, index at %d\n", (void *)exe_util_tdb.workCriDesc_, exe_util_tdb.workCriDesc_->noTuples(),((ComTdbExeUtil&)exe_util_tdb).workAtpIndex() ); workAtp_ = allocateAtp(exe_util_tdb.workCriDesc_, glob->getSpace()); pool_->get_free_tuple(workAtp_->getTupp(((ComTdbExeUtil&)exe_util_tdb).workAtpIndex()), 0); } diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index ec66854f69..7a00fb01b2 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -102,11 +102,9 @@ ExExeUtilConnectbyTcb::ExExeUtilConnectbyTcb( qparent_.down->allocatePstate(this); pool_->get_free_tuple(tuppData_, exe_util_tdb.tupleLen_); data_ = tuppData_.getDataPointer(); -// workAtp_ = allocateAtp(exe_util_tdb.workCriDesc_, glob->getSpace()); - -// pool_->get_free_tuple(workAtp_->getTupp(1), 0); -// pool_->get_free_tuple(workAtp_->getTupp(2), 0); + //pool_->get_free_tuple(workAtp_->getTupp(2), 0); + //pool_->get_free_tuple(workAtp_->getTupp(3), 0); } ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( @@ -117,105 +115,7 @@ ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( return pa.allocatePstates(this, numElems, pstateLength); } -#if 0 -short ExExeUtilConnectbyTcb::emitRows(Queue *q, ExpTupleDesc * tDesc) -{ - short retcode = 0, rc =0; - char * ptr; - Lng32 len; - - q->position(); -#if 1 - for (Lng32 idx = 0; idx < q->numEntries(); idx++) - { - OutputInfo * vi = (OutputInfo*)q->getNext(); - - if (vi == NULL) break; - for (UInt32 i = 1; i < tDesc->numAttrs() ; i++) - { - // OutputInfo * vi = (OutputInfo*)q->getNext(); - - char * src = (char*)vi->get(i); - Attributes * attr = tDesc->getAttr(i); - short srcType; - Lng32 srcLen; - short valIsNull = 0; - if(attr->getDatatype() < REC_MAX_CHARACTER) - srcType = REC_BYTE_F_ASCII; - else - srcType = attr->getDatatype(); - srcLen = attr->getLength(); - if(src == NULL) valIsNull = 1; -#if 1 - if (attr->getNullFlag()) - { - // target is nullable - if (attr->getNullIndicatorLength() == 2) - { - // set the 2 byte NULL indicator to -1 - *(short *) (&data_[attr->getNullIndOffset()]) = - valIsNull; - } - else - { - ex_assert(attr->getNullIndicatorLength() == 4, - "NULL indicator must be 2 or 4 bytes"); - *(Lng32 *) (&data_[attr->getNullIndOffset()]) = - valIsNull; - } - } - else - ex_assert(!valIsNull, - "NULL source for NOT NULL stats column"); -#endif - if (!valIsNull) - { - -#if 1 - if ( - ::convDoIt(src, srcLen, srcType, 0, 0, - &data_[attr->getOffset()], - attr->getLength(), - attr->getDatatype(),0,0, - 0, 0, NULL) != ex_expr::EXPR_OK) - { - ex_assert( - 0, - "Error from ExStatsTcb::work::convDoIt."); - } -#endif - } - } -#endif - - retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); - } - - return retcode; -} -short ExExeUtilConnectbyTcb::emitOneRow(ExpTupleDesc * tDesc, int level) -{ - short retcode = 0, rc = 0; - char * ptr; - Lng32 len; - ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_OK; - UInt32 rowLen = exeUtilTdb().outputRowlen_; //TODO - ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); - - cliInterface()->getPtrAndLen(1, ptr, len); //start from second column - //setup ATP - workAtp_->getTupp(exeUtilTdb().sourceDataTuppIndex_) - .setDataPointer(data_); - workAtp_->getTupp(2) - .setDataPointer(ptr); - - evalRetCode = (exeUtilTdb().outputExpr())->eval(pentry_down->getAtp(), workAtp_, NULL, - exeUtilTdb().tupleLen_, &rowLen); - retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); - return retcode; -} -#endif short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle) { short retcode = 0, rc =0; @@ -280,7 +180,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf } } -#if 1 + short srcType = REC_BIN32_UNSIGNED; Lng32 srcLen = 4; int src = isleaf; @@ -310,26 +210,18 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf 0, "Error from ExStatsTcb::work::convDoIt."); } -#endif //apply the expression -#if 0 - ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_OK; - UInt32 rowLen = exeUtilTdb().outputRowlen_; //TODO - ex_queue_entry * pentry_down = qparent_.down->getHeadEntry(); - - //setup ATP - workAtp_->getTupp(exeUtilTdb().workAtpIndex()) - .setDataPointer(data_); - - evalRetCode = (exeUtilTdb().scanExpr_)->eval(pentry_down->getAtp(), workAtp_, NULL, - exeUtilTdb().tupleLen_, &rowLen); -#endif -#if 1 ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_TRUE; if(exeUtilTdb().scanExpr_ ) - evalRetCode = evalScanExpr((char*)data_, exeUtilTdb().tupleLen_, FALSE); -#endif + { + //evalRetCode = evalScanExpr((char*)data_, exeUtilTdb().tupleLen_, FALSE); + + workAtp_->getTupp(exeUtilTdb().workAtpIndex()) + .setDataPointer((char*)data_); + evalRetCode = + exeUtilTdb().scanExpr_->eval(workAtp_, NULL); + } if (evalRetCode == ex_expr::EXPR_TRUE) retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); @@ -665,37 +557,21 @@ short ExExeUtilConnectbyTcb::work() if (qparent_.up->isFull()) return WORK_OK; - step_ = INITIAL_; -#if 1 - retcode = handleDone(); - if (retcode == 1) + retcode = handleDone(); + if (retcode == 1) return WORK_OK; - step_ = INITIAL_; -#endif -#if 0 - // Return EOF. - up_entry = qparent_.up->getTailEntry(); - up_entry->upState.parentIndex = - pentry_down->downState.parentIndex; - - up_entry->upState.setMatchNo(matchRowNum); - up_entry->upState.status = ex_queue::Q_NO_DATA; - - // insert into parent - qparent_.up->insert(); - - qparent_.down->removeHead(); + step_ = INITIAL_; //release the currentQueue for(int i = 0; i< currRootId ; i++) { currQueue = getCurrQueue( i, seedQueue); - //releaseCurrentQueue(currQueue, getHeap()); + releaseCurrentQueue(currQueue, getHeap()); NADELETE(currQueue, Queue, getHeap()); } NADELETE(seedQueue, Queue, getHeap()); -#endif + return WORK_OK; break; diff --git a/core/sql/exp/ExpAtp.h b/core/sql/exp/ExpAtp.h index 2e35ee49ae..ca6bd7e14c 100644 --- a/core/sql/exp/ExpAtp.h +++ b/core/sql/exp/ExpAtp.h @@ -170,6 +170,8 @@ inline ex_cri_desc * atp_struct::getCriDesc() const inline tupp & atp_struct::getTupp(Lng32 i) { #ifdef _DEBUG + if( i >= criDesc_->noTuples()) +printf("LMDBG it is %d\n", criDesc_->noTuples() ); assert(i < criDesc_->noTuples()); #endif return tuppArray_[i]; diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 6ed604ba19..8c7b325525 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5461,8 +5461,9 @@ short ExeUtilConnectby::codeGen(Generator * generator) ex_cri_desc * returnedDesc = new(space) ex_cri_desc(givenDesc->noTuples() + 1, space); ex_cri_desc * workCriDesc = new(space) ex_cri_desc(4, space); - const Int32 work_atp = 1; - const Int32 outputAtpIndex = 2; + const Int32 work_atp = 0; + Int32 theAtpIndex = returnedDesc->noTuples()-1; + const Int32 outputAtpIndex =theAtpIndex; Attributes ** attrs = new(generator->wHeap()) @@ -5492,10 +5493,6 @@ short ExeUtilConnectby::codeGen(Generator * generator) // add this descriptor to the work cri descriptor. workCriDesc->setTupleDescriptor(outputAtpIndex , tupleDesc); - Int32 theAtpIndex = returnedDesc->noTuples()-1; - expGen->assignAtpAndAtpIndex(getVirtualTableDesc()->getColumnList(), - work_atp, outputAtpIndex); - TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; Lng32 colDescSize = column_desc->columnsDesc()->length; @@ -5505,14 +5502,22 @@ short ExeUtilConnectby::codeGen(Generator * generator) ex_expr * selectPred = NULL; if (!mypredicates_.isEmpty()) + //if(NOT selectionPred().isEmpty()) { ItemExpr * selPredTree = mypredicates_.rebuildExprTree(ITM_AND,TRUE,TRUE); + //selectionPred().rebuildExprTree(ITM_AND,TRUE,TRUE); expGen->generateExpr(selPredTree->getValueId(), ex_expr::exp_SCAN_PRED, &selectPred); + + + expGen->assignAtpAndAtpIndex(getVirtualTableDesc()->getColumnList(), + 0, theAtpIndex); + } + ComTdbExeUtilConnectby * exe_util_tdb = new(space) ComTdbExeUtilConnectby (stmtText , (stmtText ? strlen(stmtText) : 0), getStmtTextCharSet(), tblnm , NULL, 0 , 0, diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index 6d324bbcf3..35b72bfdcc 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6205,7 +6205,7 @@ RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) scan_->bindNode(bindWA); boundExpr = ExeUtilExpr::bindNode(bindWA); - + if( myselection_ ) { myselection_->bindNode(bindWA); diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 106f89092c..60dadf852d 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1110,7 +1110,7 @@ class ExeUtilConnectby : public ExeUtilExpr virtual TrafDesc * createVirtualTableDesc(); virtual const char * getVirtualTableName(); -#if 0 +#if 1 virtual void pushdownCoveredExpr(const ValueIdSet & outputExprOnOperator, const ValueIdSet & newExternalInputs, diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index f2e3072918..06df0e3e7d 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -2085,7 +2085,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %type table_value_constructor %type table_expression %type from_clause -%type startwith_clause +%type startwith_clause %type join_specification %type join_condition %type where_clause @@ -13808,7 +13808,7 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ ExeUtilConnectby *euc = new (PARSERHEAP()) ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), (char*) stmt->data(), - stmtCharSet, NULL, PARSERHEAP()); + stmtCharSet, $2, PARSERHEAP()); RelRoot *temp = new (PARSERHEAP()) RelRoot(euc, REL_ROOT , $1); From 5757f25e9c2fa91b25751e24f28b04fbf903df4e Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sat, 28 Jul 2018 02:54:56 +0000 Subject: [PATCH 08/17] add test case, next to rebase and try to support is_cycle --- core/sql/executor/ExExeUtilCommon.cpp | 1 - core/sql/exp/ExpAtp.h | 2 - core/sql/regress/executor/EXPECTED021.SB | 147 ++++++++++++++++++++ core/sql/regress/executor/TEST021 | 82 +++++++++++ core/sql/regress/tools/runregr_executor.ksh | 2 +- 5 files changed, 230 insertions(+), 4 deletions(-) create mode 100644 core/sql/regress/executor/EXPECTED021.SB create mode 100644 core/sql/regress/executor/TEST021 diff --git a/core/sql/executor/ExExeUtilCommon.cpp b/core/sql/executor/ExExeUtilCommon.cpp index e644baffc9..b623ee3d8e 100644 --- a/core/sql/executor/ExExeUtilCommon.cpp +++ b/core/sql/executor/ExExeUtilCommon.cpp @@ -158,7 +158,6 @@ ExExeUtilTcb::ExExeUtilTcb(const ComTdbExeUtil & exe_util_tdb, if (exe_util_tdb.workCriDesc_) { -printf("LMDBG1: it is at %p, no is %d, index at %d\n", (void *)exe_util_tdb.workCriDesc_, exe_util_tdb.workCriDesc_->noTuples(),((ComTdbExeUtil&)exe_util_tdb).workAtpIndex() ); workAtp_ = allocateAtp(exe_util_tdb.workCriDesc_, glob->getSpace()); pool_->get_free_tuple(workAtp_->getTupp(((ComTdbExeUtil&)exe_util_tdb).workAtpIndex()), 0); } diff --git a/core/sql/exp/ExpAtp.h b/core/sql/exp/ExpAtp.h index ca6bd7e14c..2e35ee49ae 100644 --- a/core/sql/exp/ExpAtp.h +++ b/core/sql/exp/ExpAtp.h @@ -170,8 +170,6 @@ inline ex_cri_desc * atp_struct::getCriDesc() const inline tupp & atp_struct::getTupp(Lng32 i) { #ifdef _DEBUG - if( i >= criDesc_->noTuples()) -printf("LMDBG it is %d\n", criDesc_->noTuples() ); assert(i < criDesc_->noTuples()); #endif return tuppArray_[i]; diff --git a/core/sql/regress/executor/EXPECTED021.SB b/core/sql/regress/executor/EXPECTED021.SB new file mode 100644 index 0000000000..27cb668dce --- /dev/null +++ b/core/sql/regress/executor/EXPECTED021.SB @@ -0,0 +1,147 @@ +>>obey TEST021(testcases); +>> +>>-- TEST 1 +>>create table t021t1 ++>( ++> depid int, ++> depname varchar(64), ++> upperdepid int ++>); + +--- SQL operation complete. +>> +>>log log021; +>>insert into t021t1 values ( 1, 'world', null); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 2, 'china', 1); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 3, 'US', 1); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 4, 'UK', 1); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 5, 'ShangHai', 2); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 6, 'NY', 3); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 7, 'London', 4); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 8, 'ChangNing', 5); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 9, 'JingAn', 5); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 10, 'D1', 7); + +--- 1 row(s) inserted. +>> +>>insert into t021t1 values ( 11, 'LoopRoot', 15); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 12, 'L1', 11); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 13, 'L2', 12); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 14, 'L3', 13); + +--- 1 row(s) inserted. +>>insert into t021t1 values ( 15, 'L4', 12); + +--- 1 row(s) inserted. +>> +>>SELECT *, "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID; + +DEPID DEPNAME UPPERDEPID LEVEL +----------- ---------------------------------------------------------------- ----------- ---------- + + 1 world ? 0 + 2 china 1 1 + 3 US 1 1 + 4 UK 1 1 + 5 ShangHai 2 2 + 6 NY 3 2 + 7 London 4 2 + 8 ChangNing 5 3 + 9 JingAn 5 3 + 10 D1 7 3 + +--- 10 row(s) selected. +>> +>>--loop test +>>SELECT * FROM t021t1 START WITH depid = 11 CONNECT BY PRIOR DEPID = UPPERDEPID; + +DEPID DEPNAME UPPERDEPID +----------- ---------------------------------------------------------------- ----------- + + 11 LoopRoot 15 + 12 L1 11 + 13 L2 12 + 15 L4 12 + 14 L3 13 + +*** ERROR[8037] Loop detected in connect by execution. + +--- 5 row(s) selected. +>> +>>--nocycle test +>>SELECT * , "CONNECT_BY_ISCYCLE" FROM t021t1 START WITH depid = 11 CONNECT BY NOCYCLE PRIOR DEPID = UPPERDEPID; + +DEPID DEPNAME UPPERDEPID CONNECT_BY_ISCYCLE +----------- ---------------------------------------------------------------- ----------- ------------------ + + 11 LoopRoot 15 0 + 12 L1 11 0 + 13 L2 12 0 + 15 L4 12 0 + 11 LoopRoot 15 1 + 14 L3 13 0 + +--- 6 row(s) selected. +>> +>>SELECT * , "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where depid = 7; + +DEPID DEPNAME UPPERDEPID LEVEL +----------- ---------------------------------------------------------------- ----------- ---------- + + 7 London 4 2 + +--- 1 row(s) selected. +>> +>>SELECT * , "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where "LEVEL" > 2 ; + +DEPID DEPNAME UPPERDEPID LEVEL +----------- ---------------------------------------------------------------- ----------- ---------- + + 8 ChangNing 5 3 + 9 JingAn 5 3 + 10 D1 7 3 + +--- 3 row(s) selected. +>> +>>SELECT * FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID order by 2; + +DEPID DEPNAME UPPERDEPID +----------- ---------------------------------------------------------------- ----------- + + 8 ChangNing 5 + 10 D1 7 + 9 JingAn 5 + 7 London 4 + 6 NY 3 + 5 ShangHai 2 + 4 UK 1 + 3 US 1 + 2 china 1 + 1 world ? + +--- 10 row(s) selected. +>>log; diff --git a/core/sql/regress/executor/TEST021 b/core/sql/regress/executor/TEST021 new file mode 100644 index 0000000000..fb6872847e --- /dev/null +++ b/core/sql/regress/executor/TEST021 @@ -0,0 +1,82 @@ +-- Test: TEST020 (Executor) +-- @@@ START COPYRIGHT @@@ +-- +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. +-- +-- @@@ END COPYRIGHT @@@ +-- +-- Functionality: Hierachy Query (Connect By) feature +-- Expected files: EXPECTED021 +-- Table created: t021t1 +-- Limitations: +-- Revision history: + +obey TEST021(clnup); +log log021 clear; +obey TEST021(testcases); +obey TEST021(clnup); +log; +exit; + +?section clnup +drop table t021t1 cascade; + + +?section testcases + +-- TEST 1 +create table t021t1 +( + depid int, + depname varchar(64), + upperdepid int +); + +log log021; +insert into t021t1 values ( 1, 'world', null); +insert into t021t1 values ( 2, 'china', 1); +insert into t021t1 values ( 3, 'US', 1); +insert into t021t1 values ( 4, 'UK', 1); +insert into t021t1 values ( 5, 'ShangHai', 2); +insert into t021t1 values ( 6, 'NY', 3); +insert into t021t1 values ( 7, 'London', 4); +insert into t021t1 values ( 8, 'ChangNing', 5); +insert into t021t1 values ( 9, 'JingAn', 5); +insert into t021t1 values ( 10, 'D1', 7); + +insert into t021t1 values ( 11, 'LoopRoot', 15); +insert into t021t1 values ( 12, 'L1', 11); +insert into t021t1 values ( 13, 'L2', 12); +insert into t021t1 values ( 14, 'L3', 13); +insert into t021t1 values ( 15, 'L4', 12); + +SELECT *, "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID; + +--loop test +SELECT * FROM t021t1 START WITH depid = 11 CONNECT BY PRIOR DEPID = UPPERDEPID; + +--nocycle test +SELECT * , "CONNECT_BY_ISCYCLE" FROM t021t1 START WITH depid = 11 CONNECT BY NOCYCLE PRIOR DEPID = UPPERDEPID; + +SELECT * , "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where depid = 7; + +SELECT * , "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where "LEVEL" > 2 ; + +SELECT * FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID order by 2; +log; + diff --git a/core/sql/regress/tools/runregr_executor.ksh b/core/sql/regress/tools/runregr_executor.ksh index c32097a53b..0bfd3d7986 100755 --- a/core/sql/regress/tools/runregr_executor.ksh +++ b/core/sql/regress/tools/runregr_executor.ksh @@ -237,7 +237,7 @@ skippedfiles= # sbtestfiles contains the list of tests to be run in seabase mode if [ "$seabase" -ne 0 ]; then - sbtestfiles="TEST001 TEST002 TEST012 TEST013 TEST014 TEST015 TEST016 TEST020 TEST022 TEST025 TEST050 TEST063 TEST088 TEST101 TEST106 TEST107 TEST122 TEST130 TEST131 TEST140" + sbtestfiles="TEST001 TEST002 TEST012 TEST013 TEST014 TEST015 TEST016 TEST020 TEST021 TEST022 TEST025 TEST050 TEST063 TEST088 TEST101 TEST106 TEST107 TEST122 TEST130 TEST131 TEST140" sbprettyfiles= for i in $prettyfiles; do for j in $sbtestfiles; do From 1b32b6b27b7ba4686b174c41a349f320807221fe Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sat, 4 Aug 2018 10:44:33 +0000 Subject: [PATCH 09/17] support PATH, next try to support is leaf --- core/sql/comexe/ComTdbExeUtil.cpp | 1 + core/sql/comexe/ComTdbExeUtil.h | 3 + core/sql/common/OperTypeEnum.h | 2 + core/sql/executor/ExExeUtil.h | 36 +++- core/sql/executor/ExExeUtilConnectby.cpp | 260 +++++++++++++++-------- core/sql/generator/GenRelExeUtil.cpp | 44 +++- core/sql/optimizer/BindItemExpr.cpp | 11 +- core/sql/optimizer/ItemExpr.cpp | 11 + core/sql/optimizer/ItemFunc.h | 27 +++ core/sql/optimizer/RelExeUtil.cpp | 2 + core/sql/optimizer/RelExeUtil.h | 40 +++- core/sql/optimizer/SynthType.cpp | 8 + core/sql/parser/ParKeyWords.cpp | 1 + core/sql/parser/sqlparser.y | 28 ++- 14 files changed, 375 insertions(+), 99 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.cpp b/core/sql/comexe/ComTdbExeUtil.cpp index d430e3f997..ba9d59dbee 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -3069,6 +3069,7 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, connTableName_ = tableName; maxDeep_ = 200; //by default, max deep of a tree maxSize_ = 100000; //by default, the max number of rows to return for hierachy query + hasPath_ = FALSE; } Long ComTdbExeUtilConnectby::pack(void * space) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index 44ebb6b178..3e093b660e 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -4052,6 +4052,9 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil NABoolean noCycle_; Int32 maxDeep_; Int32 maxSize_; + NABoolean hasPath_; + NAString pathColName_; + NAString delimiter_; private: ExCriDescPtr myWorkCriDesc_; Int32 flags_; diff --git a/core/sql/common/OperTypeEnum.h b/core/sql/common/OperTypeEnum.h index 93f817070c..29bd91bbe4 100644 --- a/core/sql/common/OperTypeEnum.h +++ b/core/sql/common/OperTypeEnum.h @@ -812,6 +812,8 @@ enum OperatorTypeEnum { ITM_AES_ENCRYPT = 2641, ITM_AES_DECRYPT = 2642, + ITM_SYS_CONNECT_BY_PATH = 2643, + // Items for needed for Translating to UCS2 output strings ITM_DATEFMT = 2990, ITM_CURRNT_USER = 2991, diff --git a/core/sql/executor/ExExeUtil.h b/core/sql/executor/ExExeUtil.h index 241a053aff..2c91bad0e1 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4173,6 +4173,29 @@ class ExExeUtilLobInfoPrivateState : public ex_tcb_private_state protected: }; +class connectByStackItem +{ +public: + connectByStackItem() + { + seedValue = NULL; + pathItem = NULL; + pathLen = 0; + len = 0; + level = 0; + type = 0; + parentId = 0; + } + ~connectByStackItem() {} + char * seedValue; + char * pathItem; + int len; + int level; + int type; + int pathLen; + int parentId; +}; + //////////////////////////////////////////////////////////////////////////// class ExExeUtilLobInfoTablePrivateState : public ex_tcb_private_state { @@ -4215,7 +4238,18 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb ExExeUtilConnectbyTdb& exeUtilTdb() const {return (ExExeUtilConnectbyTdb&) tdb;}; - short emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle) ; + short emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle, connectByStackItem *it) ; + + Queue *currArray[200]; + Queue * getCurrentQueue(int level) { if(level <0 || level >200) abort(); return currArray[level];} + short checkDuplicate(connectByStackItem *it,int len, int level); + int currLevel_; + Int64 resultSize_; + Queue *currQueue_; + Queue *seedQueue_; + Queue *thisQueue_; + Int32 currRootId_; + Int32 connBatchSize_ ; protected: ExExeUtilConnectbyTcb *tcb_; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 7a00fb01b2..4e0c2e9e24 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -70,18 +70,6 @@ using std::ofstream; #include "ExpErrorEnums.h" #include "HdfsClient_JNI.h" - -class connectByStackItem -{ -public: - connectByStackItem() {} - ~connectByStackItem() {} - char * seedValue; - int len; - int level; - int type; -}; - class rootItem { public: @@ -102,9 +90,16 @@ ExExeUtilConnectbyTcb::ExExeUtilConnectbyTcb( qparent_.down->allocatePstate(this); pool_->get_free_tuple(tuppData_, exe_util_tdb.tupleLen_); data_ = tuppData_.getDataPointer(); - - //pool_->get_free_tuple(workAtp_->getTupp(2), 0); - //pool_->get_free_tuple(workAtp_->getTupp(3), 0); + currLevel_ = 0; + resultSize_ = 0; + currQueue_ = new(getHeap()) Queue(getHeap()) ; + thisQueue_ = NULL; + connBatchSize_ = 50; + seedQueue_ = new(getHeap()) Queue(getHeap()) ; + for( int i = 0; i< 200; i++) + { + currArray[i] = NULL; + } } ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( @@ -116,7 +111,7 @@ ex_tcb_private_state * ExExeUtilConnectbyTcb::allocatePstates( return pa.allocatePstates(this, numElems, pstateLength); } -short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle) +short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle, connectByStackItem *vi ) { short retcode = 0, rc =0; char * ptr; @@ -124,12 +119,13 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf short nullInd = 0; short *ind ; ind = &nullInd; + UInt32 vcActualLen = 0; - for (UInt32 i = 1; i < tDesc->numAttrs() - 2 ; i++) + for (UInt32 i = 2; i < tDesc->numAttrs() - 2 ; i++) { cliInterface()->getPtrAndLen(i+1, ptr, len,&ind); char * src = ptr; - Attributes * attr = tDesc->getAttr(i); + Attributes * attr = tDesc->getAttr(i-1); short srcType = 0; Lng32 srcLen; short valIsNull = 0; @@ -157,7 +153,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf else ex_assert(!valIsNull, "NULL source for NOT NULL stats column"); - UInt32 vcActualLen = 0; + if (!valIsNull) { @@ -184,7 +180,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf short srcType = REC_BIN32_UNSIGNED; Lng32 srcLen = 4; int src = isleaf; - Attributes * attr = tDesc->getAttr(tDesc->numAttrs() - 1); + Attributes * attr = tDesc->getAttr(tDesc->numAttrs() - 2); if ( ::convDoIt((char*)&src, srcLen, srcType, 0, 0, &data_[attr->getOffset()], @@ -198,7 +194,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf } src = iscycle; - attr = tDesc->getAttr(tDesc->numAttrs() - 2); + attr = tDesc->getAttr(tDesc->numAttrs() - 3); if ( ::convDoIt((char*)&src, srcLen, srcType, 0, 0, &data_[attr->getOffset()], @@ -216,15 +212,62 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf if(exeUtilTdb().scanExpr_ ) { //evalRetCode = evalScanExpr((char*)data_, exeUtilTdb().tupleLen_, FALSE); - - workAtp_->getTupp(exeUtilTdb().workAtpIndex()) + workAtp_->getTupp(exeUtilTdb().workAtpIndex()) .setDataPointer((char*)data_); - evalRetCode = + evalRetCode = exeUtilTdb().scanExpr_->eval(workAtp_, NULL); } + if (evalRetCode == ex_expr::EXPR_TRUE) - retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); +{ +#if 1 + char pathBuf[3000]; + memset(pathBuf, 0, 3000); + char tmpbuf1[256]; + int pathlength = 0; + int dlen = strlen(exeUtilTdb().delimiter_.data()); + Queue *pathq = new(getHeap()) Queue(getHeap()) ;; + if (exeUtilTdb().hasPath_ == TRUE) { + pathq->insert(vi->pathItem); + pathlength = vi->pathLen; + for(int ii = level ; ii > 0; ii--) + { + Queue *tq = getCurrentQueue(ii-1); + connectByStackItem * p = (connectByStackItem*)tq->get(vi->parentId - 1); + if(p == NULL) abort(); + pathq->insert(p->pathItem); + pathlength += p->pathLen + dlen; + vi = p; + } + for(int pi = pathq->entries(); pi > 0; pi--) + { + if(pi-1 == 0) + sprintf(tmpbuf1,"%s",(char*)(pathq->get(pi-1))); + else + sprintf(tmpbuf1,"%s%s",(char*)(pathq->get(pi-1)) ,exeUtilTdb().delimiter_.data()); + strcat(pathBuf,tmpbuf1); + } + NADELETE(pathq, Queue, getHeap()); + } + attr = tDesc->getAttr(tDesc->numAttrs() - 1); + if ( + ::convDoIt(pathBuf, pathlength, REC_BYTE_V_ASCII, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + (char*) &vcActualLen, sizeof(vcActualLen), NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } + attr->setVarLength(vcActualLen,&data_[attr->getVCLenIndOffset()]); + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); + +#endif + +} return retcode; } @@ -234,9 +277,11 @@ void releaseCurrentQueue(Queue * q, CollHeap * h) { connectByStackItem *entry = (connectByStackItem *)q->get(i); NADELETEBASIC(entry->seedValue,h); + NADELETEBASIC(entry->pathItem,h); } } + short haveDupSeed(Queue * q , connectByStackItem *it, int len, int level) { @@ -254,6 +299,20 @@ short haveDupSeed(Queue * q , connectByStackItem *it, int len, int level) return 0; } +short ExExeUtilConnectbyTcb::checkDuplicate(connectByStackItem *it, int len, int level) +{ + short rc = 0; + for(int i = 0; i < level -1; i++) + { + Queue * q = currArray[i]; + if(q == NULL) continue; + rc = haveDupSeed( q, it, len, level); + if( rc == -1 || rc == 1) return rc; + } + return rc; +} + + Queue * getCurrQueue(int id, Queue *q) { for(int i = 0; i < q->numEntries(); i++) @@ -269,16 +328,13 @@ short ExExeUtilConnectbyTcb::work() short retcode = 0; char q1[2048]; //TODO: the max len of supported query len void* uppderid = NULL; - char * ptr; - Lng32 len; + char * ptr, *ptr1; + Lng32 len, len1; short rc; NAString nq11, nq21; memset(q1, 0, sizeof(q1)); int matchRowNum = 0; - int currLevel = 1; - int resultSize = 0; //the number q2 returned, 0 means reach the leaf - // if no parent request, return if (qparent_.down->isEmpty()) return WORK_OK; @@ -294,26 +350,26 @@ short ExExeUtilConnectbyTcb::work() if(exeUtilTdb().hasStartWith_ == TRUE) { - sprintf(q1,"SELECT %s , * , cast( 0 as INT) FROM %s WHERE %s ;" ,(exeUtilTdb().parentColName_).data() , (exeUtilTdb().connTableName_).data() ,(exeUtilTdb().startWithExprString_).data() ); + sprintf(q1,"SELECT %s , cast (%s as VARCHAR(3000) ), * , cast( 0 as INT) FROM %s WHERE %s ;" ,(exeUtilTdb().parentColName_).data() , (exeUtilTdb().pathColName_).data(), (exeUtilTdb().connTableName_).data() ,(exeUtilTdb().startWithExprString_).data() ); nq11 = q1; } else { - sprintf(q1,"SELECT %s , * , cast(0 as INT) FROM %s WHERE %s is null ;" ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().connTableName_).data(), (exeUtilTdb().childColName_).data()); + sprintf(q1,"SELECT %s , cast (%s as VARCHAR(3000) ) , * , cast(0 as INT) FROM %s WHERE %s is null ;" ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().pathColName_).data(), (exeUtilTdb().connTableName_).data(), (exeUtilTdb().childColName_).data()); nq11 = q1; } ExpTupleDesc * tDesc = exeUtilTdb().workCriDesc_->getTupleDescriptor( exeUtilTdb().sourceDataTuppIndex_); - Queue * seedQueue = new(getHeap()) Queue(getHeap()) ; - Queue * currQueue = NULL ; - Queue * tmpQueue = new(getHeap()) Queue(getHeap());; - tupp p; Lng32 fsDatatype = 0; Lng32 length = 0; Lng32 indOffset = 0; Lng32 varOffset = 0; - int currRootId = 0; + + if (exeUtilTdb().hasPath_ == TRUE) + { + connBatchSize_ = 1; + } while (1) { @@ -348,26 +404,35 @@ short ExExeUtilConnectbyTcb::work() cliInterface()->getAttributes(1, FALSE, fsDatatype, length, &indOffset, &varOffset); - currQueue = new(getHeap()) Queue(getHeap()) ; + Queue* cq = new(getHeap()) Queue(getHeap()) ; rootItem * ri= new(getHeap()) rootItem(); ri->rootId = rootId; rootId++; - ri->qptr = currQueue; - seedQueue->insert(ri); - - - char *tmp = new(getHeap()) char[len]; + ri->qptr = cq; + seedQueue_->insert(ri); //TO BE REMOVED + + char *tmp = new(getHeap()) char[len]; memcpy(tmp,ptr,len); it->seedValue = tmp; - it->level = currLevel; + it->level = currLevel_; it->type = fsDatatype; it->len = len; - if(haveDupSeed(currQueue, it, len, currLevel) == 0) { - emitRow(tDesc, currLevel, 0, 0); matchRowNum++; - currQueue->insert(it); + it->parentId = -1; + if (exeUtilTdb().hasPath_ == TRUE) + { + cliInterface()->getPtrAndLen(2, ptr1, len1); + char *tmp1 = new(getHeap()) char[len1]; + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + if(checkDuplicate( it, len, currLevel_) == 0) { + emitRow(tDesc, currLevel_, 0, 0, it); matchRowNum++; + currQueue_->insert(it); } } cliInterface()->fetchRowsEpilogue(0, FALSE); + currArray[0] = currQueue_; if( matchRowNum > exeUtilTdb().maxSize_ ) { @@ -382,33 +447,36 @@ short ExExeUtilConnectbyTcb::work() step_ = ERROR_; } else - step_ = DO_CONNECT_BY_; + step_ = NEXT_LEVEL_; } break; case DO_CONNECT_BY_: { - int seedNum = currQueue->numEntries(); + currQueue_ = getCurrentQueue(currLevel_ - 1); + thisQueue_ = getCurrentQueue(currLevel_); + int seedNum = currQueue_->numEntries(); int loopDetected = 0; - currQueue->position(); - resultSize = 0; + currQueue_->position(); + resultSize_ = 0; - for(int i=0; i< seedNum; i++) { + for(int i=0; i< seedNum; ) { - sprintf(q1,"SELECT %s , *, cast( %d as INT) FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), currLevel,(exeUtilTdb().connTableName_).data()); + sprintf(q1,"SELECT %s ,cast (%s as VARCHAR(3000) ) , *, cast( %d as INT) FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().pathColName_).data(), currLevel_,(exeUtilTdb().connTableName_).data() ); nq21 = q1; nq21.append((exeUtilTdb().childColName_).data()); nq21.append(" in ( "); int sybnum = 0; - for(int batchIdx = 0; batchIdx < 10 && i < seedNum; batchIdx ++) + for(int batchIdx = 0; batchIdx < connBatchSize_ && i < seedNum; ) { - connectByStackItem * vi = (connectByStackItem*)currQueue->get(i); + connectByStackItem * vi = (connectByStackItem*)currQueue_->get(i); int tmpLevel = vi->level; i++; - if( tmpLevel == currLevel) { + if( tmpLevel == currLevel_ - 1) { sybnum++; uppderid = ((connectByStackItem*)vi)->seedValue; + batchIdx++; char tmpbuf[128]; char tmpbuf1[128]; memset(tmpbuf,0,128); @@ -424,7 +492,7 @@ short ExExeUtilConnectbyTcb::work() } nq21.append(tmpbuf); - if( i == seedNum || batchIdx ==10) continue; + if( i == seedNum || batchIdx == connBatchSize_) continue; else nq21.append(" , "); } //if( tmpLevel == currLevel) @@ -438,6 +506,7 @@ short ExExeUtilConnectbyTcb::work() step_ = NEXT_LEVEL_; break; } +//printf("q2 is %s\n", nq21.data()); retcode = cliInterface()->fetchRowsPrologue(nq21.data(), FALSE, FALSE); rc = 0; @@ -452,17 +521,31 @@ short ExExeUtilConnectbyTcb::work() } if (rc == 100) continue; - resultSize++; + resultSize_++; cliInterface()->getPtrAndLen(1, ptr, len); connectByStackItem *it = new connectByStackItem(); - char *tmp = new(getHeap()) char[len]; + char *tmp = new(getHeap()) char[len]; memcpy(tmp,ptr,len); it->seedValue = tmp; - it->level = currLevel + 1; + it->level = currLevel_ ; it->type = fsDatatype; it->len = len; - short rc1 = haveDupSeed(currQueue, it, len, currLevel) ; //loop detection - if(rc1 == 1) + it->parentId = i; + if (exeUtilTdb().hasPath_ == TRUE) + { + cliInterface()->getPtrAndLen(2, ptr1, len1); + char *tmp1 = new(getHeap()) char[len1]; + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + short rc1 = checkDuplicate(it, len, currLevel_) ; //loop detection + + if(rc1 == 0) { + thisQueue_->insert(it); + emitRow(tDesc, currLevel_, 0, 0,it); matchRowNum++; + }//if(rc1== 0) + else if(rc1 == 1) { loopDetected = 1; if(exeUtilTdb().noCycle_ == FALSE) { @@ -476,23 +559,11 @@ short ExExeUtilConnectbyTcb::work() step_ = ERROR_; } else - emitRow(tDesc, currLevel+1, 0, 1); - + emitRow(tDesc, currLevel_, 0, 1, it); } - - if(rc1 == 0) { - emitRow(tDesc, currLevel+1, 0, 0); matchRowNum++; - tmpQueue->insert(it); - }//if(haveDupSeed(currQueue, it, len, currLevel) == 0) - }// while ((rc >= 0) cliInterface()->fetchRowsEpilogue(0, FALSE); }//for(int i=0; i< seedNum; i++) - //insert tmpQueue into currQueue - for(int i = 0; i < tmpQueue->numEntries(); i++) - currQueue->insert(tmpQueue->get(i)); - NADELETE(tmpQueue, Queue, getHeap()); - tmpQueue = new(getHeap()) Queue(getHeap()); if( loopDetected == 1) { @@ -504,7 +575,7 @@ short ExExeUtilConnectbyTcb::work() step_ = ERROR_; break; } - if(resultSize == 0) + if(resultSize_ == 0) step_ = NEXT_ROOT_; else step_ = NEXT_LEVEL_; @@ -512,8 +583,11 @@ short ExExeUtilConnectbyTcb::work() break; case NEXT_LEVEL_: { - currLevel++; - if( currLevel > exeUtilTdb().maxDeep_ ) + Queue* currQueue = new(getHeap()) Queue(getHeap()) ; + currLevel_++; + currArray[currLevel_] = currQueue; + + if( currLevel_ > exeUtilTdb().maxDeep_ ) { ComDiagsArea * diags = getDiagsArea(); if(diags == NULL) @@ -531,10 +605,16 @@ short ExExeUtilConnectbyTcb::work() break; case NEXT_ROOT_: { - currRootId++; - currLevel = 1; - currQueue = getCurrQueue(currRootId, seedQueue); - if(currQueue == NULL) step_ = DONE_; + currRootId_++; + currLevel_ = 0; + currQueue_ = getCurrQueue(currRootId_, seedQueue_); + //clear currArray + for(int i =0; i< 200; i++) + { + if(currArray[i] != NULL) //comehere + NADELETE(currArray[i], Queue, getHeap()); + } + if(currQueue_ == NULL) step_ = DONE_; else step_ = DO_CONNECT_BY_; } @@ -562,16 +642,28 @@ short ExExeUtilConnectbyTcb::work() return WORK_OK; step_ = INITIAL_; - +#if 1 //release the currentQueue +#if 0 for(int i = 0; i< currRootId ; i++) { currQueue = getCurrQueue( i, seedQueue); releaseCurrentQueue(currQueue, getHeap()); NADELETE(currQueue, Queue, getHeap()); } - NADELETE(seedQueue, Queue, getHeap()); + + for(int i =1; i< 200; i++) + { + if(currArray[i] != NULL) //comehere + { + releaseCurrentQueue(currArray[i], getHeap()); + NADELETE(currArray[i], Queue, getHeap()); + } + } +#endif + NADELETE(seedQueue_, Queue, getHeap()); +#endif return WORK_OK; break; diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 14ed4946a4..726e23e165 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5258,6 +5258,7 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); tblDesc_ = cmpSBD.getSeabaseTableDesc(cat,sch,tbl,COM_BASE_TABLE_OBJECT); + //rename TrafTableDesc * td = tblDesc_->tableDesc(); td->tablename = (char*)getVirtualTableName(); @@ -5322,6 +5323,26 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() column_desc->next = col_desc; col_desc->columnsDesc()->colclass='S'; + column_desc = tblDesc_->tableDesc()->columns_desc; + tblDesc_->tableDesc()->colcount++; + i =0; + tmpOffset = 0; + while(column_desc->next) { i++; column_desc = column_desc->next; } + + tmpOffset = column_desc->columnsDesc()->offset + 4; + col_desc = TrafMakeColumnDesc( + getVirtualTableName(), + "CONNECT_BY_PATH", //info->colName, + i, + REC_BYTE_V_ASCII, + 3000, + tmpOffset, + FALSE, + SQLCHARSETCODE_UTF8, + NULL); + column_desc->next = col_desc; + col_desc->columnsDesc()->colclass='S'; + return tblDesc_; } @@ -5406,8 +5427,11 @@ short ExeUtilConnectby::codeGen(Generator * generator) TrafDesc * column_desc = tblDesc_->tableDesc()->columns_desc; Lng32 colDescSize = column_desc->columnsDesc()->length; + Scan * scanNode = (Scan*)scan_; + NAString tbl= (scanNode->getTableName()).getQualifiedNameAsString(); + char * stmtText = getStmtText(); - char *tblnm = (char*)getTableName().getQualifiedNameObj().getObjectName().data(); + char *tblnm = (char*)tbl.data(); ex_expr * selectPred = NULL; @@ -5421,13 +5445,10 @@ short ExeUtilConnectby::codeGen(Generator * generator) ex_expr::exp_SCAN_PRED, &selectPred); - expGen->assignAtpAndAtpIndex(getVirtualTableDesc()->getColumnList(), 0, theAtpIndex); - } - ComTdbExeUtilConnectby * exe_util_tdb = new(space) ComTdbExeUtilConnectby (stmtText , (stmtText ? strlen(stmtText) : 0), getStmtTextCharSet(), tblnm , NULL, 0 , 0, @@ -5451,6 +5472,21 @@ short ExeUtilConnectby::codeGen(Generator * generator) exe_util_tdb->hasStartWith_ = hasStartWith_; exe_util_tdb->startWithExprString_ = startWithExprString_; exe_util_tdb->noCycle_ = noCycle_; + + if(hasConnectByPath()) + { + exe_util_tdb->hasPath_ = TRUE; + exe_util_tdb->pathColName_ = pathColName_; + exe_util_tdb->delimiter_ = delimiter_; + } + else + { + exe_util_tdb->hasPath_ = FALSE; + exe_util_tdb->pathColName_ = "0"; + exe_util_tdb->delimiter_ = " "; + } + + generator->initTdbFields(exe_util_tdb); if (!generator->explainDisabled()) diff --git a/core/sql/optimizer/BindItemExpr.cpp b/core/sql/optimizer/BindItemExpr.cpp index f8d7b67755..9249223c8f 100644 --- a/core/sql/optimizer/BindItemExpr.cpp +++ b/core/sql/optimizer/BindItemExpr.cpp @@ -10845,7 +10845,9 @@ ItemExpr *ZZZBinderFunction::bindNode(BindWA *bindWA) "CAST( HOUR( CAST(@A1 AS TIMESTAMP) ) AS INTERVAL HOUR);"); } break; - + case ITM_SYS_CONNECT_BY_PATH: + strcpy(buf,"CAST( CONNECT_BY_PATH AS VARCHAR(3000));"); + break; case ITM_DATE_TRUNC_MINUTE: { if (enforceDateOrTimestampDatatype(bindWA,0,2)) @@ -13449,3 +13451,10 @@ NABoolean RowNumFunc::canBeUsedInGBorOB(NABoolean setErr) return FALSE; } + +ItemExpr *ItmSysConnectByPathFunc::bindNode(BindWA *bindWA) +{ + return ZZZBinderFunction::bindNode(bindWA); +} + + diff --git a/core/sql/optimizer/ItemExpr.cpp b/core/sql/optimizer/ItemExpr.cpp index f0c38258d0..402305e37f 100644 --- a/core/sql/optimizer/ItemExpr.cpp +++ b/core/sql/optimizer/ItemExpr.cpp @@ -15250,3 +15250,14 @@ ItemExpr * SplitPart::copyTopNode(ItemExpr *derivedNode, CollHeap *outHeap) return BuiltinFunction::copyTopNode(result, outHeap); } +ItemExpr * ItmSysConnectByPathFunc::copyTopNode(ItemExpr *derivedNode , + CollHeap* outHeap) +{ + ItemExpr *result = NULL; + if (derivedNode == NULL) + result = new (outHeap) ItmSysConnectByPathFunc(); + else + result = derivedNode; + + return ZZZBinderFunction::copyTopNode(result, outHeap); +} diff --git a/core/sql/optimizer/ItemFunc.h b/core/sql/optimizer/ItemFunc.h index 249c09bc9a..7d5df7198e 100644 --- a/core/sql/optimizer/ItemFunc.h +++ b/core/sql/optimizer/ItemFunc.h @@ -4708,6 +4708,33 @@ class ZZZBinderFunction : public BuiltinFunction }; +class ItmSysConnectByPathFunc : public ZZZBinderFunction +{ +public: + ItmSysConnectByPathFunc( + const char *del ="", ItemExpr *val = NULL) + : ZZZBinderFunction(ITM_SYS_CONNECT_BY_PATH, + val, NULL,NULL,NULL,NULL) + { + delimiter_ = del; + val->unparse(pathColName_, PARSER_PHASE, USER_FORMAT); + } + + virtual ItemExpr *bindNode(BindWA *bindWA); + + virtual const NAType * synthesizeType(); + + virtual ItemExpr * copyTopNode(ItemExpr *derivedNode = NULL, + CollHeap* outHeap = 0); + + NAString getDelimiter() { return delimiter_; } + NAString getPathColumnName() { return pathColName_; } + +private: + NAString delimiter_; + NAString pathColName_; +}; + // -------------------------------------------------------------------------- // // Sequence functions. These perform running and moving aggregates diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index f87d94ffd6..176fe72b44 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6290,6 +6290,8 @@ RelExpr * ExeUtilConnectby::copyTopNode(RelExpr *derivedNode, CollHeap* outHeap) result->childColName_ = childColName_; result->startWithExprString_ = startWithExprString_; result->noCycle_ = noCycle_; + result->flags_ = flags_; + return ExeUtilExpr::copyTopNode(result, outHeap); } diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 9016bedb7d..466cf87790 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1097,6 +1097,11 @@ class ExeUtilHiveTruncateLegacy : public ExeUtilExpr class ExeUtilConnectby : public ExeUtilExpr { + enum Flags { + HAS_IS_LEAF = 0x00000001, + HAS_CONNECT_BY_PATH = 0x00000002, + }; + public: ExeUtilConnectby( const CorrName &TableName, char * stmtText, @@ -1109,6 +1114,7 @@ class ExeUtilConnectby : public ExeUtilExpr hasStartWith_ = TRUE; noCycle_ = FALSE; scan_ = scan; + flags_ = 0; } virtual const NAString getText() const; @@ -1148,6 +1154,34 @@ class ExeUtilConnectby : public ExeUtilExpr ItemExpr *&castValue, NABoolean alignedFormat); + void setHasIsLeaf(NABoolean v) + { v ? flags_ |= HAS_IS_LEAF: flags_ &= ~HAS_IS_LEAF; } + + void setHasConnectByPath(NABoolean v) + { v ? flags_ |= HAS_CONNECT_BY_PATH: flags_ &= ~HAS_CONNECT_BY_PATH; } + + NABoolean hasIsLeaf() const + { return (flags_ & HAS_IS_LEAF) != 0; } + + NABoolean hasConnectByPath() const + { return (flags_ & HAS_CONNECT_BY_PATH) != 0; } + + ItemExpr *containsPath (ItemExpr * lst ) { + Int32 arity = lst->getArity(); + if(lst->getOperatorType() == ITM_SYS_CONNECT_BY_PATH) + { + return lst; + } + + for(Int32 i = 0; i < arity; i++) + if(lst->getChild(i)) + { + ItemExpr *ie = containsPath((ItemExpr*)lst->getChild(i)); + if(ie != NULL) return ie; + } + return NULL; + } + TrafDesc * tblDesc_; ItemExpr * connectByTree_; NAString parentColName_; @@ -1157,12 +1191,16 @@ class ExeUtilConnectby : public ExeUtilExpr NABoolean noCycle_; RelExpr * scan_; NAString myTableName_; + NAString pathColName_; + NAString delimiter_; ItemExpr * myselection_; ValueIdSet mypredicates_; + Int32 batchSize_; + private: - int fake_; + ULng32 flags_; }; /////////////////////////////////////////////////////////// diff --git a/core/sql/optimizer/SynthType.cpp b/core/sql/optimizer/SynthType.cpp index 9efcb41445..b2fca122fd 100644 --- a/core/sql/optimizer/SynthType.cpp +++ b/core/sql/optimizer/SynthType.cpp @@ -7208,3 +7208,11 @@ const NAType * SplitPart::synthesizeType() ); } + +const NAType * ItmSysConnectByPathFunc::synthesizeType() +{ + NAType * type; + type = new HEAP + SQLVarChar(HEAP, 3000, FALSE); + return type; +} diff --git a/core/sql/parser/ParKeyWords.cpp b/core/sql/parser/ParKeyWords.cpp index 211a522dee..44ae17e3b9 100644 --- a/core/sql/parser/ParKeyWords.cpp +++ b/core/sql/parser/ParKeyWords.cpp @@ -1117,6 +1117,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("SUSPEND", TOK_SUSPEND, NONRESTOKEN_), ParKeyWord("SYNONYM", TOK_SYNONYM, POTANS_|RESWORD_), ParKeyWord("SYNONYMS", TOK_SYNONYMS, NONRESTOKEN_), + ParKeyWord("SYS_CONNECT_BY_PATH", TOK_SYSCONNECTBYPATH, NONRESTOKEN_), ParKeyWord("SYSDATE", TOK_SYSDATE, NONRESTOKEN_), ParKeyWord("SYSTEM", TOK_SYSTEM, NONRESTOKEN_), ParKeyWord("SYSTIMESTAMP", TOK_SYSTIMESTAMP, NONRESTOKEN_), diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 3044ec0796..1e1089a50d 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -1060,6 +1060,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_SHOWDDL_SEQUENCE %token TOK_SHOWDDL /* Tandem extension non-reserved word */ %token TOK_SYSDATE +%token TOK_SYSCONNECTBYPATH %token TOK_SYSTIMESTAMP %token TOK_TARGET %token TOK_SYSTEM @@ -9869,6 +9870,11 @@ misc_function : CmpCommon::statementHeap(), 1, $3); } + | TOK_SYSCONNECTBYPATH '(' value_expression ',' QUOTED_STRING ')' + { + $$ = new (PARSERHEAP()) + ItmSysConnectByPathFunc($5->data(), $3); + } | TOK_ISNULL '(' value_expression ',' value_expression ')' { $$ = new (PARSERHEAP()) @@ -9876,7 +9882,6 @@ misc_function : CmpCommon::statementHeap(), 2, $3, $5); } - | TOK_NVL '(' value_expression ',' value_expression ')' { $$ = new (PARSERHEAP()) @@ -9884,17 +9889,15 @@ misc_function : CmpCommon::statementHeap(), 2, $3, $5); } - | TOK_JSONOBJECTFIELDTEXT '(' value_expression ',' value_expression ')' - { - $$ = new (PARSERHEAP()) - BuiltinFunction(ITM_JSONOBJECTFIELDTEXT, CmpCommon::statementHeap(), 2, $3, $5); - } + { + $$ = new (PARSERHEAP()) + BuiltinFunction(ITM_JSONOBJECTFIELDTEXT, CmpCommon::statementHeap(), 2, $3, $5); + } | TOK_NULLIF '(' value_expression ',' value_expression ')' { $$ = new (PARSERHEAP()) ZZZBinderFunction(ITM_NULLIF, $3, $5); } - | TOK_QUERYID_EXTRACT '(' value_expression ',' value_expression ')' { $$ = new (PARSERHEAP()) @@ -13868,7 +13871,7 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ RelRoot *temp = new (PARSERHEAP()) RelRoot(euc, REL_ROOT , $1); - + if( ((Scan*)$2)->getBiConnectBy()->getStartWith() == NULL) { euc->hasStartWith_ = FALSE; @@ -13878,6 +13881,15 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ euc->hasStartWith_ = TRUE; euc->startWithExprString_ = ((Scan*)$2)->getBiConnectBy()->getStartWithString(); } + ItemExpr * it = euc->containsPath($1); + if( it != NULL) + { + euc->setHasConnectByPath(TRUE); + euc->pathColName_=((ItmSysConnectByPathFunc*)it)->getPathColumnName(); + euc->delimiter_ = ((ItmSysConnectByPathFunc*)it)->getDelimiter(); + } + else + euc->setHasConnectByPath(FALSE); euc->noCycle_ = ((Scan*)$2)->getBiConnectBy()->getNoCycle(); euc->scan_ = $2; euc->myselection_ = ((Scan*)$2)->getBiConnectBy()->where_clause ; From 81ef30d0e97797e033522b711f1aeb5ba359cd94 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sun, 5 Aug 2018 09:43:03 +0000 Subject: [PATCH 10/17] add ISLEAF support, but need to wait for another enhancement --- core/sql/comexe/ComTdbExeUtil.cpp | 1 + core/sql/comexe/ComTdbExeUtil.h | 1 + core/sql/executor/ExExeUtil.h | 22 + core/sql/executor/ExExeUtilConnectby.cpp | 577 +++++++++++++++++------ core/sql/generator/GenRelExeUtil.cpp | 40 +- core/sql/optimizer/RelExeUtil.h | 23 +- core/sql/parser/sqlparser.y | 4 + 7 files changed, 489 insertions(+), 179 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.cpp b/core/sql/comexe/ComTdbExeUtil.cpp index ba9d59dbee..3d8749aede 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -3070,6 +3070,7 @@ ComTdbExeUtilConnectby::ComTdbExeUtilConnectby(char * query, maxDeep_ = 200; //by default, max deep of a tree maxSize_ = 100000; //by default, the max number of rows to return for hierachy query hasPath_ = FALSE; + hasIsLeaf_ = FALSE; } Long ComTdbExeUtilConnectby::pack(void * space) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index 3e093b660e..9ff83dd260 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -4053,6 +4053,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil Int32 maxDeep_; Int32 maxSize_; NABoolean hasPath_; + NABoolean hasIsLeaf_; NAString pathColName_; NAString delimiter_; private: diff --git a/core/sql/executor/ExExeUtil.h b/core/sql/executor/ExExeUtil.h index 2c91bad0e1..ad22ef2eca 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4195,6 +4195,25 @@ class connectByStackItem int pathLen; int parentId; }; +class connectByOneRow { + +public: + connectByOneRow() + { + data_ = NULL; + len = 0; + type = 0; + } + ~connectByOneRow() {} + char * data_; + int len; + int type; +}; + +#define CONNECT_BY_DEFAULT_BATCH_SIZE 100 +#define CONNECT_BY_MAX_LEVEL_SIZE 200 +#define CONNECT_BY_MAX_SQL_TEXT_SIZE 2048 +#define CONNECT_BY_MAX_PATH_SIZE 3000 //////////////////////////////////////////////////////////////////////////// class ExExeUtilLobInfoTablePrivateState : public ex_tcb_private_state @@ -4239,6 +4258,7 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb {return (ExExeUtilConnectbyTdb&) tdb;}; short emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle, connectByStackItem *it) ; + short emitPrevRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle, Queue* q, int index) ; Queue *currArray[200]; Queue * getCurrentQueue(int level) { if(level <0 || level >200) abort(); return currArray[level];} @@ -4248,6 +4268,8 @@ class ExExeUtilConnectbyTcb : public ExExeUtilTcb Queue *currQueue_; Queue *seedQueue_; Queue *thisQueue_; + Queue *prevQueue_; + Queue *tmpPrevQueue_; Int32 currRootId_; Int32 connBatchSize_ ; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 4e0c2e9e24..582b317e56 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -94,9 +94,12 @@ ExExeUtilConnectbyTcb::ExExeUtilConnectbyTcb( resultSize_ = 0; currQueue_ = new(getHeap()) Queue(getHeap()) ; thisQueue_ = NULL; - connBatchSize_ = 50; + prevQueue_ = NULL; + tmpPrevQueue_ = NULL; + currRootId_ = 0; + connBatchSize_ = CONNECT_BY_DEFAULT_BATCH_SIZE; seedQueue_ = new(getHeap()) Queue(getHeap()) ; - for( int i = 0; i< 200; i++) + for( int i = 0; i< CONNECT_BY_MAX_LEVEL_SIZE; i++) { currArray[i] = NULL; } @@ -220,12 +223,12 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf if (evalRetCode == ex_expr::EXPR_TRUE) { -#if 1 - char pathBuf[3000]; - memset(pathBuf, 0, 3000); + + char pathBuf[CONNECT_BY_MAX_PATH_SIZE]; + memset(pathBuf, 0, CONNECT_BY_MAX_PATH_SIZE); char tmpbuf1[256]; - int pathlength = 0; - int dlen = strlen(exeUtilTdb().delimiter_.data()); + Lng32 pathlength = 0; + Lng32 dlen = strlen(exeUtilTdb().delimiter_.data()); Queue *pathq = new(getHeap()) Queue(getHeap()) ;; if (exeUtilTdb().hasPath_ == TRUE) { pathq->insert(vi->pathItem); @@ -251,6 +254,9 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf } attr = tDesc->getAttr(tDesc->numAttrs() - 1); + + if(pathlength > CONNECT_BY_MAX_PATH_SIZE) pathlength = CONNECT_BY_MAX_PATH_SIZE; + if ( ::convDoIt(pathBuf, pathlength, REC_BYTE_V_ASCII, 0, 0, &data_[attr->getOffset()], @@ -265,7 +271,184 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf attr->setVarLength(vcActualLen,&data_[attr->getVCLenIndOffset()]); retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); -#endif +} + return retcode; +} + + +short ExExeUtilConnectbyTcb::emitPrevRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle, Queue * pq, int idx) +{ + short retcode = 0, rc =0; + connectByStackItem *vi = NULL; + char * ptr; + Lng32 len; + short nullInd = 0; + short *ind ; + ind = &nullInd; + UInt32 vcActualLen = 0; + //get the item + Queue * thatone; + int pos=0, doffset=0, lastpos = 0; + for(int i1 = 0; i1< pq->numEntries(); i1++) + { + lastpos = pos; + pos+= ((Queue *)pq->get(i1))->numEntries(); + if(idx <= pos) + { + thatone = (Queue *)pq->get(i1); + doffset = idx - lastpos; + } + } + if(level > 1) + vi = (connectByStackItem *)currArray[level - 1]->get(doffset); + OutputInfo * ti = (OutputInfo *)thatone->get(doffset); + for (UInt32 i = 2; i < tDesc->numAttrs() - 2 ; i++) + { + ti->get(i+1, ptr, len); + char * src = ptr; + Attributes * attr = tDesc->getAttr(i-1); + short srcType = 0; + Lng32 srcLen; + short valIsNull = 0; + srcType = attr->getDatatype(); + srcLen = len; + if (len == 0 ) valIsNull = -1; + + if (attr->getNullFlag()) + { + // target is nullable + if (attr->getNullIndicatorLength() == 2) + { + // set the 2 byte NULL indicator to -1 + *(short *) (&data_[attr->getNullIndOffset()]) = + valIsNull; + } + else + { + ex_assert(attr->getNullIndicatorLength() == 4, + "NULL indicator must be 2 or 4 bytes"); + *(Lng32 *) (&data_[attr->getNullIndOffset()]) = + valIsNull; + } + } + else + ex_assert(!valIsNull, + "NULL source for NOT NULL stats column"); + + + if (!valIsNull) + { + if (attr->getVCIndicatorLength() > 0) + { + ::convDoIt(src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + (char*) &vcActualLen, sizeof(vcActualLen), NULL); + attr->setVarLength(vcActualLen,&data_[attr->getVCLenIndOffset()]); + } + else + ::convDoIt(src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + NULL, 0, NULL); + + } + } + + + short srcType = REC_BIN32_UNSIGNED; + Lng32 srcLen = 4; + int src = isleaf; + Attributes * attr = tDesc->getAttr(tDesc->numAttrs() - 2); + if ( + ::convDoIt((char*)&src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + 0, 0, NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } + + src = iscycle; + attr = tDesc->getAttr(tDesc->numAttrs() - 3); + if ( + ::convDoIt((char*)&src, srcLen, srcType, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + 0, 0, NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } + + //apply the expression + ex_expr::exp_return_type evalRetCode = ex_expr::EXPR_TRUE; + if(exeUtilTdb().scanExpr_ ) + { + //evalRetCode = evalScanExpr((char*)data_, exeUtilTdb().tupleLen_, FALSE); + workAtp_->getTupp(exeUtilTdb().workAtpIndex()) + .setDataPointer((char*)data_); + evalRetCode = + exeUtilTdb().scanExpr_->eval(workAtp_, NULL); + } + + if (evalRetCode == ex_expr::EXPR_TRUE) +{ + + char pathBuf[CONNECT_BY_MAX_PATH_SIZE]; + memset(pathBuf, 0, CONNECT_BY_MAX_PATH_SIZE); + char tmpbuf1[256]; + Lng32 pathlength = 0; + Lng32 dlen = strlen(exeUtilTdb().delimiter_.data()); + Queue *pathq = new(getHeap()) Queue(getHeap()) ;; + if (exeUtilTdb().hasPath_ == TRUE) { + ti->get(2, ptr, len); + pathq->insert(ptr); + pathlength = len; + for(int ii = level - 1 ; ii > 0; ii--) + { + Queue *tq = getCurrentQueue(ii-1); + connectByStackItem * p = (connectByStackItem*)tq->get(vi->parentId - 1); + if(p == NULL) abort(); + pathq->insert(p->pathItem); + pathlength += p->pathLen + dlen; + vi = p; + } + for(int pi = pathq->entries(); pi > 0; pi--) + { + if(pi-1 == 0) + sprintf(tmpbuf1,"%s",(char*)(pathq->get(pi-1))); + else + sprintf(tmpbuf1,"%s%s",(char*)(pathq->get(pi-1)) ,exeUtilTdb().delimiter_.data()); + strcat(pathBuf,tmpbuf1); + } + NADELETE(pathq, Queue, getHeap()); + } + + attr = tDesc->getAttr(tDesc->numAttrs() - 1); + + if(pathlength > CONNECT_BY_MAX_PATH_SIZE) pathlength = CONNECT_BY_MAX_PATH_SIZE; + + if ( + ::convDoIt(pathBuf, pathlength, REC_BYTE_V_ASCII, 0, 0, + &data_[attr->getOffset()], + attr->getLength(), + attr->getDatatype(),0,0, + (char*) &vcActualLen, sizeof(vcActualLen), NULL) != ex_expr::EXPR_OK) + { + ex_assert( + 0, + "Error from ExStatsTcb::work::convDoIt."); + } + attr->setVarLength(vcActualLen,&data_[attr->getVCLenIndOffset()]); + retcode = moveRowToUpQueue(data_, exeUtilTdb().tupleLen_, &rc, FALSE); } return retcode; @@ -326,7 +509,7 @@ Queue * getCurrQueue(int id, Queue *q) short ExExeUtilConnectbyTcb::work() { short retcode = 0; - char q1[2048]; //TODO: the max len of supported query len + char q1[CONNECT_BY_MAX_SQL_TEXT_SIZE]; //TODO: the max len of supported query len void* uppderid = NULL; char * ptr, *ptr1; Lng32 len, len1; @@ -366,10 +549,13 @@ short ExExeUtilConnectbyTcb::work() Lng32 indOffset = 0; Lng32 varOffset = 0; - if (exeUtilTdb().hasPath_ == TRUE) + if (exeUtilTdb().hasPath_ == TRUE || exeUtilTdb().hasIsLeaf_ == TRUE) { connBatchSize_ = 1; } + + if(exeUtilTdb().hasIsLeaf_ == TRUE && prevQueue_ == NULL) + prevQueue_ = new(getHeap()) Queue(getHeap()) ; while (1) { @@ -385,53 +571,110 @@ short ExExeUtilConnectbyTcb::work() int rootId = 0; //get the stmt - retcode = cliInterface()->fetchRowsPrologue(nq11.data(), FALSE, FALSE); - while ((rc >= 0) && - (rc != 100)) + + if( exeUtilTdb().hasIsLeaf_ == TRUE) { - rc = cliInterface()->fetch(); - if (rc < 0) - { - cliInterface()->fetchRowsEpilogue(0, TRUE); - return rc; + Queue * rootRow = new(getHeap()) Queue(getHeap()) ; //TODO DELETE + rc = cliInterface()->fetchAllRows(rootRow, nq11.data(), 0, FALSE, FALSE, TRUE); + if (rc < 0) + { + NADELETE(rootRow, Queue, getHeap()); + return WORK_BAD_ERROR; } + //populate the seedQueue and currArray + rootRow->position(); - if (rc == 100) - continue; - - connectByStackItem *it = new connectByStackItem(); - cliInterface()->getPtrAndLen(1, ptr, len); - cliInterface()->getAttributes(1, FALSE, - fsDatatype, length, - &indOffset, &varOffset); - Queue* cq = new(getHeap()) Queue(getHeap()) ; - rootItem * ri= new(getHeap()) rootItem(); - ri->rootId = rootId; - rootId++; - ri->qptr = cq; - seedQueue_->insert(ri); //TO BE REMOVED - - char *tmp = new(getHeap()) char[len]; - memcpy(tmp,ptr,len); - it->seedValue = tmp; - it->level = currLevel_; - it->type = fsDatatype; - it->len = len; - it->parentId = -1; - if (exeUtilTdb().hasPath_ == TRUE) - { - cliInterface()->getPtrAndLen(2, ptr1, len1); - char *tmp1 = new(getHeap()) char[len1]; - memcpy(tmp1,ptr1,len1); - it->pathLen = len1; - it->pathItem = tmp1; - } - if(checkDuplicate( it, len, currLevel_) == 0) { - emitRow(tDesc, currLevel_, 0, 0, it); matchRowNum++; - currQueue_->insert(it); - } + for(int i1 = 0; i1 < rootRow->numEntries(); i1 ++) + { + OutputInfo *vi = (OutputInfo*)rootRow->getNext(); + vi->get(0, ptr, len); + connectByStackItem *it = new connectByStackItem(); + + char *tmp = new(getHeap()) char[len]; + memcpy(tmp,ptr,len); + it->seedValue = tmp; + it->level = currLevel_; + it->type = fsDatatype; + it->len = len; + it->parentId = -1; + if (exeUtilTdb().hasPath_ == TRUE) + { + vi->get(1, ptr1, len1); + char *tmp1 = new(getHeap()) char[len1]; + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + if(checkDuplicate( it, len, currLevel_) == 0) { + matchRowNum++; + Queue* cq = new(getHeap()) Queue(getHeap()) ; + cq->insert(it); + rootItem * ri= new(getHeap()) rootItem(); + ri->rootId = rootId; + rootId++; + cq->insert(it); + ri->qptr = cq; + seedQueue_->insert(ri); + } + + //populate prevQueue + prevQueue_->insert(rootRow); + } //for(int i1 = 0; i1 < rootRow->numEntries(); i1 ++) + } + else + { + retcode = cliInterface()->fetchRowsPrologue(nq11.data(), FALSE, FALSE); + while ((rc >= 0) && + (rc != 100)) + { + rc = cliInterface()->fetch(); + if (rc < 0) + { + cliInterface()->fetchRowsEpilogue(0, TRUE); + return rc; + } + + if (rc == 100) + continue; + + connectByStackItem *it = new connectByStackItem(); + cliInterface()->getPtrAndLen(1, ptr, len); + cliInterface()->getAttributes(1, FALSE, + fsDatatype, length, + &indOffset, &varOffset); + + + char *tmp = new(getHeap()) char[len]; + memcpy(tmp,ptr,len); + it->seedValue = tmp; + it->level = currLevel_; + it->type = fsDatatype; + it->len = len; + it->parentId = -1; + if (exeUtilTdb().hasPath_ == TRUE) + { + cliInterface()->getPtrAndLen(2, ptr1, len1); + char *tmp1 = new(getHeap()) char[len1]; + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + if(checkDuplicate( it, len, currLevel_) == 0) { + emitRow(tDesc, currLevel_, 0, 0, it); + matchRowNum++; + Queue* cq = new(getHeap()) Queue(getHeap()) ; + rootItem * ri= new(getHeap()) rootItem(); + cq->insert(it); + ri->rootId = rootId; + rootId++; + ri->qptr = cq; + seedQueue_->insert(ri); //TO BE REMOVED + } + + } + cliInterface()->fetchRowsEpilogue(0, FALSE); } - cliInterface()->fetchRowsEpilogue(0, FALSE); + currQueue_ = getCurrQueue(currRootId_, seedQueue_); currArray[0] = currQueue_; if( matchRowNum > exeUtilTdb().maxSize_ ) @@ -454,8 +697,10 @@ short ExExeUtilConnectbyTcb::work() { currQueue_ = getCurrentQueue(currLevel_ - 1); thisQueue_ = getCurrentQueue(currLevel_); - int seedNum = currQueue_->numEntries(); - int loopDetected = 0; + if(exeUtilTdb().hasIsLeaf_ == TRUE) + tmpPrevQueue_ = new(getHeap()) Queue(getHeap()) ; + Lng32 seedNum = currQueue_->numEntries(); + Int8 loopDetected = 0; currQueue_->position(); resultSize_ = 0; @@ -466,12 +711,12 @@ short ExExeUtilConnectbyTcb::work() nq21 = q1; nq21.append((exeUtilTdb().childColName_).data()); nq21.append(" in ( "); - int sybnum = 0; + Lng32 sybnum = 0; for(int batchIdx = 0; batchIdx < connBatchSize_ && i < seedNum; ) { connectByStackItem * vi = (connectByStackItem*)currQueue_->get(i); - int tmpLevel = vi->level; + Lng32 tmpLevel = vi->level; i++; if( tmpLevel == currLevel_ - 1) { sybnum++; @@ -507,63 +752,145 @@ short ExExeUtilConnectbyTcb::work() break; } //printf("q2 is %s\n", nq21.data()); - retcode = cliInterface()->fetchRowsPrologue(nq21.data(), FALSE, FALSE); + if(exeUtilTdb().hasIsLeaf_ == TRUE) + { + Queue * allrows = new(getHeap()) Queue(getHeap()) ; //TODO DELETE + rc = cliInterface()->fetchAllRows(allrows, nq21.data(), 0, FALSE, FALSE, TRUE); + if (rc < 0) + { + NADELETE(allrows, Queue, getHeap()); + return WORK_BAD_ERROR; + } + + allrows->position(); + if(allrows->numEntries() == 0) //no child + { + //emit parent + printf("emit parent rows\n"); + emitPrevRow(tDesc, currLevel_, 1, 0,prevQueue_, i-1); + } + else + { + //emit parent + printf("emit parent rows\n"); + emitPrevRow(tDesc, currLevel_, 0, 0,prevQueue_, i-1); + } + tmpPrevQueue_->insert(allrows); //TODO: delete it + + for(int i1 = 0; i1 < allrows->numEntries(); i1 ++) + { + resultSize_++; + OutputInfo *vi = (OutputInfo*)allrows->getNext(); + vi->get(0, ptr, len); + connectByStackItem *it = new connectByStackItem(); + char *tmp = new(getHeap()) char[len]; + memcpy(tmp,ptr,len); + it->seedValue = tmp; + it->level = currLevel_ ; + it->type = fsDatatype; + it->len = len; + it->parentId = i; + if (exeUtilTdb().hasPath_ == TRUE) + { + vi->get(1, ptr1, len1); + char *tmp1 = new(getHeap()) char[len1]; + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + short rc1 = checkDuplicate(it, len, currLevel_) ; //loop detection + + if(rc1 == 0) { + thisQueue_->insert(it); + matchRowNum++; + }//if(rc1== 0) + else if(rc1 == 1) + { + loopDetected = 1; + if(exeUtilTdb().noCycle_ == FALSE) { + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8037); + step_ = ERROR_; + } + } + } + } + else + { + retcode = cliInterface()->fetchRowsPrologue(nq21.data(), FALSE, FALSE); + + rc = 0; + while ((rc >= 0) && + (rc != 100)) + { + rc = cliInterface()->fetch(); + if (rc < 0) + { + cliInterface()->fetchRowsEpilogue(0, TRUE); + return rc; + } + if (rc == 100) + continue; + resultSize_++; + cliInterface()->getPtrAndLen(1, ptr, len); + connectByStackItem *it = new connectByStackItem(); + char *tmp = new(getHeap()) char[len]; + memcpy(tmp,ptr,len); + it->seedValue = tmp; + it->level = currLevel_ ; + it->type = fsDatatype; + it->len = len; + it->parentId = i; + if (exeUtilTdb().hasPath_ == TRUE) + { + cliInterface()->getPtrAndLen(2, ptr1, len1); + char *tmp1 = new(getHeap()) char[len1]; + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + short rc1 = checkDuplicate(it, len, currLevel_) ; //loop detection + + if(rc1 == 0) { + thisQueue_->insert(it); + emitRow(tDesc, currLevel_, 0, 0,it); + matchRowNum++; + }//if(rc1== 0) + else if(rc1 == 1) + { + loopDetected = 1; + if(exeUtilTdb().noCycle_ == FALSE) { + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8037); + step_ = ERROR_; + } + else + { + emitRow(tDesc, currLevel_, 0, 1, it); + } + } + }// while ((rc >= 0) + cliInterface()->fetchRowsEpilogue(0, FALSE); + } - rc = 0; - while ((rc >= 0) && - (rc != 100)) - { - rc = cliInterface()->fetch(); - if (rc < 0) - { - cliInterface()->fetchRowsEpilogue(0, TRUE); - return rc; - } - if (rc == 100) - continue; - resultSize_++; - cliInterface()->getPtrAndLen(1, ptr, len); - connectByStackItem *it = new connectByStackItem(); - char *tmp = new(getHeap()) char[len]; - memcpy(tmp,ptr,len); - it->seedValue = tmp; - it->level = currLevel_ ; - it->type = fsDatatype; - it->len = len; - it->parentId = i; - if (exeUtilTdb().hasPath_ == TRUE) - { - cliInterface()->getPtrAndLen(2, ptr1, len1); - char *tmp1 = new(getHeap()) char[len1]; - memcpy(tmp1,ptr1,len1); - it->pathLen = len1; - it->pathItem = tmp1; - } - short rc1 = checkDuplicate(it, len, currLevel_) ; //loop detection - - if(rc1 == 0) { - thisQueue_->insert(it); - emitRow(tDesc, currLevel_, 0, 0,it); matchRowNum++; - }//if(rc1== 0) - else if(rc1 == 1) - { - loopDetected = 1; - if(exeUtilTdb().noCycle_ == FALSE) { - ComDiagsArea * diags = getDiagsArea(); - if(diags == NULL) - { - setDiagsArea(ComDiagsArea::allocate(getHeap())); - diags = getDiagsArea(); - } - *diags << DgSqlCode(-8037); - step_ = ERROR_; - } - else - emitRow(tDesc, currLevel_, 0, 1, it); - } - }// while ((rc >= 0) - cliInterface()->fetchRowsEpilogue(0, FALSE); }//for(int i=0; i< seedNum; i++) + //this level is done + if(exeUtilTdb().hasIsLeaf_ == TRUE) + { + //release prevQueue_ + prevQueue_ = tmpPrevQueue_; + NADELETE(tmpPrevQueue_, Queue, getHeap()); + } if( loopDetected == 1) { @@ -609,7 +936,7 @@ short ExExeUtilConnectbyTcb::work() currLevel_ = 0; currQueue_ = getCurrQueue(currRootId_, seedQueue_); //clear currArray - for(int i =0; i< 200; i++) + for(int i =0; i< CONNECT_BY_MAX_LEVEL_SIZE; i++) { if(currArray[i] != NULL) //comehere NADELETE(currArray[i], Queue, getHeap()); @@ -641,31 +968,9 @@ short ExExeUtilConnectbyTcb::work() if (retcode == 1) return WORK_OK; - step_ = INITIAL_; -#if 1 - //release the currentQueue -#if 0 - for(int i = 0; i< currRootId ; i++) - { - currQueue = getCurrQueue( i, seedQueue); - releaseCurrentQueue(currQueue, getHeap()); - NADELETE(currQueue, Queue, getHeap()); - } - - - for(int i =1; i< 200; i++) - { - if(currArray[i] != NULL) //comehere - { - releaseCurrentQueue(currArray[i], getHeap()); - NADELETE(currArray[i], Queue, getHeap()); - } - } -#endif NADELETE(seedQueue_, Queue, getHeap()); -#endif + step_ = INITIAL_; return WORK_OK; - break; } } diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 726e23e165..b8794d5531 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5346,42 +5346,6 @@ TrafDesc *ExeUtilConnectby::createVirtualTableDesc() return tblDesc_; } -int ExeUtilConnectby::createAsciiColAndCastExpr2(Generator * generator, - ItemExpr * colNode, - const NAType &givenType, - ItemExpr *&asciiValue, - ItemExpr *&castValue, - NABoolean alignedFormat) -{ - asciiValue = NULL; - castValue = NULL; - CollHeap * h = generator->wHeap(); - - // if this is an upshifted datatype, remove the upshift attr. - // We dont want to upshift data during retrievals or while building keys. - // Data is only upshifted during insert or updates. - const NAType * newGivenType = &givenType; - if (newGivenType->getTypeQualifier() == NA_CHARACTER_TYPE && - ((CharType *)newGivenType)->isUpshifted()) - { - newGivenType = newGivenType->newCopy(h); - ((CharType*)newGivenType)->setUpshifted(FALSE); - } - - NABoolean encodingNeeded = FALSE; - asciiValue = new (h) NATypeToItem(newGivenType->newCopy(h)); - castValue = new(h) Cast(asciiValue, newGivenType); - - if ((!alignedFormat) && HbaseAccess::isEncodingNeededForSerialization(colNode)) - { - castValue = new(generator->wHeap()) CompDecode(castValue, - newGivenType->newCopy(h), - FALSE, TRUE); - } - - return 1; -} - short ExeUtilConnectby::codeGen(Generator * generator) { ExpGenerator * expGen = generator->getExpGenerator(); @@ -5486,6 +5450,10 @@ short ExeUtilConnectby::codeGen(Generator * generator) exe_util_tdb->delimiter_ = " "; } + if(hasIsLeaf()) + { + exe_util_tdb->hasIsLeaf_ = TRUE; + } generator->initTdbFields(exe_util_tdb); diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 466cf87790..1ec51a3ae8 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1147,13 +1147,6 @@ class ExeUtilConnectby : public ExeUtilExpr } #endif - int createAsciiColAndCastExpr2(Generator * generator, - ItemExpr * colNode, - const NAType &givenType, - ItemExpr *&asciiValue, - ItemExpr *&castValue, - NABoolean alignedFormat); - void setHasIsLeaf(NABoolean v) { v ? flags_ |= HAS_IS_LEAF: flags_ &= ~HAS_IS_LEAF; } @@ -1182,6 +1175,22 @@ class ExeUtilConnectby : public ExeUtilExpr return NULL; } + NABoolean containsIsLeaf( ItemExpr * lst) { + Int32 arity = lst->getArity(); + if(lst->getOperatorType() == ITM_REFERENCE) + { + if((((ColReference*)lst)->getColRefNameObj()).getColName() == "CONNECT_BY_ISLEAF") + return TRUE; + } + for(Int32 i = 0; i < arity; i++) + if(lst->getChild(i)) + { + NABoolean rc = containsIsLeaf((ItemExpr*)lst->getChild(i)); + if(rc == TRUE) return rc; + } + return FALSE; + } + TrafDesc * tblDesc_; ItemExpr * connectByTree_; NAString parentColName_; diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 1e1089a50d..3e91d61b50 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -13890,6 +13890,10 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ } else euc->setHasConnectByPath(FALSE); + if( euc->containsIsLeaf($1)) + { + euc->setHasIsLeaf(TRUE); + } euc->noCycle_ = ((Scan*)$2)->getBiConnectBy()->getNoCycle(); euc->scan_ = $2; euc->myselection_ = ((Scan*)$2)->getBiConnectBy()->where_clause ; From d781d881ad400e75fcd765d1856bdb509e2c6adb Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Tue, 7 Aug 2018 20:48:56 +0000 Subject: [PATCH 11/17] finish is leaf --- core/sql/executor/ExExeUtilConnectby.cpp | 12 +++++------- core/sql/parser/sqlparser.y | 2 +- core/sql/regress/executor/TEST021 | 9 ++++++++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 582b317e56..058ef55fd4 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -293,10 +293,11 @@ short ExExeUtilConnectbyTcb::emitPrevRow(ExpTupleDesc * tDesc, int level, int is { lastpos = pos; pos+= ((Queue *)pq->get(i1))->numEntries(); - if(idx <= pos) + if(idx < pos) { thatone = (Queue *)pq->get(i1); doffset = idx - lastpos; + break; } } if(level > 1) @@ -304,7 +305,7 @@ short ExExeUtilConnectbyTcb::emitPrevRow(ExpTupleDesc * tDesc, int level, int is OutputInfo * ti = (OutputInfo *)thatone->get(doffset); for (UInt32 i = 2; i < tDesc->numAttrs() - 2 ; i++) { - ti->get(i+1, ptr, len); + ti->get(i, ptr, len); char * src = ptr; Attributes * attr = tDesc->getAttr(i-1); short srcType = 0; @@ -587,7 +588,7 @@ short ExExeUtilConnectbyTcb::work() for(int i1 = 0; i1 < rootRow->numEntries(); i1 ++) { OutputInfo *vi = (OutputInfo*)rootRow->getNext(); - vi->get(0, ptr, len); + vi->get(0, ptr, len, fsDatatype); //, NULL, NULL); connectByStackItem *it = new connectByStackItem(); char *tmp = new(getHeap()) char[len]; @@ -608,7 +609,6 @@ short ExExeUtilConnectbyTcb::work() if(checkDuplicate( it, len, currLevel_) == 0) { matchRowNum++; Queue* cq = new(getHeap()) Queue(getHeap()) ; - cq->insert(it); rootItem * ri= new(getHeap()) rootItem(); ri->rootId = rootId; rootId++; @@ -766,13 +766,11 @@ short ExExeUtilConnectbyTcb::work() if(allrows->numEntries() == 0) //no child { //emit parent - printf("emit parent rows\n"); emitPrevRow(tDesc, currLevel_, 1, 0,prevQueue_, i-1); } else { //emit parent - printf("emit parent rows\n"); emitPrevRow(tDesc, currLevel_, 0, 0,prevQueue_, i-1); } tmpPrevQueue_->insert(allrows); //TODO: delete it @@ -888,8 +886,8 @@ short ExExeUtilConnectbyTcb::work() if(exeUtilTdb().hasIsLeaf_ == TRUE) { //release prevQueue_ + NADELETE(prevQueue_, Queue, getHeap()); prevQueue_ = tmpPrevQueue_; - NADELETE(tmpPrevQueue_, Queue, getHeap()); } if( loopDetected == 1) diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 3e91d61b50..efd82343ba 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -13890,7 +13890,7 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ } else euc->setHasConnectByPath(FALSE); - if( euc->containsIsLeaf($1)) + if( euc->containsIsLeaf($1) || euc->containsIsLeaf(((Scan*)$2)->getBiConnectBy()->where_clause) ) { euc->setHasIsLeaf(TRUE); } diff --git a/core/sql/regress/executor/TEST021 b/core/sql/regress/executor/TEST021 index fb6872847e..66021a67ba 100644 --- a/core/sql/regress/executor/TEST021 +++ b/core/sql/regress/executor/TEST021 @@ -71,12 +71,19 @@ SELECT *, "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID; SELECT * FROM t021t1 START WITH depid = 11 CONNECT BY PRIOR DEPID = UPPERDEPID; --nocycle test -SELECT * , "CONNECT_BY_ISCYCLE" FROM t021t1 START WITH depid = 11 CONNECT BY NOCYCLE PRIOR DEPID = UPPERDEPID; +SELECT * , CONNECT_BY_ISCYCLE FROM t021t1 START WITH depid = 11 CONNECT BY NOCYCLE PRIOR DEPID = UPPERDEPID; SELECT * , "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where depid = 7; SELECT * , "LEVEL" FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where "LEVEL" > 2 ; SELECT * FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID order by 2; + +--test isleaf: return only those leaf rows +SELECT * FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where CONNECT_BY_ISLEAF = 1; + +--test path +SELECT *, cast( SYS_CONNECT_BY_PATH(depname,'/') as char(30)) FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID ; + log; From 8ae2ed9c5fcbb1ccb47f6b952438dedc06b0d90e Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Fri, 10 Aug 2018 05:27:13 +0000 Subject: [PATCH 12/17] first phase finished --- core/sql/executor/ExExeUtilConnectby.cpp | 32 ++++++++++++---------- core/sql/optimizer/RelExeUtil.h | 3 ++ core/sql/optimizer/RelExpr.h | 6 ++++ core/sql/optimizer/RelScan.h | 7 +---- core/sql/parser/ParKeyWords.cpp | 4 +-- core/sql/parser/sqlparser.y | 21 +++++++------- core/sql/regress/executor/EXPECTED021.SB | 35 +++++++++++++++++++++++- 7 files changed, 75 insertions(+), 33 deletions(-) diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 058ef55fd4..9c31229401 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -222,7 +222,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf } if (evalRetCode == ex_expr::EXPR_TRUE) -{ + { char pathBuf[CONNECT_BY_MAX_PATH_SIZE]; memset(pathBuf, 0, CONNECT_BY_MAX_PATH_SIZE); @@ -575,7 +575,7 @@ short ExExeUtilConnectbyTcb::work() if( exeUtilTdb().hasIsLeaf_ == TRUE) { - Queue * rootRow = new(getHeap()) Queue(getHeap()) ; //TODO DELETE + Queue * rootRow = new(getHeap()) Queue(getHeap()) ; rc = cliInterface()->fetchAllRows(rootRow, nq11.data(), 0, FALSE, FALSE, TRUE); if (rc < 0) { @@ -588,7 +588,7 @@ short ExExeUtilConnectbyTcb::work() for(int i1 = 0; i1 < rootRow->numEntries(); i1 ++) { OutputInfo *vi = (OutputInfo*)rootRow->getNext(); - vi->get(0, ptr, len, fsDatatype); //, NULL, NULL); + vi->get(0, ptr, len, fsDatatype, NULL, NULL); connectByStackItem *it = new connectByStackItem(); char *tmp = new(getHeap()) char[len]; @@ -601,7 +601,8 @@ short ExExeUtilConnectbyTcb::work() if (exeUtilTdb().hasPath_ == TRUE) { vi->get(1, ptr1, len1); - char *tmp1 = new(getHeap()) char[len1]; + char *tmp1 = new(getHeap()) char[len1+1]; + memset(tmp1,0, len1+1); memcpy(tmp1,ptr1,len1); it->pathLen = len1; it->pathItem = tmp1; @@ -654,7 +655,8 @@ short ExExeUtilConnectbyTcb::work() if (exeUtilTdb().hasPath_ == TRUE) { cliInterface()->getPtrAndLen(2, ptr1, len1); - char *tmp1 = new(getHeap()) char[len1]; + char *tmp1 = new(getHeap()) char[len1+1]; + memset(tmp1,0,len1+1); memcpy(tmp1,ptr1,len1); it->pathLen = len1; it->pathItem = tmp1; @@ -707,7 +709,8 @@ short ExExeUtilConnectbyTcb::work() for(int i=0; i< seedNum; ) { - sprintf(q1,"SELECT %s ,cast (%s as VARCHAR(3000) ) , *, cast( %d as INT) FROM %s WHERE " ,(exeUtilTdb().parentColName_).data(), (exeUtilTdb().pathColName_).data(), currLevel_,(exeUtilTdb().connTableName_).data() ); + sprintf(q1,"SELECT %s ,cast (%s as VARCHAR(3000) ) , *, cast( %d as INT) FROM %s WHERE " , + (exeUtilTdb().parentColName_).data(), (exeUtilTdb().pathColName_).data(), currLevel_,(exeUtilTdb().connTableName_).data() ); nq21 = q1; nq21.append((exeUtilTdb().childColName_).data()); nq21.append(" in ( "); @@ -751,7 +754,6 @@ short ExExeUtilConnectbyTcb::work() step_ = NEXT_LEVEL_; break; } -//printf("q2 is %s\n", nq21.data()); if(exeUtilTdb().hasIsLeaf_ == TRUE) { Queue * allrows = new(getHeap()) Queue(getHeap()) ; //TODO DELETE @@ -791,7 +793,8 @@ short ExExeUtilConnectbyTcb::work() if (exeUtilTdb().hasPath_ == TRUE) { vi->get(1, ptr1, len1); - char *tmp1 = new(getHeap()) char[len1]; + char *tmp1 = new(getHeap()) char[len1+1]; + memset(tmp1,0,len1+1); memcpy(tmp1,ptr1,len1); it->pathLen = len1; it->pathItem = tmp1; @@ -847,7 +850,8 @@ short ExExeUtilConnectbyTcb::work() if (exeUtilTdb().hasPath_ == TRUE) { cliInterface()->getPtrAndLen(2, ptr1, len1); - char *tmp1 = new(getHeap()) char[len1]; + char *tmp1 = new(getHeap()) char[len1+1]; + memset(tmp1,0,len1+1); memcpy(tmp1,ptr1,len1); it->pathLen = len1; it->pathItem = tmp1; @@ -886,6 +890,8 @@ short ExExeUtilConnectbyTcb::work() if(exeUtilTdb().hasIsLeaf_ == TRUE) { //release prevQueue_ + for(int i = 0 ; i < prevQueue_->numEntries(); i ++) + NADELETE((Queue*)prevQueue_->get(i), Queue, getHeap()); NADELETE(prevQueue_, Queue, getHeap()); prevQueue_ = tmpPrevQueue_; } @@ -931,7 +937,7 @@ short ExExeUtilConnectbyTcb::work() case NEXT_ROOT_: { currRootId_++; - currLevel_ = 0; + currLevel_ = 1; currQueue_ = getCurrQueue(currRootId_, seedQueue_); //clear currArray for(int i =0; i< CONNECT_BY_MAX_LEVEL_SIZE; i++) @@ -939,7 +945,8 @@ short ExExeUtilConnectbyTcb::work() if(currArray[i] != NULL) //comehere NADELETE(currArray[i], Queue, getHeap()); } - if(currQueue_ == NULL) step_ = DONE_; + if(currQueue_ == NULL) + step_ = DONE_; else step_ = DO_CONNECT_BY_; } @@ -951,9 +958,6 @@ short ExExeUtilConnectbyTcb::work() return WORK_OK; if (handleError()) return WORK_OK; - - - step_ = DONE_; step_ = DONE_; } diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index 1ec51a3ae8..fa84711045 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1176,7 +1176,10 @@ class ExeUtilConnectby : public ExeUtilExpr } NABoolean containsIsLeaf( ItemExpr * lst) { + if(lst == NULL) + return FALSE; Int32 arity = lst->getArity(); + if(lst->getOperatorType() == ITM_REFERENCE) { if((((ColReference*)lst)->getColRefNameObj()).getColName() == "CONNECT_BY_ISLEAF") diff --git a/core/sql/optimizer/RelExpr.h b/core/sql/optimizer/RelExpr.h index 6c0b9e9cdb..b5d71b5717 100644 --- a/core/sql/optimizer/RelExpr.h +++ b/core/sql/optimizer/RelExpr.h @@ -1416,6 +1416,11 @@ class RelExpr : public ExprNode NABoolean expandShortRows() { return ((flags_ & EXPAND_SHORT_ROWS) != 0); } + void setHasConnectByFlag(NABoolean val) + { (val ? (flags_ |= HAS_CONNECT_BY) : (flags_ &= ~HAS_CONNECT_BY)); } + + NABoolean hasConnectByFlag() + { return ((flags_ & HAS_CONNECT_BY) != 0); } // For compressed internal format. // At codegen some nodes will switch from compressed internal format to // the exploded format when they are directly beneath the root node. @@ -1444,6 +1449,7 @@ class RelExpr : public ExprNode enum Flags { EXPAND_SHORT_ROWS = 0x00000001 // expand short rows when added columns ,PARENT_IS_ROOT = 0x00000002 // compressed internal format + ,HAS_CONNECT_BY = 0x00000004 // compressed internal format }; // every relational expression node has the ability to perform diff --git a/core/sql/optimizer/RelScan.h b/core/sql/optimizer/RelScan.h index e51af9bbdf..655bd0377f 100644 --- a/core/sql/optimizer/RelScan.h +++ b/core/sql/optimizer/RelScan.h @@ -600,10 +600,6 @@ class Scan : public RelExpr void setForceInverseOrder(NABoolean v=TRUE) { (v ? scanFlags_ |= FORCE_INVERSE_ORDER : scanFlags_ &= ~FORCE_INVERSE_ORDER); } - NABoolean hasConnectBy() const { return (scanFlags_ & HAS_CONNECT_BY) != 0; } - void setHasConnectBy(NABoolean v=TRUE) - { (v ? scanFlags_ |= HAS_CONNECT_BY: scanFlags_ &= ~HAS_CONNECT_BY); } - void setExtraOutputColumns(ValueIdSet outputCols) { extraOutputColumns_ = outputCols; } const ValueIdSet& getExtraOutputColumns() const @@ -691,8 +687,7 @@ class Scan : public RelExpr // operation (ex., UPDATE becomes UPDATE(SCAN) in parser), // then no security check is needed. enum ScanFlags { NO_SECURITY_CHECK = 0x0001, - FORCE_INVERSE_ORDER = 0x0002, - HAS_CONNECT_BY = 0x0004}; + FORCE_INVERSE_ORDER = 0x0002}; Cardinality baseCardinality_; // from table statistics diff --git a/core/sql/parser/ParKeyWords.cpp b/core/sql/parser/ParKeyWords.cpp index e9bf3de6a3..5196f45a87 100644 --- a/core/sql/parser/ParKeyWords.cpp +++ b/core/sql/parser/ParKeyWords.cpp @@ -272,7 +272,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("CONDITION_NUMBER", TOK_CONDITION_NUMBER, NONRESTOKEN_), ParKeyWord("CONFIG", TOK_CONFIG, NONRESTOKEN_), ParKeyWord("CONFLICT", TOK_CONFLICT, SECOND_|NONRESTOKEN_), - ParKeyWord("CONNECT", TOK_CONNECT, ANS_|NONRESTOKEN_), + ParKeyWord("CONNECT", CONNECT_IDENTIFIER, ANS_|NONRESTOKEN_), // ParKeyWord("CONNECTION", IDENTIFIER, ANS_|RESWORD_), ParKeyWord("CONNECTION_NAME", TOK_CONNECTION_NAME, NONRESTOKEN_), ParKeyWord("CONSTRAINT", TOK_CONSTRAINT, ANS_|RESWORD_), @@ -863,7 +863,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("PREPARE", TOK_PREPARE, ANS_|RESWORD_), ParKeyWord("PRESERVE", TOK_PRESERVE, ANS_|RESWORD_), ParKeyWord("PRIMARY", TOK_PRIMARY, FIRST_|ANS_|RESWORD_), - ParKeyWord("PRIOR", TOK_PRIOR, ANS_), + ParKeyWord("PRIOR", PRIOR_IDENTIFIER, ANS_), ParKeyWord("PRIORITY", TOK_PRIORITY, NONRESTOKEN_), ParKeyWord("PRIORITY_DELTA", TOK_PRIORITY_DELTA, NONRESTOKEN_), ParKeyWord("PRIVATE", TOK_PRIVATE, NONRESTOKEN_), diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 748dfd153a..af044f0430 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -946,7 +946,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_PREFER_FOR_SCAN_KEY %token TOK_PREPARE %token TOK_PRESERVE /* TD extension that HP wants to ignore */ -%token TOK_PRIOR +%token PRIOR_IDENTIFIER %token TOK_PRIORITY %token TOK_PRIORITY_DELTA %token TOK_PROCEDURE @@ -1257,7 +1257,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_COMPONENTS %token TOK_COMPRESSION %token TOK_CONFIG /* Tandem extension */ -%token TOK_CONNECT /* Tandem extension */ +%token CONNECT_IDENTIFIER /* Tandem extension */ %token TOK_CONSTRAINT %token TOK_CONSTRAINTS %token TOK_COPY @@ -13303,7 +13303,7 @@ table_expression : from_clause where_clause sample_clause SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); ((BiConnectBy*)$2)->where_clause = $3; ((Scan*)$$)->setBiConnectBy( (BiConnectBy*)$2); - ((Scan*)$$)->setHasConnectBy(TRUE); + $$->setHasConnectByFlag(TRUE); } /* type relx */ from_clause : TOK_FROM global_hint table_reference { $$ = $3; } @@ -13312,24 +13312,24 @@ from_clause : TOK_FROM global_hint table_reference { $$ = $3; } $$ = new (PARSERHEAP()) Join($1, $3, REL_JOIN); } -startwith_clause :TOK_START_WITH predicate TOK_CONNECT TOK_BY predicate +startwith_clause :TOK_START_WITH predicate CONNECT_IDENTIFIER TOK_BY predicate { $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$5); //save the predicate text $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); } - |TOK_START_WITH predicate TOK_CONNECT TOK_BY TOK_NOCYCLE predicate + |TOK_START_WITH predicate CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE predicate { $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$6); //save the predicate text $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); ((BiConnectBy*)$$)->setNoCycle(TRUE); } - | TOK_CONNECT TOK_BY predicate + | CONNECT_IDENTIFIER TOK_BY predicate { $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$3); } - | TOK_CONNECT TOK_BY TOK_NOCYCLE predicate + | CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE predicate { $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$4); ((BiConnectBy*)$$)->setNoCycle(TRUE); @@ -13866,7 +13866,7 @@ set_quantifier : { $$ = FALSE; /* by default, set quantifier is ALL */ /* type relx */ query_spec_body : query_select_list table_expression access_type optional_lock_mode { - if( ! ((Scan *)$2)->hasConnectBy()) { + if( $2->hasConnectByFlag() == FALSE ) { // use a compute node to attach select list RelRoot *temp= new (PARSERHEAP()) @@ -13923,6 +13923,7 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ } else euc->setHasConnectByPath(FALSE); + if($1) if( euc->containsIsLeaf($1) || euc->containsIsLeaf(((Scan*)$2)->getBiConnectBy()->where_clause) ) { euc->setHasIsLeaf(TRUE); @@ -19296,7 +19297,7 @@ comparison_predicate : { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } | row_subquery comparison_operator value_expression_list_paren { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } - | TOK_PRIOR value_expression comparison_operator value_expression + | PRIOR_IDENTIFIER value_expression comparison_operator value_expression { $$ = new (PARSERHEAP()) BiConnectByRelat($3, $2, $4); NAString pn, cn; $2->unparse(pn, PARSER_PHASE, USER_FORMAT); @@ -19304,7 +19305,7 @@ comparison_predicate : ( (BiConnectByRelat*)$$)->setParentColName((char*)pn.data()); ( (BiConnectByRelat*)$$)->setChildColName((char*)cn.data()); } - | value_expression comparison_operator TOK_PRIOR value_expression + | value_expression comparison_operator PRIOR_IDENTIFIER value_expression { $$ = new (PARSERHEAP()) BiConnectByRelat($2, $1, $4); NAString pn, cn; $4->unparse(pn, PARSER_PHASE, USER_FORMAT); diff --git a/core/sql/regress/executor/EXPECTED021.SB b/core/sql/regress/executor/EXPECTED021.SB index 27cb668dce..4740cdf902 100644 --- a/core/sql/regress/executor/EXPECTED021.SB +++ b/core/sql/regress/executor/EXPECTED021.SB @@ -93,7 +93,7 @@ DEPID DEPNAME U --- 5 row(s) selected. >> >>--nocycle test ->>SELECT * , "CONNECT_BY_ISCYCLE" FROM t021t1 START WITH depid = 11 CONNECT BY NOCYCLE PRIOR DEPID = UPPERDEPID; +>>SELECT * , CONNECT_BY_ISCYCLE FROM t021t1 START WITH depid = 11 CONNECT BY NOCYCLE PRIOR DEPID = UPPERDEPID; DEPID DEPNAME UPPERDEPID CONNECT_BY_ISCYCLE ----------- ---------------------------------------------------------------- ----------- ------------------ @@ -144,4 +144,37 @@ DEPID DEPNAME U 1 world ? --- 10 row(s) selected. +>> +>>--test isleaf: return only those leaf rows +>>SELECT * FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID where CONNECT_BY_ISLEAF = 1; + +DEPID DEPNAME UPPERDEPID +----------- ---------------------------------------------------------------- ----------- + + 6 NY 3 + 8 ChangNing 5 + 9 JingAn 5 + 10 D1 7 + +--- 4 row(s) selected. +>> +>>--test path +>>SELECT *, cast( SYS_CONNECT_BY_PATH(depname,'/') as char(30)) FROM t021t1 CONNECT BY PRIOR DEPID = UPPERDEPID ; + +DEPID DEPNAME UPPERDEPID (EXPR) +----------- ---------------------------------------------------------------- ----------- ------------------------------------------------------------------------------------------------------------------------ + + 1 world ? world + 2 china 1 world/china + 3 US 1 world/US + 4 UK 1 world/UK + 5 ShangHai 2 world/china/ShangHai + 6 NY 3 world/US/NY + 7 London 4 world/UK/London + 8 ChangNing 5 world/china/ShangHai/ChangNing + 9 JingAn 5 world/china/ShangHai/JingAn + 10 D1 7 world/UK/London/D1 + +--- 10 row(s) selected. +>> >>log; From 26d9b063eb97c71daa45e3fd32e3dc7305868064 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Fri, 10 Aug 2018 09:11:35 +0000 Subject: [PATCH 13/17] fix regression test case and remove some dead code --- core/sql/optimizer/BindRelExpr.cpp | 71 ++-------------------------- core/sql/optimizer/ItemLog.h | 6 --- core/sql/parser/sqlparser.y | 26 ---------- core/sql/regress/core/EXPECTED037.SB | 4 -- 4 files changed, 4 insertions(+), 103 deletions(-) diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index c66a05f630..3805cce934 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -2505,62 +2505,7 @@ RelExpr *RelExpr::bindSelf(BindWA *bindWA) if (bindWA->inViewWithCheckOption()) bindWA->predsOfViewWithCheckOption() += selectionPred(); } -#if 0 - ItemExpr *startWithTree = removeStartWithTree(); - if (startWithTree) { - bindWA->getCurrentScope()->context()->inWhereClause() = TRUE; - startWithTree->convertToValueIdSet(getStartWith(), bindWA, ITM_AND); - bindWA->getCurrentScope()->context()->inWhereClause() = FALSE; - - if (bindWA->errStatus()) return this; - - // If this is an embedded insert, then subquery predicates are not - // allowed. - // For example: To handle this query and issue an error stating - // subqueries are not allowed in embedded inserts - // - // select a from (insert into t901t01 values(22,22,222))t(a,b,c) - // where t.a IN (select m from t901t03 where t901t03.m = 77); - - if (getGroupAttr()->isEmbeddedInsert()) - { - if (!getStartWith().isEmpty() && getStartWith().containsSubquery()) - { - *CmpCommon::diags() << DgSqlCode(-4337); - bindWA->setErrStatus(); - return this; - } - } - } - - ItemExpr *connectByTree = removeConnectByTree(); - if (connectByTree) { - - bindWA->getCurrentScope()->context()->inWhereClause() = TRUE; - connectByTree->convertToValueIdSet(getConnectBy(), bindWA, ITM_AND); - bindWA->getCurrentScope()->context()->inWhereClause() = FALSE; - - if (bindWA->errStatus()) return this; - // If this is an embedded insert, then subquery predicates are not - // allowed. - // For example: To handle this query and issue an error stating - // subqueries are not allowed in embedded inserts - // - // select a from (insert into t901t01 values(22,22,222))t(a,b,c) - // where t.a IN (select m from t901t03 where t901t03.m = 77); - - if (getGroupAttr()->isEmbeddedInsert()) - { - if (!getConnectBy().isEmpty() && getConnectBy().containsSubquery()) - { - *CmpCommon::diags() << DgSqlCode(-4337); - bindWA->setErrStatus(); - return this; - } - } - } -#endif // ++MV // Bind the uniqueColumnsTree expression. // @@ -4643,19 +4588,11 @@ RelRoot * RelRoot::transformGroupByWithOrdinalPhase2(BindWA *bindWA) // make sure child of root is a groupby node or a sequence node // whose child is a group by node - if(child(0)) -{ - if (child(0)->getOperatorType() != REL_GROUPBY) - { - - if (child(0)->getOperatorType() != REL_SEQUENCE ) return this; - if (child(0)->child(0) ) - if (child(0)->child(0) && child(0)->child(0)->getOperatorType()!=REL_GROUPBY) - return this; - } -} - else + if (child(0)->getOperatorType() != REL_GROUPBY && + (child(0)->getOperatorType() != REL_SEQUENCE || + (child(0)->child(0) && child(0)->child(0)->getOperatorType()!=REL_GROUPBY))) return this; + GroupByAgg * grby; RelSequence * seqNode=NULL; diff --git a/core/sql/optimizer/ItemLog.h b/core/sql/optimizer/ItemLog.h index 20d2082fc1..065665a6f3 100644 --- a/core/sql/optimizer/ItemLog.h +++ b/core/sql/optimizer/ItemLog.h @@ -345,7 +345,6 @@ class BiRelat : public ItemExpr outerNullFilteringDetected_ (FALSE), innerNullFilteringDetected_ (FALSE), rollupColumnNum_(-1), - prior_(0), flags_(0) { #ifndef NDEBUG @@ -612,9 +611,6 @@ class BiRelat : public ItemExpr void setAddedForLikePred(NABoolean v) { (v ? flags_ |= FOR_LIKE : flags_ &= ~FOR_LIKE); } - void setPrior(Int8 v) { prior_ = v; } - Int8 getPrior() { return prior_; } - private: // helper to change literals of a cacheable query into input parameters @@ -732,8 +728,6 @@ class BiRelat : public ItemExpr // Used to return the rollup groups. Int16 rollupColumnNum_; - Int8 prior_; - UInt32 flags_; }; // class BiRelat diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index af044f0430..8cff3e1603 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -13972,32 +13972,6 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ AssignmentHostVars->clear(); $$ = temp; } -/* - |query_select_list from_clause startwith connect_by where_clause access_type optional_lock_mode - { - CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; - NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & - , PARSERHEAP() // in - NAMemory * - ); - //remove ';' - UInt32 pos = - stmt->index(";", 0, NAString::ignoreCase); - stmt->remove(pos); - - ExeUtilConnectby *euc = new (PARSERHEAP()) - ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), (char*) stmt->data(), - stmtCharSet, $2,PARSERHEAP()); - - $2->addConnectByExprTree($4); - $2->addStartWithExprTree($3); - RelRoot *temp = new (PARSERHEAP()) - RelRoot(euc, REL_ROOT , $1); - euc->connectByTree_ = $4; - if($3 == NULL) - euc->hasStartWith_ = FALSE; - $$ = temp; -} -*/ //++ MV OZ // type item diff --git a/core/sql/regress/core/EXPECTED037.SB b/core/sql/regress/core/EXPECTED037.SB index 6649293979..228f11bb6e 100755 --- a/core/sql/regress/core/EXPECTED037.SB +++ b/core/sql/regress/core/EXPECTED037.SB @@ -504,8 +504,6 @@ SELECT COMPLETION COMPLETION from (values(0)) COMPLETION(COMPLETION); >>-- Expect error [3128] >>prepare s1 from SELECT CONNECT CONNECT from (values(0)) CONNECT(CONNECT); -*** ERROR[3128] CONNECT is a reserved word. It must be delimited by double-quotes to be used as an identifier. - *** ERROR[15001] A syntax error occurred at or before: SELECT CONNECT CONNECT from (values(0)) CONNECT(CONNECT); ^ (22 characters from start of SQL statement) @@ -873,8 +871,6 @@ SELECT PRESERVE PRESERVE from (values(0)) PRESERVE(PRESERVE); >>-- Expect error [3128] >>prepare s1 from SELECT PRIOR PRIOR from (values(0)) PRIOR(PRIOR); -*** ERROR[3128] PRIOR is a reserved word. It must be delimited by double-quotes to be used as an identifier. - *** ERROR[15001] A syntax error occurred at or before: SELECT PRIOR PRIOR from (values(0)) PRIOR(PRIOR); ^ (18 characters from start of SQL statement) From 6dd9c8e92e0d2150735c66285c94a3d445ba739d Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sat, 11 Aug 2018 12:11:33 +0000 Subject: [PATCH 14/17] handle the null value --- core/sql/executor/ExExeUtilConnectby.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 9c31229401..41f0d40772 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -119,14 +119,15 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf short retcode = 0, rc =0; char * ptr; Lng32 len; - short nullInd = 0; - short *ind ; - ind = &nullInd; + short nullind=0; + short *pn = &nullind; + short **ind = &pn; UInt32 vcActualLen = 0; - for (UInt32 i = 2; i < tDesc->numAttrs() - 2 ; i++) + for (UInt32 i = 2; i < tDesc->numAttrs() - 2 ; i++) //bypass first two columns and ignore the last three system columns { - cliInterface()->getPtrAndLen(i+1, ptr, len,&ind); + cliInterface()->getPtrAndLen(i+1, ptr, len,ind); + char * src = ptr; Attributes * attr = tDesc->getAttr(i-1); short srcType = 0; @@ -134,7 +135,7 @@ short ExExeUtilConnectbyTcb::emitRow(ExpTupleDesc * tDesc, int level, int isleaf short valIsNull = 0; srcType = attr->getDatatype(); srcLen = len; - if (len == 0 ) valIsNull = -1; + if (((char*)*ind)[0] == -1) valIsNull = -1; if (attr->getNullFlag()) { @@ -283,8 +284,8 @@ short ExExeUtilConnectbyTcb::emitPrevRow(ExpTupleDesc * tDesc, int level, int is char * ptr; Lng32 len; short nullInd = 0; - short *ind ; - ind = &nullInd; + short *ind = &nullInd ; + short **indadd = &ind; UInt32 vcActualLen = 0; //get the item Queue * thatone; From d6fb4193627e90e9b5dd1a25b7b40302dce4854f Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sat, 25 Aug 2018 02:32:15 +0000 Subject: [PATCH 15/17] rework the compiler part, move the processing into binder to support JOIN --- core/sql/common/BaseTypes.h | 2 +- core/sql/executor/ExExeUtilConnectby.cpp | 15 ++- core/sql/generator/GenRelExeUtil.cpp | 15 ++- core/sql/optimizer/BindItemExpr.cpp | 5 +- core/sql/optimizer/BindRelExpr.cpp | 128 +++++++++++++++++++ core/sql/optimizer/BindWA.cpp | 2 + core/sql/optimizer/BindWA.h | 10 ++ core/sql/optimizer/ItemColRef.h | 2 + core/sql/optimizer/ItemExpr.cpp | 42 ++++-- core/sql/optimizer/ItemLog.h | 10 +- core/sql/optimizer/ItemOther.h | 4 + core/sql/optimizer/RelExeUtil.cpp | 6 +- core/sql/optimizer/RelExeUtil.h | 8 +- core/sql/optimizer/RelExpr.cpp | 2 + core/sql/optimizer/RelExpr.h | 10 ++ core/sql/optimizer/RelScan.h | 17 +-- core/sql/optimizer/ValueDesc.cpp | 3 +- core/sql/parser/ParKeyWords.cpp | 1 + core/sql/parser/sqlparser.y | 155 ++++++++++++----------- 19 files changed, 323 insertions(+), 114 deletions(-) diff --git a/core/sql/common/BaseTypes.h b/core/sql/common/BaseTypes.h index 3547035840..9025f47aef 100644 --- a/core/sql/common/BaseTypes.h +++ b/core/sql/common/BaseTypes.h @@ -212,7 +212,7 @@ enum UnparseFormatEnum { USER_FORMAT, EXPLAIN_FORMAT, FILE_FORMAT, USER_FORMAT_DELUXE, ERROR_MSG_FORMAT, MVINFO_FORMAT, MV_SHOWDDL_FORMAT, QUERY_FORMAT, COMPUTED_COLUMN_FORMAT, - HIVE_MD_FORMAT }; + HIVE_MD_FORMAT, CONNECT_BY_FORMAT }; // ----------------------------------------------------------------------- // Used to display optimizer statistics, and other debugging statements diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index 41f0d40772..cf8058eb0a 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -411,7 +411,7 @@ short ExExeUtilConnectbyTcb::emitPrevRow(ExpTupleDesc * tDesc, int level, int is Lng32 dlen = strlen(exeUtilTdb().delimiter_.data()); Queue *pathq = new(getHeap()) Queue(getHeap()) ;; if (exeUtilTdb().hasPath_ == TRUE) { - ti->get(2, ptr, len); + ti->get(1, ptr, len); pathq->insert(ptr); pathlength = len; for(int ii = level - 1 ; ii > 0; ii--) @@ -585,6 +585,11 @@ short ExExeUtilConnectbyTcb::work() } //populate the seedQueue and currArray rootRow->position(); + if(rootRow->numEntries() == 0 ) + { + step_ = DONE_; + break; + } for(int i1 = 0; i1 < rootRow->numEntries(); i1 ++) { @@ -677,6 +682,12 @@ short ExExeUtilConnectbyTcb::work() } cliInterface()->fetchRowsEpilogue(0, FALSE); } + + if(seedQueue_->numEntries() == 0 ) + { + step_ = DONE_; + break; + } currQueue_ = getCurrQueue(currRootId_, seedQueue_); currArray[0] = currQueue_; @@ -808,6 +819,8 @@ short ExExeUtilConnectbyTcb::work() }//if(rc1== 0) else if(rc1 == 1) { + thisQueue_->insert(it); + matchRowNum++; loopDetected = 1; if(exeUtilTdb().noCycle_ == FALSE) { ComDiagsArea * diags = getDiagsArea(); diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index b994d1b3fa..8d47f1606b 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5448,17 +5448,17 @@ short ExeUtilConnectby::codeGen(Generator * generator) ); exe_util_tdb->sourceDataTuppIndex_ = outputAtpIndex; - exe_util_tdb->parentColName_ = parentColName_; - exe_util_tdb->childColName_ = childColName_; + exe_util_tdb->parentColName_ = parentColName_; // ((BiConnectBy*)getBiConnectBy())->getConnectBy()->getParentColName(); + exe_util_tdb->childColName_ = childColName_; // ((BiConnectBy*)getBiConnectBy())->getConnectBy()->getChildColName(); exe_util_tdb->hasStartWith_ = hasStartWith_; exe_util_tdb->startWithExprString_ = startWithExprString_; exe_util_tdb->noCycle_ = noCycle_; - if(hasConnectByPath()) + if(generator->getBindWA()->connectByHasPath_) { exe_util_tdb->hasPath_ = TRUE; - exe_util_tdb->pathColName_ = pathColName_; - exe_util_tdb->delimiter_ = delimiter_; + exe_util_tdb->pathColName_ = generator->getBindWA()->connectByPathCol_; + exe_util_tdb->delimiter_ = generator->getBindWA()->connectByPathDel_; } else { @@ -5466,11 +5466,12 @@ short ExeUtilConnectby::codeGen(Generator * generator) exe_util_tdb->pathColName_ = "0"; exe_util_tdb->delimiter_ = " "; } - - if(hasIsLeaf()) + if(generator->getBindWA()->connectByHasIsLeaf_) { exe_util_tdb->hasIsLeaf_ = TRUE; } + else + exe_util_tdb->hasIsLeaf_ = FALSE; generator->initTdbFields(exe_util_tdb); diff --git a/core/sql/optimizer/BindItemExpr.cpp b/core/sql/optimizer/BindItemExpr.cpp index 70a9b58a13..e32faa6396 100644 --- a/core/sql/optimizer/BindItemExpr.cpp +++ b/core/sql/optimizer/BindItemExpr.cpp @@ -1791,7 +1791,7 @@ ItemExpr *ItemExpr::bindNode(BindWA *bindWA) if (bindWA->errStatus()) return this; ItemExpr* exp = this; - + // A quick way to determine whether we should worry about relaxation. // Only comparison and assign operators, SQL string functions are the // candidates. @@ -13613,6 +13613,9 @@ NABoolean RowNumFunc::canBeUsedInGBorOB(NABoolean setErr) ItemExpr *ItmSysConnectByPathFunc::bindNode(BindWA *bindWA) { + bindWA->connectByHasPath_=TRUE; + bindWA->connectByPathCol_ = getPathColumnName(); + bindWA->connectByPathDel_ = getDelimiter(); return ZZZBinderFunction::bindNode(bindWA); } diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index 3805cce934..ffdca79419 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -2409,6 +2409,9 @@ void RelExpr::bindChildren(BindWA *bindWA) for (Int32 i = 0; i < arity; i++) { if (child(i)) { + //push the connect by down + if(getBiConnectBy() != NULL) + child(i)->setBiConnectBy(getBiConnectBy()); // If doing a non-first child and the operator is // NOT one in which values/names can flow from one scope // the sibling scope, then we must clear the current RETDesc @@ -2506,6 +2509,19 @@ RelExpr *RelExpr::bindSelf(BindWA *bindWA) bindWA->predsOfViewWithCheckOption() += selectionPred(); } + predTree = getBiConnectBy(); + if (predTree) { + predTree = ((BiConnectBy *)predTree)->getConnectBy(); + bindWA->getCurrentScope()->context()->inWhereClause() = TRUE; + predTree->convertToValueIdSet(connectByPred(), bindWA, ITM_AND); + bindWA->getCurrentScope()->context()->inWhereClause() = FALSE; + if (bindWA->errStatus()) + { + connectByPred().clear(); + bindWA->resetErrStatus(); + } + } + // ++MV // Bind the uniqueColumnsTree expression. // @@ -5331,6 +5347,7 @@ RelExpr *RelRoot::bindNode(BindWA *bindWA) return this; } + if (isTrueRoot()) { // if this is simple scalar aggregate on a seabase table @@ -6352,6 +6369,21 @@ RelExpr *RelRoot::bindNode(BindWA *bindWA) } } + for (Lng32 selIndex = 0; selIndex < compExpr().entries(); selIndex++) + { + ItemExpr * ie = compExpr()[selIndex].getItemExpr(); + if(ie->getOperatorType() == ITM_REFERENCE ) + { + if((((ColReference*)ie)->getColRefNameObj()).getColName() == "CONNECT_BY_ISLEAF") + bindWA->connectByHasIsLeaf_=TRUE; + } + if(ie->getOperatorType() == ITM_BASECOLUMN) + { + if(((BaseColumn *)ie)->getColName() == "CONNECT_BY_ISLEAF") + bindWA->connectByHasIsLeaf_=TRUE; + } + } + if (hasPartitionBy()) { ItemExpr *partByTree = removePartitionByTree(); @@ -8209,6 +8241,7 @@ RelExpr *Scan::bindNode(BindWA *bindWA) // Bind the base class. // RelExpr *boundExpr = bindSelf(bindWA); + if (bindWA->errStatus()) return this; // @@ -8365,6 +8398,101 @@ RelExpr *Scan::bindNode(BindWA *bindWA) ); } } + //CONNECT BY + //If this node has connectByPred this is the Scan + if(connectByPred().entries() >0 ) + { + int match = 0; + for (ValueId exprId = connectByPred().init(); connectByPred().next(exprId); connectByPred().advance(exprId)) + { + for(int j= 0; j< exprId.getItemExpr()->getArity(); j++) + { + ValueId vid = exprId.getItemExpr()->child(j).getValueId(); + for (CollIndex i = 0; i < getTableDesc()->getColumnList().entries(); i++) + { + ValueId valId = getTableDesc()->getColumnList()[i]; + if (valId == vid ) + { + match = 1; break; + } + } + if(match == 1) break; + } + if(match == 1) break; + } + if(match == 1) + { + + ExeUtilConnectby* euc = new (bindWA->wHeap()) + ExeUtilConnectby(getTableName(), NULL, + CharInfo::DefaultCharSet , NULL , bindWA->wHeap()); + ((ExeUtilConnectby*)euc)->scan_ = this; + + ((ExeUtilConnectby*)euc)->myQualTbl_= getTableName().getQualifiedNameObj().getObjectName(); + ((ExeUtilConnectby*)euc)->myQualCat_= getTableName().getQualifiedNameObj().getCatalogName(); + ((ExeUtilConnectby*)euc)->myQualSch_= getTableName().getQualifiedNameObj().getSchemaName(); + if(getTableName().getCorrNameAsString() != "") + ((ExeUtilConnectby*)euc)->myTableName_ = getTableName().getCorrNameAsString(); + else + ((ExeUtilConnectby*)euc)->myTableName_ = getTableName().getQualifiedNameObj().getObjectName(); + + NAString pname; + ((BiConnectBy*)getBiConnectBy())->getConnectBy()->getParentColIE()->unparse(pname,OPTIMIZER_PHASE,CONNECT_BY_FORMAT); + + ((ExeUtilConnectby*)euc)->parentColName_= pname; + NAString cname ; + ((BiConnectBy*)getBiConnectBy())->getConnectBy()->getChildColIE()->unparse(cname,BINDER_PHASE,CONNECT_BY_FORMAT); + ((ExeUtilConnectby*)euc)->childColName_ = cname; + ((ExeUtilConnectby*)euc)->myselection_= ((BiConnectBy*)getBiConnectBy())->where_clause; + ((ExeUtilConnectby*)euc)->noCycle_= ((BiConnectBy*)getBiConnectBy())->getNoCycle(); + + bindWA->getCurrentScope()->getXTNM()->remove(&getTableName()); + boundExpr=euc->bindNode(bindWA); + + for (ValueId exprId = euc->mypredicates_.init(); euc->mypredicates_.next(exprId); euc->mypredicates_.advance(exprId)) + { + ItemExpr * ie = exprId.getItemExpr(); + if(ie->getOperatorType() == ITM_REFERENCE ) + { + if((((ColReference*)ie)->getColRefNameObj()).getColName() == "CONNECT_BY_ISLEAF") + bindWA->connectByHasIsLeaf_=TRUE; + } + if(ie->getOperatorType() == ITM_BASECOLUMN) + { + if(((BaseColumn *)ie)->getColName() == "CONNECT_BY_ISLEAF") + bindWA->connectByHasIsLeaf_=TRUE; + } + + for(int j= 0; j< exprId.getItemExpr()->getArity(); j++) + { + ValueId vid = exprId.getItemExpr()->child(j).getValueId(); + ItemExpr * ie = exprId.getItemExpr()->child(j); + if(ie->getOperatorType() == ITM_REFERENCE ) + { + if((((ColReference*)ie)->getColRefNameObj()).getColName() == "CONNECT_BY_ISLEAF") + bindWA->connectByHasIsLeaf_=TRUE; + } + if(ie->getOperatorType() == ITM_BASECOLUMN) + { + if(((BaseColumn *)ie)->getColName() == "CONNECT_BY_ISLEAF") + bindWA->connectByHasIsLeaf_=TRUE; + } + } + } + if(((BiConnectBy*)getBiConnectBy())->getStartWith() == NULL) + { + ((ExeUtilConnectby *)euc)->hasStartWith_ = FALSE; + } + else + { + ((ExeUtilConnectby*)euc)->hasStartWith_ = TRUE; + NAString startstr; + ((BiConnectBy*)getBiConnectBy())->getStartWith()->bindNode(bindWA); + ((BiConnectBy*)getBiConnectBy())->getStartWith()->unparse(startstr,OPTIMIZER_PHASE,CONNECT_BY_FORMAT); + ((ExeUtilConnectby*)euc)->startWithExprString_ = startstr; + } + } + } return boundExpr; } // Scan::bindNode() diff --git a/core/sql/optimizer/BindWA.cpp b/core/sql/optimizer/BindWA.cpp index a6e19d8ceb..6f8ec0adf6 100644 --- a/core/sql/optimizer/BindWA.cpp +++ b/core/sql/optimizer/BindWA.cpp @@ -188,6 +188,8 @@ BindWA::BindWA(SchemaDB *schemaDB, CmpContext* cmpContext, NABoolean inDDL, NABo , outerAggScope_(NULL) , hasCallStmts_(FALSE) , isTrafLoadPrep_(FALSE) + , connectByHasPath_(FALSE) + , connectByHasIsLeaf_(FALSE) , flags_(0) , udfList_(wHeap()) { diff --git a/core/sql/optimizer/BindWA.h b/core/sql/optimizer/BindWA.h index 45b24087bc..54e9f3b4c6 100644 --- a/core/sql/optimizer/BindWA.h +++ b/core/sql/optimizer/BindWA.h @@ -1704,6 +1704,14 @@ class BindWA : public NABasicObject const NAString & getISPExecLocation() const { return ISPExecLocation_ ;} + //ValueIdSet & connectByPred() { return connectByPredicate_; } + + NAString connectByPathCol_; + NAString connectByPathDel_; + + NABoolean connectByHasPath_; + NABoolean connectByHasIsLeaf_; + private: // -------------------------------------------------------------------- @@ -2002,6 +2010,8 @@ class BindWA : public NABasicObject NAString ISPExecLocation_; +// ValueIdSet connectByPredicate_; + }; // class BindWA class HbaseColUsageInfo : public NABasicObject diff --git a/core/sql/optimizer/ItemColRef.h b/core/sql/optimizer/ItemColRef.h index 783d3276ab..8fcff45837 100644 --- a/core/sql/optimizer/ItemColRef.h +++ b/core/sql/optimizer/ItemColRef.h @@ -133,6 +133,8 @@ class BaseColumn : public ItemExpr const NAString getTextForQuery() const; + const NAString getTextForConnectBy() const; + // return set of keyColumns referenced in the Computed Column expression void getUnderlyingColumnsForCC(ValueIdSet &underlyingCols); diff --git a/core/sql/optimizer/ItemExpr.cpp b/core/sql/optimizer/ItemExpr.cpp index 22efd94c3e..037cca8553 100644 --- a/core/sql/optimizer/ItemExpr.cpp +++ b/core/sql/optimizer/ItemExpr.cpp @@ -2296,6 +2296,10 @@ void ItemExpr::computeKwdAndFlags( NAString &kwd, else kwd = getText(); } + else if (form == CONNECT_BY_FORMAT) + { + kwd = ((BaseColumn *)this)->getTextForConnectBy(); + } else if ((form == COMPUTED_COLUMN_FORMAT) || (form == HIVE_MD_FORMAT)) kwd = ToAnsiIdentifier(((BaseColumn *)this)->getColName()); @@ -2314,7 +2318,7 @@ void ItemExpr::computeKwdAndFlags( NAString &kwd, kwd = ToAnsiIdentifier(((NamedTypeToItem *)this)->getText()); } else if (( operatorType == ITM_CACHE_PARAM) && - (form == QUERY_FORMAT) ) + (form == QUERY_FORMAT || form == CONNECT_BY_FORMAT) ) ((ConstantParameter *)this)->getConstVal()->unparse(kwd, phase, QUERY_FORMAT, tabId); else kwd = getText(); @@ -2359,7 +2363,7 @@ void ItemExpr::computeKwdAndFlags( NAString &kwd, case ITM_MINUS: if (((BiArith *) this)->isDateMathFunction() && (form == QUERY_FORMAT || - form == COMPUTED_COLUMN_FORMAT)) + form == COMPUTED_COLUMN_FORMAT || form == CONNECT_BY_FORMAT)) { // this is not a regular addition or subtractions, it's // a datetime function with special handling of the last @@ -2394,7 +2398,7 @@ void ItemExpr::computeKwdAndPostfix( NAString &kwd, { case ITM_CAST: { - if (form == QUERY_FORMAT || form == COMPUTED_COLUMN_FORMAT) + if (form == QUERY_FORMAT || form == CONNECT_BY_FORMAT|| form == COMPUTED_COLUMN_FORMAT) { kwd += "("; postfix = " AS "; @@ -2573,12 +2577,14 @@ void ItemExpr::unparse(NAString &result, computeKwdAndFlags( kwd, prefixFns, specialPrefixFns, phase, form, tabId ); + OperatorTypeEnum operatorType = getOperatorType(); Int32 arity = getArity(); if (operatorType != origOpType() && form == QUERY_FORMAT || + form == CONNECT_BY_FORMAT || form == COMPUTED_COLUMN_FORMAT) { // handle some cases where the original function was rewritten @@ -2632,6 +2638,7 @@ void ItemExpr::unparse(NAString &result, { if( ((form == MV_SHOWDDL_FORMAT) || (form == QUERY_FORMAT) || + (form == CONNECT_BY_FORMAT) || (form == COMPUTED_COLUMN_FORMAT)) && prefixFns ) { @@ -2658,6 +2665,7 @@ void ItemExpr::unparse(NAString &result, else if ( (operatorType == ITM_TRIM) && ((form == QUERY_FORMAT) || + (form == CONNECT_BY_FORMAT) || (form == COMPUTED_COLUMN_FORMAT))) { result += kwd; @@ -2669,7 +2677,7 @@ void ItemExpr::unparse(NAString &result, if((operatorType == ITM_ITEM_LIST || operatorType == ITM_AND) && (form != MV_SHOWDDL_FORMAT) && - (form != QUERY_FORMAT) ) + (form != QUERY_FORMAT && form != CONNECT_BY_FORMAT) ) { if (child(0)) child(0)->unparse(result,phase,form, tabId); @@ -4068,6 +4076,12 @@ const NAString BaseColumn::getText() const return name.getColRefAsAnsiString(FALSE, TRUE); } +const NAString BaseColumn::getTextForConnectBy() const { + return + NAString(getTableDesc()->getNATable()->getNAColumnArray()[colNumber_]-> + getColName()); +} + const NAString BaseColumn::getTextForQuery() const { // return the table in the format "table.col" where // table is the physical table name and not the corr @@ -5314,7 +5328,8 @@ void VEGPredicate::unparse(NAString &result, TableDesc * tabId) const { if ((form != MVINFO_FORMAT) && - (form != QUERY_FORMAT)) + (form != QUERY_FORMAT) && + (form != CONNECT_BY_FORMAT) ) { ItemExpr::unparse(result, phase, form, tabId); return; @@ -5326,7 +5341,7 @@ void VEGPredicate::unparse(NAString &result, ValueIdList copyList; CollIndex startIndex; - if (form == QUERY_FORMAT || form == MVINFO_FORMAT) + if (form == QUERY_FORMAT || form == MVINFO_FORMAT || form == CONNECT_BY_FORMAT) startIndex = 0; else startIndex = 1; @@ -5338,7 +5353,7 @@ void VEGPredicate::unparse(NAString &result, ItemExpr *nextExpr = nextMemberId.getItemExpr(); if (nextExpr->getOperatorType() == ITM_INDEXCOLUMN) continue; - if ((form == QUERY_FORMAT) && + if ((form == QUERY_FORMAT || form == CONNECT_BY_FORMAT) && (nextExpr->getOperatorType() == ITM_BASECOLUMN)) { BaseColumn * bs = (BaseColumn *)nextExpr; @@ -5590,7 +5605,7 @@ void VEGReference::unparse(NAString &result, TableDesc * tabId) const { if ((form == EXPLAIN_FORMAT) || (form == MVINFO_FORMAT) || - (form == QUERY_FORMAT)) + (form == QUERY_FORMAT) || (form == CONNECT_BY_FORMAT) ) { // End users won't know what a VegReference is, and // most items in EXPLAIN are already rewritten w/o VEGies. @@ -5608,7 +5623,7 @@ void VEGReference::unparse(NAString &result, vegMembers.advance(someMemberId)) { ItemExpr * someMemberExpr = someMemberId.getItemExpr(); - if (form == QUERY_FORMAT) + if (form == QUERY_FORMAT || form == CONNECT_BY_FORMAT) { // for QUERY_FORMAT, unparse the VEG member that belongs to the // given tableDesc @@ -10893,6 +10908,7 @@ const NAString ConstValue::getTextForQuery(UnparseFormatEnum form) const switch (form) { case QUERY_FORMAT: + case CONNECT_BY_FORMAT: case MV_SHOWDDL_FORMAT: case USER_FORMAT_DELUXE: { @@ -11086,7 +11102,7 @@ void ConstValue::unparse(NAString &result, } result += fullText; } - else if ((form == MVINFO_FORMAT) || (form == QUERY_FORMAT) || + else if ((form == MVINFO_FORMAT) || (form == QUERY_FORMAT) || (form == CONNECT_BY_FORMAT) || (form == MV_SHOWDDL_FORMAT) || (form == COMPUTED_COLUMN_FORMAT)) { if (getType()->getTypeQualifier() == NA_CHARACTER_TYPE) @@ -11100,7 +11116,7 @@ void ConstValue::unparse(NAString &result, if (!textIsValidatedSQLLiteralInUTF8_) result += chType->getCharSetAsPrefix(); - if ((form == MV_SHOWDDL_FORMAT) || (form == QUERY_FORMAT)) + if ((form == MV_SHOWDDL_FORMAT) || (form == QUERY_FORMAT) || (form = CONNECT_BY_FORMAT)) result += getTextForQuery(form); else result += getTextForQuery(); @@ -12209,6 +12225,7 @@ void Case::unparse(NAString &result, // Is this for MV use? if ((form != MV_SHOWDDL_FORMAT) && (form != QUERY_FORMAT) && + (form != CONNECT_BY_FORMAT) && (form != COMPUTED_COLUMN_FORMAT) ) { // No - sorry, use the default code. @@ -12503,6 +12520,7 @@ void IfThenElse::unparse(NAString &result, // Is this for MV use? if ( (form != MV_SHOWDDL_FORMAT) && (form != QUERY_FORMAT) && + (form != CONNECT_BY_FORMAT) && (form != COMPUTED_COLUMN_FORMAT)) { // No - sorry, use the default code. @@ -15007,7 +15025,7 @@ void RangeSpecRef::unparse(NAString &result, TableDesc * tabId) const { // Don't include rangespec op if query format -- it won't parse. - if (form == QUERY_FORMAT || form == COMPUTED_COLUMN_FORMAT) + if (form == QUERY_FORMAT || form == CONNECT_BY_FORMAT || form == COMPUTED_COLUMN_FORMAT) child(1)->unparse(result, phase, form, tabId); else ItemExpr::unparse(result, phase, form, tabId); diff --git a/core/sql/optimizer/ItemLog.h b/core/sql/optimizer/ItemLog.h index 065665a6f3..3ac8ee8360 100644 --- a/core/sql/optimizer/ItemLog.h +++ b/core/sql/optimizer/ItemLog.h @@ -737,21 +737,29 @@ class BiConnectByRelat :public BiRelat { BiConnectByRelat( OperatorTypeEnum otype, ItemExpr *child0 = NULL, ItemExpr *child1 = NULL) - :BiRelat(otype, NULL, NULL) + :BiRelat(otype, child0, child1) { + parentIe_ = NULL; + childIe_ = NULL; } virtual ~BiConnectByRelat() {} void setParentColName(char * v) { parentColName_ = v; } + void setParentColIE(ItemExpr* v) { parentIe_= v; } NAString getParentColName () { return parentColName_; } + ItemExpr* getParentColIE() { return parentIe_; } void setChildColName(char * v) { childColName_ = v; } + void setChildColIE(ItemExpr* v) { childIe_ = v; } NAString getChildColName() { return childColName_ ; } + ItemExpr* getChildColIE() { return childIe_; } private: NAString parentColName_; NAString childColName_; + ItemExpr * parentIe_; + ItemExpr *childIe_; }; class KeyRangeCompare : public BiRelat diff --git a/core/sql/optimizer/ItemOther.h b/core/sql/optimizer/ItemOther.h index 0f4eac462a..516cc0aa3d 100644 --- a/core/sql/optimizer/ItemOther.h +++ b/core/sql/optimizer/ItemOther.h @@ -1142,6 +1142,8 @@ class BiConnectBy :public ItemExpr { { startWith_ = start; connectBy_ = (BiConnectByRelat*)conn; + where_clause = NULL; + order_siblings_by_clause = NULL; } virtual ~BiConnectBy() {} @@ -1153,10 +1155,12 @@ class BiConnectBy :public ItemExpr { NABoolean getNoCycle() {return noCycle_; } NAString startWithString_; ItemExpr * where_clause; + ItemExpr * order_siblings_by_clause; private: BiRelat * startWith_; BiConnectByRelat * connectBy_; + ItemExpr * startWithIe_; NABoolean noCycle_; }; diff --git a/core/sql/optimizer/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index 176fe72b44..e2b999ef90 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6302,17 +6302,15 @@ RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) return this; } RelExpr * boundExpr = NULL; - bindChildren(bindWA); + //bindChildren(bindWA); - scan_->bindNode(bindWA); + //scan_->bindNode(bindWA); boundExpr = ExeUtilExpr::bindNode(bindWA); - if( myselection_ ) { myselection_->bindNode(bindWA); myselection_->convertToValueIdSet(mypredicates_, bindWA, ITM_AND); } - if (bindWA->errStatus()) return NULL; return boundExpr; diff --git a/core/sql/optimizer/RelExeUtil.h b/core/sql/optimizer/RelExeUtil.h index fa84711045..b1ec93249b 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -1112,6 +1112,7 @@ class ExeUtilConnectby : public ExeUtilExpr stmtText, stmtTextCharSet, oHeap) { hasStartWith_ = TRUE; + myselection_ = NULL; noCycle_ = FALSE; scan_ = scan; flags_ = 0; @@ -1159,7 +1160,7 @@ class ExeUtilConnectby : public ExeUtilExpr NABoolean hasConnectByPath() const { return (flags_ & HAS_CONNECT_BY_PATH) != 0; } - ItemExpr *containsPath (ItemExpr * lst ) { + static ItemExpr *containsPath (ItemExpr * lst ) { Int32 arity = lst->getArity(); if(lst->getOperatorType() == ITM_SYS_CONNECT_BY_PATH) { @@ -1175,7 +1176,7 @@ class ExeUtilConnectby : public ExeUtilExpr return NULL; } - NABoolean containsIsLeaf( ItemExpr * lst) { + static NABoolean containsIsLeaf( ItemExpr * lst) { if(lst == NULL) return FALSE; Int32 arity = lst->getArity(); @@ -1203,6 +1204,9 @@ class ExeUtilConnectby : public ExeUtilExpr NABoolean noCycle_; RelExpr * scan_; NAString myTableName_; + NAString myQualCat_; + NAString myQualSch_; + NAString myQualTbl_; NAString pathColName_; NAString delimiter_; diff --git a/core/sql/optimizer/RelExpr.cpp b/core/sql/optimizer/RelExpr.cpp index da3a7c6cae..8f18dfc5ef 100644 --- a/core/sql/optimizer/RelExpr.cpp +++ b/core/sql/optimizer/RelExpr.cpp @@ -288,6 +288,7 @@ RelExpr::RelExpr(OperatorTypeEnum otype, ,cachedResizeCIFRecord_(FALSE) ,dopReduced_(FALSE) ,originalExpr_(NULL) + ,biConnectBy_(NULL) ,operKey_(outHeap) { @@ -857,6 +858,7 @@ RelExpr * RelExpr::copyTopNode(RelExpr *derivedNode,CollHeap* outHeap) result->sourceGroupId_ = sourceGroupId_; result->costLimit_ = costLimit_; result->originalExpr_ = this; + result->biConnectBy_ = biConnectBy_; return result; } diff --git a/core/sql/optimizer/RelExpr.h b/core/sql/optimizer/RelExpr.h index b5d71b5717..51138db580 100644 --- a/core/sql/optimizer/RelExpr.h +++ b/core/sql/optimizer/RelExpr.h @@ -282,7 +282,17 @@ class RelExpr : public ExprNode static const CorrName invalid; virtual inline const CorrName& getTableName()const { return invalid;} + void setBiConnectBy(ItemExpr *b) { biConnectBy_ = b; } + ItemExpr* getBiConnectBy() {return biConnectBy_; } + ItemExpr* removeBiConnectBy() {ItemExpr * result = biConnectBy_; biConnectBy_ = NULL; return result; } + ValueIdSet & startWithPred() { CMPASSERT(NOT isCutOp()); return startWithPredicate_; } + ValueIdSet & connectByPred() { CMPASSERT(NOT isCutOp()); return connectByPredicate_; } + + ItemExpr * biConnectBy_; + + ValueIdSet startWithPredicate_; + ValueIdSet connectByPredicate_; protected: // append an ascii-version of RelExpr node into cachewa.qryText_ diff --git a/core/sql/optimizer/RelScan.h b/core/sql/optimizer/RelScan.h index 655bd0377f..f2c5bbb17f 100644 --- a/core/sql/optimizer/RelScan.h +++ b/core/sql/optimizer/RelScan.h @@ -236,8 +236,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(oHeap), hbaseAccessOptions_(NULL), - commonSubExpr_(NULL), - biConnectBy_(NULL) + commonSubExpr_(NULL) {} Scan(const CorrName& name, @@ -265,8 +264,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(CmpCommon::statementHeap()), hbaseAccessOptions_(NULL), - commonSubExpr_(NULL), - biConnectBy_(NULL) + commonSubExpr_(NULL) {} Scan(const CorrName& name, @@ -297,8 +295,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), matchingMVs_(oHeap), hbaseAccessOptions_(NULL), - commonSubExpr_(NULL), - biConnectBy_(NULL) + commonSubExpr_(NULL) {} Scan(OperatorTypeEnum otype, @@ -327,8 +324,7 @@ class Scan : public RelExpr isRewrittenMV_(FALSE), hbaseAccessOptions_(NULL), matchingMVs_(CmpCommon::statementHeap()), - commonSubExpr_(NULL), - biConnectBy_(NULL) + commonSubExpr_(NULL) {} // virtual destructor @@ -638,9 +634,6 @@ class Scan : public RelExpr CommonSubExprRef *getCommonSubExpr() const { return commonSubExpr_; } void setCommonSubExpr(CommonSubExprRef *cse) { commonSubExpr_ = cse; } - void setBiConnectBy(BiConnectBy *b) { biConnectBy_ = b; } - BiConnectBy * getBiConnectBy() {return biConnectBy_; } - protected: // Find the most promising index from the LIST, for index joins @@ -790,8 +783,6 @@ class Scan : public RelExpr // materialized common subexpr CommonSubExprRef *commonSubExpr_; - BiConnectBy * biConnectBy_; - }; // ----------------------------------------------------------------------- diff --git a/core/sql/optimizer/ValueDesc.cpp b/core/sql/optimizer/ValueDesc.cpp index 0e12ffbadc..5a21585a25 100644 --- a/core/sql/optimizer/ValueDesc.cpp +++ b/core/sql/optimizer/ValueDesc.cpp @@ -4555,7 +4555,7 @@ void ValueIdSet::unparse(NAString &result, NAString connectorText; - if ((form == MVINFO_FORMAT) || (form == QUERY_FORMAT)) + if ((form == MVINFO_FORMAT) || (form == QUERY_FORMAT) || (form == CONNECT_BY_FORMAT)) connectorText = " AND "; else connectorText = " , "; @@ -4573,6 +4573,7 @@ void ValueIdSet::unparse(NAString &result, x.getItemExpr()->unparse(result,phase,EXPLAIN_FORMAT,tabId); } else if ((form == MVINFO_FORMAT) || + (form == CONNECT_BY_FORMAT) || (form == QUERY_FORMAT)) { // MVINFO_FORMAT or QUERY_FORMAT: don't print vid's diff --git a/core/sql/parser/ParKeyWords.cpp b/core/sql/parser/ParKeyWords.cpp index 5196f45a87..6676cd741f 100644 --- a/core/sql/parser/ParKeyWords.cpp +++ b/core/sql/parser/ParKeyWords.cpp @@ -1043,6 +1043,7 @@ ParKeyWord ParKeyWords::keyWords_[] = { ParKeyWord("SHOWSHAPE", TOK_SHOWSHAPE, NONRESTOKEN_), ParKeyWord("SHOWSTATS", TOK_SHOWSTATS, NONRESTOKEN_), ParKeyWord("SHOWTRANSACTION", TOK_SHOWTRANSACTION, NONRESTOKEN_), + ParKeyWord("SIBLINGS", TOK_SIBLINGS, NONRESTOKEN_), ParKeyWord("SIGN", TOK_SIGN, NONRESTOKEN_), ParKeyWord("SIGNAL", TOK_SIGNAL, COMPAQ_|RESWORD_|NONRESTOKEN_), ParKeyWord("SIGNED", TOK_SIGNED, NONRESTOKEN_), diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 8cff3e1603..ccfc80cf56 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -383,6 +383,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_LENGTH /* ANSI SQL non-reserved word */ %token TOK_PRECISION %token TOK_SCALE /* ANSI SQL non-reserved word */ +%token TOK_SIBLINGS %token TOK_LEADING_PRECISION /* Tandem extenstion non-reserved word */ %token TOK_NULLABLE /* ANSI SQL non-reserved word */ @@ -1897,6 +1898,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %type sort_spec_list %type sort_spec %type order_by_clause +%type order_siblings_by_clause %type order_by_clause_non_empty %type declare_static_cursor %type cursor_spec @@ -13287,11 +13289,13 @@ table_expression : from_clause where_clause sample_clause SqlParser_CurrentParser->topHasOlapFunctions()); SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); } - | from_clause startwith_clause where_clause - { + | from_clause startwith_clause where_clause + { + if($1->getOperatorType() == REL_JOIN) + { $$ = getTableExpressionRelExpr($1, - NULL, + $3, NULL, NULL, NULL, @@ -13300,9 +13304,56 @@ table_expression : from_clause where_clause sample_clause NULL, FALSE, SqlParser_CurrentParser->topHasOlapFunctions()); + } + else + $$ = + getTableExpressionRelExpr($1, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + FALSE, + SqlParser_CurrentParser->topHasOlapFunctions()); + SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); ((BiConnectBy*)$2)->where_clause = $3; - ((Scan*)$$)->setBiConnectBy( (BiConnectBy*)$2); + //((BiConnectBy*)$2)->order_siblings_by_clause = $4; + $$->setBiConnectBy( $2); + $$->setHasConnectByFlag(TRUE); + } + | from_clause where_clause startwith_clause + { + if($1->getOperatorType() == REL_JOIN) + $$ = + getTableExpressionRelExpr($1, + $2, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + FALSE, + SqlParser_CurrentParser->topHasOlapFunctions()); + else + $$ = + getTableExpressionRelExpr($1, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + FALSE, + SqlParser_CurrentParser->topHasOlapFunctions()); + SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); + ((BiConnectBy*)$3)->where_clause = $2; + //((BiConnectBy*)$3)->order_siblings_by_clause = $4; + $$->setBiConnectBy( $3); $$->setHasConnectByFlag(TRUE); } /* type relx */ @@ -13312,24 +13363,24 @@ from_clause : TOK_FROM global_hint table_reference { $$ = $3; } $$ = new (PARSERHEAP()) Join($1, $3, REL_JOIN); } -startwith_clause :TOK_START_WITH predicate CONNECT_IDENTIFIER TOK_BY predicate +startwith_clause :TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY search_condition { $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$5); //save the predicate text $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); } - |TOK_START_WITH predicate CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE predicate + |TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE search_condition { $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$6); //save the predicate text $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); ((BiConnectBy*)$$)->setNoCycle(TRUE); } - | CONNECT_IDENTIFIER TOK_BY predicate + | CONNECT_IDENTIFIER TOK_BY search_condition { $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$3); } - | CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE predicate + | CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE search_condition { $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$4); ((BiConnectBy*)$$)->setNoCycle(TRUE); @@ -13866,11 +13917,9 @@ set_quantifier : { $$ = FALSE; /* by default, set quantifier is ALL */ /* type relx */ query_spec_body : query_select_list table_expression access_type optional_lock_mode { - if( $2->hasConnectByFlag() == FALSE ) { - - // use a compute node to attach select list - RelRoot *temp= new (PARSERHEAP()) - RelRoot($2, $3, $4, REL_ROOT, $1); + // use a compute node to attach select list + RelRoot *temp= new (PARSERHEAP()) + RelRoot($2, $3, $4, REL_ROOT, $1); // set relroot olap here if (SqlParser_CurrentParser->topHasOlapFunctions()) { temp->setHasOlapFunctions(TRUE); @@ -13884,61 +13933,14 @@ query_spec_body : query_select_list table_expression access_type optional_lock_ } //pop the last element which was pushed when we eneterd a new select SqlParser_CurrentParser->popHasTDFunctions(); - - $$=temp; - } - else - { - CharInfo::CharSet stmtCharSet = CharInfo::UnknownCharSet; - NAString * stmt = getSqlStmtStr ( stmtCharSet // out - CharInfo::CharSet & - , PARSERHEAP() // in - NAMemory * - ); - //remove ';' - UInt32 pos = - stmt->index(";", 0, NAString::ignoreCase); - stmt->remove(pos); - - ExeUtilConnectby *euc = new (PARSERHEAP()) - ExeUtilConnectby(CorrName( ((Scan*)$2)->getTableName(), PARSERHEAP()), (char*) stmt->data(), - stmtCharSet, $2, PARSERHEAP()); - - RelRoot *temp = new (PARSERHEAP()) - RelRoot(euc, REL_ROOT , $1); - - if( ((Scan*)$2)->getBiConnectBy()->getStartWith() == NULL) - { - euc->hasStartWith_ = FALSE; - } - else - { - euc->hasStartWith_ = TRUE; - euc->startWithExprString_ = ((Scan*)$2)->getBiConnectBy()->getStartWithString(); - } - ItemExpr * it = euc->containsPath($1); - if( it != NULL) - { - euc->setHasConnectByPath(TRUE); - euc->pathColName_=((ItmSysConnectByPathFunc*)it)->getPathColumnName(); - euc->delimiter_ = ((ItmSysConnectByPathFunc*)it)->getDelimiter(); - } - else - euc->setHasConnectByPath(FALSE); - if($1) - if( euc->containsIsLeaf($1) || euc->containsIsLeaf(((Scan*)$2)->getBiConnectBy()->where_clause) ) - { - euc->setHasIsLeaf(TRUE); + #if 0 + if( $2->hasConnectByFlag() == TRUE) { + //move it to Root + temp->setBiConnectBy($2->getBiConnectBy()); + $2->setBiConnectBy(NULL); } - euc->noCycle_ = ((Scan*)$2)->getBiConnectBy()->getNoCycle(); - euc->scan_ = $2; - euc->myselection_ = ((Scan*)$2)->getBiConnectBy()->where_clause ; - euc->myTableName_ = "_CONNECTBY_"+((Scan*)$2)->getTableName().getQualifiedNameAsString(); - euc->parentColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getParentColName(); - euc->childColName_ = ((Scan*)$2)->getBiConnectBy()->getConnectBy()->getChildColName(); - - //euc->addSelPredTree( ((Scan*)$2)->getBiConnectBy()->where_clause ); - - $$ = temp; - } + #endif + $$=temp; } | query_select_list into_clause table_expression access_type optional_lock_mode @@ -19274,18 +19276,22 @@ comparison_predicate : | PRIOR_IDENTIFIER value_expression comparison_operator value_expression { $$ = new (PARSERHEAP()) BiConnectByRelat($3, $2, $4); NAString pn, cn; - $2->unparse(pn, PARSER_PHASE, USER_FORMAT); - $4->unparse(cn, PARSER_PHASE, USER_FORMAT); + $2->unparse(pn, PARSER_PHASE, QUERY_FORMAT); + $4->unparse(cn, PARSER_PHASE, QUERY_FORMAT); ( (BiConnectByRelat*)$$)->setParentColName((char*)pn.data()); ( (BiConnectByRelat*)$$)->setChildColName((char*)cn.data()); + ( (BiConnectByRelat*)$$)->setParentColIE($2); + ( (BiConnectByRelat*)$$)->setChildColIE($4); } | value_expression comparison_operator PRIOR_IDENTIFIER value_expression { $$ = new (PARSERHEAP()) BiConnectByRelat($2, $1, $4); NAString pn, cn; - $4->unparse(pn, PARSER_PHASE, USER_FORMAT); - $1->unparse(cn, PARSER_PHASE, USER_FORMAT); + $4->unparse(pn, PARSER_PHASE, QUERY_FORMAT); + $1->unparse(cn, PARSER_PHASE, QUERY_FORMAT); ( (BiConnectByRelat*)$$)->setParentColName((char*)pn.data()); + ( (BiConnectByRelat*)$$)->setParentColIE($4); ( (BiConnectByRelat*)$$)->setChildColName((char*)cn.data()); + ( (BiConnectByRelat*)$$)->setChildColIE($1); } // BEGIN rules added for UDF @@ -23530,6 +23536,13 @@ order_by_clause : TOK_ORDER TOK_BY sort_spec_list } +/* item */ +order_siblings_by_clause : TOK_ORDER TOK_SIBLINGS TOK_BY sort_spec_list + { $$ = $4; } + | empty + { + $$ = NULL; + } /* type relx */ set_statement: set_table_statement From e1a59112bad6d2c928c12e2414d2998c0c57ef10 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sat, 25 Aug 2018 12:52:16 +0000 Subject: [PATCH 16/17] add support for order by siblyings --- core/sql/comexe/ComTdbExeUtil.h | 1 + core/sql/executor/ExExeUtilConnectby.cpp | 14 ++++++-- core/sql/generator/GenRelExeUtil.cpp | 2 ++ core/sql/optimizer/BindRelExpr.cpp | 7 ++++ core/sql/optimizer/BindWA.h | 5 +-- core/sql/optimizer/ItemExpr.h | 9 ++++- core/sql/parser/sqlparser.y | 42 ++++++++++++++++++------ 7 files changed, 65 insertions(+), 15 deletions(-) diff --git a/core/sql/comexe/ComTdbExeUtil.h b/core/sql/comexe/ComTdbExeUtil.h index 217d8a68ac..361e6e27d3 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -4072,6 +4072,7 @@ class ComTdbExeUtilConnectby : public ComTdbExeUtil NABoolean hasIsLeaf_; NAString pathColName_; NAString delimiter_; + NAString orderSiblingsByCol_; private: ExCriDescPtr myWorkCriDesc_; Int32 flags_; diff --git a/core/sql/executor/ExExeUtilConnectby.cpp b/core/sql/executor/ExExeUtilConnectby.cpp index cf8058eb0a..16b9230708 100644 --- a/core/sql/executor/ExExeUtilConnectby.cpp +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -551,7 +551,8 @@ short ExExeUtilConnectbyTcb::work() Lng32 indOffset = 0; Lng32 varOffset = 0; - if (exeUtilTdb().hasPath_ == TRUE || exeUtilTdb().hasIsLeaf_ == TRUE) + //if (exeUtilTdb().hasPath_ == TRUE || exeUtilTdb().hasIsLeaf_ == TRUE || exeUtilTdb().orderSiblingsByCol_ != "") + if (exeUtilTdb().hasPath_ == TRUE || exeUtilTdb().hasIsLeaf_ == TRUE ) { connBatchSize_ = 1; } @@ -759,7 +760,16 @@ short ExExeUtilConnectbyTcb::work() }//for(int batchIdx = 0; batchIdx < 10 && i < seedNum; batchIdx ++) - nq21.append(" );"); + if( exeUtilTdb().orderSiblingsByCol_ != "") + { + nq21.append(" ) ORDER BY "); + nq21.append((exeUtilTdb().childColName_).data()); + nq21.append(" ,"); + nq21.append(exeUtilTdb().orderSiblingsByCol_); + nq21.append(" asc;"); + } + else + nq21.append(" );"); if(sybnum == 0 ) //end { diff --git a/core/sql/generator/GenRelExeUtil.cpp b/core/sql/generator/GenRelExeUtil.cpp index 8d47f1606b..3272c7a6f2 100644 --- a/core/sql/generator/GenRelExeUtil.cpp +++ b/core/sql/generator/GenRelExeUtil.cpp @@ -5473,6 +5473,8 @@ short ExeUtilConnectby::codeGen(Generator * generator) else exe_util_tdb->hasIsLeaf_ = FALSE; + exe_util_tdb->orderSiblingsByCol_ = generator->getBindWA()->orderSiblingsByCol_; + generator->initTdbFields(exe_util_tdb); if (!generator->explainDisabled()) diff --git a/core/sql/optimizer/BindRelExpr.cpp b/core/sql/optimizer/BindRelExpr.cpp index ffdca79419..659b81bc63 100644 --- a/core/sql/optimizer/BindRelExpr.cpp +++ b/core/sql/optimizer/BindRelExpr.cpp @@ -6128,6 +6128,12 @@ RelExpr *RelRoot::bindNode(BindWA *bindWA) ItemExpr *orderByTree = removeOrderByTree(); if (orderByTree) { + //If this is ORDER SIBLINGS BY + if(orderByTree->isOrderSyblingsBy()) + { + orderByTree->unparse(bindWA->orderSiblingsByCol_,BINDER_PHASE,CONNECT_BY_FORMAT); + } + else { // // Tandem extension to ANSI (done only if source table is not grouped!): // Allow the ORDER BY clause to reference columns in the source table even @@ -6353,6 +6359,7 @@ RelExpr *RelRoot::bindNode(BindWA *bindWA) bindWA->getCurrentScope()->setRETDesc(getRETDesc()); bindWA->getCurrentScope()->context()->inOrderBy() = FALSE; + } } // validate that select list doesn't contain any expressions that cannot be diff --git a/core/sql/optimizer/BindWA.h b/core/sql/optimizer/BindWA.h index 54e9f3b4c6..da69cb96d1 100644 --- a/core/sql/optimizer/BindWA.h +++ b/core/sql/optimizer/BindWA.h @@ -1704,14 +1704,15 @@ class BindWA : public NABasicObject const NAString & getISPExecLocation() const { return ISPExecLocation_ ;} - //ValueIdSet & connectByPred() { return connectByPredicate_; } - + //added for CONNECT BY handling NAString connectByPathCol_; NAString connectByPathDel_; NABoolean connectByHasPath_; NABoolean connectByHasIsLeaf_; + NAString orderSiblingsByCol_; + private: // -------------------------------------------------------------------- diff --git a/core/sql/optimizer/ItemExpr.h b/core/sql/optimizer/ItemExpr.h index e24a1fc54c..a6eefab30f 100644 --- a/core/sql/optimizer/ItemExpr.h +++ b/core/sql/optimizer/ItemExpr.h @@ -1204,6 +1204,10 @@ class ItemExpr : public ExprNode void setIsGroupByRollup(NABoolean v) { (v ? flags_ |= IS_GROUPBY_ROLLUP : flags_ &= ~IS_GROUPBY_ROLLUP); } + NABoolean isOrderSyblingsBy() const { return (flags_ & IS_ORDER_SIBGINGS_BY) != 0; } + void setIsOrderSyblingsBy(NABoolean v) + { (v ? flags_ |= IS_ORDER_SIBGINGS_BY: flags_ &= ~IS_ORDER_SIBGINGS_BY); } + virtual QR::ExprElement getQRExprElem() const; virtual ItemExpr* removeRangeSpecItems(NormWA* normWA = NULL); @@ -1273,7 +1277,10 @@ class ItemExpr : public ExprNode // if set, the subtree rooted below was part of "groupby rollup" clause. // Currently used during parsing phase. See parser/sqlparser.y. - IS_GROUPBY_ROLLUP = 0x0080 + IS_GROUPBY_ROLLUP = 0x0080, + + // if set, the subtree was order siblings by clause + IS_ORDER_SIBGINGS_BY = 0x0100 }; // --------------------------------------------------------------------- diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index ccfc80cf56..64b18fb310 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -1898,7 +1898,6 @@ static void enableMakeQuotedStringISO88591Mechanism() %type sort_spec_list %type sort_spec %type order_by_clause -%type order_siblings_by_clause %type order_by_clause_non_empty %type declare_static_cursor %type cursor_spec @@ -13320,7 +13319,6 @@ table_expression : from_clause where_clause sample_clause SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); ((BiConnectBy*)$2)->where_clause = $3; - //((BiConnectBy*)$2)->order_siblings_by_clause = $4; $$->setBiConnectBy( $2); $$->setHasConnectByFlag(TRUE); } @@ -13376,6 +13374,23 @@ startwith_clause :TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY sear $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); ((BiConnectBy*)$$)->setNoCycle(TRUE); } +/* + | TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY search_condition order_by_clause + { + $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$5); + //save the predicate text + $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); + ((BiConnectBy*)$$)->order_siblings_by_clause = $5; + } + |TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE search_condition order_by_clause + { + $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$6); + //save the predicate text + $2->unparse(((BiConnectBy*)$$)->startWithString_, PARSER_PHASE, USER_FORMAT); + ((BiConnectBy*)$$)->setNoCycle(TRUE); + ((BiConnectBy*)$$)->order_siblings_by_clause = $6; + } +*/ | CONNECT_IDENTIFIER TOK_BY search_condition { $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$3); @@ -13385,6 +13400,19 @@ startwith_clause :TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY sear $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$4); ((BiConnectBy*)$$)->setNoCycle(TRUE); } +/* + | CONNECT_IDENTIFIER TOK_BY search_condition order_by_clause + { + $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$3); + ((BiConnectBy*)$$)->order_siblings_by_clause = $4; + } + | CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE search_condition order_by_clause + { + $$ = new (PARSERHEAP())BiConnectBy (NULL, (BiRelat*)$4); + ((BiConnectBy*)$$)->setNoCycle(TRUE); + ((BiConnectBy*)$$)->order_siblings_by_clause = $5; + } +*/ /* type item */ join_specification : join_condition @@ -23534,15 +23562,9 @@ order_by_clause : TOK_ORDER TOK_BY sort_spec_list { $$ = NULL; } + |TOK_ORDER TOK_SIBLINGS TOK_BY sort_spec_list + { $$ = $4; $$->setIsOrderSyblingsBy(TRUE); } - -/* item */ -order_siblings_by_clause : TOK_ORDER TOK_SIBLINGS TOK_BY sort_spec_list - { $$ = $4; } - | empty - { - $$ = NULL; - } /* type relx */ set_statement: set_table_statement From caed4954b8735670ac659ffbba7baf642c200dd4 Mon Sep 17 00:00:00 2001 From: Liu Ming Date: Sun, 26 Aug 2018 14:52:52 +0000 Subject: [PATCH 17/17] fix reduce/shift conflict --- core/sql/parser/sqlparser.y | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index 64b18fb310..7af3842903 100755 --- a/core/sql/parser/sqlparser.y +++ b/core/sql/parser/sqlparser.y @@ -13322,12 +13322,12 @@ table_expression : from_clause where_clause sample_clause $$->setBiConnectBy( $2); $$->setHasConnectByFlag(TRUE); } - | from_clause where_clause startwith_clause + | from_clause TOK_WHERE search_condition startwith_clause { if($1->getOperatorType() == REL_JOIN) $$ = getTableExpressionRelExpr($1, - $2, + $3, NULL, NULL, NULL, @@ -13349,9 +13349,9 @@ table_expression : from_clause where_clause sample_clause FALSE, SqlParser_CurrentParser->topHasOlapFunctions()); SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); - ((BiConnectBy*)$3)->where_clause = $2; + ((BiConnectBy*)$4)->where_clause = $3; //((BiConnectBy*)$3)->order_siblings_by_clause = $4; - $$->setBiConnectBy( $3); + $$->setBiConnectBy( $4); $$->setHasConnectByFlag(TRUE); } /* type relx */ @@ -13360,7 +13360,6 @@ from_clause : TOK_FROM global_hint table_reference { $$ = $3; } { $$ = new (PARSERHEAP()) Join($1, $3, REL_JOIN); } - startwith_clause :TOK_START_WITH search_condition CONNECT_IDENTIFIER TOK_BY search_condition { $$ = new (PARSERHEAP())BiConnectBy ((BiRelat*)$2, (BiRelat*)$5);