diff --git a/include/common/tdataformat.h b/include/common/tdataformat.h
index 19f3e222d1..cc578fbee9 100644
--- a/include/common/tdataformat.h
+++ b/include/common/tdataformat.h
@@ -155,6 +155,7 @@ int32_t tDecodeTag(SDecoder *pDecoder, STag **ppTag);
int32_t tTagToValArray(const STag *pTag, SArray **ppArray);
void debugPrintSTag(STag *pTag, const char *tag, int32_t ln); // TODO: remove
int32_t parseJsontoTagData(const char *json, SArray *pTagVals, STag **ppTag, void *pMsgBuf);
+int32_t parseGeotoTagData(const char *g, SArray *pTagVals, SSchema *pTagSchema, unsigned char *output);
// SColData ================================
typedef struct {
diff --git a/source/common/CMakeLists.txt b/source/common/CMakeLists.txt
index f10eb6a611..e9b8727ce8 100644
--- a/source/common/CMakeLists.txt
+++ b/source/common/CMakeLists.txt
@@ -49,6 +49,7 @@ target_link_libraries(
PUBLIC os
PUBLIC util
INTERFACE api
+ PRIVATE geometry
)
if(${BUILD_S3})
diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c
index e580ad33bd..7a6557fd28 100644
--- a/source/common/src/tdataformat.c
+++ b/source/common/src/tdataformat.c
@@ -15,6 +15,7 @@
#define _DEFAULT_SOURCE
#include "tdataformat.h"
+#include "geosWrapper.h"
#include "tRealloc.h"
#include "tdatablock.h"
#include "tlog.h"
@@ -3036,6 +3037,35 @@ _exit:
return code;
}
+int32_t formatGeometry(SColData *pColData, int8_t *buf, int32_t lenght, int32_t buffMaxLen) {
+ int32_t code = 0;
+ unsigned char *output = NULL;
+ size_t size = 0;
+ uint8_t *g = NULL;
+ code = tRealloc(&g, lenght);
+ if (code) {
+ return code;
+ }
+
+ (void)memcpy(g, buf, lenght);
+ code = doGeomFromText(g, &output, &size);
+ tFree(g);
+
+ if (code != TSDB_CODE_SUCCESS) {
+ goto _exit;
+ }
+ if (size > buffMaxLen) {
+ code = TSDB_CODE_PAR_VALUE_TOO_LONG;
+ goto _exit;
+ }
+
+ code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, output, size);
+
+_exit:
+ geosFreeBuffer(output);
+ return code;
+}
+
int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32_t buffMaxLen) {
int32_t code = 0;
@@ -3046,6 +3076,13 @@ int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32
}
if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = initCtxGeomFromText();
+ if (code != TSDB_CODE_SUCCESS) {
+ uError("init geom from text failed, code:%d", code);
+ return code;
+ }
+ }
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null && pBind->is_null[i]) {
if (pColData->cflag & COL_IS_KEY) {
@@ -3055,11 +3092,15 @@ int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_NULL](pColData, NULL, 0);
if (code) goto _exit;
} else if (pBind->length[i] > buffMaxLen) {
- uError("var data length too big, len:%d, max:%d", pBind->length[i], buffMaxLen);
- return TSDB_CODE_INVALID_PARA;
+ return TSDB_CODE_PAR_VALUE_TOO_LONG;
} else {
- code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](
- pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i]);
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = formatGeometry(pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i],
+ buffMaxLen);
+ } else {
+ code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](
+ pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i]);
+ }
}
}
} else { // fixed-length data type
@@ -3119,6 +3160,13 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3
if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type
uint8_t *buf = pBind->buffer;
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = initCtxGeomFromText();
+ if (code != TSDB_CODE_SUCCESS) {
+ uError("init geom from text failed, code:%d", code);
+ return code;
+ }
+ }
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null && pBind->is_null[i]) {
if (pColData->cflag & COL_IS_KEY) {
@@ -3133,10 +3181,13 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3
if (code) goto _exit;
}
} else if (pBind->length[i] > buffMaxLen) {
- uError("var data length too big, len:%d, max:%d", pBind->length[i], buffMaxLen);
- return TSDB_CODE_INVALID_PARA;
+ return TSDB_CODE_PAR_VALUE_TOO_LONG;
} else {
- code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, buf, pBind->length[i]);
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = formatGeometry(pColData, buf, pBind->length[i], buffMaxLen);
+ } else {
+ code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, buf, pBind->length[i]);
+ }
buf += pBind->length[i];
}
}
diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c
index 0979028e6d..9e78d53cc9 100644
--- a/source/libs/parser/src/parInsertStmt.c
+++ b/source/libs/parser/src/parInsertStmt.c
@@ -13,6 +13,7 @@
* along with this program. If not, see .
*/
+#include "geosWrapper.h"
#include "os.h"
#include "parInsertUtil.h"
#include "parInt.h"
@@ -187,11 +188,24 @@ int32_t qBindStmtTagsValue(void* pBlock, void* boundTags, int64_t suid, const ch
if (code != TSDB_CODE_SUCCESS) {
goto end;
}
+ } else if (pTagSchema->type == TSDB_DATA_TYPE_GEOMETRY) {
+ char* tmp = taosMemoryCalloc(1, colLen);
+ if (!tmp) {
+ code = terrno;
+ goto end;
+ }
+ memcpy(tmp, bind[c].buffer, colLen);
+ unsigned char* out = NULL;
+ code = parseGeotoTagData(tmp, pTagArray, pTagSchema, out);
+ taosMemoryFree(tmp);
+ if (code != TSDB_CODE_SUCCESS) {
+ geosFreeBuffer(out);
+ goto end;
+ }
} else {
STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
// strcpy(val.colName, pTagSchema->name);
- if (pTagSchema->type == TSDB_DATA_TYPE_BINARY || pTagSchema->type == TSDB_DATA_TYPE_VARBINARY ||
- pTagSchema->type == TSDB_DATA_TYPE_GEOMETRY) {
+ if (pTagSchema->type == TSDB_DATA_TYPE_BINARY || pTagSchema->type == TSDB_DATA_TYPE_VARBINARY) {
val.pData = (uint8_t*)bind[c].buffer;
val.nData = colLen;
} else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) {
@@ -251,6 +265,9 @@ end:
if (p->type == TSDB_DATA_TYPE_NCHAR) {
taosMemoryFreeClear(p->pData);
}
+ if (p->type == TSDB_DATA_TYPE_GEOMETRY) {
+ geosFreeBuffer(p->pData);
+ }
}
taosArrayDestroy(pTagArray);
taosArrayDestroy(tagName);
@@ -539,11 +556,24 @@ int32_t qBindStmtTagsValue2(void* pBlock, void* boundTags, int64_t suid, const c
if (code != TSDB_CODE_SUCCESS) {
goto end;
}
+ } else if (pTagSchema->type == TSDB_DATA_TYPE_GEOMETRY) {
+ char* tmp = taosMemoryCalloc(1, colLen);
+ if (!tmp) {
+ code = terrno;
+ goto end;
+ }
+ memcpy(tmp, bind[c].buffer, colLen);
+ unsigned char* out = NULL;
+ code = parseGeotoTagData(tmp, pTagArray, pTagSchema, out);
+ taosMemoryFree(tmp);
+ if (code != TSDB_CODE_SUCCESS) {
+ geosFreeBuffer(out);
+ goto end;
+ }
} else {
STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
// strcpy(val.colName, pTagSchema->name);
- if (pTagSchema->type == TSDB_DATA_TYPE_BINARY || pTagSchema->type == TSDB_DATA_TYPE_VARBINARY ||
- pTagSchema->type == TSDB_DATA_TYPE_GEOMETRY) {
+ if (pTagSchema->type == TSDB_DATA_TYPE_BINARY || pTagSchema->type == TSDB_DATA_TYPE_VARBINARY) {
val.pData = (uint8_t*)bind[c].buffer;
val.nData = colLen;
} else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) {
@@ -603,6 +633,9 @@ end:
if (p->type == TSDB_DATA_TYPE_NCHAR) {
taosMemoryFreeClear(p->pData);
}
+ if (p->type == TSDB_DATA_TYPE_GEOMETRY) {
+ geosFreeBuffer(p->pData);
+ }
}
taosArrayDestroy(pTagArray);
taosArrayDestroy(tagName);
diff --git a/source/libs/parser/src/parUtil.c b/source/libs/parser/src/parUtil.c
index e35eea9e72..fc6ed0d7b0 100644
--- a/source/libs/parser/src/parUtil.c
+++ b/source/libs/parser/src/parUtil.c
@@ -15,6 +15,7 @@
#include "parUtil.h"
#include "cJSON.h"
+#include "geosWrapper.h"
#include "querynodes.h"
#include "tarray.h"
#include "tlog.h"
@@ -518,6 +519,35 @@ end:
return retCode;
}
+int32_t parseGeotoTagData(const char* g, SArray* pTagVals, SSchema* pTagSchema, unsigned char* output) {
+ int32_t code = 0;
+ size_t size = 0;
+ STagVal val = {.cid = pTagSchema->colId, .type = pTagSchema->type};
+ code = initCtxGeomFromText();
+ if (code != TSDB_CODE_SUCCESS) {
+ goto end;
+ }
+ code = doGeomFromText(g, &output, &size);
+ if (code != TSDB_CODE_SUCCESS) {
+ goto end;
+ }
+ if (size > pTagSchema->bytes) {
+ code = TSDB_CODE_PAR_VALUE_TOO_LONG;
+ goto end;
+ }
+
+ val.pData = (uint8_t*)output;
+ val.nData = (uint32_t)size;
+
+ if (NULL == taosArrayPush(pTagVals, &val)) {
+ code = terrno;
+ goto end;
+ }
+
+end:
+ return code;
+}
+
static int32_t getInsTagsTableTargetNameFromOp(int32_t acctId, SOperatorNode* pOper, SName* pName) {
if (OP_TYPE_EQUAL != pOper->opType) {
return TSDB_CODE_SUCCESS;
diff --git a/tests/script/api/stmt2-geometry-test.c b/tests/script/api/stmt2-geometry-test.c
new file mode 100644
index 0000000000..bb53e6e42b
--- /dev/null
+++ b/tests/script/api/stmt2-geometry-test.c
@@ -0,0 +1,99 @@
+#include
+#include
+#include
+#include "taos.h"
+
+void do_query(TAOS* taos, const char* sql) {
+ printf("[sql]%s\n", sql);
+ TAOS_RES* result = taos_query(taos, sql);
+ int code = taos_errno(result);
+ if (code) {
+ printf(" failed to query: %s, reason:%s\n", sql, taos_errstr(result));
+ taos_free_result(result);
+ return;
+ }
+ taos_free_result(result);
+}
+
+void execute_test(TAOS* taos, const char* tbname, const char* tag2, const char* col2, const char* case_desc) {
+ // prepare stmt
+ TAOS_STMT2_OPTION option = {0, true, false, NULL, NULL};
+ TAOS_STMT2* stmt = taos_stmt2_init(taos, &option);
+ const char* sql;
+ if (tbname == "tb4") {
+ sql = "insert into db.? using db.stb2 tags(?, ?) values(?,?)";
+ } else {
+ sql = "insert into db.? using db.stb tags(?, ?) values(?,?)";
+ }
+ int code = taos_stmt2_prepare(stmt, sql, 0);
+ printf("\n%s\n insert into db.? using db.stb tags(?, ?) values(?,?)\n bind_tag : %s, bind_col : %s\n", case_desc,
+ tag2, col2);
+ if (code != 0) {
+ printf(" failed to execute taos_stmt2_prepare. error:%s\n", taos_stmt2_error(stmt));
+ taos_stmt2_close(stmt);
+ return;
+ }
+
+ // prepare data
+ int t1_val = 0;
+ int64_t ts = 1591060628000;
+ int32_t length[5] = {sizeof(int), 2, sizeof(int64_t), (int32_t)strlen(tag2), (int32_t)strlen(col2)};
+ TAOS_STMT2_BIND tags[2] = {{TSDB_DATA_TYPE_INT, &t1_val, &length[0], NULL, 1},
+ {TSDB_DATA_TYPE_GEOMETRY, (void*)tag2, &length[3], NULL, 1}};
+ TAOS_STMT2_BIND params[2] = {{TSDB_DATA_TYPE_TIMESTAMP, &ts, &length[2], NULL, 1},
+ {TSDB_DATA_TYPE_GEOMETRY, (void*)col2, &length[4], NULL, 1}};
+ TAOS_STMT2_BIND* tagv[1] = {&tags[0]};
+ TAOS_STMT2_BIND* paramv[1] = {¶ms[0]};
+
+ TAOS_STMT2_BINDV bindv = {1, &tbname, &tagv[0], ¶mv[0]};
+ code = taos_stmt2_bind_param(stmt, &bindv, -1);
+ if (code != 0) {
+ printf(" failed to bind param. error:%s\n", taos_stmt2_error(stmt));
+ taos_stmt2_close(stmt);
+ return;
+ }
+
+ if (taos_stmt2_exec(stmt, NULL)) {
+ printf(" failed to execute insert statement.error:%s\n", taos_stmt2_error(stmt));
+ taos_stmt2_close(stmt);
+ return;
+ }
+ printf("[ok]\n");
+
+ taos_stmt2_close(stmt);
+}
+
+void test1(TAOS* taos) {
+ execute_test(taos, "tb1", "POINT(1.0 1.0)", "LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", "[normal]case 1");
+}
+
+void test2(TAOS* taos) {
+ execute_test(taos, "tb2", "hello", "LINESTRING(1.0 1.0, 2.0 2.0, 3.0 3.0)", "[wrong tag]case 2");
+}
+
+void test3(TAOS* taos) { execute_test(taos, "tb3", "POLYGON((0 0, 4 0, 4 4, 0 4, 0 0))", "1", "[wrong col]case 3"); }
+
+void test4(TAOS* taos) {
+ execute_test(taos, "tb4", "POLYGON((0 0, 4 0, 4 4, 0 4, 0 0))", "POINT(1.0 1.0)", "[wrong size]case 4");
+}
+
+int main() {
+ TAOS* taos = taos_connect("localhost", "root", "taosdata", "", 0);
+ if (!taos) {
+ printf("failed to connect to db, reason:%s\n", taos_errstr(taos));
+ exit(1);
+ }
+ // init test db & stb table
+ do_query(taos, "drop database if exists db");
+ do_query(taos, "create database db");
+ do_query(taos, "create table db.stb (ts timestamp, b geometry(100)) tags(t1 int, t2 geometry(100))");
+ do_query(taos, "create table db.stb2 (ts timestamp, b geometry(100)) tags(t1 int, t2 geometry(10))");
+
+ test1(taos);
+ test2(taos);
+ test3(taos);
+ test4(taos);
+
+ taos_close(taos);
+ taos_cleanup();
+}