fix: add window_offset translate

This commit is contained in:
dapan1121 2023-11-28 14:35:11 +08:00
parent 19752b020f
commit 84cc80be1c
15 changed files with 633 additions and 553 deletions

View File

@ -78,7 +78,7 @@ int64_t taosTimeTruncate(int64_t ts, const SInterval* pInterval);
int32_t taosTimeCountIntervalForFill(int64_t skey, int64_t ekey, int64_t interval, char unit, int32_t precision, int32_t order);
int32_t parseAbsoluteDuration(const char* token, int32_t tokenlen, int64_t* ts, char* unit, int32_t timePrecision);
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision);
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision, bool negativeAllow);
int32_t taosParseTime(const char* timestr, int64_t* pTime, int32_t len, int32_t timePrec, int8_t dayligth);
void deltaToUtcInitOnce();

View File

@ -380,6 +380,8 @@
#define TK_NK_SPACE 600
#define TK_NK_COMMENT 601
#define TK_NK_ILLEGAL 602

View File

@ -99,10 +99,16 @@ typedef struct STargetNode {
SNode* pExpr;
} STargetNode;
#define VALUE_FLAG_IS_DURATION (1 << 0)
#define VALUE_FLAG_IS_TIME_OFFSET (1 << 1)
#define IS_DURATION_VAL(_flag) ((_flag) & VALUE_FLAG_IS_DURATION)
#define IS_TIME_OFFSET_VAL(_flag) ((_flag) & VALUE_FLAG_IS_TIME_OFFSET)
typedef struct SValueNode {
SExprNode node; // QUERY_NODE_VALUE
char* literal;
bool isDuration;
int32_t flag;
bool translate;
bool notReserved;
bool isNull;

View File

@ -659,12 +659,12 @@ int32_t parseAbsoluteDuration(const char* token, int32_t tokenlen, int64_t* dura
return getDuration(timestamp, *unit, duration, timePrecision);
}
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision) {
int32_t parseNatualDuration(const char* token, int32_t tokenLen, int64_t* duration, char* unit, int32_t timePrecision, bool negativeAllow) {
errno = 0;
/* get the basic numeric value */
*duration = taosStr2Int64(token, NULL, 10);
if (*duration < 0 || errno != 0) {
if ((*duration < 0 && !negativeAllow) || errno != 0) {
return -1;
}

View File

@ -46,7 +46,7 @@ static int32_t invaildFuncParaValueErrMsg(char* pErrBuf, int32_t len, const char
#define TIME_UNIT_TOO_SMALL 2
static int32_t validateTimeUnitParam(uint8_t dbPrec, const SValueNode* pVal) {
if (!pVal->isDuration) {
if (!IS_DURATION_VAL(pVal->flag)) {
return TIME_UNIT_INVALID;
}
@ -225,7 +225,6 @@ static int32_t addTimezoneParam(SNodeList* pList) {
}
pVal->literal = strndup(buf, len);
pVal->isDuration = false;
pVal->translate = true;
pVal->node.resType.type = TSDB_DATA_TYPE_BINARY;
pVal->node.resType.bytes = len + VARSTR_HEADER_SIZE;
@ -245,7 +244,6 @@ static int32_t addDbPrecisonParam(SNodeList** pList, uint8_t precision) {
}
pVal->literal = NULL;
pVal->isDuration = false;
pVal->translate = true;
pVal->notReserved = true;
pVal->node.resType.type = TSDB_DATA_TYPE_TINYINT;

View File

@ -125,7 +125,7 @@ static int32_t columnNodeCopy(const SColumnNode* pSrc, SColumnNode* pDst) {
static int32_t valueNodeCopy(const SValueNode* pSrc, SValueNode* pDst) {
COPY_BASE_OBJECT_FIELD(node, exprNodeCopy);
COPY_CHAR_POINT_FIELD(literal);
COPY_SCALAR_FIELD(isDuration);
COPY_SCALAR_FIELD(flag);
COPY_SCALAR_FIELD(translate);
COPY_SCALAR_FIELD(notReserved);
COPY_SCALAR_FIELD(isNull);

View File

@ -3556,7 +3556,7 @@ static int32_t jsonToColumnNode(const SJson* pJson, void* pObj) {
static const char* jkValueLiteralSize = "LiteralSize";
static const char* jkValueLiteral = "Literal";
static const char* jkValueDuration = "Duration";
static const char* jkValueFlag = "Flag";
static const char* jkValueTranslate = "Translate";
static const char* jkValueNotReserved = "NotReserved";
static const char* jkValueIsNull = "IsNull";
@ -3640,7 +3640,7 @@ static int32_t valueNodeToJson(const void* pObj, SJson* pJson) {
code = tjsonAddStringToObject(pJson, jkValueLiteral, pNode->literal);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonAddBoolToObject(pJson, jkValueDuration, pNode->isDuration);
code = tjsonAddBoolToObject(pJson, jkValueFlag, pNode->flag);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonAddBoolToObject(pJson, jkValueTranslate, pNode->translate);
@ -3794,7 +3794,7 @@ static int32_t jsonToValueNode(const SJson* pJson, void* pObj) {
code = tjsonDupStringValue(pJson, jkValueLiteral, &pNode->literal);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonGetBoolValue(pJson, jkValueDuration, &pNode->isDuration);
code = tjsonGetIntValue(pJson, jkValueFlag, &pNode->flag);
}
if (TSDB_CODE_SUCCESS == code) {
code = tjsonGetBoolValue(pJson, jkValueTranslate, &pNode->translate);

View File

@ -788,7 +788,7 @@ static int32_t msgToColumnNode(STlvDecoder* pDecoder, void* pObj) {
enum {
VALUE_CODE_EXPR_BASE = 1,
VALUE_CODE_LITERAL,
VALUE_CODE_IS_DURATION,
VALUE_CODE_FLAG,
VALUE_CODE_TRANSLATE,
VALUE_CODE_NOT_RESERVED,
VALUE_CODE_IS_NULL,
@ -849,7 +849,7 @@ static int32_t valueNodeToMsg(const void* pObj, STlvEncoder* pEncoder) {
code = tlvEncodeCStr(pEncoder, VALUE_CODE_LITERAL, pNode->literal);
}
if (TSDB_CODE_SUCCESS == code) {
code = tlvEncodeBool(pEncoder, VALUE_CODE_IS_DURATION, pNode->isDuration);
code = tlvEncodeI32(pEncoder, VALUE_CODE_FLAG, pNode->flag);
}
if (TSDB_CODE_SUCCESS == code) {
code = tlvEncodeBool(pEncoder, VALUE_CODE_TRANSLATE, pNode->translate);
@ -972,8 +972,8 @@ static int32_t msgToValueNode(STlvDecoder* pDecoder, void* pObj) {
case VALUE_CODE_LITERAL:
code = tlvDecodeCStrP(pTlv, &pNode->literal);
break;
case VALUE_CODE_IS_DURATION:
code = tlvDecodeBool(pTlv, &pNode->isDuration);
case VALUE_CODE_FLAG:
code = tlvDecodeI32(pTlv, &pNode->flag);
break;
case VALUE_CODE_TRANSLATE:
code = tlvDecodeBool(pTlv, &pNode->translate);

View File

@ -2396,7 +2396,6 @@ SValueNode* nodesMakeValueNodeFromString(char* literal) {
pValNode->datum.p = p;
pValNode->literal = tstrdup(literal);
pValNode->translate = true;
pValNode->isDuration = false;
pValNode->isNull = false;
}
return pValNode;
@ -2409,7 +2408,6 @@ SValueNode* nodesMakeValueNodeFromBool(bool b) {
pValNode->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
nodesSetValueNodeValue(pValNode, &b);
pValNode->translate = true;
pValNode->isDuration = false;
pValNode->isNull = false;
}
return pValNode;

View File

@ -111,6 +111,7 @@ SNode* createValueNode(SAstCreateContext* pCxt, int32_t dataType, const SToken*
SNodeList* createHintNodeList(SAstCreateContext* pCxt, const SToken* pLiteral);
SNode* createIdentifierValueNode(SAstCreateContext* pCxt, SToken* pLiteral);
SNode* createDurationValueNode(SAstCreateContext* pCxt, const SToken* pLiteral);
SNode* createTimeOffsetValueNode(SAstCreateContext* pCxt, const SToken* pLiteral);
SNode* createDefaultDatabaseCondValue(SAstCreateContext* pCxt);
SNode* createPlaceholderValueNode(SAstCreateContext* pCxt, const SToken* pLiteral);
SNode* setProjectionAlias(SAstCreateContext* pCxt, SNode* pNode, SToken* pAlias);

View File

@ -1096,11 +1096,15 @@ join_subtype(A) ::= WINDOW.
window_offset_clause_opt(A) ::= . { A = NULL; }
window_offset_clause_opt(A) ::= WINDOW_OFFSET NK_LP window_offset_literal(B)
NK_COMMA window_offset_literal(C) NK_RP. { A = createWindowOffsetNode(pCxt, releaseRawExprNode(pCxt, B), releaseRawExprNode(pCxt, C)); }
window_offset_literal(A) ::= NK_VARIABLE(B). { A = createRawExprNode(pCxt, &B, createDurationValueNode(pCxt, &B)); }
window_offset_literal(A) ::= NK_INTEGER(B). { A = createRawExprNode(pCxt, &B, createDurationValueNode(pCxt, &B)); }
NK_COMMA window_offset_literal(C) NK_RP. { A = createWindowOffsetNode(pCxt, releaseRawExprNode(pCxt, B), releaseRawExprNode(pCxt, C)); }
window_offset_literal(A) ::= NK_VARIABLE(B). { A = createRawExprNode(pCxt, &B, createTimeOffsetValueNode(pCxt, &B)); }
window_offset_literal(A) ::= NK_MINUS(B) NK_VARIABLE(C). {
SToken t = B;
t.n = (C.z + C.n) - B.z;
A = createRawExprNode(pCxt, &t, createTimeOffsetValueNode(pCxt, &t));
}
jlimit_clause_opt(A) ::= . { A = NULL; }
jlimit_clause_opt(A) ::= JLIMIT NK_INTEGER(B). { A = createLimitNode(pCxt, &B, NULL); }

View File

@ -366,7 +366,6 @@ SNode* createValueNode(SAstCreateContext* pCxt, int32_t dataType, const SToken*
if (TSDB_DATA_TYPE_TIMESTAMP == dataType) {
val->node.resType.precision = TSDB_TIME_PRECISION_MILLI;
}
val->isDuration = false;
val->translate = false;
return (SNode*)val;
}
@ -544,7 +543,7 @@ SNode* createDurationValueNode(SAstCreateContext* pCxt, const SToken* pLiteral)
val->literal = strndup(pLiteral->z, pLiteral->n);
}
CHECK_OUT_OF_MEM(val->literal);
val->isDuration = true;
val->flag |= VALUE_FLAG_IS_DURATION;
val->translate = false;
val->node.resType.type = TSDB_DATA_TYPE_BIGINT;
val->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes;
@ -552,6 +551,52 @@ SNode* createDurationValueNode(SAstCreateContext* pCxt, const SToken* pLiteral)
return (SNode*)val;
}
SNode* createTimeOffsetValueNode(SAstCreateContext* pCxt, const SToken* pLiteral) {
CHECK_PARSER_STATUS(pCxt);
SValueNode* val = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
CHECK_OUT_OF_MEM(val);
if (pLiteral->type == TK_NK_STRING) {
// like '100s' or "100d"
// check format: ^[0-9]+[smwbauhdny]$'
if (pLiteral->n < 4) {
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, pLiteral->z);
return NULL;
}
char unit = pLiteral->z[pLiteral->n - 2];
switch (unit) {
case 'a':
case 'b':
case 'd':
case 'h':
case 'm':
case 's':
case 'u':
case 'w':
break;
default:
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, pLiteral->z);
return NULL;
}
for (uint32_t i = 1; i < pLiteral->n - 2; ++i) {
if (!isdigit(pLiteral->z[i])) {
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_SYNTAX_ERROR, pLiteral->z);
return NULL;
}
}
val->literal = strndup(pLiteral->z + 1, pLiteral->n - 2);
} else {
val->literal = strndup(pLiteral->z, pLiteral->n);
}
CHECK_OUT_OF_MEM(val->literal);
val->flag |= VALUE_FLAG_IS_TIME_OFFSET;
val->translate = false;
val->node.resType.type = TSDB_DATA_TYPE_BIGINT;
val->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes;
val->node.resType.precision = TSDB_TIME_PRECISION_MILLI;
return (SNode*)val;
}
SNode* createDefaultDatabaseCondValue(SAstCreateContext* pCxt) {
CHECK_PARSER_STATUS(pCxt);
if (NULL == pCxt->pQueryCxt->db) {
@ -562,7 +607,6 @@ SNode* createDefaultDatabaseCondValue(SAstCreateContext* pCxt) {
CHECK_OUT_OF_MEM(val);
val->literal = taosStrdup(pCxt->pQueryCxt->db);
CHECK_OUT_OF_MEM(val->literal);
val->isDuration = false;
val->translate = false;
val->node.resType.type = TSDB_DATA_TYPE_BINARY;
val->node.resType.bytes = strlen(val->literal);

View File

@ -1182,13 +1182,23 @@ static int32_t parseBoolFromValueNode(STranslateContext* pCxt, SValueNode* pVal)
static EDealRes translateDurationValue(STranslateContext* pCxt, SValueNode* pVal) {
if (parseNatualDuration(pVal->literal, strlen(pVal->literal), &pVal->datum.i, &pVal->unit,
pVal->node.resType.precision) != TSDB_CODE_SUCCESS) {
pVal->node.resType.precision, false) != TSDB_CODE_SUCCESS) {
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
}
*(int64_t*)&pVal->typeData = pVal->datum.i;
return DEAL_RES_CONTINUE;
}
static EDealRes translateTimeOffsetValue(STranslateContext* pCxt, SValueNode* pVal) {
if (parseNatualDuration(pVal->literal, strlen(pVal->literal), &pVal->datum.i, &pVal->unit,
pVal->node.resType.precision, true) != TSDB_CODE_SUCCESS) {
return generateDealNodeErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
}
*(int64_t*)&pVal->typeData = pVal->datum.i;
return DEAL_RES_CONTINUE;
}
static EDealRes translateNormalValue(STranslateContext* pCxt, SValueNode* pVal, SDataType targetDt, bool strict) {
int32_t code = TSDB_CODE_SUCCESS;
switch (targetDt.type) {
@ -1371,8 +1381,10 @@ static EDealRes translateValueImpl(STranslateContext* pCxt, SValueNode* pVal, SD
pVal->node.resType.precision = getPrecisionFromCurrStmt(pCxt->pCurrStmt, targetDt.precision);
EDealRes res = DEAL_RES_CONTINUE;
if (pVal->isDuration) {
if (IS_DURATION_VAL(pVal->flag)) {
res = translateDurationValue(pCxt, pVal);
} else if (IS_TIME_OFFSET_VAL(pVal->flag)) {
res = translateTimeOffsetValue(pCxt, pVal);
} else {
res = translateNormalValue(pCxt, pVal, targetDt, strict);
}
@ -2861,7 +2873,6 @@ static EDealRes doTranslateTbName(SNode** pNode, void* pContext) {
pCxt->errCode = TSDB_CODE_OUT_OF_MEMORY;
return DEAL_RES_ERROR;
}
pVal->isDuration = false;
pVal->translate = true;
pVal->node.resType.type = TSDB_DATA_TYPE_BINARY;
pVal->node.resType.bytes = tbLen + VARSTR_HEADER_SIZE;
@ -2914,6 +2925,7 @@ static int32_t checkJoinTable(STranslateContext* pCxt, SJoinTableNode* pJoinTabl
}
static int32_t translateJoinTable(STranslateContext* pCxt, SJoinTableNode* pJoinTable) {
int32_t code = TSDB_CODE_SUCCESS;
EJoinType type = pJoinTable->joinType;
EJoinSubType* pSType = &pJoinTable->subType;
@ -2935,17 +2947,20 @@ static int32_t translateJoinTable(STranslateContext* pCxt, SJoinTableNode* pJoin
break;
}
if (NULL != pJoinTable->pWindowOffset && *pSType != JOIN_STYPE_WIN) {
return buildInvalidOperationMsg(&pCxt->msgBuf, "WINDOW_OFFSET only supported for WINDOW join");
}
if (NULL == pJoinTable->pWindowOffset && *pSType == JOIN_STYPE_WIN) {
if (NULL != pJoinTable->pWindowOffset) {
if (*pSType != JOIN_STYPE_WIN) {
return buildInvalidOperationMsg(&pCxt->msgBuf, "WINDOW_OFFSET only supported for WINDOW join");
}
code = translateExpr(pCxt, &pJoinTable->pWindowOffset);
} else if (*pSType == JOIN_STYPE_WIN) {
return buildInvalidOperationMsg(&pCxt->msgBuf, "WINDOW_OFFSET required for WINDOW join");
}
if (NULL != pJoinTable->pJLimit && *pSType != JOIN_STYPE_ASOF && *pSType != JOIN_STYPE_WIN) {
if (TSDB_CODE_SUCCESS == code && NULL != pJoinTable->pJLimit && *pSType != JOIN_STYPE_ASOF && *pSType != JOIN_STYPE_WIN) {
return buildInvalidOperationMsgExt(&pCxt->msgBuf, "JLIMIT not supported for %s join", getFullJoinTypeString(type, *pSType));
}
return TSDB_CODE_SUCCESS;
return code;
}
int32_t translateTable(STranslateContext* pCxt, SNode** pTable) {
@ -3841,7 +3856,7 @@ static int32_t createDefaultEveryNode(STranslateContext* pCxt, SNode** pOutput)
pEvery->node.resType.type = TSDB_DATA_TYPE_BIGINT;
pEvery->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes;
pEvery->isDuration = true;
pEvery->flag |= VALUE_FLAG_IS_DURATION;
pEvery->literal = taosStrdup("1s");
*pOutput = (SNode*)pEvery;
@ -4746,7 +4761,7 @@ static int64_t getUnitPerMinute(uint8_t precision) {
}
static int64_t getBigintFromValueNode(SValueNode* pVal) {
if (pVal->isDuration) {
if (IS_DURATION_VAL(pVal->flag)) {
return pVal->datum.i / getUnitPerMinute(pVal->node.resType.precision);
}
return pVal->datum.i;
@ -4863,12 +4878,12 @@ static int32_t checkDbKeepOption(STranslateContext* pCxt, SDatabaseOptions* pOpt
if (DEAL_RES_ERROR == translateValue(pCxt, pVal)) {
return pCxt->errCode;
}
if (pVal->isDuration && TIME_UNIT_MINUTE != pVal->unit && TIME_UNIT_HOUR != pVal->unit &&
if (IS_DURATION_VAL(pVal->flag) && TIME_UNIT_MINUTE != pVal->unit && TIME_UNIT_HOUR != pVal->unit &&
TIME_UNIT_DAY != pVal->unit) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_DB_OPTION,
"Invalid option keep unit: %c, only m, h, d allowed", pVal->unit);
}
if (!pVal->isDuration) {
if (!IS_DURATION_VAL(pVal->flag)) {
pVal->datum.i = pVal->datum.i * 1440;
}
}
@ -5010,16 +5025,16 @@ static int32_t checkDbRetentionsOption(STranslateContext* pCxt, SNodeList* pRete
SValueNode* pFreq = (SValueNode*)nodesListGetNode(((SNodeListNode*)pRetention)->pNodeList, 0);
SValueNode* pKeep = (SValueNode*)nodesListGetNode(((SNodeListNode*)pRetention)->pNodeList, 1);
ASSERTS(pFreq->isDuration && pKeep->isDuration, "Retentions freq/keep should have unit");
ASSERTS(IS_DURATION_VAL(pFreq->flag) && IS_DURATION_VAL(pKeep->flag), "Retentions freq/keep should have unit");
// check unit
if (pFreq->isDuration && TIME_UNIT_SECOND != pFreq->unit && TIME_UNIT_MINUTE != pFreq->unit &&
if (IS_DURATION_VAL(pFreq->flag) && TIME_UNIT_SECOND != pFreq->unit && TIME_UNIT_MINUTE != pFreq->unit &&
TIME_UNIT_HOUR != pFreq->unit && TIME_UNIT_DAY != pFreq->unit && TIME_UNIT_WEEK != pFreq->unit) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_DB_OPTION,
"Invalid option retentions(freq): %s, only s, m, h, d, w allowed", pFreq->literal);
}
if (pKeep->isDuration && TIME_UNIT_MINUTE != pKeep->unit && TIME_UNIT_HOUR != pKeep->unit &&
if (IS_DURATION_VAL(pKeep->flag) && TIME_UNIT_MINUTE != pKeep->unit && TIME_UNIT_HOUR != pKeep->unit &&
TIME_UNIT_DAY != pKeep->unit) {
return generateSyntaxErrMsgExt(&pCxt->msgBuf, TSDB_CODE_PAR_INVALID_DB_OPTION,
"Invalid option retentions(keep): %s, only m, h, d allowed", pKeep->literal);
@ -5970,7 +5985,7 @@ static SNode* makeIntervalVal(SRetention* pRetension, int8_t precision) {
nodesDestroyNode((SNode*)pVal);
return NULL;
}
pVal->isDuration = true;
pVal->flag |= VALUE_FLAG_IS_DURATION;
pVal->node.resType.type = TSDB_DATA_TYPE_BIGINT;
pVal->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BIGINT].bytes;
pVal->node.resType.precision = precision;

File diff suppressed because it is too large Load Diff

View File

@ -557,7 +557,8 @@ static int32_t createJoinLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect
// set the output
if (TSDB_CODE_SUCCESS == code) {
SNodeList* pColList = NULL;
if (QUERY_NODE_REAL_TABLE == nodeType(pJoinTable->pLeft) && !pJoin->isLowLevelJoin) {
// if (QUERY_NODE_REAL_TABLE == nodeType(pJoinTable->pLeft) && !pJoin->isLowLevelJoin) {
if (QUERY_NODE_REAL_TABLE == nodeType(pJoinTable->pLeft)) {
code = nodesCollectColumns(pSelect, SQL_CLAUSE_WHERE, ((SRealTableNode*)pJoinTable->pLeft)->table.tableAlias, COLLECT_COL_TYPE_ALL, &pColList);
} else {
pJoin->node.pTargets = nodesCloneList(pLeft->pTargets);
@ -573,7 +574,8 @@ static int32_t createJoinLogicNode(SLogicPlanContext* pCxt, SSelectStmt* pSelect
if (TSDB_CODE_SUCCESS == code) {
SNodeList* pColList = NULL;
if (QUERY_NODE_REAL_TABLE == nodeType(pJoinTable->pRight) && !pJoin->isLowLevelJoin) {
// if (QUERY_NODE_REAL_TABLE == nodeType(pJoinTable->pRight) && !pJoin->isLowLevelJoin) {
if (QUERY_NODE_REAL_TABLE == nodeType(pJoinTable->pRight)) {
code = nodesCollectColumns(pSelect, SQL_CLAUSE_WHERE, ((SRealTableNode*)pJoinTable->pRight)->table.tableAlias, COLLECT_COL_TYPE_ALL, &pColList);
} else {
if (pJoin->node.pTargets) {