Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b1665bf

Browse files
committed
Allow hyphens in ltree labels
Also increase the allowed length of labels to 1000 characters Garen Torikian Discussion: https://postgr.es/m/CAGXsc+-mNg9Gc0rp-ER0sv+zkZSZp2wE9-LX6XcoWSLVz22tZA@mail.gmail.com
1 parent a46a701 commit b1665bf

File tree

6 files changed

+60
-38
lines changed

6 files changed

+60
-38
lines changed

contrib/ltree/expected/ltree.out

+32-18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
CREATE EXTENSION ltree;
2+
-- max length for a label
3+
\set maxlbl 1000
24
-- Check whether any of our opclasses fail amvalidate
35
SELECT amname, opcname
46
FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod
@@ -25,6 +27,12 @@ SELECT '1.2'::ltree;
2527
1.2
2628
(1 row)
2729

30+
SELECT '1.2.-3'::ltree;
31+
ltree
32+
--------
33+
1.2.-3
34+
(1 row)
35+
2836
SELECT '1.2._3'::ltree;
2937
ltree
3038
--------
@@ -45,15 +53,15 @@ ERROR: ltree syntax error
4553
LINE 1: SELECT '1.2.'::ltree;
4654
^
4755
DETAIL: Unexpected end of input.
48-
SELECT repeat('x', 255)::ltree;
49-
repeat
50-
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
51-
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
56+
SELECT repeat('x', :maxlbl)::ltree;
57+
repeat
58+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
59+
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
5260
(1 row)
5361

54-
SELECT repeat('x', 256)::ltree;
62+
SELECT repeat('x', :maxlbl + 1)::ltree;
5563
ERROR: label string is too long
56-
DETAIL: Label length is 256, must be at most 255, at character 257.
64+
DETAIL: Label length is 1001, must be at most 1000, at character 1002.
5765
SELECT ltree2text('1.2.3.34.sdf');
5866
ltree2text
5967
--------------
@@ -531,24 +539,24 @@ SELECT '1.2.3|@.4'::lquery;
531539
ERROR: lquery syntax error at character 7
532540
LINE 1: SELECT '1.2.3|@.4'::lquery;
533541
^
534-
SELECT (repeat('x', 255) || '*@@*')::lquery;
535-
lquery
536-
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
537-
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@*
542+
SELECT (repeat('x', :maxlbl) || '*@@*')::lquery;
543+
lquery
544+
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
545+
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@*
538546
(1 row)
539547

540-
SELECT (repeat('x', 256) || '*@@*')::lquery;
548+
SELECT (repeat('x', :maxlbl + 1) || '*@@*')::lquery;
541549
ERROR: label string is too long
542-
DETAIL: Label length is 256, must be at most 255, at character 257.
543-
SELECT ('!' || repeat('x', 255))::lquery;
544-
lquery
545-
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
546-
!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
550+
DETAIL: Label length is 1001, must be at most 1000, at character 1002.
551+
SELECT ('!' || repeat('x', :maxlbl))::lquery;
552+
lquery
553+
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
554+
!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
547555
(1 row)
548556

549-
SELECT ('!' || repeat('x', 256))::lquery;
557+
SELECT ('!' || repeat('x', :maxlbl + 1))::lquery;
550558
ERROR: label string is too long
551-
DETAIL: Label length is 256, must be at most 255, at character 258.
559+
DETAIL: Label length is 1001, must be at most 1000, at character 1003.
552560
SELECT nlevel('1.2.3.4');
553561
nlevel
554562
--------
@@ -1195,6 +1203,12 @@ SELECT 'tree & aw_qw%*'::ltxtquery;
11951203
tree & aw_qw%*
11961204
(1 row)
11971205

1206+
SELECT 'tree & aw-qw%*'::ltxtquery;
1207+
ltxtquery
1208+
----------------
1209+
tree & aw-qw%*
1210+
(1 row)
1211+
11981212
SELECT 'ltree.awdfg'::ltree @ '!tree & aWdf@*'::ltxtquery;
11991213
?column?
12001214
----------

contrib/ltree/ltree.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212

1313
/*
1414
* We want the maximum length of a label to be encoding-independent, so
15-
* set it somewhat arbitrarily at 255 characters (not bytes), while using
15+
* set it somewhat arbitrarily at 1000 characters (not bytes), while using
1616
* uint16 fields to hold the byte length.
1717
*/
18-
#define LTREE_LABEL_MAX_CHARS 255
18+
#define LTREE_LABEL_MAX_CHARS 1000
1919

2020
/*
2121
* LOWER_NODE used to be defined in the Makefile via the compile flags.
@@ -126,7 +126,8 @@ typedef struct
126126

127127
#define LQUERY_HASNOT 0x01
128128

129-
#define ISALNUM(x) ( t_isalnum(x) || t_iseq(x, '_') )
129+
/* valid label chars are alphanumerics, underscores and hyphens */
130+
#define ISLABEL(x) ( t_isalnum(x) || t_iseq(x, '_') || t_iseq(x, '-') )
130131

131132
/* full text query */
132133

contrib/ltree/ltree_io.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ parse_ltree(const char *buf, struct Node *escontext)
7474
switch (state)
7575
{
7676
case LTPRS_WAITNAME:
77-
if (ISALNUM(ptr))
77+
if (ISLABEL(ptr))
7878
{
7979
lptr->start = ptr;
8080
lptr->wlen = 0;
@@ -92,7 +92,7 @@ parse_ltree(const char *buf, struct Node *escontext)
9292
lptr++;
9393
state = LTPRS_WAITNAME;
9494
}
95-
else if (!ISALNUM(ptr))
95+
else if (!ISLABEL(ptr))
9696
UNCHAR;
9797
break;
9898
default:
@@ -316,7 +316,7 @@ parse_lquery(const char *buf, struct Node *escontext)
316316
switch (state)
317317
{
318318
case LQPRS_WAITLEVEL:
319-
if (ISALNUM(ptr))
319+
if (ISLABEL(ptr))
320320
{
321321
GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
322322
lptr->start = ptr;
@@ -339,7 +339,7 @@ parse_lquery(const char *buf, struct Node *escontext)
339339
UNCHAR;
340340
break;
341341
case LQPRS_WAITVAR:
342-
if (ISALNUM(ptr))
342+
if (ISLABEL(ptr))
343343
{
344344
lptr++;
345345
lptr->start = ptr;
@@ -385,7 +385,7 @@ parse_lquery(const char *buf, struct Node *escontext)
385385
state = LQPRS_WAITLEVEL;
386386
curqlevel = NEXTLEV(curqlevel);
387387
}
388-
else if (ISALNUM(ptr))
388+
else if (ISLABEL(ptr))
389389
{
390390
/* disallow more chars after a flag */
391391
if (lptr->flag)

contrib/ltree/ltxtquery_io.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint
8080
(state->buf)++;
8181
return OPEN;
8282
}
83-
else if (ISALNUM(state->buf))
83+
else if (ISLABEL(state->buf))
8484
{
8585
state->state = INOPERAND;
8686
*strval = state->buf;
@@ -93,7 +93,7 @@ gettoken_query(QPRS_STATE *state, int32 *val, int32 *lenval, char **strval, uint
9393
errmsg("operand syntax error")));
9494
break;
9595
case INOPERAND:
96-
if (ISALNUM(state->buf))
96+
if (ISLABEL(state->buf))
9797
{
9898
if (*flag)
9999
ereturn(state->escontext, ERR,

contrib/ltree/sql/ltree.sql

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
CREATE EXTENSION ltree;
22

3+
-- max length for a label
4+
\set maxlbl 1000
5+
36
-- Check whether any of our opclasses fail amvalidate
47
SELECT amname, opcname
58
FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod
@@ -8,15 +11,16 @@ WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid);
811
SELECT ''::ltree;
912
SELECT '1'::ltree;
1013
SELECT '1.2'::ltree;
14+
SELECT '1.2.-3'::ltree;
1115
SELECT '1.2._3'::ltree;
1216

1317
-- empty labels not allowed
1418
SELECT '.2.3'::ltree;
1519
SELECT '1..3'::ltree;
1620
SELECT '1.2.'::ltree;
1721

18-
SELECT repeat('x', 255)::ltree;
19-
SELECT repeat('x', 256)::ltree;
22+
SELECT repeat('x', :maxlbl)::ltree;
23+
SELECT repeat('x', :maxlbl + 1)::ltree;
2024

2125
SELECT ltree2text('1.2.3.34.sdf');
2226
SELECT text2ltree('1.2.3.34.sdf');
@@ -111,10 +115,10 @@ SELECT '1.!.3'::lquery;
111115
SELECT '1.2.!'::lquery;
112116
SELECT '1.2.3|@.4'::lquery;
113117

114-
SELECT (repeat('x', 255) || '*@@*')::lquery;
115-
SELECT (repeat('x', 256) || '*@@*')::lquery;
116-
SELECT ('!' || repeat('x', 255))::lquery;
117-
SELECT ('!' || repeat('x', 256))::lquery;
118+
SELECT (repeat('x', :maxlbl) || '*@@*')::lquery;
119+
SELECT (repeat('x', :maxlbl + 1) || '*@@*')::lquery;
120+
SELECT ('!' || repeat('x', :maxlbl))::lquery;
121+
SELECT ('!' || repeat('x', :maxlbl + 1))::lquery;
118122

119123
SELECT nlevel('1.2.3.4');
120124
SELECT nlevel(('1' || repeat('.1', 65534))::ltree);
@@ -233,6 +237,8 @@ SELECT 'QWER_GY'::ltree ~ 'q_t%@*';
233237
--ltxtquery
234238
SELECT '!tree & aWdf@*'::ltxtquery;
235239
SELECT 'tree & aw_qw%*'::ltxtquery;
240+
SELECT 'tree & aw-qw%*'::ltxtquery;
241+
236242
SELECT 'ltree.awdfg'::ltree @ '!tree & aWdf@*'::ltxtquery;
237243
SELECT 'tree.awdfg'::ltree @ '!tree & aWdf@*'::ltxtquery;
238244
SELECT 'tree.awdfg'::ltree @ '!tree | aWdf@*'::ltxtquery;

doc/src/sgml/ltree.sgml

+5-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@
2323
<title>Definitions</title>
2424

2525
<para>
26-
A <firstterm>label</firstterm> is a sequence of alphanumeric characters
27-
and underscores (for example, in C locale the characters
28-
<literal>A-Za-z0-9_</literal> are allowed).
29-
Labels must be less than 256 characters long.
26+
A <firstterm>label</firstterm> is a sequence of alphanumeric characters,
27+
underscores, and hyphens. Valid alphanumeric character ranges are
28+
dependent on the database locale. For example, in C locale, the characters
29+
<literal>A-Za-z0-9_-</literal> are allowed.
30+
Labels must be no more than 1000 characters long.
3031
</para>
3132

3233
<para>

0 commit comments

Comments
 (0)