diff --git a/contrib/ltree/crc32.c b/contrib/ltree/crc32.c index 0c3e45923b..8fed3346e8 100644 --- a/contrib/ltree/crc32.c +++ b/contrib/ltree/crc32.c @@ -20,10 +20,10 @@ #include "utils/pg_crc.h" unsigned int -ltree_crc32_sz(char *buf, int size) +ltree_crc32_sz(const char *buf, int size) { pg_crc32 crc; - char *p = buf; + const char *p = buf; INIT_TRADITIONAL_CRC32(crc); while (size > 0) 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.1--1.2.sql b/contrib/ltree/ltree--1.1--1.2.sql index 186381e61d..e38e76b31e 100644 --- a/contrib/ltree/ltree--1.1--1.2.sql +++ b/contrib/ltree/ltree--1.1--1.2.sql @@ -3,6 +3,43 @@ -- complain if script is sourced in psql, rather than via ALTER EXTENSION \echo Use "ALTER EXTENSION ltree UPDATE TO '1.2'" to load this file. \quit +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; + +ALTER TYPE ltree SET ( RECEIVE = ltree_recv, SEND = ltree_send ); + +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; + +ALTER TYPE lquery SET ( RECEIVE = lquery_recv, SEND = lquery_send ); + +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; + +ALTER TYPE ltxtquery SET ( RECEIVE = ltxtq_recv, SEND = ltxtq_send ); + + CREATE FUNCTION ltree_gist_options(internal) RETURNS void AS 'MODULE_PATHNAME', 'ltree_gist_options' diff --git a/contrib/ltree/ltree_io.c b/contrib/ltree/ltree_io.c index c6ea5dec8c..b928b82d62 100644 --- a/contrib/ltree/ltree_io.c +++ b/contrib/ltree/ltree_io.c @@ -8,18 +8,14 @@ #include #include "crc32.h" +#include "libpq/pqformat.h" #include "ltree.h" #include "utils/memutils.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); - typedef struct { - char *start; + const char *start; int len; /* length in bytes */ int flag; int wlen; /* length in characters */ @@ -28,11 +24,14 @@ typedef struct #define LTPRS_WAITNAME 0 #define LTPRS_WAITDELIM 1 -Datum -ltree_in(PG_FUNCTION_ARGS) +/* + * expects a null terminated string + * returns an ltree + */ +static ltree * +parse_ltree(const char *buf) { - char *buf = (char *) PG_GETARG_POINTER(0); - char *ptr; + const char *ptr; nodeitem *list, *lptr; int num = 0, @@ -141,15 +140,18 @@ ltree_in(PG_FUNCTION_ARGS) } pfree(list); - PG_RETURN_POINTER(result); + return result; #undef UNCHAR } -Datum -ltree_out(PG_FUNCTION_ARGS) +/* + * expects an ltree + * returns a null terminated string + */ +static char * +deparse_ltree(const ltree *in) { - ltree *in = PG_GETARG_LTREE_P(0); char *buf, *ptr; int i; @@ -170,11 +172,84 @@ ltree_out(PG_FUNCTION_ARGS) } *ptr = '\0'; - PG_FREE_IF_COPY(in, 0); - - PG_RETURN_POINTER(buf); + return buf; } +/* + * Basic ltree I/O functions + */ +PG_FUNCTION_INFO_V1(ltree_in); +Datum +ltree_in(PG_FUNCTION_ARGS) +{ + char *buf = (char *) PG_GETARG_POINTER(0); + + PG_RETURN_POINTER(parse_ltree(buf)); +} + +PG_FUNCTION_INFO_V1(ltree_out); +Datum +ltree_out(PG_FUNCTION_ARGS) +{ + ltree *in = PG_GETARG_LTREE_P(0); + + PG_RETURN_POINTER(deparse_ltree(in)); +} + +/* + * ltree type send function + * + * The type is sent as text in binary mode, so this is almost the same + * as the output 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, strlen(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) + elog(ERROR, "unsupported ltree version number %d", version); + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + res = parse_ltree(str); + pfree(str); + + PG_RETURN_POINTER(res); +} + + #define LQPRS_WAITLEVEL 0 #define LQPRS_WAITDELIM 1 #define LQPRS_WAITOPEN 2 @@ -190,11 +265,14 @@ ltree_out(PG_FUNCTION_ARGS) #define ITEMSIZE MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*)) #define NEXTLEV(x) ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) ) -Datum -lquery_in(PG_FUNCTION_ARGS) +/* + * expects a null terminated string + * returns an lquery + */ +static lquery * +parse_lquery(const char *buf) { - char *buf = (char *) PG_GETARG_POINTER(0); - char *ptr; + const char *ptr; int num = 0, totallen = 0, numOR = 0; @@ -563,15 +641,18 @@ lquery_in(PG_FUNCTION_ARGS) } pfree(tmpql); - PG_RETURN_POINTER(result); + return result; #undef UNCHAR } -Datum -lquery_out(PG_FUNCTION_ARGS) +/* + * expects an lquery + * returns a null terminated string + */ +static char * +deparse_lquery(const lquery *in) { - lquery *in = PG_GETARG_LQUERY_P(0); char *buf, *ptr; int i, @@ -679,7 +760,79 @@ lquery_out(PG_FUNCTION_ARGS) } *ptr = '\0'; - PG_FREE_IF_COPY(in, 0); - - PG_RETURN_POINTER(buf); + return buf; +} + +/* + * Basic lquery I/O functions + */ +PG_FUNCTION_INFO_V1(lquery_in); +Datum +lquery_in(PG_FUNCTION_ARGS) +{ + char *buf = (char *) PG_GETARG_POINTER(0); + + PG_RETURN_POINTER(parse_lquery(buf)); +} + +PG_FUNCTION_INFO_V1(lquery_out); +Datum +lquery_out(PG_FUNCTION_ARGS) +{ + lquery *in = PG_GETARG_LQUERY_P(0); + + PG_RETURN_POINTER(deparse_lquery(in)); +} + +/* + * lquery type send function + * + * The type is sent as text in binary mode, so this is almost the same + * as the output 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, strlen(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) + elog(ERROR, "unsupported lquery version number %d", version); + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + res = parse_lquery(str); + pfree(str); + + PG_RETURN_POINTER(res); } diff --git a/contrib/ltree/ltxtquery_io.c b/contrib/ltree/ltxtquery_io.c index db347f7772..d967f92110 100644 --- a/contrib/ltree/ltxtquery_io.c +++ b/contrib/ltree/ltxtquery_io.c @@ -8,12 +8,10 @@ #include #include "crc32.h" +#include "libpq/pqformat.h" #include "ltree.h" #include "miscadmin.h" -PG_FUNCTION_INFO_V1(ltxtq_in); -PG_FUNCTION_INFO_V1(ltxtq_out); - /* parser's states */ #define WAITOPERAND 1 @@ -381,12 +379,41 @@ 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) + elog(ERROR, "unsupported ltxtquery version number %d", version); + + str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); + res = queryin(str); + pfree(str); + + PG_RETURN_POINTER(res); +} + /* * out function */ @@ -511,6 +538,7 @@ infix(INFIX *in, bool first) } } +PG_FUNCTION_INFO_V1(ltxtq_out); Datum ltxtq_out(PG_FUNCTION_ARGS) { @@ -530,6 +558,43 @@ ltxtq_out(PG_FUNCTION_ARGS) nrm.op = GETOPERAND(query); infix(&nrm, true); - 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 output 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); + + pq_begintypsend(&buf); + pq_sendint8(&buf, version); + pq_sendtext(&buf, nrm.buf, strlen(nrm.buf)); + pfree(nrm.buf); + + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +}