Commit 71e1f531 authored by Bruce Momjian's avatar Bruce Momjian

Please apply patches for contrib/ltree.

ltree_73.patch.gz - for 7.3 :
        Fix ~ operation bug: eg '1.1.1' ~ '*.1'

ltree_74.patch.gz - for current CVS
    Fix ~ operation bug: eg '1.1.1' ~ '*.1'
    Add ? operation
    Optimize index storage

Last change needs drop/create all ltree indexes, so only for 7.4

Teodor Sigaev
parent a286f732
......@@ -110,6 +110,9 @@ ltree <@ ltree
equal).
ltree ~ lquery, lquery ~ ltree
- return TRUE if node represented by ltree satisfies lquery.
ltree ? lquery[], lquery ? ltree[]
- return TRUE if node represented by ltree satisfies at least one lquery
from array.
ltree @ ltxtquery, ltxtquery @ ltree
- return TRUE if node represented by ltree satisfies ltxtquery.
ltree || ltree, ltree || text, text || ltree
......@@ -123,6 +126,9 @@ ltree @> ltree[], ltree[] <@ ltree
- returns TRUE if array ltree[] contains a descendant of ltree.
ltree[] ~ lquery, lquery ~ ltree[]
- returns TRUE if array ltree[] contains label paths matched lquery.
ltree[] ? lquery[], lquery[] ? ltree[]
- returns TRUE if array ltree[] contains label paths matched atleaset one
lquery from array.
ltree[] @ ltxtquery, ltxtquery @ ltree[]
- returns TRUE if array ltree[] contains label paths matched ltxtquery
(full text search).
......@@ -142,11 +148,11 @@ Various indices could be created to speed up execution of operations:
* B-tree index over ltree:
<, <=, =, =>, >
* GiST index over ltree:
<, <=, =, =>, >, @>, <@, @, ~
<, <=, =, =>, >, @>, <@, @, ~, ?
Example:
create index path_gist_idx on test using gist (path);
* GiST index over ltree[]:
ltree[]<@ ltree, ltree @> ltree[], @, ~.
ltree[]<@ ltree, ltree @> ltree[], @, ~, ?.
Example:
create index path_gist_idx on test using gist (array_path);
Notices: This index is lossy.
......@@ -426,6 +432,10 @@ appreciate your input. So far, below some (rather obvious) results:
CHANGES
Feb 7, 2003
Add ? operation
Fix ~ operation bug: eg '1.1.1' ~ '*.1'
Optimize index storage
Aug 9, 2002
Fixed very stupid but important bug :-)
July 31, 2002
......
......@@ -96,7 +96,7 @@ _ltree_compress(PG_FUNCTION_ARGS)
entry->rel, entry->page,
entry->offset, key->len, FALSE);
}
else
else if ( !LTG_ISALLTRUE(entry->key) )
{
int4 i,
len;
......@@ -105,10 +105,9 @@ _ltree_compress(PG_FUNCTION_ARGS)
BITVECP sign = LTG_SIGN(DatumGetPointer(entry->key));
ALOOPBYTE(
if (sign[i] != 0xff)
if ((sign[i]&0xff) != 0xff)
PG_RETURN_POINTER(retval);
);
len = LTG_HDRSIZE;
key = (ltree_gist *) palloc(len);
key->len = len;
......@@ -222,7 +221,7 @@ _ltree_penalty(PG_FUNCTION_ARGS)
if (LTG_ISALLTRUE(origval))
{
*penalty = 0.0;
*penalty = 0.1;
PG_RETURN_POINTER(penalty);
}
......@@ -489,7 +488,7 @@ _ltree_picksplit(PG_FUNCTION_ARGS)
);
}
if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.00001))
{
if (!LTG_ISALLTRUE(datum_l))
{
......@@ -613,6 +612,22 @@ gist_qe(ltree_gist * key, lquery * query)
return true;
}
static bool
_arrq_cons(ltree_gist *key, ArrayType *_query) {
lquery *query = (lquery *) ARR_DATA_PTR(_query);
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
if (ARR_NDIM(_query) != 1)
elog(ERROR, "Dimension of array != 1");
while (num > 0) {
if ( gist_qe(key, query) )
return true;
num--;
query = (lquery*)NEXTVAL(query);
}
return false;
}
Datum
_ltree_consistent(PG_FUNCTION_ARGS)
......@@ -641,6 +656,10 @@ _ltree_consistent(PG_FUNCTION_ARGS)
case 15:
res = gist_qtxt(key, (ltxtquery *) query);
break;
case 16:
case 17:
res = _arrq_cons(key, (ArrayType *) query);
break;
default:
elog(ERROR, "Unknown StrategyNumber: %d", strategy);
}
......
......@@ -13,6 +13,8 @@ PG_FUNCTION_INFO_V1(_ltree_risparent);
PG_FUNCTION_INFO_V1(_ltree_r_risparent);
PG_FUNCTION_INFO_V1(_ltq_regex);
PG_FUNCTION_INFO_V1(_ltq_rregex);
PG_FUNCTION_INFO_V1(_lt_q_regex);
PG_FUNCTION_INFO_V1(_lt_q_rregex);
PG_FUNCTION_INFO_V1(_ltxtq_exec);
PG_FUNCTION_INFO_V1(_ltxtq_rexec);
......@@ -126,6 +128,42 @@ _ltq_rregex(PG_FUNCTION_ARGS)
));
}
Datum
_lt_q_regex(PG_FUNCTION_ARGS)
{
ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
lquery *query = (lquery *) ARR_DATA_PTR(_query);
bool res = false;
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
if (ARR_NDIM(_query) != 1)
elog(ERROR, "Dimension of array != 1");
while (num > 0) {
if ( array_iterator(_tree, ltq_regex, (void*)query, NULL) ) {
res = true;
break;
}
num--;
query = (lquery*)NEXTVAL(query);
}
PG_FREE_IF_COPY(_tree, 0);
PG_FREE_IF_COPY(_query, 1);
PG_RETURN_BOOL(res);
}
Datum
_lt_q_rregex(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
));
}
Datum
_ltxtq_exec(PG_FUNCTION_ARGS)
{
......
This diff is collapsed.
......@@ -5,10 +5,16 @@
#include "ltree.h"
#include <ctype.h>
#include "utils/array.h"
PG_FUNCTION_INFO_V1(ltq_regex);
PG_FUNCTION_INFO_V1(ltq_rregex);
PG_FUNCTION_INFO_V1(lt_q_regex);
PG_FUNCTION_INFO_V1(lt_q_rregex);
#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
typedef struct
{
lquery_level *q;
......@@ -39,7 +45,7 @@ getlexem(char *start, char *end, int *len)
}
bool
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
{
char *endt = t->name + t->len;
char *endq = qn + len;
......@@ -117,6 +123,11 @@ printFieldNot(FieldNot *fn ) {
}
*/
static struct {
bool muse;
uint32 high_pos;
} SomeStack = {false,0,};
static bool
checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_numlevel, FieldNot * ptr)
{
......@@ -129,6 +140,14 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
lquery_level *prevq = NULL;
ltree_level *prevt = NULL;
if ( SomeStack.muse ) {
high_pos = SomeStack.high_pos;
qlen--;
prevq = curq;
curq = LQL_NEXT(curq);
SomeStack.muse = false;
}
while (tlen > 0 && qlen > 0)
{
if (curq->numvar)
......@@ -181,6 +200,15 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
curt = LEVEL_NEXT(curt);
tlen--;
cur_tpos++;
if ( isok && prevq && prevq->numvar==0 && tlen>0 && cur_tpos <= high_pos ) {
FieldNot tmpptr;
if ( ptr )
memcpy(&tmpptr,ptr,sizeof(FieldNot));
SomeStack.high_pos = high_pos-cur_tpos;
SomeStack.muse = true;
if ( checkCond(prevq, qlen+1, curt, tlen, (ptr) ? &tmpptr : NULL) )
return true;
}
if (!isok && ptr)
ptr->nt++;
}
......@@ -278,3 +306,42 @@ ltq_rregex(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(0)
));
}
Datum
lt_q_regex(PG_FUNCTION_ARGS)
{
ltree *tree = PG_GETARG_LTREE(0);
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
lquery *query = (lquery *) ARR_DATA_PTR(_query);
bool res = false;
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
if (ARR_NDIM(_query) != 1)
elog(ERROR, "Dimension of array != 1");
while (num > 0) {
if (DatumGetBool(DirectFunctionCall2(ltq_regex,
PointerGetDatum(tree), PointerGetDatum(query)))) {
res = true;
break;
}
num--;
query = NEXTVAL(query);
}
PG_FREE_IF_COPY(tree, 0);
PG_FREE_IF_COPY(_query, 1);
PG_RETURN_BOOL(res);
}
Datum
lt_q_rregex(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(DirectFunctionCall2(lt_q_regex,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
));
}
......@@ -140,10 +140,14 @@ Datum ltree_isparent(PG_FUNCTION_ARGS);
Datum ltree_risparent(PG_FUNCTION_ARGS);
Datum ltq_regex(PG_FUNCTION_ARGS);
Datum ltq_rregex(PG_FUNCTION_ARGS);
Datum lt_q_regex(PG_FUNCTION_ARGS);
Datum lt_q_rregex(PG_FUNCTION_ARGS);
Datum ltxtq_exec(PG_FUNCTION_ARGS);
Datum ltxtq_rexec(PG_FUNCTION_ARGS);
Datum _ltq_regex(PG_FUNCTION_ARGS);
Datum _ltq_rregex(PG_FUNCTION_ARGS);
Datum _lt_q_regex(PG_FUNCTION_ARGS);
Datum _lt_q_rregex(PG_FUNCTION_ARGS);
Datum _ltxtq_exec(PG_FUNCTION_ARGS);
Datum _ltxtq_rexec(PG_FUNCTION_ARGS);
Datum _ltree_isparent(PG_FUNCTION_ARGS);
......@@ -173,7 +177,7 @@ ltree *lca_inner(ltree ** a, int len);
/* GiST support for ltree */
#define BITBYTE 8
#define SIGLENINT 8
#define SIGLENINT 2
#define SIGLEN ( sizeof(int4)*SIGLENINT )
#define SIGLENBIT (SIGLEN*BITBYTE)
typedef unsigned char BITVEC[SIGLEN];
......
......@@ -339,6 +339,53 @@ CREATE OPERATOR ^~ (
JOIN = contjoinsel
);
CREATE FUNCTION lt_q_regex(ltree,_lquery)
RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE 'C' WITH (isstrict,iscachable);
CREATE FUNCTION lt_q_rregex(_lquery,ltree)
RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE 'C' WITH (isstrict,iscachable);
CREATE OPERATOR ? (
LEFTARG = ltree,
RIGHTARG = _lquery,
PROCEDURE = lt_q_regex,
COMMUTATOR = '?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR ? (
LEFTARG = _lquery,
RIGHTARG = ltree,
PROCEDURE = lt_q_rregex,
COMMUTATOR = '?',
RESTRICT = contsel,
JOIN = contjoinsel
);
--not-indexed
CREATE OPERATOR ^? (
LEFTARG = ltree,
RIGHTARG = _lquery,
PROCEDURE = lt_q_regex,
COMMUTATOR = '^?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR ^? (
LEFTARG = _lquery,
RIGHTARG = ltree,
PROCEDURE = lt_q_rregex,
COMMUTATOR = '^?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE FUNCTION ltxtq_in(cstring)
RETURNS ltxtquery
AS 'MODULE_PATHNAME'
......@@ -452,6 +499,8 @@ CREATE OPERATOR CLASS gist_ltree_ops
OPERATOR 13 ~ (lquery, ltree) ,
OPERATOR 14 @ (ltree, ltxtquery) ,
OPERATOR 15 @ (ltxtquery, ltree) ,
OPERATOR 16 ? (ltree, _lquery) ,
OPERATOR 17 ? (_lquery, ltree) ,
FUNCTION 1 ltree_consistent (internal, internal, int2),
FUNCTION 2 ltree_union (bytea, internal),
FUNCTION 3 ltree_compress (internal),
......@@ -494,6 +543,16 @@ RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE 'C' WITH (isstrict,iscachable);
CREATE FUNCTION _lt_q_regex(_ltree,_lquery)
RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE 'C' WITH (isstrict,iscachable);
CREATE FUNCTION _lt_q_rregex(_lquery,_ltree)
RETURNS bool
AS 'MODULE_PATHNAME'
LANGUAGE 'C' WITH (isstrict,iscachable);
CREATE FUNCTION _ltxtq_exec(_ltree, ltxtquery)
RETURNS bool
AS 'MODULE_PATHNAME'
......@@ -558,6 +617,24 @@ CREATE OPERATOR ~ (
JOIN = contjoinsel
);
CREATE OPERATOR ? (
LEFTARG = _ltree,
RIGHTARG = _lquery,
PROCEDURE = _lt_q_regex,
COMMUTATOR = '?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR ? (
LEFTARG = _lquery,
RIGHTARG = _ltree,
PROCEDURE = _lt_q_rregex,
COMMUTATOR = '?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR @ (
LEFTARG = _ltree,
RIGHTARG = ltxtquery,
......@@ -632,6 +709,24 @@ CREATE OPERATOR ^~ (
JOIN = contjoinsel
);
CREATE OPERATOR ^? (
LEFTARG = _ltree,
RIGHTARG = _lquery,
PROCEDURE = _lt_q_regex,
COMMUTATOR = '^?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR ^? (
LEFTARG = _lquery,
RIGHTARG = _ltree,
PROCEDURE = _lt_q_rregex,
COMMUTATOR = '^?',
RESTRICT = contsel,
JOIN = contjoinsel
);
CREATE OPERATOR ^@ (
LEFTARG = _ltree,
RIGHTARG = ltxtquery,
......@@ -729,6 +824,8 @@ CREATE OPERATOR CLASS gist__ltree_ops
OPERATOR 13 ~ (lquery, _ltree) RECHECK ,
OPERATOR 14 @ (_ltree, ltxtquery) RECHECK ,
OPERATOR 15 @ (ltxtquery, _ltree) RECHECK ,
OPERATOR 16 ? (_ltree, _lquery) RECHECK ,
OPERATOR 17 ? (_lquery, _ltree) RECHECK ,
FUNCTION 1 _ltree_consistent (internal, internal, int2),
FUNCTION 2 _ltree_union (bytea, internal),
FUNCTION 3 _ltree_compress (internal),
......
......@@ -7,9 +7,11 @@
#include "access/gist.h"
#include "access/rtree.h"
#include "access/nbtree.h"
#include "utils/array.h"
#include "crc32.h"
#define NEXTVAL(x) ( (lquery*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
PG_FUNCTION_INFO_V1(ltree_gist_in);
Datum ltree_gist_in(PG_FUNCTION_ARGS);
......@@ -596,6 +598,22 @@ gist_qtxt(ltree_gist * key, ltxtquery * query)
);
}
static bool
arrq_cons(ltree_gist *key, ArrayType *_query) {
lquery *query = (lquery *) ARR_DATA_PTR(_query);
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
if (ARR_NDIM(_query) != 1)
elog(ERROR, "Dimension of array != 1");
while (num > 0) {
if ( gist_qe(key, query) && gist_between(key, query) )
return true;
num--;
query = NEXTVAL(query);
}
return false;
}
Datum
ltree_consistent(PG_FUNCTION_ARGS)
......@@ -672,6 +690,16 @@ ltree_consistent(PG_FUNCTION_ARGS)
else
res = gist_qtxt(key, (ltxtquery *) query);
break;
case 16:
case 17:
if (GIST_LEAF(entry))
res = DatumGetBool(DirectFunctionCall2(lt_q_regex,
PointerGetDatum(LTG_NODE(key)),
PointerGetDatum((ArrayType *) query)
));
else
res = arrq_cons(key, (ArrayType *) query);
break;
default:
elog(ERROR, "Unknown StrategyNumber: %d", strategy);
}
......
......@@ -139,6 +139,7 @@ SELECT 'a.b.c.d.e'::ltree ~ '!b.*{1}.!c.*';
SELECT 'a.b.c.d.e'::ltree ~ '*.!b.*{1}.!c.*';
SELECT 'a.b.c.d.e'::ltree ~ '*.!b.*.!c.*';
SELECT 'QWER_TY'::ltree ~ 'q%@*';
SELECT 'QWER_TY'::ltree ~ 'Q_t%@*';
SELECT 'QWER_GY'::ltree ~ 'q_t%@*';
......@@ -175,6 +176,11 @@ SELECT '{1.2.3.4.5, 7.12.asd}'::ltree[] @> '1.2.3.4';
SELECT '{1.3.3, 7.12.asd}'::ltree[] @> '1.2.3.4';
SELECT '{ltree.asd, tree.awdfg}'::ltree[] @ 'tree & aWdfg@'::ltxtquery;
SELECT '{j.k.l.m, g.b.c.d.e}'::ltree[] ~ 'A*@|g.b.c.d.e';
SELECT 'a.b.c.d.e'::ltree ? '{A.b.c.d.e}';
SELECT 'a.b.c.d.e'::ltree ? '{a.b.c.d.e}';
SELECT 'a.b.c.d.e'::ltree ? '{A.b.c.d.e, a.*}';
SELECT '{a.b.c.d.e,B.df}'::ltree[] ? '{A.b.c.d.e}';
SELECT '{a.b.c.d.e,B.df}'::ltree[] ? '{A.b.c.d.e,*.df}';
--exractors
SELECT ('{3456,1.2.3.34}'::ltree[] ?@> '1.2.3.4') is null;
......@@ -194,11 +200,13 @@ SELECT * FROM ltreetest WHERE t >= '12.3' order by t asc;
SELECT * FROM ltreetest WHERE t > '12.3' order by t asc;
SELECT * FROM ltreetest WHERE t @> '1.1.1' order by t asc;
SELECT * FROM ltreetest WHERE t <@ '1.1.1' order by t asc;
SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '1.1.1.*' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc;
SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
create unique index tstidx on ltreetest (t);
set enable_seqscan=off;
......@@ -220,31 +228,37 @@ SELECT * FROM ltreetest WHERE t >= '12.3' order by t asc;
SELECT * FROM ltreetest WHERE t > '12.3' order by t asc;
SELECT * FROM ltreetest WHERE t @> '1.1.1' order by t asc;
SELECT * FROM ltreetest WHERE t <@ '1.1.1' order by t asc;
SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '1.1.1.*' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '*.1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*{1}.1' order by t asc;
SELECT * FROM ltreetest WHERE t @ '23 & 1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*.1' order by t asc;
SELECT * FROM ltreetest WHERE t ~ '23.*.2' order by t asc;
SELECT * FROM ltreetest WHERE t ? '{23.*.1,23.*.2}' order by t asc;
create table _ltreetest (t ltree[]);
\copy _ltreetest FROM 'data/_ltree.data'
SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ;
SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ;
SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ;
SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
create index _tstidx on _ltreetest using gist (t);
set enable_seqscan=off;
SELECT count(*) FROM _ltreetest WHERE t @> '1.1.1' ;
SELECT count(*) FROM _ltreetest WHERE t <@ '1.1.1' ;
SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '1.1.1.*' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '*.1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*{1}.1' ;
SELECT count(*) FROM _ltreetest WHERE t @ '23 & 1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.1' ;
SELECT count(*) FROM _ltreetest WHERE t ~ '23.*.2' ;
SELECT count(*) FROM _ltreetest WHERE t ? '{23.*.1,23.*.2}' ;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment