/* * Copyright (c) 2019 TAOS Data, Inc. * * This program is free software: you can use, redistribute, and/or modify * it under the terms of the GNU Affero General Public License, version 3 * or later ("AGPL"), as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "parser.h" #include "parInt.h" #include "parToken.h" static bool isInsertSql(const char* pStr, size_t length) { int32_t index = 0; do { SToken t0 = tStrGetToken((char*) pStr, &index, false); if (t0.type != TK_NK_LP) { return t0.type == TK_INSERT || t0.type == TK_IMPORT; } } while (1); } static int32_t parseSqlIntoAst(SParseContext* pCxt, SQuery** pQuery) { int32_t code = parse(pCxt, pQuery); if (TSDB_CODE_SUCCESS == code) { code = translate(pCxt, *pQuery); } if (TSDB_CODE_SUCCESS == code) { code = calculateConstant(pCxt, *pQuery); } return code; } int32_t qParseQuerySql(SParseContext* pCxt, SQuery** pQuery) { int32_t code = TSDB_CODE_SUCCESS; if (isInsertSql(pCxt->pSql, pCxt->sqlLen)) { code = parseInsertSql(pCxt, pQuery); } else { code = parseSqlIntoAst(pCxt, pQuery); } terrno = code; return code; } int32_t qCreateSName(SName* pName, char* pTableName, int32_t acctId, char* dbName, char *msgBuf, int32_t msgBufLen) { SMsgBuf msg = {.buf = msgBuf, .len =msgBufLen}; SToken sToken; int32_t code = 0; char *tbName = NULL; NEXT_TOKEN(pTableName, sToken); if (sToken.n == 0) { return buildInvalidOperationMsg(&msg, "empty table name"); } code = createSName(pName, &sToken, acctId, dbName, &msg); if (code) { return code; } NEXT_TOKEN(pTableName, sToken); if (SToken.n > 0) { return buildInvalidOperationMsg(&msg, "table name format is wrong"); } return TSDB_CODE_SUCCESS; } int32_t qBindStmtData(STableDataBlocks *pDataBlock, TAOS_MULTI_BIND *bind, char *msgBuf, int32_t msgBufLen) { SSchema* pSchema = getTableColumnSchema(pDataBlock->pTableMeta); int32_t extendedRowSize = getExtendedRowSize(pDataBlock); SParsedDataColInfo* spd = &pDataBlock->boundColumnInfo; SRowBuilder* pBuilder = &pDataBlock->rowBuilder; SMemParam param = {.rb = pBuilder}; SMsgBuf pBuf = {.buf = msgBuf, .len = msgBufLen}; CHECK_CODE(allocateMemForSize(pDataBlock, extendedRowSize * bind->num); for (int32_t r = 0; r < bind->num; ++r) { STSRow* row = (STSRow*)(pDataBlock->pData + pDataBlock->size); // skip the SSubmitBlk header tdSRowResetBuf(pBuilder, row); // 1. set the parsed value from sql string for (int c = 0; c < spd->numOfBound; ++c) { SSchema* pColSchema = &pSchema[spd->boundColumns[c] - 1]; param.schema = pColSchema; getSTSRowAppendInfo(pBuilder->rowType, spd, c, ¶m.toffset, ¶m.colIdx); if (bind[c].is_null && bind[c].is_null[r]) { CHECK_CODE(MemRowAppend(&pBuf, NULL, 0, ¶m)); } else { int32_t colLen = pColSchema->bytes; if (IS_VAR_DATA_TYPE(pColSchema->type)) { colLen = bind[c].length[r]; } CHECK_CODE(MemRowAppend(&pBuf, (char *)bind[c].buffer + bind[c].buffer_length * r, colLen, ¶m)); } if (PRIMARYKEY_TIMESTAMP_COL_ID == pColSchema->colId) { TSKEY tsKey = TD_ROW_KEY(row); checkTimestamp(pDataBlock, (const char *)&tsKey); } } // set the null value for the columns that do not assign values if ((spd->numOfBound < spd->numOfCols) && TD_IS_TP_ROW(row)) { for (int32_t i = 0; i < spd->numOfCols; ++i) { if (spd->cols[i].valStat == VAL_STAT_NONE) { // the primary TS key is not VAL_STAT_NONE tdAppendColValToTpRow(pBuilder, TD_VTYPE_NONE, getNullValue(pSchema[i].type), true, pSchema[i].type, i, spd->cols[i].toffset); } } } pDataBlock->size += extendedRowSize; } SSubmitBlk *pBlocks = (SSubmitBlk *)(pDataBlock->pData); if (TSDB_CODE_SUCCESS != setBlockInfo(pBlocks, pDataBlock, bind->num)) { return buildInvalidOperationMsg(&pBuf, "too many rows in sql, total number of rows should be less than 32767"); } return TSDB_CODE_SUCCESS; } int32_t qBuildStmtOutput(SQuery* pQuery, SHashObj* pVgHash, SHashObj* pBlockHash) { SVnodeModifOpStmt *modifyNode = (SVnodeModifOpStmt *)pQuery->pRoot; int32_t code = 0; SInsertParseContext insertCtx = { .pVgroupsHashObj = pVgHash, .pTableBlockHashObj = pBlockHash, .pOutput = pQuery->pRoot }; // merge according to vgId if (taosHashGetSize(insertCtx.pTableBlockHashObj) > 0) { CHECK_CODE_GOTO(mergeTableDataBlocks(insertCtx.pTableBlockHashObj, modifyNode->payloadType, &insertCtx.pVgDataBlocks), _return); } CHECK_CODE(buildOutput(&insertCtx)); return TSDB_CODE_SUCCESS; } int32_t buildBoundFields(SParsedDataColInfo *boundInfo, SSchema *pSchema, int32_t *fieldNum, TAOS_FIELD** fields) { *fields = taosMemoryCalloc(boundInfo->numOfBound, sizeof(TAOS_FIELD)); if (NULL == *fields) { return TSDB_CODE_OUT_OF_MEMORY; } for (int32_t i = 0; i < boundInfo->numOfBound; ++i) { SSchema* pTagSchema = &pSchema[boundInfo->boundColumns[i] - 1]; strcpy((*fields)[i].name, pTagSchema->name); (*fields)[i].type = pTagSchema->type; (*fields)[i].bytes = pTagSchema->bytes; } *fieldNum = boundInfo->numOfBound; return TSDB_CODE_SUCCESS; } int32_t qBuildStmtTagFields(STableDataBlocks *pDataBlock, void *boundTags, int32_t *fieldNum, TAOS_FIELD** fields) { SParsedDataColInfo* tags = (SParsedDataColInfo*)boundTags; if (NULL == tags) { return TSDB_CODE_QRY_APP_ERROR; } SSchema* pSchema = getTableTagSchema(pDataBlock->pTableMeta); if (tags->numOfBound <= 0) { *fieldNum = 0; *fields = NULL; return TSDB_CODE_SUCCESS; } CHECK_CODE(buildBoundFields(tags, pSchema, fieldNum, fields)); return TSDB_CODE_SUCCESS; } int32_t qBuildStmtColFields(STableDataBlocks *pDataBlock, int32_t *fieldNum, TAOS_FIELD** fields) { SSchema* pSchema = getTableColumnSchema(pDataBlock->pTableMeta); if (pDataBlock->boundColumnInfo.numOfBound <= 0) { *fieldNum = 0; *fields = NULL; return TSDB_CODE_SUCCESS; } CHECK_CODE(buildBoundFields(&pDataBlock->boundColumnInfo, pSchema, fieldNum, fields)); return TSDB_CODE_SUCCESS; } void qDestroyQuery(SQuery* pQueryNode) { if (NULL == pQueryNode) { return; } nodesDestroyNode(pQueryNode->pRoot); taosMemoryFreeClear(pQueryNode->pResSchema); if (NULL != pQueryNode->pCmdMsg) { taosMemoryFreeClear(pQueryNode->pCmdMsg->pMsg); taosMemoryFreeClear(pQueryNode->pCmdMsg); } taosArrayDestroy(pQueryNode->pDbList); taosArrayDestroy(pQueryNode->pTableList); taosMemoryFreeClear(pQueryNode); } int32_t qExtractResultSchema(const SNode* pRoot, int32_t* numOfCols, SSchema** pSchema) { return extractResultSchema(pRoot, numOfCols, pSchema); }