From 5ed10d3a4c0014ae590e8437baced296b74db97e Mon Sep 17 00:00:00 2001 From: yihaoDeng Date: Sun, 13 Sep 2020 21:18:55 +0000 Subject: [PATCH] suppport cmd show-create-table and show-create-db --- src/client/inc/tsclient.h | 1 + src/client/src/tscLocal.c | 582 +++++++++++++++++++++++++++++++-- src/client/src/tscSQLParser.c | 33 ++ src/client/src/tscSchemaUtil.c | 1 + src/client/src/tscServer.c | 7 + src/client/src/tscSql.c | 2 + src/client/src/tscSubquery.c | 1 + src/common/inc/tcmdtype.h | 3 + src/inc/taosmsg.h | 1 + src/inc/ttokendef.h | 198 +++++------ src/mnode/src/mnodeTable.c | 3 + src/query/inc/sql.y | 10 + 12 files changed, 717 insertions(+), 125 deletions(-) diff --git a/src/client/inc/tsclient.h b/src/client/inc/tsclient.h index 5f4a46ddad..8bb146b1ad 100644 --- a/src/client/inc/tsclient.h +++ b/src/client/inc/tsclient.h @@ -98,6 +98,7 @@ typedef struct STableMeta { uint8_t tableType; int16_t sversion; int16_t tversion; + char sTableId[TSDB_TABLE_FNAME_LEN]; SCMVgroupInfo vgroupInfo; SCMCorVgroupInfo corVgroupInfo; STableId id; diff --git a/src/client/src/tscLocal.c b/src/client/src/tscLocal.c index b240d357a8..6d48350f73 100644 --- a/src/client/src/tscLocal.c +++ b/src/client/src/tscLocal.c @@ -24,7 +24,30 @@ #include "tscUtil.h" #include "tschemautil.h" #include "tsclient.h" - +#include "taos.h" +#include "tscSubquery.h" + +#define STR_NOCASE_EQUAL(str1, len1, str2, len2) ((len1 == len2) && 0 == strncasecmp(str1, str2, len1)) + +typedef enum BuildType { + SCREATE_BUILD_TABLE = 1, + SCREATE_BUILD_DB = 2, +} BuildType; + +typedef enum Stage { + SCREATE_CALLBACK_QUERY = 1, + SCREATE_CALLBACK_RETRIEVE = 2, +} Stage; + +// support 'show create table' +typedef struct SCreateBuilder { + char sTableName[TSDB_TABLE_FNAME_LEN]; + char buf[TSDB_TABLE_FNAME_LEN]; + SSqlObj *pParentSql; + SSqlObj *pInterSql; + int32_t (*fp)(void *para, char* result); + Stage callStage; +} SCreateBuilder; static void tscSetLocalQueryResult(SSqlObj *pSql, const char *val, const char *columnName, int16_t type, size_t valueLength); static int32_t getToStringLength(const char *pData, int32_t length, int32_t type) { @@ -273,14 +296,512 @@ static int32_t tscProcessDescribeTable(SSqlObj *pSql) { tscFieldInfoUpdateOffset(pQueryInfo); return tscSetValueToResObj(pSql, rowLen); } +static int32_t tscGetNthFieldResult(TAOS_ROW row, TAOS_FIELD* fields, int *lengths, int idx, char *result) { + const char *val = row[idx]; + if (val == NULL) { + sprintf(result, "%s", TSDB_DATA_NULL_STR); + return -1; + } + uint8_t type = fields[idx].type; + int32_t length = lengths[idx]; + + switch (type) { + case TSDB_DATA_TYPE_BOOL: + sprintf(result, "%s", ((((int)(*((char *)val))) == 1) ? "true" : "false")); + break; + case TSDB_DATA_TYPE_TINYINT: + sprintf(result, "%d", (int)(*((char *)val))); + break; + case TSDB_DATA_TYPE_SMALLINT: + sprintf(result, "%d", (int)(*((short *)val))); + break; + case TSDB_DATA_TYPE_INT: + sprintf(result, "%d", *((int *)val)); + break; + case TSDB_DATA_TYPE_BIGINT: + sprintf(result, "%"PRId64, *((int64_t *)val)); + break; + case TSDB_DATA_TYPE_FLOAT: + sprintf(result, "%f", GET_FLOAT_VAL(val)); + break; + case TSDB_DATA_TYPE_DOUBLE: + sprintf(result, "%f", GET_DOUBLE_VAL(val)); + break; + case TSDB_DATA_TYPE_NCHAR: + case TSDB_DATA_TYPE_BINARY: + memcpy(result, val, length); + break; + case TSDB_DATA_TYPE_TIMESTAMP: + ///formatTimestamp(buf, *(int64_t*)val, TSDB_TIME_PRECISION_MICRO); + //memcpy(result, val, strlen(buf)); + sprintf(result, "%"PRId64, *((int64_t *)val)); + break; + default: + break; + } + return 0; +} + +void tscSCreateCallBack(void *param, TAOS_RES *tres, int code) { + if (param == NULL || tres == NULL) { + return; + } + SCreateBuilder *builder = (SCreateBuilder *)(param); + SSqlObj *pParentSql = builder->pParentSql; + SSqlObj *pSql = (SSqlObj *)tres; + + SSqlRes *pRes = &pParentSql->res; + pRes->code = taos_errno(pSql); + if (pRes->code != TSDB_CODE_SUCCESS) { + taos_free_result(pSql); + free(builder); + tscQueueAsyncRes(pParentSql); + return; + } + + if (builder->callStage == SCREATE_CALLBACK_QUERY) { + taos_fetch_rows_a(tres, tscSCreateCallBack, param); + builder->callStage = SCREATE_CALLBACK_RETRIEVE; + } else { + char *result = calloc(1, TSDB_MAX_BINARY_LEN); + pRes->code = builder->fp(builder, result); + + taos_free_result(pSql); + free(builder); + free(result); + + if (pRes->code == TSDB_CODE_SUCCESS) { + (*pParentSql->fp)(pParentSql->param, pParentSql, code); + } else { + tscQueueAsyncRes(pParentSql); + } + } +} + +TAOS_ROW tscFetchRow(void *param) { + SCreateBuilder *builder = (SCreateBuilder *)param; + if (builder == NULL) { + return NULL; + } + SSqlObj *pSql = builder->pInterSql; + if (pSql == NULL || pSql->signature != pSql) { + terrno = TSDB_CODE_TSC_DISCONNECTED; + return NULL; + } + + SSqlCmd *pCmd = &pSql->cmd; + SSqlRes *pRes = &pSql->res; + + if (pRes->qhandle == 0 || + pCmd->command == TSDB_SQL_RETRIEVE_EMPTY_RESULT || + pCmd->command == TSDB_SQL_INSERT) { + return NULL; + } + + // set the sql object owner + tscSetSqlOwner(pSql); + + // current data set are exhausted, fetch more data from node + if (pRes->row >= pRes->numOfRows && (pRes->completed != true || hasMoreVnodesToTry(pSql) || hasMoreClauseToTry(pSql)) && + (pCmd->command == TSDB_SQL_RETRIEVE || + pCmd->command == TSDB_SQL_RETRIEVE_LOCALMERGE || + pCmd->command == TSDB_SQL_TABLE_JOIN_RETRIEVE || + pCmd->command == TSDB_SQL_FETCH || + pCmd->command == TSDB_SQL_SHOW || + pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE || + pCmd->command == TSDB_SQL_SHOW_CREATE_DATABASE || + pCmd->command == TSDB_SQL_SELECT || + pCmd->command == TSDB_SQL_DESCRIBE_TABLE || + pCmd->command == TSDB_SQL_SERV_STATUS || + pCmd->command == TSDB_SQL_CURRENT_DB || + pCmd->command == TSDB_SQL_SERV_VERSION || + pCmd->command == TSDB_SQL_CLI_VERSION || + pCmd->command == TSDB_SQL_CURRENT_USER )) { + taos_fetch_rows_a(pSql, tscSCreateCallBack, param); + return NULL; + } + + void* data = doSetResultRowData(pSql, true); + + tscClearSqlOwner(pSql); + return data; +} +static int32_t tscGetTableTagValue(SCreateBuilder *builder, char *result) { + TAOS_ROW row = tscFetchRow(builder); + SSqlObj* pSql = builder->pInterSql; + + if (row == NULL) { + return TSDB_CODE_MND_INVALID_TABLE_NAME; + } + + int32_t* lengths = taos_fetch_lengths(pSql); + int num_fields = taos_num_fields(pSql); + TAOS_FIELD *fields = taos_fetch_fields(pSql); + + char buf[TSDB_COL_NAME_LEN + 16]; + for (int i = 0; i < num_fields; i++) { + memset(buf, 0, sizeof(buf)); + int32_t ret = tscGetNthFieldResult(row, fields, lengths, i, buf); + + if (i == 0) { + snprintf(result + strlen(result), TSDB_MAX_BINARY_LEN - strlen(result), "%s", "("); + } + if ((fields[i].type == TSDB_DATA_TYPE_NCHAR + || fields[i].type == TSDB_DATA_TYPE_BINARY + || fields[i].type == TSDB_DATA_TYPE_TIMESTAMP) && 0 == ret) { + snprintf(result + strlen(result), TSDB_MAX_BINARY_LEN - strlen(result), "\"%s\",", buf); + } else { + snprintf(result + strlen(result), TSDB_MAX_BINARY_LEN - strlen(result), "%s,", buf); + } + if (i == num_fields - 1) { + sprintf(result + strlen(result) - 1, "%s", ")"); + } + } + + if (0 == strlen(result)) { + return TSDB_CODE_MND_INVALID_TABLE_NAME; + } + return TSDB_CODE_SUCCESS; +} + + +// build 'show create table/database' result fields +static int32_t tscSCreateBuildResultFields(SSqlObj *pSql, BuildType type, const char *ddl) { + int32_t rowLen = 0; + int16_t ddlLen = strlen(ddl); + SColumnIndex index = {0}; + pSql->cmd.numOfCols = 2; + + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + pQueryInfo->order.order = TSDB_ORDER_ASC; + + TAOS_FIELD f; + if (type == SCREATE_BUILD_TABLE) { + f.type = TSDB_DATA_TYPE_BINARY; + f.bytes = (TSDB_COL_NAME_LEN - 1) + VARSTR_HEADER_SIZE; + tstrncpy(f.name, "Table", sizeof(f.name)); + } else { + f.type = TSDB_DATA_TYPE_BINARY; + f.bytes = (TSDB_DB_NAME_LEN - 1) + VARSTR_HEADER_SIZE; + tstrncpy(f.name, "Database", sizeof(f.name)); + } + + SFieldSupInfo* pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f); + pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, + f.bytes, f.bytes - VARSTR_HEADER_SIZE, false); + + rowLen += f.bytes; + f.bytes = (int16_t)(ddlLen + VARSTR_HEADER_SIZE); + f.type = TSDB_DATA_TYPE_BINARY; + if (type == SCREATE_BUILD_TABLE) { + tstrncpy(f.name, "Create Table", sizeof(f.name)); + } else { + tstrncpy(f.name, "Create Database", sizeof(f.name)); + } + + pInfo = tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f); + pInfo->pSqlExpr = tscSqlExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &index, TSDB_DATA_TYPE_BINARY, + (int16_t)(ddlLen + VARSTR_HEADER_SIZE), ddlLen, false); + + rowLen += ddlLen + VARSTR_HEADER_SIZE; + + return rowLen; +} +static int32_t tscSCreateSetValueToResObj(SSqlObj *pSql, int32_t rowLen, const char *tableName, const char *ddl) { + SSqlRes *pRes = &pSql->res; + + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + int32_t numOfRows = 1; + if (strlen(ddl) == 0) { + + } + tscInitResObjForLocalQuery(pSql, numOfRows, rowLen); + + TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, 0); + char* dst = pRes->data + tscFieldInfoGetOffset(pQueryInfo, 0) * numOfRows; + STR_WITH_MAXSIZE_TO_VARSTR(dst, tableName, pField->bytes); + + pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, 1); + dst = pRes->data + tscFieldInfoGetOffset(pQueryInfo, 1) * numOfRows; + STR_WITH_MAXSIZE_TO_VARSTR(dst, ddl, pField->bytes); + return 0; +} +static int32_t tscSCreateBuildResult(SSqlObj *pSql, BuildType type, const char *str, const char *result) { + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + int32_t rowLen = tscSCreateBuildResultFields(pSql, type, result); + + tscFieldInfoUpdateOffset(pQueryInfo); + return tscSCreateSetValueToResObj(pSql, rowLen, str, result); +} +int32_t tscRebuildCreateTableStatement(void *param,char *result) { + SCreateBuilder *builder = (SCreateBuilder *)param; + int32_t code = TSDB_CODE_SUCCESS; + + char *buf = calloc(1,TSDB_MAX_BINARY_LEN); + if (buf == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + code = tscGetTableTagValue(builder, buf); + if (code == TSDB_CODE_SUCCESS) { + snprintf(result + strlen(result), TSDB_MAX_BINARY_LEN - strlen(result), "CREATE TABLE %s USING %s TAGS %s", builder->buf, builder->sTableName, buf); + code = tscSCreateBuildResult(builder->pParentSql, SCREATE_BUILD_TABLE, builder->buf, result); + } + free(buf); + return code; +} + +static int32_t tscGetDBInfo(SCreateBuilder *builder, char *result) { + TAOS_ROW row = tscFetchRow(builder); + if (row == NULL) { + return TSDB_CODE_MND_DB_NOT_SELECTED; + } + const char *showColumns[] = {"REPLICA", "QUORUM", "DAYS", "KEEP", "BLOCKS", NULL}; + + SSqlObj *pSql = builder->pInterSql; + TAOS_FIELD *fields = taos_fetch_fields(pSql); + int num_fields = taos_num_fields(pSql); + + char buf[TSDB_DB_NAME_LEN + 64] = {0}; + do { + int32_t* lengths = taos_fetch_lengths(pSql); + int32_t ret = tscGetNthFieldResult(row, fields, lengths, 0, buf); + if (0 == ret && STR_NOCASE_EQUAL(buf, strlen(buf), builder->buf, strlen(builder->buf))) { + snprintf(result + strlen(result), TSDB_MAX_BINARY_LEN - strlen(result), "CREATE DATABASE %s", buf); + for (int i = 1; i < num_fields; i++) { + for (int j = 0; showColumns[j] != NULL; j++) { + if (STR_NOCASE_EQUAL(fields[i].name, strlen(fields[i].name), showColumns[j], strlen(showColumns[j]))) { + memset(buf, 0, sizeof(buf)); + ret = tscGetNthFieldResult(row, fields, lengths, i, buf); + if (ret == 0) { + snprintf(result + strlen(result), TSDB_MAX_BINARY_LEN - strlen(result), " %s %s", showColumns[j], buf); + } + } + } + } + break; + } + + row = tscFetchRow(builder); + } while (row != NULL); + + if (0 == strlen(result)) { + return TSDB_CODE_MND_DB_NOT_SELECTED; + } + + return TSDB_CODE_SUCCESS; +} +int32_t tscRebuildCreateDBStatement(void *param,char *result) { + SCreateBuilder *builder = (SCreateBuilder *)param; + int32_t code = TSDB_CODE_SUCCESS; + + char *buf = calloc(1, TSDB_MAX_BINARY_LEN); + if (buf == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + code = tscGetDBInfo(param, buf); + if (code == TSDB_CODE_SUCCESS) { + code = tscSCreateBuildResult(builder->pParentSql, SCREATE_BUILD_DB, builder->buf, buf); + } + free(buf); + return code; +} + +static int32_t tscGetTableTagColumnName(SSqlObj *pSql, char **result) { + char *buf = (char *)malloc(TSDB_MAX_BINARY_LEN); + if (buf == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + buf[0] = 0; + + STableMeta *pMeta = tscGetTableMetaInfoFromCmd(&pSql->cmd, 0, 0)->pTableMeta; + if (pMeta->tableType == TSDB_SUPER_TABLE || pMeta->tableType == TSDB_NORMAL_TABLE || + pMeta->tableType == TSDB_STREAM_TABLE) { + free(buf); + return TSDB_CODE_TSC_INVALID_VALUE; + } + + SSchema *pTagsSchema = tscGetTableTagSchema(pMeta); + int32_t numOfTags = tscGetNumOfTags(pMeta); + for (int32_t i = 0; i < numOfTags; i++) { + if (i != numOfTags - 1) { + snprintf(buf + strlen(buf), TSDB_MAX_BINARY_LEN - strlen(buf), "%s,", pTagsSchema[i].name); + } else { + snprintf(buf + strlen(buf), TSDB_MAX_BINARY_LEN - strlen(buf), "%s", pTagsSchema[i].name); + } + } + + *result = buf; + return TSDB_CODE_SUCCESS; +} +static int32_t tscRebuildDDLForSubTable(SSqlObj *pSql, const char *tableName, char *ddl) { + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + + STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + STableMeta * pMeta = pTableMetaInfo->pTableMeta; + + SSqlObj *pInterSql = (SSqlObj *)calloc(1, sizeof(SSqlObj)); + if (pInterSql == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + SCreateBuilder *param = (SCreateBuilder *)malloc(sizeof(SCreateBuilder)); + if (param == NULL) { + free(pInterSql); + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + char fullName[TSDB_TABLE_FNAME_LEN] = {0}; + extractDBName(pTableMetaInfo->name, fullName); + extractTableName(pMeta->sTableId, param->sTableName); + snprintf(fullName + strlen(fullName), TSDB_TABLE_FNAME_LEN - strlen(fullName), ".%s", param->sTableName); + extractTableName(pTableMetaInfo->name, param->buf); + + //tstrncpy(param->tableName, pTableMetaInfo->name, TSDB_TABLE_FNAME_LEN); + param->pParentSql = pSql; + param->pInterSql = pInterSql; + param->fp = tscRebuildCreateTableStatement; + param->callStage = SCREATE_CALLBACK_QUERY; + + char *query = (char *)calloc(1, TSDB_MAX_BINARY_LEN); + if (query == NULL) { + free(param); + free(pInterSql); + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + char *columns = NULL; + int32_t code = tscGetTableTagColumnName(pSql, &columns) ; + if (code != TSDB_CODE_SUCCESS) { + free(param); + free(pInterSql); + return code; + } + + snprintf(query + strlen(query), TSDB_MAX_BINARY_LEN - strlen(query), "SELECT %s FROM %s WHERE TBNAME IN(\'%s\')", columns, fullName, param->buf); + doAsyncQuery(pSql->pTscObj, pInterSql, tscSCreateCallBack, param, query, strlen(query)); + free(query); + free(columns); + + return TSDB_CODE_TSC_ACTION_IN_PROGRESS; +} +static int32_t tscRebuildDDLForNormalTable(SSqlObj *pSql, const char *tableName, char *ddl) { + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + STableMeta * pMeta = pTableMetaInfo->pTableMeta; + + int32_t numOfRows = tscGetNumOfColumns(pMeta); + SSchema *pSchema = tscGetTableSchema(pMeta); + + char *result = ddl; + sprintf(result, "create table %s (", tableName); + for (int32_t i = 0; i < numOfRows; ++i) { + uint8_t type = pSchema[i].type; + if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_NCHAR) { + sprintf(result + strlen(result), "%s %s(%d),", pSchema[i].name,tDataTypeDesc[pSchema[i].type].aName,pSchema->bytes); + } else { + sprintf(result + strlen(result), "%s %s,", pSchema[i].name, tDataTypeDesc[pSchema[i].type].aName); + } + } + sprintf(result + strlen(result) - 1, "%s", ")"); + + return TSDB_CODE_SUCCESS; +} +static int32_t tscRebuildDDLForSuperTable(SSqlObj *pSql, const char *tableName, char *ddl) { + char *result = ddl; + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + STableMeta * pMeta = pTableMetaInfo->pTableMeta; + + int32_t numOfRows = tscGetNumOfColumns(pMeta); + int32_t totalRows = numOfRows + tscGetNumOfTags(pMeta); + SSchema *pSchema = tscGetTableSchema(pMeta); + + sprintf(result, "create table %s (", tableName); + for (int32_t i = 0; i < numOfRows; ++i) { + uint8_t type = pSchema[i].type; + if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_NCHAR) { + sprintf(result + strlen(result), "%s %s(%d),", pSchema[i].name,tDataTypeDesc[pSchema[i].type].aName,pSchema->bytes); + } else { + sprintf(result + strlen(result), "%s %s,", pSchema[i].name, tDataTypeDesc[type].aName); + } + } + sprintf(result + strlen(result) - 1, "%s ", ")"); + + sprintf(result + strlen(result), "TAGS ("); + for (int32_t i = numOfRows; i < totalRows; i++) { + uint8_t type = pSchema[i].type; + if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_NCHAR) { + sprintf(result + strlen(result), "%s %s(%d),", pSchema[i].name,tDataTypeDesc[pSchema[i].type].aName,pSchema->bytes); + } else { + sprintf(result + strlen(result), "%s %s,", pSchema[i].name, tDataTypeDesc[type].aName); + } + + } + sprintf(result + strlen(result) - 1, "%s", ")"); + + return TSDB_CODE_SUCCESS; +} + +static int32_t tscProcessShowCreateTable(SSqlObj *pSql) { + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + assert(pTableMetaInfo->pTableMeta != NULL); + + char tableName[TSDB_TABLE_NAME_LEN] = {0}; + extractTableName(pTableMetaInfo->name, tableName); + + char result[TSDB_MAX_BYTES_PER_ROW] = {0}; + int32_t code = TSDB_CODE_SUCCESS; + if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { + code = tscRebuildDDLForSuperTable(pSql, tableName, result); + } else if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo)) { + code = tscRebuildDDLForNormalTable(pSql, tableName, result); + } else if (UTIL_TABLE_IS_CHILD_TABLE(pTableMetaInfo)) { + code = tscRebuildDDLForSubTable(pSql, tableName, result); + } else { + code = TSDB_CODE_TSC_INVALID_VALUE; + } + + if (code != TSDB_CODE_SUCCESS) { + return code; + } + return tscSCreateBuildResult(pSql, SCREATE_BUILD_TABLE, tableName, result); +} + +static int32_t tscProcessShowCreateDatabase(SSqlObj *pSql) { + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); + + STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0); + + SSqlObj *pInterSql = (SSqlObj *)calloc(1, sizeof(SSqlObj)); + if (pInterSql == NULL) { + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + + SCreateBuilder *param = (SCreateBuilder *)malloc(sizeof(SCreateBuilder)); + if (param == NULL) { + free(pInterSql); + return TSDB_CODE_TSC_OUT_OF_MEMORY; + } + extractTableName(pTableMetaInfo->name, param->buf); + param->pParentSql = pSql; + param->pInterSql = pInterSql; + param->fp = tscRebuildCreateDBStatement; + param->callStage = SCREATE_CALLBACK_QUERY; + + const char *query = "show databases"; + doAsyncQuery(pSql->pTscObj, pInterSql, tscSCreateCallBack, param, query, strlen(query)); + return TSDB_CODE_TSC_ACTION_IN_PROGRESS; +} static int32_t tscProcessCurrentUser(SSqlObj *pSql) { SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); - + SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0); pExpr->resBytes = TSDB_USER_LEN + TSDB_DATA_TYPE_BINARY; pExpr->resType = TSDB_DATA_TYPE_BINARY; - + char* vx = calloc(1, pExpr->resBytes); if (vx == NULL) { return TSDB_CODE_TSC_OUT_OF_MEMORY; @@ -288,7 +809,7 @@ static int32_t tscProcessCurrentUser(SSqlObj *pSql) { size_t size = sizeof(pSql->pTscObj->user); STR_WITH_MAXSIZE_TO_VARSTR(vx, pSql->pTscObj->user, size); - + tscSetLocalQueryResult(pSql, vx, pExpr->aliasName, pExpr->resType, pExpr->resBytes); free(vx); @@ -298,15 +819,15 @@ static int32_t tscProcessCurrentUser(SSqlObj *pSql) { static int32_t tscProcessCurrentDB(SSqlObj *pSql) { char db[TSDB_DB_NAME_LEN] = {0}; extractDBName(pSql->pTscObj->db, db); - + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex); - + SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0); pExpr->resType = TSDB_DATA_TYPE_BINARY; - + size_t t = strlen(db); pExpr->resBytes = TSDB_DB_NAME_LEN + VARSTR_HEADER_SIZE; - + char* vx = calloc(1, pExpr->resBytes); if (vx == NULL) { return TSDB_CODE_TSC_OUT_OF_MEMORY; @@ -317,7 +838,7 @@ static int32_t tscProcessCurrentDB(SSqlObj *pSql) { } else { STR_WITH_SIZE_TO_VARSTR(vx, db, (VarDataLenT)t); } - + tscSetLocalQueryResult(pSql, vx, pExpr->aliasName, pExpr->resType, pExpr->resBytes); free(vx); @@ -327,49 +848,53 @@ static int32_t tscProcessCurrentDB(SSqlObj *pSql) { static int32_t tscProcessServerVer(SSqlObj *pSql) { const char* v = pSql->pTscObj->sversion; SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, pSql->cmd.clauseIndex); - + SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0); pExpr->resType = TSDB_DATA_TYPE_BINARY; - + size_t t = strlen(v); pExpr->resBytes = (int16_t)(t + VARSTR_HEADER_SIZE); - + char* vx = calloc(1, pExpr->resBytes); if (vx == NULL) { return TSDB_CODE_TSC_OUT_OF_MEMORY; + } STR_WITH_SIZE_TO_VARSTR(vx, v, (VarDataLenT)t); tscSetLocalQueryResult(pSql, vx, pExpr->aliasName, pExpr->resType, pExpr->resBytes); - + free(vx); return TSDB_CODE_SUCCESS; + } static int32_t tscProcessClientVer(SSqlObj *pSql) { SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); - + SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0); pExpr->resType = TSDB_DATA_TYPE_BINARY; - + size_t t = strlen(version); pExpr->resBytes = (int16_t)(t + VARSTR_HEADER_SIZE); - + char* v = calloc(1, pExpr->resBytes); if (v == NULL) { return TSDB_CODE_TSC_OUT_OF_MEMORY; + } STR_WITH_SIZE_TO_VARSTR(v, version, (VarDataLenT)t); tscSetLocalQueryResult(pSql, v, pExpr->aliasName, pExpr->resType, pExpr->resBytes); - + free(v); return TSDB_CODE_SUCCESS; + } static int32_t tscProcessServStatus(SSqlObj *pSql) { STscObj* pObj = pSql->pTscObj; - + if (pObj->pHb != NULL) { if (pObj->pHb->res.code == TSDB_CODE_RPC_NETWORK_UNAVAIL) { pSql->res.code = TSDB_CODE_RPC_NETWORK_UNAVAIL; @@ -380,9 +905,9 @@ static int32_t tscProcessServStatus(SSqlObj *pSql) { return pSql->res.code; } } - + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0); - + SSqlExpr* pExpr = taosArrayGetP(pQueryInfo->exprList, 0); int32_t val = 1; tscSetLocalQueryResult(pSql, (char*) &val, pExpr->aliasName, TSDB_DATA_TYPE_INT, sizeof(int32_t)); @@ -394,23 +919,23 @@ void tscSetLocalQueryResult(SSqlObj *pSql, const char *val, const char *columnNa SSqlRes *pRes = &pSql->res; pCmd->numOfCols = 1; - + SQueryInfo* pQueryInfo = tscGetQueryInfoDetail(pCmd, pCmd->clauseIndex); pQueryInfo->order.order = TSDB_ORDER_ASC; - + tscFieldInfoClear(&pQueryInfo->fieldsInfo); pQueryInfo->fieldsInfo.pFields = taosArrayInit(1, sizeof(TAOS_FIELD)); pQueryInfo->fieldsInfo.pSupportInfo = taosArrayInit(1, sizeof(SFieldSupInfo)); - + TAOS_FIELD f = tscCreateField((int8_t)type, columnName, (int16_t)valueLength); tscFieldInfoAppend(&pQueryInfo->fieldsInfo, &f); - + tscInitResObjForLocalQuery(pSql, 1, (int32_t)valueLength); TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, 0); SFieldSupInfo* pInfo = tscFieldInfoGetSupp(&pQueryInfo->fieldsInfo, 0); pInfo->pSqlExpr = taosArrayGetP(pQueryInfo->exprList, 0); - + memcpy(pRes->data, val, pField->bytes); } @@ -429,6 +954,10 @@ int tscProcessLocalCmd(SSqlObj *pSql) { */ pRes->qhandle = 0x1; pRes->numOfRows = 0; + } else if (pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE) { + pRes->code = tscProcessShowCreateTable(pSql); + } else if (pCmd->command == TSDB_SQL_SHOW_CREATE_DATABASE) { + pRes->code = tscProcessShowCreateDatabase(pSql); } else if (pCmd->command == TSDB_SQL_RESET_CACHE) { taosCacheEmpty(tscCacheHandle); pRes->code = TSDB_CODE_SUCCESS; @@ -448,12 +977,13 @@ int tscProcessLocalCmd(SSqlObj *pSql) { } // keep the code in local variable in order to avoid invalid read in case of async query + int32_t code = pRes->code; if (code == TSDB_CODE_SUCCESS) { (*pSql->fp)(pSql->param, pSql, code); + } else if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS){ } else { tscQueueAsyncRes(pSql); } - return code; } diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index c248b08ddd..631ee4acc1 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -366,7 +366,40 @@ int32_t tscToSQLCmd(SSqlObj* pSql, struct SSqlInfo* pInfo) { return tscGetTableMeta(pSql, pTableMetaInfo); } + case TSDB_SQL_SHOW_CREATE_TABLE: { + SStrToken* pToken = &pInfo->pDCLInfo->a[0]; + const char* msg1 = "invalid table name"; + const char* msg2 = "table name is too long"; + + if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); + } + if (!tscValidateTableNameLength(pToken->n)) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); + } + + if (tscSetTableFullName(pTableMetaInfo, pToken, pSql) != TSDB_CODE_SUCCESS) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); + } + return tscGetTableMeta(pSql, pTableMetaInfo); + } + case TSDB_SQL_SHOW_CREATE_DATABASE: { + const char* msg1 = "invalid database name"; + const char* msg2 = "table name is too long"; + SStrToken* pToken = &pInfo->pDCLInfo->a[0]; + + if (tscValidateName(pToken) != TSDB_CODE_SUCCESS) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); + } + if (pToken->n > TSDB_DB_NAME_LEN) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg1); + } + if (tscSetTableFullName(pTableMetaInfo, pToken, pSql) != TSDB_CODE_SUCCESS) { + return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg2); + } + return TSDB_CODE_SUCCESS; + } case TSDB_SQL_CFG_DNODE: { const char* msg2 = "invalid configure options or values, such as resetlog / debugFlag 135 / balance 'vnode:2-dnode:2' / monitor 1 "; const char* msg3 = "invalid dnode ep"; diff --git a/src/client/src/tscSchemaUtil.c b/src/client/src/tscSchemaUtil.c index 244bb81164..1e841c68fd 100644 --- a/src/client/src/tscSchemaUtil.c +++ b/src/client/src/tscSchemaUtil.c @@ -170,6 +170,7 @@ STableMeta* tscCreateTableMetaFromMsg(STableMetaMsg* pTableMetaMsg, size_t* size pTableMeta->sversion = pTableMetaMsg->sversion; pTableMeta->tversion = pTableMetaMsg->tversion; + tstrncpy(pTableMeta->sTableId, pTableMetaMsg->sTableId, TSDB_TABLE_FNAME_LEN); memcpy(pTableMeta->schema, pTableMetaMsg->schema, schemaSize); diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index ae2013cd2b..9c8b94cc2d 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -2072,6 +2072,9 @@ int tscProcessAlterDbMsgRsp(SSqlObj *pSql) { UNUSED(pSql); return 0; } +int tscProcessShowCreateRsp(SSqlObj *pSql) { + return tscLocalResultCommonBuilder(pSql, 1); +} int tscProcessQueryRsp(SSqlObj *pSql) { SSqlRes *pRes = &pSql->res; @@ -2343,6 +2346,10 @@ void tscInitMsgsFp() { tscProcessMsgRsp[TSDB_SQL_ALTER_TABLE] = tscProcessAlterTableMsgRsp; tscProcessMsgRsp[TSDB_SQL_ALTER_DB] = tscProcessAlterDbMsgRsp; + tscProcessMsgRsp[TSDB_SQL_SHOW_CREATE_TABLE] = tscProcessShowCreateRsp; + tscProcessMsgRsp[TSDB_SQL_SHOW_CREATE_DATABASE] = tscProcessShowCreateRsp; + + tscKeepConn[TSDB_SQL_SHOW] = 1; tscKeepConn[TSDB_SQL_RETRIEVE] = 1; tscKeepConn[TSDB_SQL_SELECT] = 1; diff --git a/src/client/src/tscSql.c b/src/client/src/tscSql.c index 9fa4db999f..24768c243b 100644 --- a/src/client/src/tscSql.c +++ b/src/client/src/tscSql.c @@ -451,6 +451,8 @@ TAOS_ROW taos_fetch_row(TAOS_RES *res) { pCmd->command == TSDB_SQL_TABLE_JOIN_RETRIEVE || pCmd->command == TSDB_SQL_FETCH || pCmd->command == TSDB_SQL_SHOW || + pCmd->command == TSDB_SQL_SHOW_CREATE_TABLE || + pCmd->command == TSDB_SQL_SHOW_CREATE_DATABASE || pCmd->command == TSDB_SQL_SELECT || pCmd->command == TSDB_SQL_DESCRIBE_TABLE || pCmd->command == TSDB_SQL_SERV_STATUS || diff --git a/src/client/src/tscSubquery.c b/src/client/src/tscSubquery.c index e264fa9b33..abfe8b8813 100644 --- a/src/client/src/tscSubquery.c +++ b/src/client/src/tscSubquery.c @@ -23,6 +23,7 @@ #include "tscSubquery.h" #include "tschemautil.h" #include "tsclient.h" +#include "tscSubquery.h" typedef struct SInsertSupporter { SSubqueryState* pState; diff --git a/src/common/inc/tcmdtype.h b/src/common/inc/tcmdtype.h index 90fb5bf478..69bbccd67e 100644 --- a/src/common/inc/tcmdtype.h +++ b/src/common/inc/tcmdtype.h @@ -78,6 +78,9 @@ enum { TSDB_DEFINE_SQL_TYPE( TSDB_SQL_RETRIEVE_LOCALMERGE, "retrieve-localmerge" ) TSDB_DEFINE_SQL_TYPE( TSDB_SQL_TABLE_JOIN_RETRIEVE, "join-retrieve" ) + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SHOW_CREATE_TABLE, "show-create-table") + TSDB_DEFINE_SQL_TYPE( TSDB_SQL_SHOW_CREATE_DATABASE, "show-create-database") + /* * build empty result instead of accessing dnode to fetch result * reset the client cache diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index e2df886320..f33d26c53b 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -677,6 +677,7 @@ typedef struct { typedef struct STableMetaMsg { int32_t contLen; char tableId[TSDB_TABLE_FNAME_LEN]; // table id + char sTableId[TSDB_TABLE_FNAME_LEN]; uint8_t numOfTags; uint8_t precision; uint8_t tableType; diff --git a/src/inc/ttokendef.h b/src/inc/ttokendef.h index c5831a9b8a..bc49d3c81b 100644 --- a/src/inc/ttokendef.h +++ b/src/inc/ttokendef.h @@ -16,105 +16,105 @@ #ifndef TDENGINE_TTOKENDEF_H #define TDENGINE_TTOKENDEF_H -#define TK_ID 1 -#define TK_BOOL 2 -#define TK_TINYINT 3 -#define TK_SMALLINT 4 -#define TK_INTEGER 5 -#define TK_BIGINT 6 -#define TK_FLOAT 7 -#define TK_DOUBLE 8 -#define TK_STRING 9 -#define TK_TIMESTAMP 10 -#define TK_BINARY 11 -#define TK_NCHAR 12 -#define TK_OR 13 -#define TK_AND 14 -#define TK_NOT 15 -#define TK_EQ 16 -#define TK_NE 17 -#define TK_ISNULL 18 -#define TK_NOTNULL 19 -#define TK_IS 20 -#define TK_LIKE 21 -#define TK_GLOB 22 -#define TK_BETWEEN 23 -#define TK_IN 24 -#define TK_GT 25 -#define TK_GE 26 -#define TK_LT 27 -#define TK_LE 28 -#define TK_BITAND 29 -#define TK_BITOR 30 -#define TK_LSHIFT 31 -#define TK_RSHIFT 32 -#define TK_PLUS 33 -#define TK_MINUS 34 -#define TK_DIVIDE 35 -#define TK_TIMES 36 -#define TK_STAR 37 -#define TK_SLASH 38 -#define TK_REM 39 -#define TK_CONCAT 40 -#define TK_UMINUS 41 -#define TK_UPLUS 42 -#define TK_BITNOT 43 -#define TK_SHOW 44 -#define TK_DATABASES 45 -#define TK_MNODES 46 -#define TK_DNODES 47 -#define TK_ACCOUNTS 48 -#define TK_USERS 49 -#define TK_MODULES 50 -#define TK_QUERIES 51 -#define TK_CONNECTIONS 52 -#define TK_STREAMS 53 -#define TK_VARIABLES 54 -#define TK_SCORES 55 -#define TK_GRANTS 56 -#define TK_VNODES 57 -#define TK_IPTOKEN 58 -#define TK_DOT 59 -#define TK_TABLES 60 -#define TK_STABLES 61 -#define TK_VGROUPS 62 -#define TK_DROP 63 -#define TK_TABLE 64 -#define TK_DATABASE 65 -#define TK_DNODE 66 -#define TK_USER 67 -#define TK_ACCOUNT 68 -#define TK_USE 69 -#define TK_DESCRIBE 70 -#define TK_ALTER 71 -#define TK_PASS 72 -#define TK_PRIVILEGE 73 -#define TK_LOCAL 74 -#define TK_IF 75 -#define TK_EXISTS 76 -#define TK_CREATE 77 -#define TK_PPS 78 -#define TK_TSERIES 79 -#define TK_DBS 80 -#define TK_STORAGE 81 -#define TK_QTIME 82 -#define TK_CONNS 83 -#define TK_STATE 84 -#define TK_KEEP 85 -#define TK_CACHE 86 -#define TK_REPLICA 87 -#define TK_QUORUM 88 -#define TK_DAYS 89 -#define TK_MINROWS 90 -#define TK_MAXROWS 91 -#define TK_BLOCKS 92 -#define TK_CTIME 93 -#define TK_WAL 94 -#define TK_FSYNC 95 -#define TK_COMP 96 -#define TK_PRECISION 97 -#define TK_LP 98 -#define TK_RP 99 +#define TK_ID 1 +#define TK_BOOL 2 +#define TK_TINYINT 3 +#define TK_SMALLINT 4 +#define TK_INTEGER 5 +#define TK_BIGINT 6 +#define TK_FLOAT 7 +#define TK_DOUBLE 8 +#define TK_STRING 9 +#define TK_TIMESTAMP 10 +#define TK_BINARY 11 +#define TK_NCHAR 12 +#define TK_OR 13 +#define TK_AND 14 +#define TK_NOT 15 +#define TK_EQ 16 +#define TK_NE 17 +#define TK_ISNULL 18 +#define TK_NOTNULL 19 +#define TK_IS 20 +#define TK_LIKE 21 +#define TK_GLOB 22 +#define TK_BETWEEN 23 +#define TK_IN 24 +#define TK_GT 25 +#define TK_GE 26 +#define TK_LT 27 +#define TK_LE 28 +#define TK_BITAND 29 +#define TK_BITOR 30 +#define TK_LSHIFT 31 +#define TK_RSHIFT 32 +#define TK_PLUS 33 +#define TK_MINUS 34 +#define TK_DIVIDE 35 +#define TK_TIMES 36 +#define TK_STAR 37 +#define TK_SLASH 38 +#define TK_REM 39 +#define TK_CONCAT 40 +#define TK_UMINUS 41 +#define TK_UPLUS 42 +#define TK_BITNOT 43 +#define TK_SHOW 44 +#define TK_DATABASES 45 +#define TK_MNODES 46 +#define TK_DNODES 47 +#define TK_ACCOUNTS 48 +#define TK_USERS 49 +#define TK_MODULES 50 +#define TK_QUERIES 51 +#define TK_CONNECTIONS 52 +#define TK_STREAMS 53 +#define TK_VARIABLES 54 +#define TK_SCORES 55 +#define TK_GRANTS 56 +#define TK_VNODES 57 +#define TK_IPTOKEN 58 +#define TK_DOT 59 +#define TK_CREATE 60 +#define TK_TABLE 61 +#define TK_DATABASE 62 +#define TK_TABLES 63 +#define TK_STABLES 64 +#define TK_VGROUPS 65 +#define TK_DROP 66 +#define TK_DNODE 67 +#define TK_USER 68 +#define TK_ACCOUNT 69 +#define TK_USE 70 +#define TK_DESCRIBE 71 +#define TK_ALTER 72 +#define TK_PASS 73 +#define TK_PRIVILEGE 74 +#define TK_LOCAL 75 +#define TK_IF 76 +#define TK_EXISTS 77 +#define TK_PPS 78 +#define TK_TSERIES 79 +#define TK_DBS 80 +#define TK_STORAGE 81 +#define TK_QTIME 82 +#define TK_CONNS 83 +#define TK_STATE 84 +#define TK_KEEP 85 +#define TK_CACHE 86 +#define TK_REPLICA 87 +#define TK_QUORUM 88 +#define TK_DAYS 89 +#define TK_MINROWS 90 +#define TK_MAXROWS 91 +#define TK_BLOCKS 92 +#define TK_CTIME 93 +#define TK_WAL 94 +#define TK_FSYNC 95 +#define TK_COMP 96 +#define TK_PRECISION 97 +#define TK_LP 98 +#define TK_RP 99 #define TK_TAGS 100 #define TK_USING 101 #define TK_AS 102 diff --git a/src/mnode/src/mnodeTable.c b/src/mnode/src/mnodeTable.c index 4400927e9b..72e4f196a7 100644 --- a/src/mnode/src/mnodeTable.c +++ b/src/mnode/src/mnodeTable.c @@ -2090,6 +2090,9 @@ static int32_t mnodeDoGetChildTableMeta(SMnodeMsg *pMsg, STableMetaMsg *pMeta) { pMeta->precision = pDb->cfg.precision; pMeta->tableType = pTable->info.type; tstrncpy(pMeta->tableId, pTable->info.tableId, TSDB_TABLE_FNAME_LEN); + if (pTable->superTable) { + tstrncpy(pMeta->sTableId, pTable->superTable->info.tableId, TSDB_TABLE_FNAME_LEN); + } if (pTable->info.type == TSDB_CHILD_TABLE) { pMeta->sversion = htons(pTable->superTable->sversion); diff --git a/src/query/inc/sql.y b/src/query/inc/sql.y index 79aec2f349..0196ff68a2 100644 --- a/src/query/inc/sql.y +++ b/src/query/inc/sql.y @@ -80,6 +80,7 @@ cmd ::= SHOW GRANTS. { setShowOptions(pInfo, TSDB_MGMT_TABLE_GRANTS, 0, 0); cmd ::= SHOW VNODES. { setShowOptions(pInfo, TSDB_MGMT_TABLE_VNODES, 0, 0); } cmd ::= SHOW VNODES IPTOKEN(X). { setShowOptions(pInfo, TSDB_MGMT_TABLE_VNODES, &X, 0); } + %type dbPrefix {SStrToken} dbPrefix(A) ::=. {A.n = 0; A.type = 0;} dbPrefix(A) ::= ids(X) DOT. {A = X; } @@ -88,6 +89,15 @@ dbPrefix(A) ::= ids(X) DOT. {A = X; } cpxName(A) ::= . {A.n = 0; } cpxName(A) ::= DOT ids(Y). {A = Y; A.n += 1; } +cmd ::= SHOW CREATE TABLE ids(X) cpxName(Y). { + X.n += Y.n; + setDCLSQLElems(pInfo, TSDB_SQL_SHOW_CREATE_TABLE, 1, &X); +} + +cmd ::= SHOW CREATE DATABASE ids(X). { + setDCLSQLElems(pInfo, TSDB_SQL_SHOW_CREATE_DATABASE, 1, &X); +} + cmd ::= SHOW dbPrefix(X) TABLES. { setShowOptions(pInfo, TSDB_MGMT_TABLE_TABLE, &X, 0); } -- GitLab