diff --git a/docs/examples/node/websocketexample/all_type_stmt.js b/docs/examples/node/websocketexample/all_type_stmt.js
old mode 100644
new mode 100755
index f095bee090..2297923e75
--- a/docs/examples/node/websocketexample/all_type_stmt.js
+++ b/docs/examples/node/websocketexample/all_type_stmt.js
@@ -95,8 +95,8 @@ async function all_type_example() {
tagParams.setBoolean([true]);
tagParams.setVarchar(["hello"]);
tagParams.setNchar(["stmt"]);
- tagParams.setGeometry([geometryData]);
tagParams.setVarBinary([vbData]);
+ tagParams.setGeometry([geometryData]);
await stmt.setTags(tagParams);
@@ -108,8 +108,8 @@ async function all_type_example() {
bindParams.setBoolean([true]);
bindParams.setVarchar(["hello"]);
bindParams.setNchar(["stmt"]);
- bindParams.setGeometry([geometryData]);
bindParams.setVarBinary([vbData]);
+ bindParams.setGeometry([geometryData]);
await stmt.bind(bindParams);
await stmt.batch();
diff --git a/include/common/tdataformat.h b/include/common/tdataformat.h
index 19f3e222d1..f899fc5589 100644
--- a/include/common/tdataformat.h
+++ b/include/common/tdataformat.h
@@ -57,9 +57,9 @@ const static uint8_t BIT2_MAP[4] = {0b11111100, 0b11110011, 0b11001111, 0b001111
#define ONE ((uint8_t)1)
#define THREE ((uint8_t)3)
#define DIV_8(i) ((i) >> 3)
-#define MOD_8(i) ((i)&7)
+#define MOD_8(i) ((i) & 7)
#define DIV_4(i) ((i) >> 2)
-#define MOD_4(i) ((i)&3)
+#define MOD_4(i) ((i) & 3)
#define MOD_4_TIME_2(i) (MOD_4(i) << 1)
#define BIT1_SIZE(n) (DIV_8((n)-1) + 1)
#define BIT2_SIZE(n) (DIV_4((n)-1) + 1)
@@ -173,6 +173,8 @@ typedef struct {
} SColDataCompressInfo;
typedef void *(*xMallocFn)(void *, int32_t);
+typedef int32_t (*checkWKBGeometryFn)(const unsigned char *geoWKB, size_t nGeom);
+typedef int32_t (*initGeosFn)();
void tColDataDestroy(void *ph);
void tColDataInit(SColData *pColData, int16_t cid, int8_t type, int8_t cflag);
@@ -191,7 +193,8 @@ int32_t tColDataCompress(SColData *colData, SColDataCompressInfo *info, SBuffer
int32_t tColDataDecompress(void *input, SColDataCompressInfo *info, SColData *colData, SBuffer *assist);
// for stmt bind
-int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32_t buffMaxLen);
+int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32_t buffMaxLen, initGeosFn igeos,
+ checkWKBGeometryFn cgeos);
int32_t tColDataSortMerge(SArray **arr);
// for raw block
@@ -378,7 +381,8 @@ int32_t tRowBuildFromBind(SBindInfo *infos, int32_t numOfInfos, bool infoSorted,
SArray *rowArray);
// stmt2 binding
-int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen);
+int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen, initGeosFn igeos,
+ checkWKBGeometryFn cgeos);
typedef struct {
int32_t columnId;
diff --git a/include/libs/geometry/geosWrapper.h b/include/libs/geometry/geosWrapper.h
index a5bc0cec17..d27d300b82 100644
--- a/include/libs/geometry/geosWrapper.h
+++ b/include/libs/geometry/geosWrapper.h
@@ -35,6 +35,7 @@ int32_t doGeomFromText(const char *inputWKT, unsigned char **outputGeom, size_t
int32_t initCtxAsText();
int32_t doAsText(const unsigned char *inputGeom, size_t size, char **outputWKT);
+int32_t checkWKB(const unsigned char *wkb, size_t size);
int32_t initCtxRelationFunc();
int32_t doIntersects(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
@@ -47,11 +48,12 @@ int32_t doCovers(const GEOSGeometry *geom1, const GEOSPreparedGeometry *prepared
bool swapped, char *res);
int32_t doContains(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
bool swapped, char *res);
-int32_t doContainsProperly(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
- bool swapped, char *res);
+int32_t doContainsProperly(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1,
+ const GEOSGeometry *geom2, bool swapped, char *res);
-int32_t readGeometry(const unsigned char *input, GEOSGeometry **outputGeom, const GEOSPreparedGeometry **outputPreparedGeom);
-void destroyGeometry(GEOSGeometry **geom, const GEOSPreparedGeometry **preparedGeom);
+int32_t readGeometry(const unsigned char *input, GEOSGeometry **outputGeom,
+ const GEOSPreparedGeometry **outputPreparedGeom);
+void destroyGeometry(GEOSGeometry **geom, const GEOSPreparedGeometry **preparedGeom);
#ifdef __cplusplus
}
diff --git a/source/common/src/tdataformat.c b/source/common/src/tdataformat.c
index e580ad33bd..a38842735c 100644
--- a/source/common/src/tdataformat.c
+++ b/source/common/src/tdataformat.c
@@ -3036,7 +3036,8 @@ _exit:
return code;
}
-int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32_t buffMaxLen) {
+int32_t tColDataAddValueByBind(SColData *pColData, TAOS_MULTI_BIND *pBind, int32_t buffMaxLen, initGeosFn igeos,
+ checkWKBGeometryFn cgeos) {
int32_t code = 0;
if (!(pBind->num == 1 && pBind->is_null && *pBind->is_null)) {
@@ -3046,6 +3047,12 @@ 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 = igeos();
+ if (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,9 +3062,12 @@ 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 {
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = cgeos((char *)pBind->buffer + pBind->buffer_length * i, (size_t)pBind->length[i]);
+ if (code) goto _exit;
+ }
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](
pColData, (uint8_t *)pBind->buffer + pBind->buffer_length * i, pBind->length[i]);
}
@@ -3108,7 +3118,8 @@ _exit:
return code;
}
-int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen) {
+int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int32_t buffMaxLen, initGeosFn igeos,
+ checkWKBGeometryFn cgeos) {
int32_t code = 0;
if (!(pBind->num == 1 && pBind->is_null && *pBind->is_null)) {
@@ -3118,6 +3129,13 @@ int32_t tColDataAddValueByBind2(SColData *pColData, TAOS_STMT2_BIND *pBind, int3
}
if (IS_VAR_DATA_TYPE(pColData->type)) { // var-length data type
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = igeos();
+ if (code) {
+ return code;
+ }
+ }
+
uint8_t *buf = pBind->buffer;
for (int32_t i = 0; i < pBind->num; ++i) {
if (pBind->is_null && pBind->is_null[i]) {
@@ -3133,9 +3151,12 @@ 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 {
+ if (pColData->type == TSDB_DATA_TYPE_GEOMETRY) {
+ code = cgeos(buf, pBind->length[i]);
+ if (code) goto _exit;
+ }
code = tColDataAppendValueImpl[pColData->flag][CV_FLAG_VALUE](pColData, buf, pBind->length[i]);
buf += pBind->length[i];
}
diff --git a/source/libs/geometry/src/geosWrapper.c b/source/libs/geometry/src/geosWrapper.c
index 13c5f7208e..8789762a85 100644
--- a/source/libs/geometry/src/geosWrapper.c
+++ b/source/libs/geometry/src/geosWrapper.c
@@ -63,7 +63,7 @@ int32_t initCtxMakePoint() {
int32_t doMakePoint(double x, double y, unsigned char **outputGeom, size_t *size) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
GEOSGeometry *geom = NULL;
@@ -170,7 +170,7 @@ static int32_t initWktRegex(pcre2_code **ppRegex, pcre2_match_data **ppMatchData
int32_t initCtxGeomFromText() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
if (geosCtx->handle == NULL) {
@@ -208,7 +208,7 @@ int32_t initCtxGeomFromText() {
int32_t doGeomFromText(const char *inputWKT, unsigned char **outputGeom, size_t *size) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
GEOSGeometry *geom = NULL;
@@ -245,7 +245,7 @@ _exit:
int32_t initCtxAsText() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
if (geosCtx->handle == NULL) {
@@ -283,11 +283,11 @@ int32_t initCtxAsText() {
int32_t doAsText(const unsigned char *inputGeom, size_t size, char **outputWKT) {
int32_t code = TSDB_CODE_FAILED;
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
- GEOSGeometry *geom = NULL;
- char *wkt = NULL;
+ GEOSGeometry *geom = NULL;
+ char *wkt = NULL;
geom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, inputGeom, size);
if (geom == NULL) {
@@ -313,10 +313,35 @@ _exit:
return code;
}
+int32_t checkWKB(const unsigned char *wkb, size_t size) {
+ int32_t code = TSDB_CODE_SUCCESS;
+ GEOSGeometry *geom = NULL;
+ SGeosContext *geosCtx = NULL;
+
+ TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
+
+ geom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, wkb, size);
+ if (geom == NULL) {
+ return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
+ }
+
+ if (!GEOSisValid_r(geosCtx->handle, geom)) {
+ code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
+ goto _exit;
+ }
+
+_exit:
+ if (geom) {
+ GEOSGeom_destroy_r(geosCtx->handle, geom);
+ geom = NULL;
+ }
+ return code;
+}
+
int32_t initCtxRelationFunc() {
int32_t code = TSDB_CODE_FAILED;
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
if (geosCtx->handle == NULL) {
@@ -343,7 +368,7 @@ int32_t doGeosRelation(const GEOSGeometry *geom1, const GEOSPreparedGeometry *pr
_geosPreparedRelationFunc_t preparedRelationFn,
_geosPreparedRelationFunc_t swappedPreparedRelationFn) {
SGeosContext *geosCtx = NULL;
-
+
TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
if (!preparedGeom1) {
diff --git a/source/libs/parser/src/parInsertStmt.c b/source/libs/parser/src/parInsertStmt.c
index 0979028e6d..bedd4fa540 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"
@@ -192,6 +193,12 @@ int32_t qBindStmtTagsValue(void* pBlock, void* boundTags, int64_t suid, const ch
// 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_GEOMETRY) {
+ if (initCtxAsText() || checkWKB(bind[c].buffer, colLen)) {
+ code = buildSyntaxErrMsg(&pBuf, "invalid geometry tag", bind[c].buffer);
+ goto end;
+ }
+ }
val.pData = (uint8_t*)bind[c].buffer;
val.nData = colLen;
} else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) {
@@ -409,7 +416,8 @@ int32_t qBindStmtColsValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bind, c
}
code = tColDataAddValueByBind(pCol, pBind,
- IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1);
+ IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1,
+ initCtxAsText, checkWKB);
if (code) {
goto _return;
}
@@ -461,7 +469,8 @@ int32_t qBindStmtSingleColValue(void* pBlock, SArray* pCols, TAOS_MULTI_BIND* bi
}
code = tColDataAddValueByBind(pCol, pBind,
- IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1);
+ IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1,
+ initCtxAsText, checkWKB);
qDebug("stmt col %d bind %d rows data", colIdx, rowNum);
@@ -544,6 +553,12 @@ int32_t qBindStmtTagsValue2(void* pBlock, void* boundTags, int64_t suid, const c
// 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_GEOMETRY) {
+ if (initCtxAsText() || checkWKB(bind[c].buffer, colLen)) {
+ code = buildSyntaxErrMsg(&pBuf, "invalid geometry tag", bind[c].buffer);
+ goto end;
+ }
+ }
val.pData = (uint8_t*)bind[c].buffer;
val.nData = colLen;
} else if (pTagSchema->type == TSDB_DATA_TYPE_NCHAR) {
@@ -824,7 +839,8 @@ int32_t qBindStmtColsValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* bind,
}
code = tColDataAddValueByBind2(pCol, pBind,
- IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1);
+ IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1,
+ initCtxAsText, checkWKB);
if (code) {
goto _return;
}
@@ -876,7 +892,8 @@ int32_t qBindStmtSingleColValue2(void* pBlock, SArray* pCols, TAOS_STMT2_BIND* b
}
code = tColDataAddValueByBind2(pCol, pBind,
- IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1);
+ IS_VAR_DATA_TYPE(pColSchema->type) ? pColSchema->bytes - VARSTR_HEADER_SIZE : -1,
+ initCtxAsText, checkWKB);
qDebug("stmt col %d bind %d rows data", colIdx, rowNum);
diff --git a/tests/script/api/stmt2-geometry-test.c b/tests/script/api/stmt2-geometry-test.c
new file mode 100644
index 0000000000..46fd9081ae
--- /dev/null
+++ b/tests/script/api/stmt2-geometry-test.c
@@ -0,0 +1,107 @@
+#include
+#include
+#include
+#include "taos.h"
+
+int8_t byteArray[21] = {0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40};
+int8_t worngArray[21] = {0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x59, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x40};
+
+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* tbname1, const char* tbname2, int8_t* tag2, int8_t* col2,
+ const char* case_desc, int size) {
+ // prepare stmt
+ TAOS_STMT2_OPTION option = {0, true, false, NULL, NULL};
+ TAOS_STMT2* stmt = taos_stmt2_init(taos, &option);
+ const char* sql;
+ if (tbname1 == "tb41") {
+ 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", case_desc);
+ 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;
+ const char* tbname[2] = {tbname1, tbname2};
+ int32_t length[5] = {sizeof(int), 2, sizeof(int64_t), size, 20, sizeof(col2)};
+
+ TAOS_STMT2_BIND tags[2][2] = {
+ {{TSDB_DATA_TYPE_INT, &t1_val, &length[0], NULL, 2}, {TSDB_DATA_TYPE_GEOMETRY, tag2, &length[3], NULL, 2}},
+ {{TSDB_DATA_TYPE_INT, &t1_val, &length[0], NULL, 2}, {TSDB_DATA_TYPE_GEOMETRY, tag2, &length[3], NULL, 2}}};
+ TAOS_STMT2_BIND params[2][2] = {
+ {{TSDB_DATA_TYPE_TIMESTAMP, &ts, &length[2], NULL, 1}, {TSDB_DATA_TYPE_GEOMETRY, col2, &length[3], NULL, 1}},
+ {{TSDB_DATA_TYPE_TIMESTAMP, &ts, &length[2], NULL, 1}, {TSDB_DATA_TYPE_GEOMETRY, col2, &length[3], NULL, 1}}};
+ TAOS_STMT2_BIND* tagv[2] = {&tags[0][0], &tags[1][0]};
+ TAOS_STMT2_BIND* paramv[2] = {¶ms[0][0], ¶ms[1][0]};
+
+ TAOS_STMT2_BINDV bindv = {2, &tbname[0], &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, "tb11", "tb12", &byteArray[0], &byteArray[0], "[normal]case 1", 21); }
+
+void test2(TAOS* taos) {
+ execute_test(taos, "tb21", "tb22", &worngArray[0], &byteArray[0], "[wrong WKB tag]case 2", 21);
+}
+
+void test3(TAOS* taos) {
+ execute_test(taos, "tb31", "tb32", "POLYGON((0 0, 4 0, 4 4, 0 4, 0 0))", "POLYGON((0 0, 4 0, 4 4, 0 4, 0 0))",
+ "[wrong WKT col]case 3", sizeof("POLYGON((0 0, 4 0, 4 4, 0 4, 0 0))"));
+}
+
+void test4(TAOS* taos) { execute_test(taos, "tb41", "tb42", &byteArray[0], &byteArray[0], "[wrong size]case 4", 21); }
+
+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();
+}