0001-Implements-ltree-lquery-and-ltxtquery-binary-protoco.patch
application/octet-stream
Filename: 0001-Implements-ltree-lquery-and-ltxtquery-binary-protoco.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: Implements ltree, lquery, and ltxtquery binary protocol support
| File | + | − |
|---|---|---|
| contrib/ltree/crc32.c | 1 | 1 |
| contrib/ltree/crc32.h | 1 | 1 |
| contrib/ltree/ltree--1.2.sql | 907 | 0 |
| contrib/ltree/ltree.control | 1 | 1 |
| contrib/ltree/ltree_io.c | 698 | 547 |
| contrib/ltree/ltxtquery_io.c | 71 | 4 |
| contrib/ltree/Makefile | 1 | 1 |
From 8f43d2e60bf2a91bc326a50ceb0675ad7e476557 Mon Sep 17 00:00:00 2001
From: Nino Floris <mail@ninofloris.com>
Date: Sun, 18 Aug 2019 16:30:30 +0200
Subject: [PATCH] Implements ltree, lquery, and ltxtquery binary protocol
support
---
contrib/ltree/Makefile | 2 +-
contrib/ltree/crc32.c | 2 +-
contrib/ltree/crc32.h | 2 +-
contrib/ltree/ltree--1.2.sql | 907 +++++++++++++++++++++++++
contrib/ltree/ltree.control | 2 +-
contrib/ltree/ltree_io.c | 1245 +++++++++++++++++++---------------
contrib/ltree/ltxtquery_io.c | 75 +-
7 files changed, 1680 insertions(+), 555 deletions(-)
create mode 100644 contrib/ltree/ltree--1.2.sql
diff --git a/contrib/ltree/Makefile b/contrib/ltree/Makefile
index 416c8da312..2a17593212 100644
--- a/contrib/ltree/Makefile
+++ b/contrib/ltree/Makefile
@@ -6,7 +6,7 @@ OBJS = ltree_io.o ltree_op.o lquery_op.o _ltree_op.o crc32.o \
PG_CPPFLAGS = -DLOWER_NODE
EXTENSION = ltree
-DATA = ltree--1.1.sql ltree--1.0--1.1.sql ltree--unpackaged--1.0.sql
+DATA = ltree--1.2.sql ltree--1.1.sql ltree--1.0--1.1.sql ltree--unpackaged--1.0.sql
PGFILEDESC = "ltree - hierarchical label data type"
HEADERS = ltree.h
diff --git a/contrib/ltree/crc32.c b/contrib/ltree/crc32.c
index 447e4b2960..62939463a0 100644
--- a/contrib/ltree/crc32.c
+++ b/contrib/ltree/crc32.c
@@ -20,7 +20,7 @@
#include "crc32.h"
unsigned int
-ltree_crc32_sz(char *buf, int size)
+ltree_crc32_sz(const char *buf, int size)
{
pg_crc32 crc;
char *p = buf;
diff --git a/contrib/ltree/crc32.h b/contrib/ltree/crc32.h
index 269d05d0c1..958812214d 100644
--- a/contrib/ltree/crc32.h
+++ b/contrib/ltree/crc32.h
@@ -4,7 +4,7 @@
/* contrib/ltree/crc32.h */
/* Returns crc32 of data block */
-extern unsigned int ltree_crc32_sz(char *buf, int size);
+extern unsigned int ltree_crc32_sz(const char *buf, int size);
/* Returns crc32 of null-terminated string */
#define crc32(buf) ltree_crc32_sz((buf),strlen(buf))
diff --git a/contrib/ltree/ltree--1.2.sql b/contrib/ltree/ltree--1.2.sql
new file mode 100644
index 0000000000..ab762597e4
--- /dev/null
+++ b/contrib/ltree/ltree--1.2.sql
@@ -0,0 +1,907 @@
+/* contrib/ltree/ltree--1.2.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION ltree" to load this file. \quit
+
+CREATE FUNCTION ltree_in(cstring)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_out(ltree)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_recv(internal)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_send(ltree)
+RETURNS bytea
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE TYPE ltree (
+ INTERNALLENGTH = -1,
+ INPUT = ltree_in,
+ OUTPUT = ltree_out,
+ RECEIVE = ltree_recv,
+ SEND = ltree_send,
+ STORAGE = extended
+);
+
+--Compare function for ltree
+CREATE FUNCTION ltree_cmp(ltree,ltree)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_lt(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_le(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_eq(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_ge(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_gt(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_ne(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+
+CREATE OPERATOR < (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_lt,
+ COMMUTATOR = '>',
+ NEGATOR = '>=',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR <= (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_le,
+ COMMUTATOR = '>=',
+ NEGATOR = '>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR >= (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_ge,
+ COMMUTATOR = '<=',
+ NEGATOR = '<',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR > (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_gt,
+ COMMUTATOR = '<',
+ NEGATOR = '<=',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR = (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_eq,
+ COMMUTATOR = '=',
+ NEGATOR = '<>',
+ RESTRICT = eqsel,
+ JOIN = eqjoinsel,
+ SORT1 = '<',
+ SORT2 = '<'
+);
+
+CREATE OPERATOR <> (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_ne,
+ COMMUTATOR = '<>',
+ NEGATOR = '=',
+ RESTRICT = neqsel,
+ JOIN = neqjoinsel
+);
+
+--util functions
+
+CREATE FUNCTION subltree(ltree,int4,int4)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION subpath(ltree,int4,int4)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION subpath(ltree,int4)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION index(ltree,ltree)
+RETURNS int4
+AS 'MODULE_PATHNAME', 'ltree_index'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION index(ltree,ltree,int4)
+RETURNS int4
+AS 'MODULE_PATHNAME', 'ltree_index'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION nlevel(ltree)
+RETURNS int4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree2text(ltree)
+RETURNS text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION text2ltree(text)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(_ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME','_lca'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree,ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree,ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lca(ltree,ltree,ltree,ltree,ltree,ltree,ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_isparent(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_risparent(ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_addltree(ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_addtext(ltree,text)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_textadd(text,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltreeparentsel(internal, oid, internal, integer)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR @> (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_isparent,
+ COMMUTATOR = '<@',
+ RESTRICT = ltreeparentsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^@> (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_isparent,
+ COMMUTATOR = '^<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR <@ (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_risparent,
+ COMMUTATOR = '@>',
+ RESTRICT = ltreeparentsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^<@ (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_risparent,
+ COMMUTATOR = '^@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR || (
+ LEFTARG = ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_addltree
+);
+
+CREATE OPERATOR || (
+ LEFTARG = ltree,
+ RIGHTARG = text,
+ PROCEDURE = ltree_addtext
+);
+
+CREATE OPERATOR || (
+ LEFTARG = text,
+ RIGHTARG = ltree,
+ PROCEDURE = ltree_textadd
+);
+
+
+-- B-tree support
+
+CREATE OPERATOR CLASS ltree_ops
+ DEFAULT FOR TYPE ltree USING btree AS
+ OPERATOR 1 < ,
+ OPERATOR 2 <= ,
+ OPERATOR 3 = ,
+ OPERATOR 4 >= ,
+ OPERATOR 5 > ,
+ FUNCTION 1 ltree_cmp(ltree, ltree);
+
+
+--lquery type
+CREATE FUNCTION lquery_in(cstring)
+RETURNS lquery
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lquery_out(lquery)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lquery_recv(internal)
+RETURNS lquery
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lquery_send(lquery)
+RETURNS bytea
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE TYPE lquery (
+ INTERNALLENGTH = -1,
+ INPUT = lquery_in,
+ OUTPUT = lquery_out,
+ RECEIVE = lquery_recv,
+ SEND = lquery_send,
+ STORAGE = extended
+);
+
+CREATE FUNCTION ltq_regex(ltree,lquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltq_rregex(lquery,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR ~ (
+ LEFTARG = ltree,
+ RIGHTARG = lquery,
+ PROCEDURE = ltq_regex,
+ COMMUTATOR = '~',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~ (
+ LEFTARG = lquery,
+ RIGHTARG = ltree,
+ PROCEDURE = ltq_rregex,
+ COMMUTATOR = '~',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+--not-indexed
+CREATE OPERATOR ^~ (
+ LEFTARG = ltree,
+ RIGHTARG = lquery,
+ PROCEDURE = ltq_regex,
+ COMMUTATOR = '^~',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^~ (
+ LEFTARG = lquery,
+ RIGHTARG = ltree,
+ PROCEDURE = ltq_rregex,
+ COMMUTATOR = '^~',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE FUNCTION lt_q_regex(ltree,_lquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION lt_q_rregex(_lquery,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+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'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltxtq_out(ltxtquery)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltxtq_recv(internal)
+RETURNS ltxtquery
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltxtq_send(ltxtquery)
+RETURNS bytea
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE TYPE ltxtquery (
+ INTERNALLENGTH = -1,
+ INPUT = ltxtq_in,
+ OUTPUT = ltxtq_out,
+ RECEIVE = ltxtq_recv,
+ SEND = ltxtq_send,
+ STORAGE = extended
+);
+
+-- operations WITH ltxtquery
+
+CREATE FUNCTION ltxtq_exec(ltree, ltxtquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltxtq_rexec(ltxtquery, ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR @ (
+ LEFTARG = ltree,
+ RIGHTARG = ltxtquery,
+ PROCEDURE = ltxtq_exec,
+ COMMUTATOR = '@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR @ (
+ LEFTARG = ltxtquery,
+ RIGHTARG = ltree,
+ PROCEDURE = ltxtq_rexec,
+ COMMUTATOR = '@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+--not-indexed
+CREATE OPERATOR ^@ (
+ LEFTARG = ltree,
+ RIGHTARG = ltxtquery,
+ PROCEDURE = ltxtq_exec,
+ COMMUTATOR = '^@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^@ (
+ LEFTARG = ltxtquery,
+ RIGHTARG = ltree,
+ PROCEDURE = ltxtq_rexec,
+ COMMUTATOR = '^@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+--GiST support for ltree
+CREATE FUNCTION ltree_gist_in(cstring)
+RETURNS ltree_gist
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION ltree_gist_out(ltree_gist)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE TYPE ltree_gist (
+ internallength = -1,
+ input = ltree_gist_in,
+ output = ltree_gist_out,
+ storage = plain
+);
+
+
+CREATE FUNCTION ltree_consistent(internal,ltree,int2,oid,internal)
+RETURNS bool as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION ltree_compress(internal)
+RETURNS internal as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION ltree_decompress(internal)
+RETURNS internal as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION ltree_penalty(internal,internal,internal)
+RETURNS internal as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION ltree_picksplit(internal, internal)
+RETURNS internal as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION ltree_union(internal, internal)
+RETURNS ltree_gist as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION ltree_same(ltree_gist, ltree_gist, internal)
+RETURNS internal as 'MODULE_PATHNAME' LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE OPERATOR CLASS gist_ltree_ops
+ DEFAULT FOR TYPE ltree USING gist AS
+ OPERATOR 1 < ,
+ OPERATOR 2 <= ,
+ OPERATOR 3 = ,
+ OPERATOR 4 >= ,
+ OPERATOR 5 > ,
+ OPERATOR 10 @> ,
+ OPERATOR 11 <@ ,
+ OPERATOR 12 ~ (ltree, lquery) ,
+ 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, ltree, int2, oid, internal),
+ FUNCTION 2 ltree_union (internal, internal),
+ FUNCTION 3 ltree_compress (internal),
+ FUNCTION 4 ltree_decompress (internal),
+ FUNCTION 5 ltree_penalty (internal, internal, internal),
+ FUNCTION 6 ltree_picksplit (internal, internal),
+ FUNCTION 7 ltree_same (ltree_gist, ltree_gist, internal),
+ STORAGE ltree_gist;
+
+
+-- arrays of ltree
+
+CREATE FUNCTION _ltree_isparent(_ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_r_isparent(ltree,_ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_risparent(_ltree,ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_r_risparent(ltree,_ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltq_regex(_ltree,lquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltq_rregex(lquery,_ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _lt_q_regex(_ltree,_lquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _lt_q_rregex(_lquery,_ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltxtq_exec(_ltree, ltxtquery)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION _ltxtq_rexec(ltxtquery, _ltree)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR @> (
+ LEFTARG = _ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = _ltree_isparent,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR <@ (
+ LEFTARG = ltree,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltree_r_isparent,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR <@ (
+ LEFTARG = _ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = _ltree_risparent,
+ COMMUTATOR = '@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR @> (
+ LEFTARG = ltree,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltree_r_risparent,
+ COMMUTATOR = '<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~ (
+ LEFTARG = _ltree,
+ RIGHTARG = lquery,
+ PROCEDURE = _ltq_regex,
+ COMMUTATOR = '~',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ~ (
+ LEFTARG = lquery,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltq_rregex,
+ COMMUTATOR = '~',
+ RESTRICT = contsel,
+ 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,
+ PROCEDURE = _ltxtq_exec,
+ COMMUTATOR = '@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR @ (
+ LEFTARG = ltxtquery,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltxtq_rexec,
+ COMMUTATOR = '@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+
+--not indexed
+CREATE OPERATOR ^@> (
+ LEFTARG = _ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = _ltree_isparent,
+ COMMUTATOR = '^<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^<@ (
+ LEFTARG = ltree,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltree_r_isparent,
+ COMMUTATOR = '^@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^<@ (
+ LEFTARG = _ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = _ltree_risparent,
+ COMMUTATOR = '^@>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^@> (
+ LEFTARG = ltree,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltree_r_risparent,
+ COMMUTATOR = '^<@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^~ (
+ LEFTARG = _ltree,
+ RIGHTARG = lquery,
+ PROCEDURE = _ltq_regex,
+ COMMUTATOR = '^~',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^~ (
+ LEFTARG = lquery,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltq_rregex,
+ COMMUTATOR = '^~',
+ RESTRICT = contsel,
+ 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,
+ PROCEDURE = _ltxtq_exec,
+ COMMUTATOR = '^@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR ^@ (
+ LEFTARG = ltxtquery,
+ RIGHTARG = _ltree,
+ PROCEDURE = _ltxtq_rexec,
+ COMMUTATOR = '^@',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+--extractors
+CREATE FUNCTION _ltree_extract_isparent(_ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR ?@> (
+ LEFTARG = _ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = _ltree_extract_isparent
+);
+
+CREATE FUNCTION _ltree_extract_risparent(_ltree,ltree)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR ?<@ (
+ LEFTARG = _ltree,
+ RIGHTARG = ltree,
+ PROCEDURE = _ltree_extract_risparent
+);
+
+CREATE FUNCTION _ltq_extract_regex(_ltree,lquery)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR ?~ (
+ LEFTARG = _ltree,
+ RIGHTARG = lquery,
+ PROCEDURE = _ltq_extract_regex
+);
+
+CREATE FUNCTION _ltxtq_extract_exec(_ltree,ltxtquery)
+RETURNS ltree
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR ?@ (
+ LEFTARG = _ltree,
+ RIGHTARG = ltxtquery,
+ PROCEDURE = _ltxtq_extract_exec
+);
+
+--GiST support for ltree[]
+CREATE FUNCTION _ltree_consistent(internal,_ltree,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_union(internal, internal)
+RETURNS ltree_gist
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION _ltree_same(ltree_gist, ltree_gist, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE OPERATOR CLASS gist__ltree_ops
+ DEFAULT FOR TYPE _ltree USING gist AS
+ OPERATOR 10 <@ (_ltree, ltree),
+ OPERATOR 11 @> (ltree, _ltree),
+ OPERATOR 12 ~ (_ltree, lquery),
+ 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, _ltree, int2, oid, internal),
+ FUNCTION 2 _ltree_union (internal, internal),
+ FUNCTION 3 _ltree_compress (internal),
+ FUNCTION 4 ltree_decompress (internal),
+ FUNCTION 5 _ltree_penalty (internal, internal, internal),
+ FUNCTION 6 _ltree_picksplit (internal, internal),
+ FUNCTION 7 _ltree_same (ltree_gist, ltree_gist, internal),
+ STORAGE ltree_gist;
diff --git a/contrib/ltree/ltree.control b/contrib/ltree/ltree.control
index 03c3fb1ab5..61c8cdf40a 100644
--- a/contrib/ltree/ltree.control
+++ b/contrib/ltree/ltree.control
@@ -1,5 +1,5 @@
# ltree extension
comment = 'data type for hierarchical tree-like structures'
-default_version = '1.1'
+default_version = '1.2'
module_pathname = '$libdir/ltree'
relocatable = true
diff --git a/contrib/ltree/ltree_io.c b/contrib/ltree/ltree_io.c
index f54f037443..2ecfbdd23a 100644
--- a/contrib/ltree/ltree_io.c
+++ b/contrib/ltree/ltree_io.c
@@ -4,28 +4,23 @@
* contrib/ltree/ltree_io.c
*/
#include "postgres.h"
+#include "libpq/pqformat.h"
#include <ctype.h>
#include "ltree.h"
#include "utils/memutils.h"
+#include "utils/builtins.h"
#include "crc32.h"
-PG_FUNCTION_INFO_V1(ltree_in);
-PG_FUNCTION_INFO_V1(ltree_out);
-PG_FUNCTION_INFO_V1(lquery_in);
-PG_FUNCTION_INFO_V1(lquery_out);
-
-
#define UNCHAR ereport(ERROR, \
(errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("syntax error at position %d", \
pos)));
-
typedef struct
{
- char *start;
+ const char *start;
int len; /* length in bytes */
int flag;
int wlen; /* length in characters */
@@ -34,147 +29,225 @@ typedef struct
#define LTPRS_WAITNAME 0
#define LTPRS_WAITDELIM 1
+/*
+ * expects a null terminated string
+ * returns an ltree
+ */
+static ltree*
+parse_ltree(const char* buf)
+{
+ const char *ptr;
+ nodeitem *list,
+ *lptr;
+ int num = 0,
+ totallen = 0;
+ int state = LTPRS_WAITNAME;
+ ltree *result;
+ ltree_level *curlevel;
+ int charlen;
+ int pos = 0;
+
+ ptr = buf;
+ while (*ptr)
+ {
+ charlen = pg_mblen(ptr);
+ if (charlen == 1 && t_iseq(ptr, '.'))
+ num++;
+ ptr += charlen;
+ }
+
+ if (num + 1 > MaxAllocSize / sizeof(nodeitem))
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
+ num + 1, (int) (MaxAllocSize / sizeof(nodeitem)))));
+ list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
+ ptr = buf;
+ while (*ptr)
+ {
+ charlen = pg_mblen(ptr);
+
+ if (state == LTPRS_WAITNAME)
+ {
+ if (ISALNUM(ptr))
+ {
+ lptr->start = ptr;
+ lptr->wlen = 0;
+ state = LTPRS_WAITDELIM;
+ }
+ else
+ UNCHAR;
+ }
+ else if (state == LTPRS_WAITDELIM)
+ {
+ if (charlen == 1 && t_iseq(ptr, '.'))
+ {
+ lptr->len = ptr - lptr->start;
+ if (lptr->wlen > 255)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of level is too long"),
+ errdetail("Name length is %d, must "
+ "be < 256, in position %d.",
+ lptr->wlen, pos)));
+
+ totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
+ lptr++;
+ state = LTPRS_WAITNAME;
+ }
+ else if (!ISALNUM(ptr))
+ UNCHAR;
+ }
+ else
+ /* internal error */
+ elog(ERROR, "internal error in parser");
+
+ ptr += charlen;
+ lptr->wlen++;
+ pos++;
+ }
+
+ if (state == LTPRS_WAITDELIM)
+ {
+ lptr->len = ptr - lptr->start;
+ if (lptr->wlen > 255)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of level is too long"),
+ errdetail("Name length is %d, must "
+ "be < 256, in position %d.",
+ lptr->wlen, pos)));
+
+ totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
+ lptr++;
+ }
+ else if (!(state == LTPRS_WAITNAME && lptr == list))
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error"),
+ errdetail("Unexpected end of line.")));
+
+ result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
+ SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
+ result->numlevel = lptr - list;
+ curlevel = LTREE_FIRST(result);
+ lptr = list;
+ while (lptr - list < result->numlevel)
+ {
+ curlevel->len = (uint16) lptr->len;
+ memcpy(curlevel->name, lptr->start, lptr->len);
+ curlevel = LEVEL_NEXT(curlevel);
+ lptr++;
+ }
+
+ pfree(list);
+ return result;
+}
+
+/*
+ * expects an ltree
+ * returns a null terminated string
+ */
+static char*
+deparse_ltree(const ltree* in)
+{
+ char *buf,
+ *ptr;
+ int i;
+ ltree_level *curlevel;
+
+ ptr = buf = (char *) palloc(VARSIZE(in));
+ curlevel = LTREE_FIRST(in);
+ for (i = 0; i < in->numlevel; i++)
+ {
+ if (i != 0)
+ {
+ *ptr = '.';
+ ptr++;
+ }
+ memcpy(ptr, curlevel->name, curlevel->len);
+ ptr += curlevel->len;
+ curlevel = LEVEL_NEXT(curlevel);
+ }
+
+ *ptr = '\0';
+ return buf;
+}
+
+PG_FUNCTION_INFO_V1(ltree_in);
Datum
ltree_in(PG_FUNCTION_ARGS)
{
char *buf = (char *) PG_GETARG_POINTER(0);
- char *ptr;
- nodeitem *list,
- *lptr;
- int num = 0,
- totallen = 0;
- int state = LTPRS_WAITNAME;
- ltree *result;
- ltree_level *curlevel;
- int charlen;
- int pos = 0;
-
- ptr = buf;
- while (*ptr)
- {
- charlen = pg_mblen(ptr);
- if (charlen == 1 && t_iseq(ptr, '.'))
- num++;
- ptr += charlen;
- }
-
- if (num + 1 > MaxAllocSize / sizeof(nodeitem))
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
- num + 1, (int) (MaxAllocSize / sizeof(nodeitem)))));
- list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
- ptr = buf;
- while (*ptr)
- {
- charlen = pg_mblen(ptr);
-
- if (state == LTPRS_WAITNAME)
- {
- if (ISALNUM(ptr))
- {
- lptr->start = ptr;
- lptr->wlen = 0;
- state = LTPRS_WAITDELIM;
- }
- else
- UNCHAR;
- }
- else if (state == LTPRS_WAITDELIM)
- {
- if (charlen == 1 && t_iseq(ptr, '.'))
- {
- lptr->len = ptr - lptr->start;
- if (lptr->wlen > 255)
- ereport(ERROR,
- (errcode(ERRCODE_NAME_TOO_LONG),
- errmsg("name of level is too long"),
- errdetail("Name length is %d, must "
- "be < 256, in position %d.",
- lptr->wlen, pos)));
-
- totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
- lptr++;
- state = LTPRS_WAITNAME;
- }
- else if (!ISALNUM(ptr))
- UNCHAR;
- }
- else
- /* internal error */
- elog(ERROR, "internal error in parser");
-
- ptr += charlen;
- lptr->wlen++;
- pos++;
- }
-
- if (state == LTPRS_WAITDELIM)
- {
- lptr->len = ptr - lptr->start;
- if (lptr->wlen > 255)
- ereport(ERROR,
- (errcode(ERRCODE_NAME_TOO_LONG),
- errmsg("name of level is too long"),
- errdetail("Name length is %d, must "
- "be < 256, in position %d.",
- lptr->wlen, pos)));
-
- totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
- lptr++;
- }
- else if (!(state == LTPRS_WAITNAME && lptr == list))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error"),
- errdetail("Unexpected end of line.")));
-
- result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
- SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
- result->numlevel = lptr - list;
- curlevel = LTREE_FIRST(result);
- lptr = list;
- while (lptr - list < result->numlevel)
- {
- curlevel->len = (uint16) lptr->len;
- memcpy(curlevel->name, lptr->start, lptr->len);
- curlevel = LEVEL_NEXT(curlevel);
- lptr++;
- }
-
- pfree(list);
+ ltree *result = parse_ltree(buf);
PG_RETURN_POINTER(result);
}
+PG_FUNCTION_INFO_V1(ltree_out);
Datum
ltree_out(PG_FUNCTION_ARGS)
{
ltree *in = PG_GETARG_LTREE_P(0);
- char *buf,
- *ptr;
- int i;
- ltree_level *curlevel;
-
- ptr = buf = (char *) palloc(VARSIZE(in));
- curlevel = LTREE_FIRST(in);
- for (i = 0; i < in->numlevel; i++)
- {
- if (i != 0)
- {
- *ptr = '.';
- ptr++;
- }
- memcpy(ptr, curlevel->name, curlevel->len);
- ptr += curlevel->len;
- curlevel = LEVEL_NEXT(curlevel);
- }
-
- *ptr = '\0';
+ char *buf = deparse_ltree(in);
PG_FREE_IF_COPY(in, 0);
PG_RETURN_POINTER(buf);
}
+/*
+ * ltree type send function
+ *
+ * The type is sent as text in binary mode, so this is almost the same
+ * as the input function, but it's prefixed with a version number so we
+ * can change the binary format sent in future if necessary. For now,
+ * only version 1 is supported.
+ */
+PG_FUNCTION_INFO_V1(ltree_send);
+Datum
+ltree_send(PG_FUNCTION_ARGS)
+{
+ ltree *in = PG_GETARG_LTREE_P(0);
+ StringInfoData buf;
+ int version = 1;
+ char *res = deparse_ltree(in);
+
+ pq_begintypsend(&buf);
+ pq_sendint8(&buf, version);
+ pq_sendtext(&buf, res, pg_mbstrlen(res));
+ pfree(res);
+
+ PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+/*
+ * ltree type recv function
+ *
+ * The type is sent as text in binary mode, so this is almost the same
+ * as the input function, but it's prefixed with a version number so we
+ * can change the binary format sent in future if necessary. For now,
+ * only version 1 is supported.
+ */
+PG_FUNCTION_INFO_V1(ltree_recv);
+Datum
+ltree_recv(PG_FUNCTION_ARGS)
+{
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+ int version = pq_getmsgint(buf, 1);
+ char *str;
+ int nbytes;
+ ltree *res;
+
+ if (version == 1)
+ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+ else
+ elog(ERROR, "unsupported ltree version number %d", version);
+
+ res = parse_ltree(str);
+ pfree(str);
+
+ PG_RETURN_POINTER(res);
+}
+
#define LQPRS_WAITLEVEL 0
#define LQPRS_WAITDELIM 1
#define LQPRS_WAITOPEN 2
@@ -190,431 +263,509 @@ ltree_out(PG_FUNCTION_ARGS)
#define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
#define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
+/*
+ * expects a null terminated string
+ * returns an lquery
+ */
+static lquery*
+parse_lquery(const char* buf)
+{
+ const char *ptr;
+ int num = 0,
+ totallen = 0,
+ numOR = 0;
+ int state = LQPRS_WAITLEVEL;
+ lquery *result;
+ nodeitem *lptr = NULL;
+ lquery_level *cur,
+ *curqlevel,
+ *tmpql;
+ lquery_variant *lrptr = NULL;
+ bool hasnot = false;
+ bool wasbad = false;
+ int charlen;
+ int pos = 0;
+
+ ptr = buf;
+ while (*ptr)
+ {
+ charlen = pg_mblen(ptr);
+
+ if (charlen == 1)
+ {
+ if (t_iseq(ptr, '.'))
+ num++;
+ else if (t_iseq(ptr, '|'))
+ numOR++;
+ }
+
+ ptr += charlen;
+ }
+
+ num++;
+ if (num > MaxAllocSize / ITEMSIZE)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
+ num, (int) (MaxAllocSize / ITEMSIZE))));
+ curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
+ ptr = buf;
+ while (*ptr)
+ {
+ charlen = pg_mblen(ptr);
+
+ if (state == LQPRS_WAITLEVEL)
+ {
+ if (ISALNUM(ptr))
+ {
+ GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
+ lptr->start = ptr;
+ state = LQPRS_WAITDELIM;
+ curqlevel->numvar = 1;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '!'))
+ {
+ GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
+ lptr->start = ptr + 1;
+ state = LQPRS_WAITDELIM;
+ curqlevel->numvar = 1;
+ curqlevel->flag |= LQL_NOT;
+ hasnot = true;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '*'))
+ state = LQPRS_WAITOPEN;
+ else
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITVAR)
+ {
+ if (ISALNUM(ptr))
+ {
+ lptr++;
+ lptr->start = ptr;
+ state = LQPRS_WAITDELIM;
+ curqlevel->numvar++;
+ }
+ else
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITDELIM)
+ {
+ if (charlen == 1 && t_iseq(ptr, '@'))
+ {
+ if (lptr->start == ptr)
+ UNCHAR;
+ lptr->flag |= LVAR_INCASE;
+ curqlevel->flag |= LVAR_INCASE;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '*'))
+ {
+ if (lptr->start == ptr)
+ UNCHAR;
+ lptr->flag |= LVAR_ANYEND;
+ curqlevel->flag |= LVAR_ANYEND;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '%'))
+ {
+ if (lptr->start == ptr)
+ UNCHAR;
+ lptr->flag |= LVAR_SUBLEXEME;
+ curqlevel->flag |= LVAR_SUBLEXEME;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '|'))
+ {
+ lptr->len = ptr - lptr->start -
+ ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
+ ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
+ ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
+ if (lptr->wlen > 255)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of level is too long"),
+ errdetail("Name length is %d, must "
+ "be < 256, in position %d.",
+ lptr->wlen, pos)));
+
+ state = LQPRS_WAITVAR;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '.'))
+ {
+ lptr->len = ptr - lptr->start -
+ ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
+ ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
+ ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
+ if (lptr->wlen > 255)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of level is too long"),
+ errdetail("Name length is %d, must "
+ "be < 256, in position %d.",
+ lptr->wlen, pos)));
+
+ state = LQPRS_WAITLEVEL;
+ curqlevel = NEXTLEV(curqlevel);
+ }
+ else if (ISALNUM(ptr))
+ {
+ if (lptr->flag)
+ UNCHAR;
+ }
+ else
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITOPEN)
+ {
+ if (charlen == 1 && t_iseq(ptr, '{'))
+ state = LQPRS_WAITFNUM;
+ else if (charlen == 1 && t_iseq(ptr, '.'))
+ {
+ curqlevel->low = 0;
+ curqlevel->high = 0xffff;
+ curqlevel = NEXTLEV(curqlevel);
+ state = LQPRS_WAITLEVEL;
+ }
+ else
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITFNUM)
+ {
+ if (charlen == 1 && t_iseq(ptr, ','))
+ state = LQPRS_WAITSNUM;
+ else if (t_isdigit(ptr))
+ {
+ curqlevel->low = atoi(ptr);
+ state = LQPRS_WAITND;
+ }
+ else
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITSNUM)
+ {
+ if (t_isdigit(ptr))
+ {
+ curqlevel->high = atoi(ptr);
+ state = LQPRS_WAITCLOSE;
+ }
+ else if (charlen == 1 && t_iseq(ptr, '}'))
+ {
+ curqlevel->high = 0xffff;
+ state = LQPRS_WAITEND;
+ }
+ else
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITCLOSE)
+ {
+ if (charlen == 1 && t_iseq(ptr, '}'))
+ state = LQPRS_WAITEND;
+ else if (!t_isdigit(ptr))
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITND)
+ {
+ if (charlen == 1 && t_iseq(ptr, '}'))
+ {
+ curqlevel->high = curqlevel->low;
+ state = LQPRS_WAITEND;
+ }
+ else if (charlen == 1 && t_iseq(ptr, ','))
+ state = LQPRS_WAITSNUM;
+ else if (!t_isdigit(ptr))
+ UNCHAR;
+ }
+ else if (state == LQPRS_WAITEND)
+ {
+ if (charlen == 1 && t_iseq(ptr, '.'))
+ {
+ state = LQPRS_WAITLEVEL;
+ curqlevel = NEXTLEV(curqlevel);
+ }
+ else
+ UNCHAR;
+ }
+ else
+ /* internal error */
+ elog(ERROR, "internal error in parser");
+
+ ptr += charlen;
+ if (state == LQPRS_WAITDELIM)
+ lptr->wlen++;
+ pos++;
+ }
+
+ if (state == LQPRS_WAITDELIM)
+ {
+ if (lptr->start == ptr)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error"),
+ errdetail("Unexpected end of line.")));
+
+ lptr->len = ptr - lptr->start -
+ ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
+ ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
+ ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
+ if (lptr->len == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error"),
+ errdetail("Unexpected end of line.")));
+
+ if (lptr->wlen > 255)
+ ereport(ERROR,
+ (errcode(ERRCODE_NAME_TOO_LONG),
+ errmsg("name of level is too long"),
+ errdetail("Name length is %d, must "
+ "be < 256, in position %d.",
+ lptr->wlen, pos)));
+ }
+ else if (state == LQPRS_WAITOPEN)
+ curqlevel->high = 0xffff;
+ else if (state != LQPRS_WAITEND)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error"),
+ errdetail("Unexpected end of line.")));
+
+ curqlevel = tmpql;
+ totallen = LQUERY_HDRSIZE;
+ while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
+ {
+ totallen += LQL_HDRSIZE;
+ if (curqlevel->numvar)
+ {
+ lptr = GETVAR(curqlevel);
+ while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
+ {
+ totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
+ lptr++;
+ }
+ }
+ else if (curqlevel->low > curqlevel->high)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error"),
+ errdetail("Low limit(%d) is greater than upper(%d).",
+ curqlevel->low, curqlevel->high)));
+
+ curqlevel = NEXTLEV(curqlevel);
+ }
+
+ result = (lquery *) palloc0(totallen);
+ SET_VARSIZE(result, totallen);
+ result->numlevel = num;
+ result->firstgood = 0;
+ result->flag = 0;
+ if (hasnot)
+ result->flag |= LQUERY_HASNOT;
+ cur = LQUERY_FIRST(result);
+ curqlevel = tmpql;
+ while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
+ {
+ memcpy(cur, curqlevel, LQL_HDRSIZE);
+ cur->totallen = LQL_HDRSIZE;
+ if (curqlevel->numvar)
+ {
+ lrptr = LQL_FIRST(cur);
+ lptr = GETVAR(curqlevel);
+ while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
+ {
+ cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
+ lrptr->len = lptr->len;
+ lrptr->flag = lptr->flag;
+ lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
+ memcpy(lrptr->name, lptr->start, lptr->len);
+ lptr++;
+ lrptr = LVAR_NEXT(lrptr);
+ }
+ pfree(GETVAR(curqlevel));
+ if (cur->numvar > 1 || cur->flag != 0)
+ wasbad = true;
+ else if (wasbad == false)
+ (result->firstgood)++;
+ }
+ else
+ wasbad = true;
+ curqlevel = NEXTLEV(curqlevel);
+ cur = LQL_NEXT(cur);
+ }
+
+ pfree(tmpql);
+ return result;
+}
+
+/*
+ * expects an lquery
+ * returns a null terminated string
+ */
+static char*
+deparse_lquery(const lquery* in)
+{
+ char *buf,
+ *ptr;
+ int i,
+ j,
+ totallen = 1;
+ lquery_level *curqlevel;
+ lquery_variant *curtlevel;
+
+ curqlevel = LQUERY_FIRST(in);
+ for (i = 0; i < in->numlevel; i++)
+ {
+ totallen++;
+ if (curqlevel->numvar)
+ totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
+ else
+ totallen += 2 * 11 + 4;
+ curqlevel = LQL_NEXT(curqlevel);
+ }
+
+ ptr = buf = (char *) palloc(totallen);
+ curqlevel = LQUERY_FIRST(in);
+ for (i = 0; i < in->numlevel; i++)
+ {
+ if (i != 0)
+ {
+ *ptr = '.';
+ ptr++;
+ }
+ if (curqlevel->numvar)
+ {
+ if (curqlevel->flag & LQL_NOT)
+ {
+ *ptr = '!';
+ ptr++;
+ }
+ curtlevel = LQL_FIRST(curqlevel);
+ for (j = 0; j < curqlevel->numvar; j++)
+ {
+ if (j != 0)
+ {
+ *ptr = '|';
+ ptr++;
+ }
+ memcpy(ptr, curtlevel->name, curtlevel->len);
+ ptr += curtlevel->len;
+ if ((curtlevel->flag & LVAR_SUBLEXEME))
+ {
+ *ptr = '%';
+ ptr++;
+ }
+ if ((curtlevel->flag & LVAR_INCASE))
+ {
+ *ptr = '@';
+ ptr++;
+ }
+ if ((curtlevel->flag & LVAR_ANYEND))
+ {
+ *ptr = '*';
+ ptr++;
+ }
+ curtlevel = LVAR_NEXT(curtlevel);
+ }
+ }
+ else
+ {
+ if (curqlevel->low == curqlevel->high)
+ {
+ sprintf(ptr, "*{%d}", curqlevel->low);
+ }
+ else if (curqlevel->low == 0)
+ {
+ if (curqlevel->high == 0xffff)
+ {
+ *ptr = '*';
+ *(ptr + 1) = '\0';
+ }
+ else
+ sprintf(ptr, "*{,%d}", curqlevel->high);
+ }
+ else if (curqlevel->high == 0xffff)
+ {
+ sprintf(ptr, "*{%d,}", curqlevel->low);
+ }
+ else
+ sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
+ ptr = strchr(ptr, '\0');
+ }
+
+ curqlevel = LQL_NEXT(curqlevel);
+ }
+
+ *ptr = '\0';
+ return buf;
+}
+
+PG_FUNCTION_INFO_V1(lquery_in);
Datum
lquery_in(PG_FUNCTION_ARGS)
{
char *buf = (char *) PG_GETARG_POINTER(0);
- char *ptr;
- int num = 0,
- totallen = 0,
- numOR = 0;
- int state = LQPRS_WAITLEVEL;
- lquery *result;
- nodeitem *lptr = NULL;
- lquery_level *cur,
- *curqlevel,
- *tmpql;
- lquery_variant *lrptr = NULL;
- bool hasnot = false;
- bool wasbad = false;
- int charlen;
- int pos = 0;
-
- ptr = buf;
- while (*ptr)
- {
- charlen = pg_mblen(ptr);
-
- if (charlen == 1)
- {
- if (t_iseq(ptr, '.'))
- num++;
- else if (t_iseq(ptr, '|'))
- numOR++;
- }
-
- ptr += charlen;
- }
-
- num++;
- if (num > MaxAllocSize / ITEMSIZE)
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
- num, (int) (MaxAllocSize / ITEMSIZE))));
- curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
- ptr = buf;
- while (*ptr)
- {
- charlen = pg_mblen(ptr);
-
- if (state == LQPRS_WAITLEVEL)
- {
- if (ISALNUM(ptr))
- {
- GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
- lptr->start = ptr;
- state = LQPRS_WAITDELIM;
- curqlevel->numvar = 1;
- }
- else if (charlen == 1 && t_iseq(ptr, '!'))
- {
- GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
- lptr->start = ptr + 1;
- state = LQPRS_WAITDELIM;
- curqlevel->numvar = 1;
- curqlevel->flag |= LQL_NOT;
- hasnot = true;
- }
- else if (charlen == 1 && t_iseq(ptr, '*'))
- state = LQPRS_WAITOPEN;
- else
- UNCHAR;
- }
- else if (state == LQPRS_WAITVAR)
- {
- if (ISALNUM(ptr))
- {
- lptr++;
- lptr->start = ptr;
- state = LQPRS_WAITDELIM;
- curqlevel->numvar++;
- }
- else
- UNCHAR;
- }
- else if (state == LQPRS_WAITDELIM)
- {
- if (charlen == 1 && t_iseq(ptr, '@'))
- {
- if (lptr->start == ptr)
- UNCHAR;
- lptr->flag |= LVAR_INCASE;
- curqlevel->flag |= LVAR_INCASE;
- }
- else if (charlen == 1 && t_iseq(ptr, '*'))
- {
- if (lptr->start == ptr)
- UNCHAR;
- lptr->flag |= LVAR_ANYEND;
- curqlevel->flag |= LVAR_ANYEND;
- }
- else if (charlen == 1 && t_iseq(ptr, '%'))
- {
- if (lptr->start == ptr)
- UNCHAR;
- lptr->flag |= LVAR_SUBLEXEME;
- curqlevel->flag |= LVAR_SUBLEXEME;
- }
- else if (charlen == 1 && t_iseq(ptr, '|'))
- {
- lptr->len = ptr - lptr->start -
- ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
- ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
- ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
- if (lptr->wlen > 255)
- ereport(ERROR,
- (errcode(ERRCODE_NAME_TOO_LONG),
- errmsg("name of level is too long"),
- errdetail("Name length is %d, must "
- "be < 256, in position %d.",
- lptr->wlen, pos)));
-
- state = LQPRS_WAITVAR;
- }
- else if (charlen == 1 && t_iseq(ptr, '.'))
- {
- lptr->len = ptr - lptr->start -
- ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
- ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
- ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
- if (lptr->wlen > 255)
- ereport(ERROR,
- (errcode(ERRCODE_NAME_TOO_LONG),
- errmsg("name of level is too long"),
- errdetail("Name length is %d, must "
- "be < 256, in position %d.",
- lptr->wlen, pos)));
-
- state = LQPRS_WAITLEVEL;
- curqlevel = NEXTLEV(curqlevel);
- }
- else if (ISALNUM(ptr))
- {
- if (lptr->flag)
- UNCHAR;
- }
- else
- UNCHAR;
- }
- else if (state == LQPRS_WAITOPEN)
- {
- if (charlen == 1 && t_iseq(ptr, '{'))
- state = LQPRS_WAITFNUM;
- else if (charlen == 1 && t_iseq(ptr, '.'))
- {
- curqlevel->low = 0;
- curqlevel->high = 0xffff;
- curqlevel = NEXTLEV(curqlevel);
- state = LQPRS_WAITLEVEL;
- }
- else
- UNCHAR;
- }
- else if (state == LQPRS_WAITFNUM)
- {
- if (charlen == 1 && t_iseq(ptr, ','))
- state = LQPRS_WAITSNUM;
- else if (t_isdigit(ptr))
- {
- curqlevel->low = atoi(ptr);
- state = LQPRS_WAITND;
- }
- else
- UNCHAR;
- }
- else if (state == LQPRS_WAITSNUM)
- {
- if (t_isdigit(ptr))
- {
- curqlevel->high = atoi(ptr);
- state = LQPRS_WAITCLOSE;
- }
- else if (charlen == 1 && t_iseq(ptr, '}'))
- {
- curqlevel->high = 0xffff;
- state = LQPRS_WAITEND;
- }
- else
- UNCHAR;
- }
- else if (state == LQPRS_WAITCLOSE)
- {
- if (charlen == 1 && t_iseq(ptr, '}'))
- state = LQPRS_WAITEND;
- else if (!t_isdigit(ptr))
- UNCHAR;
- }
- else if (state == LQPRS_WAITND)
- {
- if (charlen == 1 && t_iseq(ptr, '}'))
- {
- curqlevel->high = curqlevel->low;
- state = LQPRS_WAITEND;
- }
- else if (charlen == 1 && t_iseq(ptr, ','))
- state = LQPRS_WAITSNUM;
- else if (!t_isdigit(ptr))
- UNCHAR;
- }
- else if (state == LQPRS_WAITEND)
- {
- if (charlen == 1 && t_iseq(ptr, '.'))
- {
- state = LQPRS_WAITLEVEL;
- curqlevel = NEXTLEV(curqlevel);
- }
- else
- UNCHAR;
- }
- else
- /* internal error */
- elog(ERROR, "internal error in parser");
-
- ptr += charlen;
- if (state == LQPRS_WAITDELIM)
- lptr->wlen++;
- pos++;
- }
-
- if (state == LQPRS_WAITDELIM)
- {
- if (lptr->start == ptr)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error"),
- errdetail("Unexpected end of line.")));
-
- lptr->len = ptr - lptr->start -
- ((lptr->flag & LVAR_SUBLEXEME) ? 1 : 0) -
- ((lptr->flag & LVAR_INCASE) ? 1 : 0) -
- ((lptr->flag & LVAR_ANYEND) ? 1 : 0);
- if (lptr->len == 0)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error"),
- errdetail("Unexpected end of line.")));
-
- if (lptr->wlen > 255)
- ereport(ERROR,
- (errcode(ERRCODE_NAME_TOO_LONG),
- errmsg("name of level is too long"),
- errdetail("Name length is %d, must "
- "be < 256, in position %d.",
- lptr->wlen, pos)));
- }
- else if (state == LQPRS_WAITOPEN)
- curqlevel->high = 0xffff;
- else if (state != LQPRS_WAITEND)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error"),
- errdetail("Unexpected end of line.")));
-
- curqlevel = tmpql;
- totallen = LQUERY_HDRSIZE;
- while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
- {
- totallen += LQL_HDRSIZE;
- if (curqlevel->numvar)
- {
- lptr = GETVAR(curqlevel);
- while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
- {
- totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
- lptr++;
- }
- }
- else if (curqlevel->low > curqlevel->high)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("syntax error"),
- errdetail("Low limit(%d) is greater than upper(%d).",
- curqlevel->low, curqlevel->high)));
-
- curqlevel = NEXTLEV(curqlevel);
- }
-
- result = (lquery *) palloc0(totallen);
- SET_VARSIZE(result, totallen);
- result->numlevel = num;
- result->firstgood = 0;
- result->flag = 0;
- if (hasnot)
- result->flag |= LQUERY_HASNOT;
- cur = LQUERY_FIRST(result);
- curqlevel = tmpql;
- while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
- {
- memcpy(cur, curqlevel, LQL_HDRSIZE);
- cur->totallen = LQL_HDRSIZE;
- if (curqlevel->numvar)
- {
- lrptr = LQL_FIRST(cur);
- lptr = GETVAR(curqlevel);
- while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
- {
- cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
- lrptr->len = lptr->len;
- lrptr->flag = lptr->flag;
- lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
- memcpy(lrptr->name, lptr->start, lptr->len);
- lptr++;
- lrptr = LVAR_NEXT(lrptr);
- }
- pfree(GETVAR(curqlevel));
- if (cur->numvar > 1 || cur->flag != 0)
- wasbad = true;
- else if (wasbad == false)
- (result->firstgood)++;
- }
- else
- wasbad = true;
- curqlevel = NEXTLEV(curqlevel);
- cur = LQL_NEXT(cur);
- }
-
- pfree(tmpql);
+ lquery *result = parse_lquery(buf);
PG_RETURN_POINTER(result);
}
+PG_FUNCTION_INFO_V1(lquery_out);
Datum
lquery_out(PG_FUNCTION_ARGS)
{
lquery *in = PG_GETARG_LQUERY_P(0);
- char *buf,
- *ptr;
- int i,
- j,
- totallen = 1;
- lquery_level *curqlevel;
- lquery_variant *curtlevel;
-
- curqlevel = LQUERY_FIRST(in);
- for (i = 0; i < in->numlevel; i++)
- {
- totallen++;
- if (curqlevel->numvar)
- totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
- else
- totallen += 2 * 11 + 4;
- curqlevel = LQL_NEXT(curqlevel);
- }
-
- ptr = buf = (char *) palloc(totallen);
- curqlevel = LQUERY_FIRST(in);
- for (i = 0; i < in->numlevel; i++)
- {
- if (i != 0)
- {
- *ptr = '.';
- ptr++;
- }
- if (curqlevel->numvar)
- {
- if (curqlevel->flag & LQL_NOT)
- {
- *ptr = '!';
- ptr++;
- }
- curtlevel = LQL_FIRST(curqlevel);
- for (j = 0; j < curqlevel->numvar; j++)
- {
- if (j != 0)
- {
- *ptr = '|';
- ptr++;
- }
- memcpy(ptr, curtlevel->name, curtlevel->len);
- ptr += curtlevel->len;
- if ((curtlevel->flag & LVAR_SUBLEXEME))
- {
- *ptr = '%';
- ptr++;
- }
- if ((curtlevel->flag & LVAR_INCASE))
- {
- *ptr = '@';
- ptr++;
- }
- if ((curtlevel->flag & LVAR_ANYEND))
- {
- *ptr = '*';
- ptr++;
- }
- curtlevel = LVAR_NEXT(curtlevel);
- }
- }
- else
- {
- if (curqlevel->low == curqlevel->high)
- {
- sprintf(ptr, "*{%d}", curqlevel->low);
- }
- else if (curqlevel->low == 0)
- {
- if (curqlevel->high == 0xffff)
- {
- *ptr = '*';
- *(ptr + 1) = '\0';
- }
- else
- sprintf(ptr, "*{,%d}", curqlevel->high);
- }
- else if (curqlevel->high == 0xffff)
- {
- sprintf(ptr, "*{%d,}", curqlevel->low);
- }
- else
- sprintf(ptr, "*{%d,%d}", curqlevel->low, curqlevel->high);
- ptr = strchr(ptr, '\0');
- }
-
- curqlevel = LQL_NEXT(curqlevel);
- }
-
- *ptr = '\0';
- PG_FREE_IF_COPY(in, 0);
+ char *buf = deparse_lquery(in);
+ PG_FREE_IF_COPY(in, 0);
PG_RETURN_POINTER(buf);
}
+
+/*
+ * lquery type send function
+ *
+ * The type is sent as text in binary mode, so this is almost the same
+ * as the input function, but it's prefixed with a version number so we
+ * can change the binary format sent in future if necessary. For now,
+ * only version 1 is supported.
+ */
+PG_FUNCTION_INFO_V1(lquery_send);
+Datum
+lquery_send(PG_FUNCTION_ARGS)
+{
+ lquery *in = PG_GETARG_LQUERY_P(0);
+ StringInfoData buf;
+ int version = 1;
+ char *res = deparse_lquery(in);
+
+ pq_begintypsend(&buf);
+ pq_sendint8(&buf, version);
+ pq_sendtext(&buf, res, pg_mbstrlen(res));
+ pfree(res);
+
+ PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
+
+/*
+ * lquery type recv function
+ *
+ * The type is sent as text in binary mode, so this is almost the same
+ * as the input function, but it's prefixed with a version number so we
+ * can change the binary format sent in future if necessary. For now,
+ * only version 1 is supported.
+ */
+PG_FUNCTION_INFO_V1(lquery_recv);
+Datum
+lquery_recv(PG_FUNCTION_ARGS)
+{
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+ int version = pq_getmsgint(buf, 1);
+ char *str;
+ int nbytes;
+ lquery *res;
+
+ if (version == 1)
+ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+ else
+ elog(ERROR, "unsupported lquery version number %d", version);
+
+ res = parse_lquery(str);
+ pfree(str);
+
+ PG_RETURN_POINTER(res);
+}
\ No newline at end of file
diff --git a/contrib/ltree/ltxtquery_io.c b/contrib/ltree/ltxtquery_io.c
index 56bf39d145..1e349ae8f8 100644
--- a/contrib/ltree/ltxtquery_io.c
+++ b/contrib/ltree/ltxtquery_io.c
@@ -4,6 +4,7 @@
* contrib/ltree/ltxtquery_io.c
*/
#include "postgres.h"
+#include "libpq/pqformat.h"
#include <ctype.h>
@@ -11,10 +12,6 @@
#include "ltree.h"
#include "miscadmin.h"
-PG_FUNCTION_INFO_V1(ltxtq_in);
-PG_FUNCTION_INFO_V1(ltxtq_out);
-
-
/* parser's states */
#define WAITOPERAND 1
#define INOPERAND 2
@@ -382,12 +379,42 @@ queryin(char *buf)
/*
* in without morphology
*/
+PG_FUNCTION_INFO_V1(ltxtq_in);
Datum
ltxtq_in(PG_FUNCTION_ARGS)
{
PG_RETURN_POINTER(queryin((char *) PG_GETARG_POINTER(0)));
}
+/*
+ * ltxtquery type recv function
+ *
+ * The type is sent as text in binary mode, so this is almost the same
+ * as the input function, but it's prefixed with a version number so we
+ * can change the binary format sent in future if necessary. For now,
+ * only version 1 is supported.
+ */
+PG_FUNCTION_INFO_V1(ltxtq_recv);
+Datum
+ltxtq_recv(PG_FUNCTION_ARGS)
+{
+ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
+ int version = pq_getmsgint(buf, 1);
+ char *str;
+ int nbytes;
+ ltxtquery *res;
+
+ if (version == 1)
+ str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
+ else
+ elog(ERROR, "unsupported ltxtquery version number %d", version);
+
+ res = queryin(str);
+ pfree(str);
+
+ PG_RETURN_POINTER(res);
+}
+
/*
* out function
*/
@@ -512,6 +539,7 @@ infix(INFIX *in, bool first)
}
}
+PG_FUNCTION_INFO_V1(ltxtq_out);
Datum
ltxtq_out(PG_FUNCTION_ARGS)
{
@@ -534,3 +562,42 @@ ltxtq_out(PG_FUNCTION_ARGS)
PG_FREE_IF_COPY(query, 0);
PG_RETURN_POINTER(nrm.buf);
}
+
+/*
+ * ltxtquery type send function
+ *
+ * The type is sent as text in binary mode, so this is almost the same
+ * as the input function, but it's prefixed with a version number so we
+ * can change the binary format sent in future if necessary. For now,
+ * only version 1 is supported.
+ */
+PG_FUNCTION_INFO_V1(ltxtq_send);
+Datum
+ltxtq_send(PG_FUNCTION_ARGS)
+{
+ ltxtquery *query = PG_GETARG_LTXTQUERY_P(0);
+ StringInfoData buf;
+ int version = 1;
+ INFIX nrm;
+
+ if (query->size == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error"),
+ errdetail("Empty query.")));
+
+ nrm.curpol = GETQUERY(query);
+ nrm.buflen = 32;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+ *(nrm.cur) = '\0';
+ nrm.op = GETOPERAND(query);
+ infix(&nrm, true);
+
+ PG_FREE_IF_COPY(query, 0);
+ pq_begintypsend(&buf);
+ pq_sendint8(&buf, version);
+ pq_sendtext(&buf, nrm.buf, pg_mbstrlen(nrm.buf));
+ pfree(nrm.buf);
+
+ PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
+}
\ No newline at end of file
--
2.21.0