Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9950c8a

Browse files
committed
Fix lquery's behavior for consecutive '*' items.
Something like "*{2}.*{3}" should presumably mean the same as"*{5}", but it didn't. Improve that.Get rid of an undocumented and remarkably ugly (though not, as far asI can tell, actually unsafe) static variable in favor of passing morearguments to checkCond().Reverse-engineer some commentary. This function, like all of ltree,is still far short of what I would consider the minimum acceptablelevel of internal documentation, but at least now it has more thanzero comments.Although this certainly seems like a bug fix, people might notthank us for changing query behavior in stable branches, sono back-patch.Nikita Glukhov, with cosmetic improvements by meDiscussion:https://postgr.es/m/CAP_rww=waX2Oo6q+MbMSiZ9ktdj6eaJj0cQzNu=Ry2cCDij5fw@mail.gmail.com
1 parent95f7ddf commit9950c8a

File tree

4 files changed

+123
-46
lines changed

4 files changed

+123
-46
lines changed

‎contrib/ltree/expected/ltree.out

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,30 @@ SELECT 'a.b.c.d.e'::ltree ~ '*.!b.*.!c.*';
959959
f
960960
(1 row)
961961

962+
SELECT 'a.b.c.d.e'::ltree ~ 'a.*{2}.*{2}';
963+
?column?
964+
----------
965+
t
966+
(1 row)
967+
968+
SELECT 'a.b.c.d.e'::ltree ~ 'a.*{1}.*{2}.e';
969+
?column?
970+
----------
971+
t
972+
(1 row)
973+
974+
SELECT 'a.b.c.d.e'::ltree ~ 'a.*{1}.*{4}';
975+
?column?
976+
----------
977+
f
978+
(1 row)
979+
980+
SELECT 'a.b.c.d.e'::ltree ~ 'a.*{5}.*';
981+
?column?
982+
----------
983+
f
984+
(1 row)
985+
962986
SELECT 'QWER_TY'::ltree ~ 'q%@*';
963987
?column?
964988
----------

‎contrib/ltree/lquery_op.c

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ ltree_strncasecmp(const char *a, const char *b, size_t s)
9898
returnres;
9999
}
100100

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+
*/
101106
staticbool
102107
checkLevel(lquery_level*curq,ltree_level*curt)
103108
{
@@ -136,42 +141,49 @@ printFieldNot(FieldNot *fn ) {
136141
}
137142
*/
138143

139-
staticstruct
140-
{
141-
boolmuse;
142-
uint32high_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+
*/
149157
staticbool
150-
checkCond(lquery_level*curq,intquery_numlevel,ltree_level*curt,inttree_numlevel,FieldNot*ptr)
158+
checkCond(lquery_level*curq,intquery_numlevel,
159+
ltree_level*curt,inttree_numlevel,
160+
FieldNot*ptr,
161+
uint32high_pos,
162+
boolforce_advance)
151163
{
152-
uint32low_pos=0,
153-
high_pos=0,
154-
cur_tpos=0;
155-
inttlen=tree_numlevel,
164+
uint32low_pos=0,/* first allowed ltree position for match */
165+
cur_tpos=0;/* ltree position of curt */
166+
inttlen=tree_numlevel,/* counts of remaining items */
156167
qlen=query_numlevel;
157-
intisok;
158168
lquery_level*prevq=NULL;
159-
ltree_level*prevt=NULL;
160169

161-
if (SomeStack.muse)
170+
/* advance curq (setting up prevq) if requested */
171+
if (force_advance)
162172
{
163-
high_pos=SomeStack.high_pos;
164-
qlen--;
173+
Assert(qlen>0);
165174
prevq=curq;
166175
curq=LQL_NEXT(curq);
167-
SomeStack.muse= false;
176+
qlen--;
168177
}
169178

170179
while (tlen>0&&qlen>0)
171180
{
172181
if (curq->numvar)
173182
{
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 */
175187
while (cur_tpos<low_pos)
176188
{
177189
curt=LEVEL_NEXT(curt);
@@ -183,8 +195,9 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
183195
ptr->nt++;
184196
}
185197

186-
if (ptr&&curq->flag&LQL_NOT)
198+
if (ptr&&(curq->flag&LQL_NOT))
187199
{
200+
/* Deal with a NOT item */
188201
if (!(prevq&&prevq->numvar==0))
189202
prevq=curq;
190203
if (ptr->q==NULL)
@@ -212,33 +225,42 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
212225
}
213226
else
214227
{
215-
isok= false;
228+
/* Not a NOT item, check for normal match */
229+
boolisok= false;
230+
216231
while (cur_tpos <=high_pos&&tlen>0&& !isok)
217232
{
218233
isok=checkLevel(curq,curt);
219234
curt=LEVEL_NEXT(curt);
220235
tlen--;
221236
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)
223239
{
224240
FieldNottmpptr;
225241

226242
if (ptr)
227243
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))
231249
return true;
232250
}
233-
if (!isok&&ptr)
251+
if (!isok&&ptr&&ptr->q)
234252
ptr->nt++;
235253
}
236254
if (!isok)
237255
return false;
238256

239257
if (ptr&&ptr->q)
240258
{
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))
242264
return false;
243265
ptr->q=NULL;
244266
}
@@ -248,8 +270,14 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
248270
}
249271
else
250272
{
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+
253281
if (ptr&&ptr->q)
254282
{
255283
ptr->nq++;
@@ -263,9 +291,11 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
263291
qlen--;
264292
}
265293

294+
/* Fail if we've already run out of ltree items */
266295
if (low_pos>tree_numlevel||tree_numlevel>high_pos)
267296
return false;
268297

298+
/* Remaining lquery items must be NOT or '*' items */
269299
while (qlen>0)
270300
{
271301
if (curq->numvar)
@@ -275,18 +305,29 @@ checkCond(lquery_level *curq, int query_numlevel, ltree_level *curt, int tree_nu
275305
}
276306
else
277307
{
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);
280314
}
281315

282316
curq=LQL_NEXT(curq);
283317
qlen--;
284318
}
285319

320+
/* Fail if trailing '*'s require more ltree items than we have */
286321
if (low_pos>tree_numlevel||tree_numlevel>high_pos)
287322
return false;
288323

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))
290331
return false;
291332

292333
return true;
@@ -306,12 +347,18 @@ ltq_regex(PG_FUNCTION_ARGS)
306347
fn.q=NULL;
307348

308349
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);
310354
}
311355
else
312356
{
313357
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);
315362
}
316363

317364
PG_FREE_IF_COPY(tree,0);

‎contrib/ltree/ltree.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ typedef struct
3434
{
3535
int32val;
3636
uint16len;
37-
uint8flag;
37+
uint8flag;/* see LVAR_xxx flags below */
3838
charname[FLEXIBLE_ARRAY_MEMBER];
3939
}lquery_variant;
4040

@@ -47,11 +47,12 @@ typedef struct
4747

4848
typedefstruct
4949
{
50-
uint16totallen;
51-
uint16flag;
52-
uint16numvar;
53-
uint16low;
54-
uint16high;
50+
uint16totallen;/* total length of this level, in bytes */
51+
uint16flag;/* see LQL_xxx flags below */
52+
uint16numvar;/* number of variants; 0 means '*' */
53+
uint16low;/* minimum repeat count for '*' */
54+
uint16high;/* maximum repeat count for '*' */
55+
/* Array of maxalign'd lquery_variant structs follows: */
5556
charvariants[FLEXIBLE_ARRAY_MEMBER];
5657
}lquery_level;
5758

@@ -60,6 +61,7 @@ typedef struct
6061
#defineLQL_FIRST(x)( (lquery_variant*)( ((char*)(x))+LQL_HDRSIZE ) )
6162

6263
#defineLQL_NOT0x10
64+
6365
#ifdefLOWER_NODE
6466
#defineFLG_CANLOOKSIGN(x) ( ( (x) & ( LQL_NOT | LVAR_ANYEND | LVAR_SUBLEXEME ) ) == 0 )
6567
#else
@@ -70,9 +72,10 @@ typedef struct
7072
typedefstruct
7173
{
7274
int32vl_len_;/* varlena header (do not touch directly!) */
73-
uint16numlevel;
75+
uint16numlevel;/* number of lquery_levels */
7476
uint16firstgood;
75-
uint16flag;
77+
uint16flag;/* see LQUERY_xxx flags below */
78+
/* Array of maxalign'd lquery_level structs follows: */
7679
chardata[FLEXIBLE_ARRAY_MEMBER];
7780
}lquery;
7881

‎contrib/ltree/sql/ltree.sql

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ SELECT 'a.b.c.d.e'::ltree ~ 'a.!b.*{1}.!c.*';
179179
SELECT'a.b.c.d.e'::ltree ~'!b.*{1}.!c.*';
180180
SELECT'a.b.c.d.e'::ltree ~'*.!b.*{1}.!c.*';
181181
SELECT'a.b.c.d.e'::ltree ~'*.!b.*.!c.*';
182-
182+
SELECT'a.b.c.d.e'::ltree ~'a.*{2}.*{2}';
183+
SELECT'a.b.c.d.e'::ltree ~'a.*{1}.*{2}.e';
184+
SELECT'a.b.c.d.e'::ltree ~'a.*{1}.*{4}';
185+
SELECT'a.b.c.d.e'::ltree ~'a.*{5}.*';
183186

184187
SELECT'QWER_TY'::ltree ~'q%@*';
185188
SELECT'QWER_TY'::ltree ~'Q_t%@*';

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp