@@ -98,6 +98,11 @@ ltree_strncasecmp(const char *a, const char *b, size_t s)
98
98
return res ;
99
99
}
100
100
101
+ /*
102
+ * See if a (non-star) lquery_level matches an ltree_level
103
+ *
104
+ * Does not consider level's possible LQL_NOT flag.
105
+ */
101
106
static bool
102
107
checkLevel (lquery_level * curq , ltree_level * curt )
103
108
{
@@ -136,42 +141,49 @@ printFieldNot(FieldNot *fn ) {
136
141
}
137
142
*/
138
143
139
- static struct
140
- {
141
- bool muse ;
142
- uint32 high_pos ;
143
- } SomeStack =
144
-
145
- {
146
- false, 0 ,
147
- };
148
-
144
+ /*
145
+ * Try to match an lquery (of query_numlevel items) to an ltree (of
146
+ * tree_numlevel items)
147
+ *
148
+ * If the query contains any NOT flags, "ptr" must point to a FieldNot
149
+ * workspace initialized with ptr->q == NULL. Otherwise it can be NULL.
150
+ * (LQL_NOT flags will be ignored if ptr == NULL.)
151
+ *
152
+ * high_pos is the last ltree position the first lquery item is allowed
153
+ * to match at; it should be zero for external calls.
154
+ *
155
+ * force_advance must be false except in internal recursive calls.
156
+ */
149
157
static bool
150
- checkCond (lquery_level * curq , int query_numlevel , ltree_level * curt , int tree_numlevel , FieldNot * ptr )
158
+ checkCond (lquery_level * curq , int query_numlevel ,
159
+ ltree_level * curt , int tree_numlevel ,
160
+ FieldNot * ptr ,
161
+ uint32 high_pos ,
162
+ bool force_advance )
151
163
{
152
- uint32 low_pos = 0 ,
153
- high_pos = 0 ,
154
- cur_tpos = 0 ;
155
- int tlen = tree_numlevel ,
164
+ uint32 low_pos = 0 , /* first allowed ltree position for match */
165
+ cur_tpos = 0 ; /* ltree position of curt */
166
+ int tlen = tree_numlevel , /* counts of remaining items */
156
167
qlen = query_numlevel ;
157
- int isok ;
158
168
lquery_level * prevq = NULL ;
159
- ltree_level * prevt = NULL ;
160
169
161
- if (SomeStack .muse )
170
+ /* advance curq (setting up prevq) if requested */
171
+ if (force_advance )
162
172
{
163
- high_pos = SomeStack .high_pos ;
164
- qlen -- ;
173
+ Assert (qlen > 0 );
165
174
prevq = curq ;
166
175
curq = LQL_NEXT (curq );
167
- SomeStack . muse = false ;
176
+ qlen -- ;
168
177
}
169
178
170
179
while (tlen > 0 && qlen > 0 )
171
180
{
172
181
if (curq -> numvar )
173
182
{
174
- prevt = curt ;
183
+ /* Current query item is not '*' */
184
+ ltree_level * prevt = curt ;
185
+
186
+ /* skip tree items that must be ignored due to prior * items */
175
187
while (cur_tpos < low_pos )
176
188
{
177
189
curt = LEVEL_NEXT (curt );
@@ -183,8 +195,9 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
183
195
ptr -> nt ++ ;
184
196
}
185
197
186
- if (ptr && curq -> flag & LQL_NOT )
198
+ if (ptr && ( curq -> flag & LQL_NOT ) )
187
199
{
200
+ /* Deal with a NOT item */
188
201
if (!(prevq && prevq -> numvar == 0 ))
189
202
prevq = curq ;
190
203
if (ptr -> q == NULL )
@@ -212,33 +225,42 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
212
225
}
213
226
else
214
227
{
215
- isok = false;
228
+ /* Not a NOT item, check for normal match */
229
+ bool isok = false;
230
+
216
231
while (cur_tpos <= high_pos && tlen > 0 && !isok )
217
232
{
218
233
isok = checkLevel (curq , curt );
219
234
curt = LEVEL_NEXT (curt );
220
235
tlen -- ;
221
236
cur_tpos ++ ;
222
- if (isok && prevq && prevq -> numvar == 0 && tlen > 0 && cur_tpos <= high_pos )
237
+ if (isok && prevq && prevq -> numvar == 0 &&
238
+ tlen > 0 && cur_tpos <= high_pos )
223
239
{
224
240
FieldNot tmpptr ;
225
241
226
242
if (ptr )
227
243
memcpy (& tmpptr , ptr , sizeof (FieldNot ));
228
- SomeStack .high_pos = high_pos - cur_tpos ;
229
- SomeStack .muse = true;
230
- if (checkCond (prevq , qlen + 1 , curt , tlen , (ptr ) ? & tmpptr : NULL ))
244
+ if (checkCond (prevq , qlen + 1 ,
245
+ curt , tlen ,
246
+ (ptr ) ? & tmpptr : NULL ,
247
+ high_pos - cur_tpos ,
248
+ true))
231
249
return true;
232
250
}
233
- if (!isok && ptr )
251
+ if (!isok && ptr && ptr -> q )
234
252
ptr -> nt ++ ;
235
253
}
236
254
if (!isok )
237
255
return false;
238
256
239
257
if (ptr && ptr -> q )
240
258
{
241
- if (checkCond (ptr -> q , ptr -> nq , ptr -> t , ptr -> nt , NULL ))
259
+ if (checkCond (ptr -> q , ptr -> nq ,
260
+ ptr -> t , ptr -> nt ,
261
+ NULL ,
262
+ 0 ,
263
+ false))
242
264
return false;
243
265
ptr -> q = NULL ;
244
266
}
@@ -248,8 +270,14 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
248
270
}
249
271
else
250
272
{
251
- low_pos = cur_tpos + curq -> low ;
252
- high_pos = cur_tpos + curq -> high ;
273
+ /* Current query item is '*' */
274
+ low_pos += curq -> low ;
275
+
276
+ if (low_pos > tree_numlevel )
277
+ return false;
278
+
279
+ high_pos = Min (high_pos + curq -> high , tree_numlevel );
280
+
253
281
if (ptr && ptr -> q )
254
282
{
255
283
ptr -> nq ++ ;
@@ -263,9 +291,11 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
263
291
qlen -- ;
264
292
}
265
293
294
+ /* Fail if we've already run out of ltree items */
266
295
if (low_pos > tree_numlevel || tree_numlevel > high_pos )
267
296
return false;
268
297
298
+ /* Remaining lquery items must be NOT or '*' items */
269
299
while (qlen > 0 )
270
300
{
271
301
if (curq -> numvar )
@@ -275,18 +305,29 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
275
305
}
276
306
else
277
307
{
278
- low_pos = cur_tpos + curq -> low ;
279
- high_pos = cur_tpos + curq -> high ;
308
+ low_pos += curq -> low ;
309
+
310
+ if (low_pos > tree_numlevel )
311
+ return false;
312
+
313
+ high_pos = Min (high_pos + curq -> high , tree_numlevel );
280
314
}
281
315
282
316
curq = LQL_NEXT (curq );
283
317
qlen -- ;
284
318
}
285
319
320
+ /* Fail if trailing '*'s require more ltree items than we have */
286
321
if (low_pos > tree_numlevel || tree_numlevel > high_pos )
287
322
return false;
288
323
289
- if (ptr && ptr -> q && checkCond (ptr -> q , ptr -> nq , ptr -> t , ptr -> nt , NULL ))
324
+ /* Finish pending NOT check, if any */
325
+ if (ptr && ptr -> q &&
326
+ checkCond (ptr -> q , ptr -> nq ,
327
+ ptr -> t , ptr -> nt ,
328
+ NULL ,
329
+ 0 ,
330
+ false))
290
331
return false;
291
332
292
333
return true;
@@ -306,12 +347,18 @@ ltq_regex(PG_FUNCTION_ARGS)
306
347
fn .q = NULL ;
307
348
308
349
res = checkCond (LQUERY_FIRST (query ), query -> numlevel ,
309
- LTREE_FIRST (tree ), tree -> numlevel , & fn );
350
+ LTREE_FIRST (tree ), tree -> numlevel ,
351
+ & fn ,
352
+ 0 ,
353
+ false);
310
354
}
311
355
else
312
356
{
313
357
res = checkCond (LQUERY_FIRST (query ), query -> numlevel ,
314
- LTREE_FIRST (tree ), tree -> numlevel , NULL );
358
+ LTREE_FIRST (tree ), tree -> numlevel ,
359
+ NULL ,
360
+ 0 ,
361
+ false);
315
362
}
316
363
317
364
PG_FREE_IF_COPY (tree , 0 );
0 commit comments