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

Lines changed: 2 additions & 2 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 37 additions & 0 deletions
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

Lines changed: 179 additions & 26 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy