diff --git a/core/sql/bin/SqlciErrors.txt b/core/sql/bin/SqlciErrors.txt index 7032bf77be..dc992a88de 100644 --- a/core/sql/bin/SqlciErrors.txt +++ b/core/sql/bin/SqlciErrors.txt @@ -1515,6 +1515,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 +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/ComTdb.cpp b/core/sql/comexe/ComTdb.cpp index 4770f59a3c..230fbffc64 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 e00728f205..df269d2c41 100644 --- a/core/sql/comexe/ComTdb.h +++ b/core/sql/comexe/ComTdb.h @@ -290,6 +290,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 df34a5df6e..3d8749aede 100644 --- a/core/sql/comexe/ComTdbExeUtil.cpp +++ b/core/sql/comexe/ComTdbExeUtil.cpp @@ -3028,3 +3028,59 @@ 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_expr * scan_expr, + 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, + scan_expr, + work_cri_desc, work_atp_index, + given_cri_desc, returned_cri_desc, + down, up, + num_buffers, buffer_size), + flags_(0), + myWorkCriDesc_(workCriDesc), + tupleLen_(outputRowSize) +{ + 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 + hasPath_ = FALSE; + hasIsLeaf_ = FALSE; +} + +Long ComTdbExeUtilConnectby::pack(void * space) +{ + myWorkCriDesc_.pack(space); + return ComTdbExeUtil::pack(space); +} + +Lng32 ComTdbExeUtilConnectby::unpack(void * base, void * reallocator) +{ + 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 afb29fbb18..361e6e27d3 100644 --- a/core/sql/comexe/ComTdbExeUtil.h +++ b/core/sql/comexe/ComTdbExeUtil.h @@ -91,7 +91,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() @@ -4016,7 +4017,78 @@ class ComTdbExeUtilLobInfo : public ComTdbExeUtil NABoolean tableFormat_; }; -#endif +class ComTdbExeUtilConnectby : public ComTdbExeUtil +{ + friend class ExExeUtilConnectbyTcb; + +public: + 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_expr * scan_expr, + 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() + : ComTdbExeUtil() { hasStartWith_ = TRUE; noCycle_ = FALSE; } + + Long pack(void *); + Lng32 unpack(void *, void * reallocator); + + virtual short getClassSize() {return (short)sizeof(ComTdbExeUtilConnectby);} + + virtual const char *getNodeName() const + { + return "CONNECT_BY"; + }; + UInt16 sourceDataTuppIndex_; + NAString parentColName_; + NAString childColName_; + NAString connTableName_; + NAString startWithExprString_; + NABoolean hasStartWith_; + NABoolean noCycle_; + Int32 maxDeep_; + Int32 maxSize_; + NABoolean hasPath_; + NABoolean hasIsLeaf_; + NAString pathColName_; + NAString delimiter_; + NAString orderSiblingsByCol_; +private: + ExCriDescPtr myWorkCriDesc_; + Int32 flags_; + Int32 tupleLen_; +}; + +class ExExeUtilConnectbyTdb : public ComTdbExeUtilConnectby +{ +public: + ExExeUtilConnectbyTdb() + {} + virtual ~ExExeUtilConnectbyTdb() + {} + + virtual ex_tcb *build(ex_globals *globals); +}; + +#endif 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/common/OperTypeEnum.h b/core/sql/common/OperTypeEnum.h index fd3776c108..54ea680416 100644 --- a/core/sql/common/OperTypeEnum.h +++ b/core/sql/common/OperTypeEnum.h @@ -679,6 +679,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, @@ -813,6 +815,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/ExComTdb.cpp b/core/sql/executor/ExComTdb.cpp index 005cdf14de..99d5816e66 100644 --- a/core/sql/executor/ExComTdb.cpp +++ b/core/sql/executor/ExComTdb.cpp @@ -566,6 +566,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 435dfb5230..ad22ef2eca 100644 --- a/core/sql/executor/ExExeUtil.h +++ b/core/sql/executor/ExExeUtil.h @@ -4138,6 +4138,7 @@ class ExExeUtilLobInfoTableTcb : public ExExeUtilTcb DONE_ }; Step step_; + char * data_; protected: Int64 getEmbeddedNumValue(char* &sep, char endChar, @@ -4172,6 +4173,48 @@ 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 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 { @@ -4183,6 +4226,72 @@ class ExExeUtilLobInfoTablePrivateState : public ex_tcb_private_state protected: }; +class ExExeUtilConnectbyTcb : public ExExeUtilTcb +{ + friend class ExExeUtilConnectbyTdb; + +public: + 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_, + EVAL_OUTPUT_EXPR_, + NEXT_LEVEL_, + NEXT_ROOT_, + ERROR_, + DONE_ + }; + Step step_; + ExExeUtilConnectbyTdb& exeUtilTdb() const + {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];} + short checkDuplicate(connectByStackItem *it,int len, int level); + int currLevel_; + Int64 resultSize_; + Queue *currQueue_; + Queue *seedQueue_; + Queue *thisQueue_; + Queue *prevQueue_; + Queue *tmpPrevQueue_; + Int32 currRootId_; + Int32 connBatchSize_ ; + +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..16b9230708 --- /dev/null +++ b/core/sql/executor/ExExeUtilConnectby.cpp @@ -0,0 +1,1024 @@ +/********************************************************************** +// @@@ 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 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(); + currLevel_ = 0; + resultSize_ = 0; + currQueue_ = new(getHeap()) Queue(getHeap()) ; + thisQueue_ = NULL; + prevQueue_ = NULL; + tmpPrevQueue_ = NULL; + currRootId_ = 0; + connBatchSize_ = CONNECT_BY_DEFAULT_BATCH_SIZE; + seedQueue_ = new(getHeap()) Queue(getHeap()) ; + for( int i = 0; i< CONNECT_BY_MAX_LEVEL_SIZE; i++) + { + currArray[i] = NULL; + } +} + +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::emitRow(ExpTupleDesc * tDesc, int level, int isleaf, int iscycle, connectByStackItem *vi ) +{ + short retcode = 0, rc =0; + char * ptr; + Lng32 len; + short nullind=0; + short *pn = &nullind; + short **ind = &pn; + UInt32 vcActualLen = 0; + + 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); + + char * src = ptr; + Attributes * attr = tDesc->getAttr(i-1); + short srcType = 0; + Lng32 srcLen; + short valIsNull = 0; + srcType = attr->getDatatype(); + srcLen = len; + if (((char*)*ind)[0] == -1) 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) { + 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(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; +} + + +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 = &nullInd ; + short **indadd = &ind; + 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; + break; + } + } + 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, 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(1, 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; +} + +void releaseCurrentQueue(Queue * q, CollHeap * h) +{ + for(int i = 0; i < q->numEntries(); i++) + { + connectByStackItem *entry = (connectByStackItem *)q->get(i); + NADELETEBASIC(entry->seedValue,h); + NADELETEBASIC(entry->pathItem,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::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++) + { + rootItem * ri = (rootItem*) q->get(i); + if(ri->rootId == id) return ri->qptr; + } + return NULL; +} + +short ExExeUtilConnectbyTcb::work() +{ + short retcode = 0; + 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; + short rc; + NAString nq11, nq21; + memset(q1, 0, sizeof(q1)); + int matchRowNum = 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; + + if(exeUtilTdb().hasStartWith_ == TRUE) + { + 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 (%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_); + + Lng32 fsDatatype = 0; + Lng32 length = 0; + Lng32 indOffset = 0; + Lng32 varOffset = 0; + + //if (exeUtilTdb().hasPath_ == TRUE || exeUtilTdb().hasIsLeaf_ == TRUE || exeUtilTdb().orderSiblingsByCol_ != "") + if (exeUtilTdb().hasPath_ == TRUE || exeUtilTdb().hasIsLeaf_ == TRUE ) + { + connBatchSize_ = 1; + } + + if(exeUtilTdb().hasIsLeaf_ == TRUE && prevQueue_ == NULL) + prevQueue_ = new(getHeap()) Queue(getHeap()) ; + + 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; + int rootId = 0; + + //get the stmt + + if( exeUtilTdb().hasIsLeaf_ == TRUE) + { + Queue * rootRow = new(getHeap()) Queue(getHeap()) ; + 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(rootRow->numEntries() == 0 ) + { + step_ = DONE_; + break; + } + + for(int i1 = 0; i1 < rootRow->numEntries(); i1 ++) + { + OutputInfo *vi = (OutputInfo*)rootRow->getNext(); + vi->get(0, ptr, len, fsDatatype, NULL, NULL); + 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+1]; + memset(tmp1,0, len1+1); + memcpy(tmp1,ptr1,len1); + it->pathLen = len1; + it->pathItem = tmp1; + } + if(checkDuplicate( it, len, currLevel_) == 0) { + matchRowNum++; + Queue* cq = new(getHeap()) Queue(getHeap()) ; + 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+1]; + memset(tmp1,0,len1+1); + 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); + } + + if(seedQueue_->numEntries() == 0 ) + { + step_ = DONE_; + break; + } + currQueue_ = getCurrQueue(currRootId_, seedQueue_); + currArray[0] = currQueue_; + + if( matchRowNum > exeUtilTdb().maxSize_ ) + { + ComDiagsArea * diags = getDiagsArea(); + if(diags == NULL) + { + setDiagsArea(ComDiagsArea::allocate(getHeap())); + diags = getDiagsArea(); + } + *diags << DgSqlCode(-8039); + + step_ = ERROR_; + } + else + step_ = NEXT_LEVEL_; + } + break; + case DO_CONNECT_BY_: + { + currQueue_ = getCurrentQueue(currLevel_ - 1); + thisQueue_ = getCurrentQueue(currLevel_); + if(exeUtilTdb().hasIsLeaf_ == TRUE) + tmpPrevQueue_ = new(getHeap()) Queue(getHeap()) ; + Lng32 seedNum = currQueue_->numEntries(); + Int8 loopDetected = 0; + + currQueue_->position(); + resultSize_ = 0; + + 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() ); + nq21 = q1; + nq21.append((exeUtilTdb().childColName_).data()); + nq21.append(" in ( "); + Lng32 sybnum = 0; + + for(int batchIdx = 0; batchIdx < connBatchSize_ && i < seedNum; ) + { + connectByStackItem * vi = (connectByStackItem*)currQueue_->get(i); + Lng32 tmpLevel = vi->level; + i++; + if( tmpLevel == currLevel_ - 1) { + sybnum++; + uppderid = ((connectByStackItem*)vi)->seedValue; + batchIdx++; + char tmpbuf[128]; + char tmpbuf1[128]; + memset(tmpbuf,0,128); + memset(tmpbuf1,0,128); + 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,"'"); + } + + nq21.append(tmpbuf); + if( i == seedNum || batchIdx == connBatchSize_) continue; + else + nq21.append(" , "); + } //if( tmpLevel == currLevel) + + }//for(int batchIdx = 0; batchIdx < 10 && i < seedNum; batchIdx ++) + + 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 + { + step_ = NEXT_LEVEL_; + break; + } + 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 + emitPrevRow(tDesc, currLevel_, 1, 0,prevQueue_, i-1); + } + else + { + //emit parent + 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+1]; + memset(tmp1,0,len1+1); + 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) + { + thisQueue_->insert(it); + matchRowNum++; + 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+1]; + memset(tmp1,0,len1+1); + 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_ + for(int i = 0 ; i < prevQueue_->numEntries(); i ++) + NADELETE((Queue*)prevQueue_->get(i), Queue, getHeap()); + NADELETE(prevQueue_, Queue, getHeap()); + prevQueue_ = tmpPrevQueue_; + } + + if( loopDetected == 1) + { + if( exeUtilTdb().noCycle_ == TRUE) + { + step_ = NEXT_ROOT_; + } + else + step_ = ERROR_; + break; + } + if(resultSize_ == 0) + step_ = NEXT_ROOT_; + else + step_ = NEXT_LEVEL_; + } + break; + case NEXT_LEVEL_: + { + Queue* currQueue = new(getHeap()) Queue(getHeap()) ; + currLevel_++; + currArray[currLevel_] = currQueue; + + 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_: + { + currRootId_++; + currLevel_ = 1; + currQueue_ = getCurrQueue(currRootId_, seedQueue_); + //clear currArray + for(int i =0; i< CONNECT_BY_MAX_LEVEL_SIZE; i++) + { + if(currArray[i] != NULL) //comehere + NADELETE(currArray[i], Queue, getHeap()); + } + if(currQueue_ == NULL) + step_ = DONE_; + else + step_ = DO_CONNECT_BY_; + } + break; + case ERROR_: + { + + if (qparent_.up->isFull()) + return WORK_OK; + if (handleError()) + return WORK_OK; + + step_ = DONE_; + } + break; + case DONE_: + if (qparent_.up->isFull()) + return WORK_OK; + + retcode = handleDone(); + if (retcode == 1) + return WORK_OK; + + NADELETE(seedQueue_, Queue, getHeap()); + step_ = INITIAL_; + 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 1e5509bf8a..3272c7a6f2 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" #include "CmpDDLCatErrorCodes.h" // need for authorization checks @@ -5257,6 +5258,236 @@ short ExeUtilOrcFastAggr::codeGen(Generator * generator) } +const char * ExeUtilConnectby::getVirtualTableName() +{ + return myTableName_.data(); +} + +TrafDesc *ExeUtilConnectby::createVirtualTableDesc() +{ + CmpSeabaseDDL cmpSBD((NAHeap *)CmpCommon::statementHeap()); + NAString cat; + NAString sch; + NAString tbl; + Scan * scanNode = (Scan*)scan_; + cat= (scanNode->getTableName()).getQualifiedNameObj().getCatalogName(); + sch= (scanNode->getTableName()).getQualifiedNameObj().getSchemaName(); + tbl= (scanNode->getTableName()).getQualifiedNameObj().getObjectName(); + + 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++; + //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( + getVirtualTableName(), + "LEVEL", //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( + getVirtualTableName(), + "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( + getVirtualTableName(), + "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'; + + 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_; +} + +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 = 0; + Int32 theAtpIndex = returnedDesc->noTuples()-1; + const Int32 outputAtpIndex =theAtpIndex; + + 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); + + 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*)tbl.data(); + + 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, + 0 , 0, + selectPred, + workCriDesc , outputAtpIndex, + colDescSize, + tupleLength, + givenDesc, + returnedDesc, + (queue_index)8, + (queue_index)1024, + 10, + 32000, + workCriDesc + ); + + exe_util_tdb->sourceDataTuppIndex_ = outputAtpIndex; + 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(generator->getBindWA()->connectByHasPath_) + { + exe_util_tdb->hasPath_ = TRUE; + exe_util_tdb->pathColName_ = generator->getBindWA()->connectByPathCol_; + exe_util_tdb->delimiter_ = generator->getBindWA()->connectByPathDel_; + } + else + { + exe_util_tdb->hasPath_ = FALSE; + exe_util_tdb->pathColName_ = "0"; + exe_util_tdb->delimiter_ = " "; + } + if(generator->getBindWA()->connectByHasIsLeaf_) + { + exe_util_tdb->hasIsLeaf_ = TRUE; + } + else + exe_util_tdb->hasIsLeaf_ = FALSE; + + exe_util_tdb->orderSiblingsByCol_ = generator->getBindWA()->orderSiblingsByCol_; + + 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/BindItemExpr.cpp b/core/sql/optimizer/BindItemExpr.cpp index 7c07652aa1..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. @@ -10896,7 +10896,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)) @@ -13608,3 +13610,13 @@ NABoolean RowNumFunc::canBeUsedInGBorOB(NABoolean setErr) return FALSE; } + +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 716a9c67c2..659b81bc63 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. // @@ -4589,8 +4605,8 @@ 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))) + (child(0)->getOperatorType() != REL_SEQUENCE || + (child(0)->child(0) && child(0)->child(0)->getOperatorType()!=REL_GROUPBY))) return this; GroupByAgg * grby; @@ -5331,6 +5347,7 @@ RelExpr *RelRoot::bindNode(BindWA *bindWA) return this; } + if (isTrueRoot()) { // if this is simple scalar aggregate on a seabase table @@ -6111,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 @@ -6336,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 @@ -6352,6 +6376,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,7 +8248,9 @@ RelExpr *Scan::bindNode(BindWA *bindWA) // Bind the base class. // 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. @@ -8364,7 +8405,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..da69cb96d1 100644 --- a/core/sql/optimizer/BindWA.h +++ b/core/sql/optimizer/BindWA.h @@ -1704,6 +1704,15 @@ class BindWA : public NABasicObject const NAString & getISPExecLocation() const { return ISPExecLocation_ ;} + //added for CONNECT BY handling + NAString connectByPathCol_; + NAString connectByPathDel_; + + NABoolean connectByHasPath_; + NABoolean connectByHasIsLeaf_; + + NAString orderSiblingsByCol_; + private: // -------------------------------------------------------------------- @@ -2002,6 +2011,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 0071cc27ea..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); @@ -15295,3 +15313,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/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/optimizer/ItemFunc.h b/core/sql/optimizer/ItemFunc.h index ed83930ad6..6c7664c528 100644 --- a/core/sql/optimizer/ItemFunc.h +++ b/core/sql/optimizer/ItemFunc.h @@ -4751,6 +4751,33 @@ class ZZZBinderFunction : public BuiltinFunction Int64 flags_; }; +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/ItemLog.h b/core/sql/optimizer/ItemLog.h index a6597f5371..3ac8ee8360 100644 --- a/core/sql/optimizer/ItemLog.h +++ b/core/sql/optimizer/ItemLog.h @@ -732,6 +732,36 @@ class BiRelat : public ItemExpr }; // class BiRelat +class BiConnectByRelat :public BiRelat { +public: + BiConnectByRelat( OperatorTypeEnum otype, + ItemExpr *child0 = NULL, + ItemExpr *child1 = 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 4ebdad50fa..516cc0aa3d 100644 --- a/core/sql/optimizer/ItemOther.h +++ b/core/sql/optimizer/ItemOther.h @@ -1131,6 +1131,40 @@ 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; + where_clause = NULL; + order_siblings_by_clause = NULL; + } + 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_; + ItemExpr * where_clause; + ItemExpr * order_siblings_by_clause; + +private: + BiRelat * startWith_; + BiConnectByRelat * connectBy_; + ItemExpr * startWithIe_; + 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/RelExeUtil.cpp b/core/sql/optimizer/RelExeUtil.cpp index 88d544e439..e2b999ef90 100644 --- a/core/sql/optimizer/RelExeUtil.cpp +++ b/core/sql/optimizer/RelExeUtil.cpp @@ -6273,6 +6273,64 @@ 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, NULL,outHeap); + else + 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->flags_ = flags_; + + return ExeUtilExpr::copyTopNode(result, outHeap); +} + +RelExpr * ExeUtilConnectby::bindNode(BindWA *bindWA) +{ + if (nodeIsBound()) { + bindWA->getCurrentScope()->setRETDesc(getRETDesc()); + return this; + } + 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; + return boundExpr; + +} + +RelExpr * ExeUtilConnectby::normalizeNode(NormWA & normWARef) +{ + return RelExpr::normalizeNode(normWARef); +} + +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 4ddb8cca52..b1ec93249b 100644 --- a/core/sql/optimizer/RelExeUtil.h +++ b/core/sql/optimizer/RelExeUtil.h @@ -521,6 +521,7 @@ class ExeUtilExpr : public GenericUtilExpr HIVE_TRUNCATE_LEGACY_ = 39, LOB_UPDATE_UTIL_ = 40, HIVE_QUERY_ = 41, + CONNECT_BY_ = 42, HIVE_TRUNCATE_ = 45 }; @@ -1094,6 +1095,130 @@ class ExeUtilHiveTruncateLegacy : public ExeUtilExpr NABoolean noSecurityCheck_; }; +class ExeUtilConnectby : public ExeUtilExpr +{ + enum Flags { + HAS_IS_LEAF = 0x00000001, + HAS_CONNECT_BY_PATH = 0x00000002, + }; + +public: + ExeUtilConnectby( const CorrName &TableName, + char * stmtText, + CharInfo::CharSet stmtTextCharSet, + RelExpr * scan, + CollHeap *oHeap = CmpCommon::statementHeap()) + : ExeUtilExpr(CONNECT_BY_, TableName, NULL, scan, + stmtText, stmtTextCharSet, oHeap) + { + hasStartWith_ = TRUE; + myselection_ = NULL; + noCycle_ = FALSE; + scan_ = scan; + flags_ = 0; + } + 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(); +#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 + + 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; } + + static 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; + } + + static 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") + 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_; + NAString childColName_; + NAString startWithExprString_; + NABoolean hasStartWith_; + NABoolean noCycle_; + RelExpr * scan_; + NAString myTableName_; + NAString myQualCat_; + NAString myQualSch_; + NAString myQualTbl_; + NAString pathColName_; + NAString delimiter_; + + ItemExpr * myselection_; + ValueIdSet mypredicates_; + + Int32 batchSize_; + +private: + ULng32 flags_; +}; + /////////////////////////////////////////////////////////// // ExeUtilHiveTruncate /////////////////////////////////////////////////////////// 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 44ed08663d..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_ @@ -385,8 +395,13 @@ 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_; } @@ -525,7 +540,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". // -------------------------------------------------------------------- @@ -1411,6 +1426,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. @@ -1439,6 +1459,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 c026914a45..f2c5bbb17f 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 @@ -781,6 +782,7 @@ class Scan : public RelExpr // pointer to the common subexpression, if this is a scan of a // materialized common subexpr CommonSubExprRef *commonSubExpr_; + }; // ----------------------------------------------------------------------- diff --git a/core/sql/optimizer/SynthType.cpp b/core/sql/optimizer/SynthType.cpp index e2cb7af67e..30c462fc03 100644 --- a/core/sql/optimizer/SynthType.cpp +++ b/core/sql/optimizer/SynthType.cpp @@ -7291,3 +7291,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/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 3dc4d6d69a..6676cd741f 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", IDENTIFIER, ANS_|RESWORD_), + ParKeyWord("CONNECT", CONNECT_IDENTIFIER, ANS_|NONRESTOKEN_), // ParKeyWord("CONNECTION", IDENTIFIER, ANS_|RESWORD_), ParKeyWord("CONNECTION_NAME", TOK_CONNECTION_NAME, NONRESTOKEN_), ParKeyWord("CONSTRAINT", TOK_CONSTRAINT, ANS_|RESWORD_), @@ -755,6 +755,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_), @@ -862,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", IDENTIFIER, ANS_|RESWORD_), + ParKeyWord("PRIOR", PRIOR_IDENTIFIER, ANS_), ParKeyWord("PRIORITY", TOK_PRIORITY, NONRESTOKEN_), ParKeyWord("PRIORITY_DELTA", TOK_PRIORITY_DELTA, NONRESTOKEN_), ParKeyWord("PRIVATE", TOK_PRIVATE, NONRESTOKEN_), @@ -1042,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_), @@ -1091,7 +1093,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 @@ -1119,6 +1121,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("SYS_GUID", TOK_SYS_GUID, NONRESTOKEN_), ParKeyWord("SYSTEM", TOK_SYSTEM, NONRESTOKEN_), diff --git a/core/sql/parser/sqlparser.y b/core/sql/parser/sqlparser.y index af518b8b9e..7af3842903 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 */ @@ -479,6 +480,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 @@ -945,6 +947,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_PREFER_FOR_SCAN_KEY %token TOK_PREPARE %token TOK_PRESERVE /* TD extension that HP wants to ignore */ +%token PRIOR_IDENTIFIER %token TOK_PRIORITY %token TOK_PRIORITY_DELTA %token TOK_PROCEDURE @@ -1063,6 +1066,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_SHOWDDL_USER %token TOK_SHOWDDL /* Tandem extension non-reserved word */ %token TOK_SYSDATE +%token TOK_SYSCONNECTBYPATH %token TOK_SYSTIMESTAMP %token TOK_TARGET %token TOK_SYSTEM @@ -1192,6 +1196,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 @@ -1253,6 +1258,7 @@ static void enableMakeQuotedStringISO88591Mechanism() %token TOK_COMPONENTS %token TOK_COMPRESSION %token TOK_CONFIG /* Tandem extension */ +%token CONNECT_IDENTIFIER /* Tandem extension */ %token TOK_CONSTRAINT %token TOK_CONSTRAINTS %token TOK_COPY @@ -1549,7 +1555,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 @@ -2100,6 +2106,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 @@ -9441,18 +9448,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()) @@ -9897,6 +9904,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()) @@ -9904,7 +9916,6 @@ misc_function : CmpCommon::statementHeap(), 2, $3, $5); } - | TOK_NVL '(' value_expression ',' value_expression ')' { $$ = new (PARSERHEAP()) @@ -9912,17 +9923,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()) @@ -13179,7 +13188,6 @@ list_of_values : '(' insert_value_expression_list ')' } // end of fix: left recursion for insert statement values. - table_expression : from_clause where_clause sample_clause cond_transpose_clause_list sequence_by_clause @@ -13280,13 +13288,130 @@ table_expression : from_clause where_clause sample_clause SqlParser_CurrentParser->topHasOlapFunctions()); SqlParser_CurrentParser->setTopHasTDFunctions(FALSE); } + | from_clause startwith_clause where_clause + { + if($1->getOperatorType() == REL_JOIN) + { + $$ = + getTableExpressionRelExpr($1, + $3, + 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*)$2)->where_clause = $3; + $$->setBiConnectBy( $2); + $$->setHasConnectByFlag(TRUE); + } + | from_clause TOK_WHERE search_condition startwith_clause + { + if($1->getOperatorType() == REL_JOIN) + $$ = + getTableExpressionRelExpr($1, + $3, + 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*)$4)->where_clause = $3; + //((BiConnectBy*)$3)->order_siblings_by_clause = $4; + $$->setBiConnectBy( $4); + $$->setHasConnectByFlag(TRUE); + } /* 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 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 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); + } +/* + | 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); + } + | CONNECT_IDENTIFIER TOK_BY TOK_NOCYCLE search_condition + { + $$ = 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 @@ -13719,7 +13844,6 @@ query_specification :select_token set_quantifier query_spec_body ((RelRoot*)$$)->setAnalyzeOnly(); } - query_specification : exe_util_maintain_object { RelRoot *root = new (PARSERHEAP()) @@ -13820,9 +13944,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 { - // 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); @@ -13836,9 +13960,16 @@ 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(); - + #if 0 + if( $2->hasConnectByFlag() == TRUE) { + //move it to Root + temp->setBiConnectBy($2->getBiConnectBy()); + $2->setBiConnectBy(NULL); + } + #endif $$=temp; } + | query_select_list into_clause table_expression access_type optional_lock_mode { // use a compute node to attach select list @@ -19169,6 +19300,26 @@ comparison_predicate : { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } | row_subquery comparison_operator value_expression_list_paren { $$ = new (PARSERHEAP()) BiRelat($2, $1, $3); } + | PRIOR_IDENTIFIER value_expression comparison_operator value_expression + { $$ = new (PARSERHEAP()) BiConnectByRelat($3, $2, $4); + NAString pn, cn; + $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, 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 /* COMMENTED OUT FOR R2.5. CAUSES GRAMMAR CONFLICTS. @@ -23410,7 +23561,8 @@ order_by_clause : TOK_ORDER TOK_BY sort_spec_list { $$ = NULL; } - + |TOK_ORDER TOK_SIBLINGS TOK_BY sort_spec_list + { $$ = $4; $$->setIsOrderSyblingsBy(TRUE); } /* type relx */ set_statement: set_table_statement @@ -24640,7 +24792,7 @@ param_name : IDENTIFIER temp.toUpper(); $$ = new (PARSERHEAP())ElemDDLParamName(temp); } - | nonreserved_func_word + | nonreserved_func_word { NAString temp = *(unicodeToChar (ToTokvalPlusYYText(&$1)->yytext, diff --git a/core/sql/parser/ulexer.cpp b/core/sql/parser/ulexer.cpp index 3021814d86..c19fe0ea06 100644 --- a/core/sql/parser/ulexer.cpp +++ b/core/sql/parser/ulexer.cpp @@ -3179,6 +3179,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, 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) diff --git a/core/sql/regress/executor/EXPECTED021.SB b/core/sql/regress/executor/EXPECTED021.SB new file mode 100644 index 0000000000..4740cdf902 --- /dev/null +++ b/core/sql/regress/executor/EXPECTED021.SB @@ -0,0 +1,180 @@ +>>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. +>> +>>--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; diff --git a/core/sql/regress/executor/TEST021 b/core/sql/regress/executor/TEST021 new file mode 100644 index 0000000000..66021a67ba --- /dev/null +++ b/core/sql/regress/executor/TEST021 @@ -0,0 +1,89 @@ +-- 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; + +--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; + 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 diff --git a/core/sql/sqlcomp/DefaultConstants.h b/core/sql/sqlcomp/DefaultConstants.h index 2098024fcd..237d4ef374 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 @@ -3350,6 +3349,9 @@ enum DefaultConstants // both compressed and uncompressed hdfs files HDFS_IO_INTERIM_BYTEARRAY_SIZE_IN_KB, + CONNECTBY_MAX_DEEP, + CONNECTBY_MAX_SIZE, + // This enum constant must be the LAST one in the list; it's a count, // not an Attribute (it's not IN DefaultDefaults; it's the SIZE of it)! __NUM_DEFAULT_ATTRIBUTES diff --git a/core/sql/sqlcomp/nadefaults.cpp b/core/sql/sqlcomp/nadefaults.cpp index e56efa5b9d..067cd5b3dd 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"),