Skip to content

Commit 949a9f0

Browse files
committed
Add support for binary I/O of ltree, lquery, and ltxtquery types.
Not much to say here --- does what it says on the tin. The "binary" representation in each case is really just the same as the text format, though we prefix a version-number byte in case anyone ever feels motivated to change that. Thus, there's not any expectation of improved speed or reduced space; the point here is just to allow clients to use binary format for all columns of a query result or COPY data. This makes use of the recently added ALTER TYPE support to add binary I/O functions to an existing data type. As in commit a808186, we can piggy-back on there already being a new-for-v13 version of the ltree extension, so we don't need a new update script file. Nino Floris, reviewed by Alexander Korotkov and myself Discussion: https://postgr.es/m/CANmj9Vxx50jOo1L7iSRxd142NyTz6Bdcgg7u9P3Z8o0=HGkYyQ@mail.gmail.com
1 parent 501b018 commit 949a9f0

File tree

5 files changed

+288
-33
lines changed

5 files changed

+288
-33
lines changed

contrib/ltree/crc32.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
#include "utils/pg_crc.h"
2121

2222
unsigned int
23-
ltree_crc32_sz(char *buf, int size)
23+
ltree_crc32_sz(const char *buf, int size)
2424
{
2525
pg_crc32 crc;
26-
char *p = buf;
26+
const char *p = buf;
2727

2828
INIT_TRADITIONAL_CRC32(crc);
2929
while (size > 0)

contrib/ltree/crc32.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
/* contrib/ltree/crc32.h */
55

66
/* Returns crc32 of data block */
7-
extern unsigned int ltree_crc32_sz(char *buf, int size);
7+
extern unsigned int ltree_crc32_sz(const char *buf, int size);
88

99
/* Returns crc32 of null-terminated string */
1010
#define crc32(buf) ltree_crc32_sz((buf),strlen(buf))

contrib/ltree/ltree--1.1--1.2.sql

+37
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,43 @@
33
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
44
\echo Use "ALTER EXTENSION ltree UPDATE TO '1.2'" to load this file. \quit
55

6+
CREATE FUNCTION ltree_recv(internal)
7+
RETURNS ltree
8+
AS 'MODULE_PATHNAME'
9+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
10+
11+
CREATE FUNCTION ltree_send(ltree)
12+
RETURNS bytea
13+
AS 'MODULE_PATHNAME'
14+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
15+
16+
ALTER TYPE ltree SET ( RECEIVE = ltree_recv, SEND = ltree_send );
17+
18+
CREATE FUNCTION lquery_recv(internal)
19+
RETURNS lquery
20+
AS 'MODULE_PATHNAME'
21+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
22+
23+
CREATE FUNCTION lquery_send(lquery)
24+
RETURNS bytea
25+
AS 'MODULE_PATHNAME'
26+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
27+
28+
ALTER TYPE lquery SET ( RECEIVE = lquery_recv, SEND = lquery_send );
29+
30+
CREATE FUNCTION ltxtq_recv(internal)
31+
RETURNS ltxtquery
32+
AS 'MODULE_PATHNAME'
33+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
34+
35+
CREATE FUNCTION ltxtq_send(ltxtquery)
36+
RETURNS bytea
37+
AS 'MODULE_PATHNAME'
38+
LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
39+
40+
ALTER TYPE ltxtquery SET ( RECEIVE = ltxtq_recv, SEND = ltxtq_send );
41+
42+
643
CREATE FUNCTION ltree_gist_options(internal)
744
RETURNS void
845
AS 'MODULE_PATHNAME', 'ltree_gist_options'

contrib/ltree/ltree_io.c

+179-26
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,14 @@
88
#include <ctype.h>
99

1010
#include "crc32.h"
11+
#include "libpq/pqformat.h"
1112
#include "ltree.h"
1213
#include "utils/memutils.h"
1314

14-
PG_FUNCTION_INFO_V1(ltree_in);
15-
PG_FUNCTION_INFO_V1(ltree_out);
16-
PG_FUNCTION_INFO_V1(lquery_in);
17-
PG_FUNCTION_INFO_V1(lquery_out);
18-
1915

2016
typedef struct
2117
{
22-
char *start;
18+
const char *start;
2319
int len; /* length in bytes */
2420
int flag;
2521
int wlen; /* length in characters */
@@ -28,11 +24,14 @@ typedef struct
2824
#define LTPRS_WAITNAME 0
2925
#define LTPRS_WAITDELIM 1
3026

31-
Datum
32-
ltree_in(PG_FUNCTION_ARGS)
27+
/*
28+
* expects a null terminated string
29+
* returns an ltree
30+
*/
31+
static ltree *
32+
parse_ltree(const char *buf)
3333
{
34-
char *buf = (char *) PG_GETARG_POINTER(0);
35-
char *ptr;
34+
const char *ptr;
3635
nodeitem *list,
3736
*lptr;
3837
int num = 0,
@@ -141,15 +140,18 @@ ltree_in(PG_FUNCTION_ARGS)
141140
}
142141

143142
pfree(list);
144-
PG_RETURN_POINTER(result);
143+
return result;
145144

146145
#undef UNCHAR
147146
}
148147

149-
Datum
150-
ltree_out(PG_FUNCTION_ARGS)
148+
/*
149+
* expects an ltree
150+
* returns a null terminated string
151+
*/
152+
static char *
153+
deparse_ltree(const ltree *in)
151154
{
152-
ltree *in = PG_GETARG_LTREE_P(0);
153155
char *buf,
154156
*ptr;
155157
int i;
@@ -170,11 +172,84 @@ ltree_out(PG_FUNCTION_ARGS)
170172
}
171173

172174
*ptr = '\0';
173-
PG_FREE_IF_COPY(in, 0);
175+
return buf;
176+
}
177+
178+
/*
179+
* Basic ltree I/O functions
180+
*/
181+
PG_FUNCTION_INFO_V1(ltree_in);
182+
Datum
183+
ltree_in(PG_FUNCTION_ARGS)
184+
{
185+
char *buf = (char *) PG_GETARG_POINTER(0);
186+
187+
PG_RETURN_POINTER(parse_ltree(buf));
188+
}
189+
190+
PG_FUNCTION_INFO_V1(ltree_out);
191+
Datum
192+
ltree_out(PG_FUNCTION_ARGS)
193+
{
194+
ltree *in = PG_GETARG_LTREE_P(0);
195+
196+
PG_RETURN_POINTER(deparse_ltree(in));
197+
}
198+
199+
/*
200+
* ltree type send function
201+
*
202+
* The type is sent as text in binary mode, so this is almost the same
203+
* as the output function, but it's prefixed with a version number so we
204+
* can change the binary format sent in future if necessary. For now,
205+
* only version 1 is supported.
206+
*/
207+
PG_FUNCTION_INFO_V1(ltree_send);
208+
Datum
209+
ltree_send(PG_FUNCTION_ARGS)
210+
{
211+
ltree *in = PG_GETARG_LTREE_P(0);
212+
StringInfoData buf;
213+
int version = 1;
214+
char *res = deparse_ltree(in);
215+
216+
pq_begintypsend(&buf);
217+
pq_sendint8(&buf, version);
218+
pq_sendtext(&buf, res, strlen(res));
219+
pfree(res);
220+
221+
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
222+
}
223+
224+
/*
225+
* ltree type recv function
226+
*
227+
* The type is sent as text in binary mode, so this is almost the same
228+
* as the input function, but it's prefixed with a version number so we
229+
* can change the binary format sent in future if necessary. For now,
230+
* only version 1 is supported.
231+
*/
232+
PG_FUNCTION_INFO_V1(ltree_recv);
233+
Datum
234+
ltree_recv(PG_FUNCTION_ARGS)
235+
{
236+
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
237+
int version = pq_getmsgint(buf, 1);
238+
char *str;
239+
int nbytes;
240+
ltree *res;
174241

175-
PG_RETURN_POINTER(buf);
242+
if (version != 1)
243+
elog(ERROR, "unsupported ltree version number %d", version);
244+
245+
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
246+
res = parse_ltree(str);
247+
pfree(str);
248+
249+
PG_RETURN_POINTER(res);
176250
}
177251

252+
178253
#define LQPRS_WAITLEVEL 0
179254
#define LQPRS_WAITDELIM 1
180255
#define LQPRS_WAITOPEN 2
@@ -190,11 +265,14 @@ ltree_out(PG_FUNCTION_ARGS)
190265
#define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
191266
#define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
192267

193-
Datum
194-
lquery_in(PG_FUNCTION_ARGS)
268+
/*
269+
* expects a null terminated string
270+
* returns an lquery
271+
*/
272+
static lquery *
273+
parse_lquery(const char *buf)
195274
{
196-
char *buf = (char *) PG_GETARG_POINTER(0);
197-
char *ptr;
275+
const char *ptr;
198276
int num = 0,
199277
totallen = 0,
200278
numOR = 0;
@@ -563,15 +641,18 @@ lquery_in(PG_FUNCTION_ARGS)
563641
}
564642

565643
pfree(tmpql);
566-
PG_RETURN_POINTER(result);
644+
return result;
567645

568646
#undef UNCHAR
569647
}
570648

571-
Datum
572-
lquery_out(PG_FUNCTION_ARGS)
649+
/*
650+
* expects an lquery
651+
* returns a null terminated string
652+
*/
653+
static char *
654+
deparse_lquery(const lquery *in)
573655
{
574-
lquery *in = PG_GETARG_LQUERY_P(0);
575656
char *buf,
576657
*ptr;
577658
int i,
@@ -679,7 +760,79 @@ lquery_out(PG_FUNCTION_ARGS)
679760
}
680761

681762
*ptr = '\0';
682-
PG_FREE_IF_COPY(in, 0);
763+
return buf;
764+
}
765+
766+
/*
767+
* Basic lquery I/O functions
768+
*/
769+
PG_FUNCTION_INFO_V1(lquery_in);
770+
Datum
771+
lquery_in(PG_FUNCTION_ARGS)
772+
{
773+
char *buf = (char *) PG_GETARG_POINTER(0);
774+
775+
PG_RETURN_POINTER(parse_lquery(buf));
776+
}
777+
778+
PG_FUNCTION_INFO_V1(lquery_out);
779+
Datum
780+
lquery_out(PG_FUNCTION_ARGS)
781+
{
782+
lquery *in = PG_GETARG_LQUERY_P(0);
783+
784+
PG_RETURN_POINTER(deparse_lquery(in));
785+
}
786+
787+
/*
788+
* lquery type send function
789+
*
790+
* The type is sent as text in binary mode, so this is almost the same
791+
* as the output function, but it's prefixed with a version number so we
792+
* can change the binary format sent in future if necessary. For now,
793+
* only version 1 is supported.
794+
*/
795+
PG_FUNCTION_INFO_V1(lquery_send);
796+
Datum
797+
lquery_send(PG_FUNCTION_ARGS)
798+
{
799+
lquery *in = PG_GETARG_LQUERY_P(0);
800+
StringInfoData buf;
801+
int version = 1;
802+
char *res = deparse_lquery(in);
803+
804+
pq_begintypsend(&buf);
805+
pq_sendint8(&buf, version);
806+
pq_sendtext(&buf, res, strlen(res));
807+
pfree(res);
808+
809+
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
810+
}
811+
812+
/*
813+
* lquery type recv function
814+
*
815+
* The type is sent as text in binary mode, so this is almost the same
816+
* as the input function, but it's prefixed with a version number so we
817+
* can change the binary format sent in future if necessary. For now,
818+
* only version 1 is supported.
819+
*/
820+
PG_FUNCTION_INFO_V1(lquery_recv);
821+
Datum
822+
lquery_recv(PG_FUNCTION_ARGS)
823+
{
824+
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
825+
int version = pq_getmsgint(buf, 1);
826+
char *str;
827+
int nbytes;
828+
lquery *res;
829+
830+
if (version != 1)
831+
elog(ERROR, "unsupported lquery version number %d", version);
832+
833+
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
834+
res = parse_lquery(str);
835+
pfree(str);
683836

684-
PG_RETURN_POINTER(buf);
837+
PG_RETURN_POINTER(res);
685838
}

0 commit comments

Comments
 (0)