• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taosdata / TDengine / #3531

19 Nov 2024 10:42AM UTC coverage: 60.213% (-0.006%) from 60.219%
#3531

push

travis-ci

web-flow
Merge pull request #28777 from taosdata/fix/3.0/TD-32366

fix:TD-32366/stmt add geometry datatype check

118529 of 252344 branches covered (46.97%)

Branch coverage included in aggregate %.

7 of 48 new or added lines in 3 files covered. (14.58%)

2282 existing lines in 115 files now uncovered.

199096 of 275161 relevant lines covered (72.36%)

6067577.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.56
/source/libs/geometry/src/geosWrapper.c
1
/*
2
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
3
 *
4
 * This program is free software: you can use, redistribute, and/or modify
5
 * it under the terms of the GNU Affero General Public License, version 3
6
 * or later ("AGPL"), as published by the Free Software Foundation.
7
 *
8
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
 * FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * You should have received a copy of the GNU Affero General Public License
13
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14
 */
15

16
#include "geosWrapper.h"
17
#include "tutil.h"
18
#include "types.h"
19

20
typedef char (*_geosRelationFunc_t)(GEOSContextHandle_t handle, const GEOSGeometry *g1, const GEOSGeometry *g2);
21
typedef char (*_geosPreparedRelationFunc_t)(GEOSContextHandle_t handle, const GEOSPreparedGeometry *pg1,
22
                                            const GEOSGeometry *g2);
23

24
void geosFreeBuffer(void *buffer) {
11,277✔
25
  if (buffer) {
11,277✔
26
    SGeosContext *pCtx = acquireThreadLocalGeosCtx();
8,825✔
27
    if (pCtx) GEOSFree_r(pCtx->handle, buffer);
8,825!
28
  }
29
}
11,277✔
30

31
void geosErrMsgeHandler(const char *errMsg, void *userData) {
49✔
32
  char *targetErrMsg = userData;
49✔
33
  (void)snprintf(targetErrMsg, 512, "%s", errMsg);
49✔
34
}
49✔
35

36
int32_t initCtxMakePoint() {
×
37
  int32_t       code = TSDB_CODE_FAILED;
×
38
  SGeosContext *geosCtx = NULL;
×
39

40
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
×
41

42
  if (geosCtx->handle == NULL) {
×
43
    geosCtx->handle = GEOS_init_r();
×
44
    if (geosCtx->handle == NULL) {
×
45
      return code;
×
46
    }
47

48
    (void)GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
×
49
  }
50

51
  if (geosCtx->WKBWriter == NULL) {
×
52
    geosCtx->WKBWriter = GEOSWKBWriter_create_r(geosCtx->handle);
×
53
    if (geosCtx->WKBWriter == NULL) {
×
54
      return code;
×
55
    }
56
  }
57

58
  return TSDB_CODE_SUCCESS;
×
59
}
60

61
// outputWKT is a zero ending string
62
// need to call geosFreeBuffer(*outputGeom) later
63
int32_t doMakePoint(double x, double y, unsigned char **outputGeom, size_t *size) {
×
64
  int32_t       code = TSDB_CODE_FAILED;
×
65
  SGeosContext *geosCtx = NULL;
×
66

67
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
×
68

69
  GEOSGeometry  *geom = NULL;
×
70
  unsigned char *wkb = NULL;
×
71

72
  geom = GEOSGeom_createPointFromXY_r(geosCtx->handle, x, y);
×
73
  if (geom == NULL) {
×
74
    code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
75
    goto _exit;
×
76
  }
77

78
  wkb = GEOSWKBWriter_write_r(geosCtx->handle, geosCtx->WKBWriter, geom, size);
×
79
  if (wkb == NULL) {
×
80
    goto _exit;
×
81
  }
82
  *outputGeom = wkb;
×
83

84
  code = TSDB_CODE_SUCCESS;
×
85

86
_exit:
×
87
  if (geom) {
×
88
    GEOSGeom_destroy_r(geosCtx->handle, geom);
×
89
    geom = NULL;
×
90
  }
91

92
  return code;
×
93
}
94

95
static int32_t initWktRegex(pcre2_code **ppRegex, pcre2_match_data **ppMatchData) {
155✔
96
  int32_t code = 0;
155✔
97
  char   *wktPatternWithSpace = taosMemoryCalloc(4, 1024);
155✔
98
  if (NULL == wktPatternWithSpace) {
155!
99
    return terrno;
×
100
  }
101

102
  (void)sprintf(
155✔
103
      wktPatternWithSpace,
104
      "^( *)point( *)z?m?( *)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
105
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *)\\)))|linestring( *)z?m?( "
106
      "*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
107
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
108
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
109
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))|polygon( *)z?m?( "
110
      "*)((empty)|(\\(( *)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
111
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
112
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
113
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
114
      "*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
115
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
116
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
117
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( "
118
      "*)\\)))|multipoint( *)z?m?( *)((empty)|(\\(( "
119
      "*)((([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
120
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}|((empty)|(\\(( "
121
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
122
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *)\\))))(( *)(,)( "
123
      "*)((([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
124
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}|((empty)|(\\(( "
125
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
126
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *)\\))))( *))*( "
127
      "*)\\)))|multilinestring( *)z?m?( *)((empty)|(\\(( *)((empty)|(\\(( "
128
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
129
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
130
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
131
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
132
      "*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
133
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
134
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
135
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( "
136
      "*)\\)))|multipolygon( *)z?m?( *)((empty)|(\\(( *)((empty)|(\\(( *)((empty)|(\\(( "
137
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
138
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
139
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
140
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
141
      "*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
142
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
143
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
144
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( *)\\)))(( *)(,)( "
145
      "*)((empty)|(\\(( *)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
146
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
147
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
148
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))(( *)(,)( "
149
      "*)((empty)|(\\(( *)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
150
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}(( *)(,)( "
151
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?(( "
152
      "*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( *)\\)))( *))*( "
153
      "*)\\)))|(GEOCOLLECTION\\((?R)(( *)(,)( *)(?R))*( *)\\))( *)$");
154

155
  pcre2_code       *pRegex = NULL;
155✔
156
  pcre2_match_data *pMatchData = NULL;
155✔
157
  code = doRegComp(&pRegex, &pMatchData, wktPatternWithSpace);
155✔
158
  if (code < 0) {
155!
159
    taosMemoryFree(wktPatternWithSpace);
×
160
    return TSDB_CODE_OUT_OF_MEMORY;
×
161
  }
162

163
  *ppRegex = pRegex;
155✔
164
  *ppMatchData = pMatchData;
155✔
165

166
  taosMemoryFree(wktPatternWithSpace);
155✔
167
  return code;
155✔
168
}
169

170
int32_t initCtxGeomFromText() {
10,216✔
171
  int32_t       code = TSDB_CODE_FAILED;
10,216✔
172
  SGeosContext *geosCtx = NULL;
10,216✔
173

174
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
10,216!
175

176
  if (geosCtx->handle == NULL) {
10,216✔
177
    geosCtx->handle = GEOS_init_r();
155✔
178
    if (geosCtx->handle == NULL) {
155!
179
      return code;
×
180
    }
181

182
    (void)GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
155✔
183
  }
184

185
  if (geosCtx->WKTReader == NULL) {
10,216✔
186
    geosCtx->WKTReader = GEOSWKTReader_create_r(geosCtx->handle);
155✔
187
    if (geosCtx->WKTReader == NULL) {
155!
188
      return code;
×
189
    }
190
  }
191

192
  if (geosCtx->WKBWriter == NULL) {
10,216✔
193
    geosCtx->WKBWriter = GEOSWKBWriter_create_r(geosCtx->handle);
155✔
194
    if (geosCtx->WKBWriter == NULL) {
155!
195
      return code;
×
196
    }
197
  }
198

199
  if (geosCtx->WKTRegex == NULL) {
10,216✔
200
    if (initWktRegex(&geosCtx->WKTRegex, &geosCtx->WKTMatchData) != 0) return code;
155!
201
  }
202

203
  return TSDB_CODE_SUCCESS;
10,216✔
204
}
205

206
// inputWKT is a zero ending string
207
// need to call geosFreeBuffer(*outputGeom) later
208
int32_t doGeomFromText(const char *inputWKT, unsigned char **outputGeom, size_t *size) {
10,228✔
209
  int32_t       code = TSDB_CODE_FAILED;
10,228✔
210
  SGeosContext *geosCtx = NULL;
10,228✔
211

212
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
10,228!
213

214
  GEOSGeometry  *geom = NULL;
10,228✔
215
  unsigned char *wkb = NULL;
10,228✔
216

217
  if (doRegExec(inputWKT, geosCtx->WKTRegex, geosCtx->WKTMatchData) != 0) {
10,228✔
218
    code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
1,468✔
219
    goto _exit;
1,468✔
220
  }
221

222
  geom = GEOSWKTReader_read_r(geosCtx->handle, geosCtx->WKTReader, inputWKT);
8,760✔
223
  if (geom == NULL) {
8,760✔
224
    code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
49✔
225
    goto _exit;
49✔
226
  }
227

228
  wkb = GEOSWKBWriter_write_r(geosCtx->handle, geosCtx->WKBWriter, geom, size);
8,711✔
229
  if (wkb == NULL) {
8,711!
230
    goto _exit;
×
231
  }
232
  *outputGeom = wkb;
8,711✔
233

234
  code = TSDB_CODE_SUCCESS;
8,711✔
235

236
_exit:
10,228✔
237
  if (geom) {
10,228✔
238
    GEOSGeom_destroy_r(geosCtx->handle, geom);
8,711✔
239
    geom = NULL;
8,711✔
240
  }
241

242
  return code;
10,228✔
243
}
244

245
int32_t initCtxAsText() {
94✔
246
  int32_t       code = TSDB_CODE_FAILED;
94✔
247
  SGeosContext *geosCtx = NULL;
94✔
248

249
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
94!
250

251
  if (geosCtx->handle == NULL) {
94✔
252
    geosCtx->handle = GEOS_init_r();
21✔
253
    if (geosCtx->handle == NULL) {
21!
254
      return code;
×
255
    }
256

257
    (void)GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
21✔
258
  }
259

260
  if (geosCtx->WKBReader == NULL) {
94✔
261
    geosCtx->WKBReader = GEOSWKBReader_create_r(geosCtx->handle);
30✔
262
    if (geosCtx->WKBReader == NULL) {
30!
263
      return code;
×
264
    }
265
  }
266

267
  if (geosCtx->WKTWriter == NULL) {
94✔
268
    geosCtx->WKTWriter = GEOSWKTWriter_create_r(geosCtx->handle);
30✔
269

270
    if (geosCtx->WKTWriter) {
30!
271
      GEOSWKTWriter_setRoundingPrecision_r(geosCtx->handle, geosCtx->WKTWriter, 6);
30✔
272
      GEOSWKTWriter_setTrim_r(geosCtx->handle, geosCtx->WKTWriter, 0);
30✔
273
    } else {
274
      return code;
×
275
    }
276
  }
277

278
  return TSDB_CODE_SUCCESS;
94✔
279
}
280

281
// outputWKT is a zero ending string
282
// need to call geosFreeBuffer(*outputWKT) later
283
int32_t doAsText(const unsigned char *inputGeom, size_t size, char **outputWKT) {
99✔
284
  int32_t       code = TSDB_CODE_FAILED;
99✔
285
  SGeosContext *geosCtx = NULL;
99✔
286

287
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
99!
288

289
  GEOSGeometry *geom = NULL;
99✔
290
  char         *wkt = NULL;
99✔
291

292
  geom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, inputGeom, size);
99✔
293
  if (geom == NULL) {
99!
294
    code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
295
    goto _exit;
×
296
  }
297

298
  wkt = GEOSWKTWriter_write_r(geosCtx->handle, geosCtx->WKTWriter, geom);
99✔
299
  if (wkt == NULL) {
99!
300
    code = TSDB_CODE_MSG_DECODE_ERROR;
×
301
    goto _exit;
×
302
  }
303
  *outputWKT = wkt;
99✔
304

305
  code = TSDB_CODE_SUCCESS;
99✔
306

307
_exit:
99✔
308
  if (geom) {
99!
309
    GEOSGeom_destroy_r(geosCtx->handle, geom);
99✔
310
    geom = NULL;
99✔
311
  }
312

313
  return code;
99✔
314
}
315

NEW
316
int32_t checkWKB(const unsigned char *wkb, size_t size) {
×
NEW
317
  int32_t       code = TSDB_CODE_SUCCESS;
×
NEW
318
  GEOSGeometry *geom = NULL;
×
NEW
319
  SGeosContext *geosCtx = NULL;
×
320

NEW
321
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
×
322

NEW
323
  geom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, wkb, size);
×
NEW
324
  if (geom == NULL) {
×
NEW
325
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
326
  }
327

NEW
328
  if (!GEOSisValid_r(geosCtx->handle, geom)) {
×
NEW
329
    code = TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
NEW
330
    goto _exit;
×
331
  }
332

NEW
333
_exit:
×
NEW
334
  if (geom) {
×
NEW
335
    GEOSGeom_destroy_r(geosCtx->handle, geom);
×
NEW
336
    geom = NULL;
×
337
  }
NEW
338
  return code;
×
339
}
340

341
int32_t initCtxRelationFunc() {
54✔
342
  int32_t       code = TSDB_CODE_FAILED;
54✔
343
  SGeosContext *geosCtx = NULL;
54✔
344

345
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
54!
346

347
  if (geosCtx->handle == NULL) {
54✔
348
    geosCtx->handle = GEOS_init_r();
19✔
349
    if (geosCtx->handle == NULL) {
19!
350
      return code;
×
351
    }
352

353
    (void)GEOSContext_setErrorMessageHandler_r(geosCtx->handle, geosErrMsgeHandler, geosCtx->errMsg);
19✔
354
  }
355

356
  if (geosCtx->WKBReader == NULL) {
54✔
357
    geosCtx->WKBReader = GEOSWKBReader_create_r(geosCtx->handle);
40✔
358
    if (geosCtx->WKBReader == NULL) {
40!
359
      return code;
×
360
    }
361
  }
362

363
  return TSDB_CODE_SUCCESS;
54✔
364
}
365

366
int32_t doGeosRelation(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
84✔
367
                       bool swapped, char *res, _geosRelationFunc_t relationFn, _geosRelationFunc_t swappedRelationFn,
368
                       _geosPreparedRelationFunc_t preparedRelationFn,
369
                       _geosPreparedRelationFunc_t swappedPreparedRelationFn) {
370
  SGeosContext *geosCtx = NULL;
84✔
371

372
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
84!
373

374
  if (!preparedGeom1) {
84✔
375
    if (!swapped) {
14✔
376
      if (!relationFn) {
11!
377
        return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
378
      }
379
      *res = relationFn(geosCtx->handle, geom1, geom2);
11✔
380
    } else {
381
      if (!swappedRelationFn) {
3!
382
        return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
383
      }
384
      *res = swappedRelationFn(geosCtx->handle, geom1, geom2);
3✔
385
    }
386
  } else {
387
    if (!swapped) {
70✔
388
      if (!preparedRelationFn) {
58!
389
        return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
390
      }
391
      *res = preparedRelationFn(geosCtx->handle, preparedGeom1, geom2);
58✔
392
    } else {
393
      if (!swappedPreparedRelationFn) {
12!
394
        return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
395
      }
396
      *res = swappedPreparedRelationFn(geosCtx->handle, preparedGeom1, geom2);
12✔
397
    }
398
  }
399

400
  return TSDB_CODE_SUCCESS;
84✔
401
}
402

403
int32_t doIntersects(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
14✔
404
                     bool swapped, char *res) {
405
  return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res, GEOSIntersects_r, GEOSIntersects_r,
14✔
406
                        GEOSPreparedIntersects_r, GEOSPreparedIntersects_r);
407
}
408

409
int32_t doEquals(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
14✔
410
                 bool swapped, char *res) {
411
  return doGeosRelation(geom1, NULL, geom2, swapped, res, GEOSEquals_r, GEOSEquals_r, NULL,
14✔
412
                        NULL);  // no prepared version for eguals()
413
}
414

415
int32_t doTouches(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
14✔
416
                  bool swapped, char *res) {
417
  return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res, GEOSTouches_r, GEOSTouches_r, GEOSPreparedTouches_r,
14✔
418
                        GEOSPreparedTouches_r);
419
}
420

421
int32_t doCovers(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
14✔
422
                 bool swapped, char *res) {
423
  return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res, GEOSCovers_r, GEOSCoveredBy_r, GEOSPreparedCovers_r,
14✔
424
                        GEOSPreparedCoveredBy_r);
425
}
426

427
int32_t doContains(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1, const GEOSGeometry *geom2,
14✔
428
                   bool swapped, char *res) {
429
  return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res, GEOSContains_r, GEOSWithin_r, GEOSPreparedContains_r,
14✔
430
                        GEOSPreparedWithin_r);
431
}
432

433
int32_t doContainsProperly(const GEOSGeometry *geom1, const GEOSPreparedGeometry *preparedGeom1,
14✔
434
                           const GEOSGeometry *geom2, bool swapped, char *res) {
435
  return doGeosRelation(geom1, preparedGeom1, geom2, swapped, res, NULL, NULL, GEOSPreparedContainsProperly_r, NULL);
14✔
436
}
437

438
// input is with VARSTR format
439
// need to call destroyGeometry(outputGeom, outputPreparedGeom) later
440
int32_t readGeometry(const unsigned char *input, GEOSGeometry **outputGeom,
132✔
441
                     const GEOSPreparedGeometry **outputPreparedGeom) {
442
  if (!outputGeom) {
132!
443
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
444
  }
445

446
  *outputGeom = NULL;
132✔
447

448
  if (outputPreparedGeom) {  // it means not to generate PreparedGeometry if outputPreparedGeom is NULL
132✔
449
    *outputPreparedGeom = NULL;
50✔
450
  }
451

452
  if (varDataLen(input) == 0) {  // empty value
132!
453
    return TSDB_CODE_SUCCESS;
×
454
  }
455

456
  SGeosContext *geosCtx = NULL;
132✔
457
  TAOS_CHECK_RETURN(getThreadLocalGeosCtx(&geosCtx));
132!
458
  *outputGeom = GEOSWKBReader_read_r(geosCtx->handle, geosCtx->WKBReader, varDataVal(input), varDataLen(input));
132✔
459
  if (*outputGeom == NULL) {
132!
460
    return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
×
461
  }
462

463
  if (outputPreparedGeom) {
132✔
464
    *outputPreparedGeom = GEOSPrepare_r(geosCtx->handle, *outputGeom);
50✔
465
    if (*outputPreparedGeom == NULL) {
50!
466
      return TSDB_CODE_FAILED;
×
467
    }
468
  }
469

470
  return TSDB_CODE_SUCCESS;
132✔
471
}
472

473
void destroyGeometry(GEOSGeometry **geom, const GEOSPreparedGeometry **preparedGeom) {
162✔
474
  SGeosContext *geosCtx = acquireThreadLocalGeosCtx();
162✔
475
  if (!geosCtx) return;
162!
476

477
  if (preparedGeom && *preparedGeom) {
162✔
478
    GEOSPreparedGeom_destroy_r(geosCtx->handle, *preparedGeom);
50✔
479
    *preparedGeom = NULL;
50✔
480
  }
481

482
  if (geom && *geom) {
162!
483
    GEOSGeom_destroy_r(geosCtx->handle, *geom);
132✔
484
    *geom = NULL;
132✔
485
  }
486
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc