TD-13338 SELECT statement translate code
This commit is contained in:
parent
69d196815b
commit
090250f994
|
@ -121,6 +121,14 @@ typedef struct SColumnNode {
|
|||
typedef struct SValueNode {
|
||||
SExprNode node; // QUERY_NODE_VALUE
|
||||
char* literal;
|
||||
bool isDuration;
|
||||
union {
|
||||
bool b;
|
||||
int64_t i;
|
||||
uint64_t u;
|
||||
double d;
|
||||
char* p;
|
||||
} datum;
|
||||
} SValueNode;
|
||||
|
||||
typedef enum EOperatorType {
|
||||
|
@ -181,7 +189,7 @@ typedef struct SNodeListNode {
|
|||
} SNodeListNode;
|
||||
|
||||
typedef struct SFunctionNode {
|
||||
SExprNode type; // QUERY_NODE_FUNCTION
|
||||
SExprNode node; // QUERY_NODE_FUNCTION
|
||||
char functionName[TSDB_FUNC_NAME_LEN];
|
||||
int32_t funcId;
|
||||
SNodeList* pParameterList;
|
||||
|
|
|
@ -441,10 +441,13 @@ int32_t* taosGetErrno();
|
|||
#define TSDB_CODE_SCH_INTERNAL_ERROR TAOS_DEF_ERROR_CODE(0, 0x2502) //scheduler internal error
|
||||
|
||||
//parser
|
||||
#define TSDB_CODE_PARSER_INVALID_COLUMN TAOS_DEF_ERROR_CODE(0, 0x2601) //invalid column name
|
||||
#define TSDB_CODE_PARSER_TABLE_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x2602) //table not exist
|
||||
#define TSDB_CODE_PARSER_AMBIGUOUS_COLUMN TAOS_DEF_ERROR_CODE(0, 0x2603) //ambiguous column
|
||||
#define TSDB_CODE_PARSER_WRONG_VALUE_TYPE TAOS_DEF_ERROR_CODE(0, 0x2604) //wrong value type
|
||||
#define TSDB_CODE_PAR_INVALID_COLUMN TAOS_DEF_ERROR_CODE(0, 0x2601) //invalid column name
|
||||
#define TSDB_CODE_PAR_TABLE_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x2602) //table not exist
|
||||
#define TSDB_CODE_PAR_AMBIGUOUS_COLUMN TAOS_DEF_ERROR_CODE(0, 0x2603) //ambiguous column
|
||||
#define TSDB_CODE_PAR_WRONG_VALUE_TYPE TAOS_DEF_ERROR_CODE(0, 0x2604) //wrong value type
|
||||
#define TSDB_CODE_PAR_FUNTION_PARA_NUM TAOS_DEF_ERROR_CODE(0, 0x2605) //invalid number of arguments
|
||||
#define TSDB_CODE_PAR_FUNTION_PARA_TYPE TAOS_DEF_ERROR_CODE(0, 0x2606) //inconsistent datatypes
|
||||
#define TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION TAOS_DEF_ERROR_CODE(0, 0x2607) //there mustn't be aggregation
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -78,3 +78,11 @@ FuncDef setExecFuncs(FuncDef def, FExecGetEnv getEnv, FExecInit init, FExecProce
|
|||
int32_t registerFunc(FuncDef func) {
|
||||
|
||||
}
|
||||
|
||||
int32_t fmGetFuncResultType(FuncMgtHandle handle, SFunctionNode* pFunc) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
bool fmIsAggFunc(int32_t funcId) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -118,14 +118,22 @@ SNode* createValueNode(SAstCreateContext* pCxt, int32_t dataType, const SToken*
|
|||
val->literal = strndup(pLiteral->z, pLiteral->n);
|
||||
CHECK_OUT_OF_MEM(val->literal);
|
||||
val->node.resType.type = dataType;
|
||||
val->node.resType.bytes = tDataTypes[TSDB_DATA_TYPE_BOOL].bytes;
|
||||
val->node.resType.bytes = tDataTypes[dataType].bytes;
|
||||
if (TSDB_DATA_TYPE_TIMESTAMP == dataType) {
|
||||
val->node.resType.precision = TSDB_TIME_PRECISION_MILLI;
|
||||
}
|
||||
return (SNode*)val;
|
||||
}
|
||||
|
||||
SNode* createDurationValueNode(SAstCreateContext* pCxt, const SToken* pLiteral) {
|
||||
SValueNode* val = (SValueNode*)nodesMakeNode(QUERY_NODE_VALUE);
|
||||
CHECK_OUT_OF_MEM(val);
|
||||
// todo : calc, for example, 10s
|
||||
val->literal = strndup(pLiteral->z, pLiteral->n);
|
||||
CHECK_OUT_OF_MEM(val->literal);
|
||||
val->isDuration = true;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
#include "parserImpl.h"
|
||||
|
||||
#include "astCreateContext.h"
|
||||
#include "functionMgt.h"
|
||||
#include "parserInt.h"
|
||||
#include "tglobal.h"
|
||||
#include "ttime.h"
|
||||
#include "ttoken.h"
|
||||
|
||||
typedef void* (*FMalloc)(size_t);
|
||||
|
@ -240,6 +243,7 @@ typedef enum ESqlClause {
|
|||
|
||||
typedef struct STranslateContext {
|
||||
SParseContext* pParseCxt;
|
||||
FuncMgtHandle fmgt;
|
||||
int32_t errCode;
|
||||
SMsgBuf msgBuf;
|
||||
SArray* pNsLevel; // element is SArray*, the element of this subarray is STableNode*
|
||||
|
@ -251,21 +255,30 @@ static int32_t translateSubquery(STranslateContext* pCxt, SNode* pNode);
|
|||
|
||||
static char* getSyntaxErrFormat(int32_t errCode) {
|
||||
switch (errCode) {
|
||||
case TSDB_CODE_PARSER_INVALID_COLUMN:
|
||||
case TSDB_CODE_PAR_INVALID_COLUMN:
|
||||
return "Invalid column name : %s";
|
||||
case TSDB_CODE_PARSER_TABLE_NOT_EXIST:
|
||||
case TSDB_CODE_PAR_TABLE_NOT_EXIST:
|
||||
return "Table does not exist : %s";
|
||||
case TSDB_CODE_PARSER_AMBIGUOUS_COLUMN:
|
||||
case TSDB_CODE_PAR_AMBIGUOUS_COLUMN:
|
||||
return "Column ambiguously defined : %s";
|
||||
case TSDB_CODE_PARSER_WRONG_VALUE_TYPE:
|
||||
case TSDB_CODE_PAR_WRONG_VALUE_TYPE:
|
||||
return "Invalid value type : %s";
|
||||
case TSDB_CODE_PAR_FUNTION_PARA_NUM:
|
||||
return "Invalid number of arguments : %s";
|
||||
case TSDB_CODE_PAR_FUNTION_PARA_TYPE:
|
||||
return "Inconsistent datatypes : %s";
|
||||
case TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION:
|
||||
return "There mustn't be aggregation";
|
||||
default:
|
||||
return "Unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t generateSyntaxErrMsg(STranslateContext* pCxt, int32_t errCode, const char* additionalInfo) {
|
||||
snprintf(pCxt->msgBuf.buf, pCxt->msgBuf.len, getSyntaxErrFormat(errCode), additionalInfo);
|
||||
static int32_t generateSyntaxErrMsg(STranslateContext* pCxt, int32_t errCode, ...) {
|
||||
va_list vArgList;
|
||||
va_start(vArgList, errCode);
|
||||
vsnprintf(pCxt->msgBuf.buf, pCxt->msgBuf.len, getSyntaxErrFormat(errCode), vArgList);
|
||||
va_end(vArgList);
|
||||
pCxt->errCode = errCode;
|
||||
return errCode;
|
||||
}
|
||||
|
@ -394,7 +407,7 @@ static bool translateColumnWithPrefix(STranslateContext* pCxt, SColumnNode* pCol
|
|||
if (findAndSetColumn(pCol, pTable)) {
|
||||
break;
|
||||
}
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_INVALID_COLUMN, pCol->colName);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -409,14 +422,14 @@ static bool translateColumnWithoutPrefix(STranslateContext* pCxt, SColumnNode* p
|
|||
STableNode* pTable = taosArrayGetP(pTables, i);
|
||||
if (findAndSetColumn(pCol, pTable)) {
|
||||
if (found) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_AMBIGUOUS_COLUMN, pCol->colName);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_AMBIGUOUS_COLUMN, pCol->colName);
|
||||
return false;
|
||||
}
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_INVALID_COLUMN, pCol->colName);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_INVALID_COLUMN, pCol->colName);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -429,8 +442,72 @@ static bool translateColumn(STranslateContext* pCxt, SColumnNode* pCol) {
|
|||
return translateColumnWithoutPrefix(pCxt, pCol);
|
||||
}
|
||||
|
||||
// check literal format
|
||||
static int32_t trimStringCopy(const char* src, int32_t len, char* dst) {
|
||||
// delete escape character: \\, \', \"
|
||||
char delim = src[0];
|
||||
int32_t cnt = 0;
|
||||
int32_t j = 0;
|
||||
for (uint32_t k = 1; k < len - 1; ++k) {
|
||||
if (src[k] == '\\' || (src[k] == delim && src[k + 1] == delim)) {
|
||||
dst[j] = src[k + 1];
|
||||
cnt++;
|
||||
j++;
|
||||
k++;
|
||||
continue;
|
||||
}
|
||||
dst[j] = src[k];
|
||||
j++;
|
||||
}
|
||||
dst[j] = '\0';
|
||||
return j;
|
||||
}
|
||||
|
||||
static bool translateValue(STranslateContext* pCxt, SValueNode* pVal) {
|
||||
if (pVal->isDuration) {
|
||||
char unit = 0;
|
||||
if (parseAbsoluteDuration(pVal->literal, strlen(pVal->literal), &pVal->datum.i, &unit, pVal->node.resType.precision) != TSDB_CODE_SUCCESS) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
switch (pVal->node.resType.type) {
|
||||
case TSDB_DATA_TYPE_NULL:
|
||||
break;
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
pVal->datum.b = (0 == strcasecmp(pVal->literal, "true"));
|
||||
break;
|
||||
case TSDB_DATA_TYPE_BIGINT: {
|
||||
char* endPtr = NULL;
|
||||
pVal->datum.i = strtoull(pVal->literal, &endPtr, 10);
|
||||
break;
|
||||
}
|
||||
case TSDB_DATA_TYPE_DOUBLE: {
|
||||
char* endPtr = NULL;
|
||||
pVal->datum.d = strtold(pVal->literal, &endPtr);
|
||||
break;
|
||||
}
|
||||
case TSDB_DATA_TYPE_BINARY: {
|
||||
int32_t n = strlen(pVal->literal);
|
||||
pVal->datum.p = calloc(1, n);
|
||||
trimStringCopy(pVal->literal, n, pVal->datum.p);
|
||||
break;
|
||||
}
|
||||
case TSDB_DATA_TYPE_TIMESTAMP: {
|
||||
int32_t n = strlen(pVal->literal);
|
||||
char* tmp = calloc(1, n);
|
||||
int32_t len = trimStringCopy(pVal->literal, n, tmp);
|
||||
if (taosParseTime(tmp, &pVal->datum.u, len, pVal->node.resType.precision, tsDaylight) != TSDB_CODE_SUCCESS) {
|
||||
tfree(tmp);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, pVal->literal);
|
||||
return false;
|
||||
}
|
||||
tfree(tmp);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -440,7 +517,7 @@ static bool translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
|||
if (nodesIsArithmeticOp(pOp)) {
|
||||
if (TSDB_DATA_TYPE_JSON == ldt.type || TSDB_DATA_TYPE_BLOB == ldt.type ||
|
||||
TSDB_DATA_TYPE_JSON == rdt.type || TSDB_DATA_TYPE_BLOB == rdt.type) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||
return false;
|
||||
}
|
||||
pOp->node.resType.type = TSDB_DATA_TYPE_DOUBLE;
|
||||
|
@ -449,7 +526,7 @@ static bool translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
|||
} else if (nodesIsComparisonOp(pOp)) {
|
||||
if (TSDB_DATA_TYPE_JSON == ldt.type || TSDB_DATA_TYPE_BLOB == ldt.type ||
|
||||
TSDB_DATA_TYPE_JSON == rdt.type || TSDB_DATA_TYPE_BLOB == rdt.type) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_WRONG_VALUE_TYPE, ((SExprNode*)(pOp->pRight))->aliasName);
|
||||
return false;
|
||||
}
|
||||
pOp->node.resType.type = TSDB_DATA_TYPE_BOOL;
|
||||
|
@ -463,6 +540,15 @@ static bool translateOperator(STranslateContext* pCxt, SOperatorNode* pOp) {
|
|||
}
|
||||
|
||||
static bool translateFunction(STranslateContext* pCxt, SFunctionNode* pFunc) {
|
||||
int32_t code = fmGetFuncResultType(pCxt->fmgt, pFunc);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
generateSyntaxErrMsg(pCxt, code, pFunc->functionName);
|
||||
return false;
|
||||
}
|
||||
if (fmIsAggFunc(pFunc->funcId) && (SQL_CLAUSE_FROM == pCxt->currClause || SQL_CLAUSE_WHERE == pCxt->currClause)) {
|
||||
generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -504,7 +590,7 @@ static int32_t translateTable(STranslateContext* pCxt, SNode* pTable) {
|
|||
code = catalogGetTableMeta(pCxt->pParseCxt->pCatalog, pCxt->pParseCxt->pTransporter, &(pCxt->pParseCxt->mgmtEpSet),
|
||||
toName(pCxt->pParseCxt->acctId, pRealTable, &name), &(pRealTable->pMeta));
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
return generateSyntaxErrMsg(pCxt, TSDB_CODE_PARSER_TABLE_NOT_EXIST, pRealTable->table.tableName);
|
||||
return generateSyntaxErrMsg(pCxt, TSDB_CODE_PAR_TABLE_NOT_EXIST, pRealTable->table.tableName);
|
||||
}
|
||||
code = addNamespace(pCxt, pRealTable);
|
||||
break;
|
||||
|
|
|
@ -118,6 +118,53 @@ private:
|
|||
return "Unknown Data Type " + to_string(dt.type);
|
||||
}
|
||||
|
||||
void valueNodeToStr(const SValueNode* pVal, string& str, bool isProject) {
|
||||
switch (pVal->node.resType.type) {
|
||||
case TSDB_DATA_TYPE_NULL:
|
||||
str.append("null");
|
||||
break;
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
str.append(pVal->datum.b ? "true" : "false");
|
||||
break;
|
||||
case TSDB_DATA_TYPE_TINYINT:
|
||||
case TSDB_DATA_TYPE_SMALLINT:
|
||||
case TSDB_DATA_TYPE_INT:
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
str.append(to_string(pVal->datum.i));
|
||||
break;
|
||||
case TSDB_DATA_TYPE_FLOAT:
|
||||
case TSDB_DATA_TYPE_DOUBLE:
|
||||
str.append(to_string(pVal->datum.d));
|
||||
break;
|
||||
case TSDB_DATA_TYPE_BINARY:
|
||||
case TSDB_DATA_TYPE_NCHAR:
|
||||
case TSDB_DATA_TYPE_VARCHAR:
|
||||
case TSDB_DATA_TYPE_VARBINARY:
|
||||
str.append(pVal->datum.p);
|
||||
break;
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
str.append(to_string(pVal->datum.u));
|
||||
break;
|
||||
case TSDB_DATA_TYPE_UTINYINT:
|
||||
case TSDB_DATA_TYPE_USMALLINT:
|
||||
case TSDB_DATA_TYPE_UINT:
|
||||
case TSDB_DATA_TYPE_UBIGINT:
|
||||
str.append(to_string(pVal->datum.u));
|
||||
break;
|
||||
case TSDB_DATA_TYPE_JSON:
|
||||
case TSDB_DATA_TYPE_DECIMAL:
|
||||
case TSDB_DATA_TYPE_BLOB:
|
||||
str.append("JSON or DECIMAL or BLOB");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
str.append(" [" + dataTypeToStr(pVal->node.resType) + "]");
|
||||
if (isProject) {
|
||||
str.append(" AS " + string(pVal->node.aliasName));
|
||||
}
|
||||
}
|
||||
|
||||
void nodeToStr(const SNode* node, string& str, bool isProject) {
|
||||
if (nullptr == node) {
|
||||
return;
|
||||
|
@ -142,12 +189,7 @@ private:
|
|||
break;
|
||||
}
|
||||
case QUERY_NODE_VALUE: {
|
||||
SValueNode* pVal = (SValueNode*)node;
|
||||
str.append(pVal->literal);
|
||||
str.append(" [" + dataTypeToStr(pVal->node.resType) + "]");
|
||||
if (isProject) {
|
||||
str.append(" AS " + string(pVal->node.aliasName));
|
||||
}
|
||||
valueNodeToStr((SValueNode*)node, str, isProject);
|
||||
break;
|
||||
}
|
||||
case QUERY_NODE_OPERATOR: {
|
||||
|
@ -391,10 +433,20 @@ TEST_F(NewParserTest, selectSimple) {
|
|||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(NewParserTest, selectConstant) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT 123, 20.4, 'abc', \"wxy\", TIMESTAMP '2022-02-09 17:30:20', true, false, 10s FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
|
||||
bind("SELECT 1234567890123456789012345678901234567890, 20.1234567890123456789012345678901234567890, 'abc', \"wxy\", TIMESTAMP '2022-02-09 17:30:20', true, false, 15s FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
TEST_F(NewParserTest, selectExpression) {
|
||||
setDatabase("root", "test");
|
||||
|
||||
bind("SELECT c1 + 10, c2 FROM t1");
|
||||
bind("SELECT ts + 10s, c1 + 10, concat(c2, 'abc') FROM t1");
|
||||
ASSERT_TRUE(run());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue