PostgreSQL Source Code  git master
ltree_io.c File Reference
#include "postgres.h"
#include <ctype.h>
#include "crc32.h"
#include "libpq/pqformat.h"
#include "ltree.h"
#include "utils/memutils.h"
Include dependency graph for ltree_io.c:

Go to the source code of this file.

Data Structures

struct  nodeitem
 

Macros

#define LTPRS_WAITNAME   0
 
#define LTPRS_WAITDELIM   1
 
#define UNCHAR
 
#define LQPRS_WAITLEVEL   0
 
#define LQPRS_WAITDELIM   1
 
#define LQPRS_WAITOPEN   2
 
#define LQPRS_WAITFNUM   3
 
#define LQPRS_WAITSNUM   4
 
#define LQPRS_WAITND   5
 
#define LQPRS_WAITCLOSE   6
 
#define LQPRS_WAITEND   7
 
#define LQPRS_WAITVAR   8
 
#define GETVAR(x)   ( *((nodeitem**)LQL_FIRST(x)) )
 
#define ITEMSIZE   MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))
 
#define NEXTLEV(x)   ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )
 
#define UNCHAR
 

Functions

static void finish_nodeitem (nodeitem *lptr, const char *ptr, bool is_lquery, int pos)
 
static ltreeparse_ltree (const char *buf)
 
static char * deparse_ltree (const ltree *in)
 
 PG_FUNCTION_INFO_V1 (ltree_in)
 
Datum ltree_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ltree_out)
 
Datum ltree_out (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ltree_send)
 
Datum ltree_send (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (ltree_recv)
 
Datum ltree_recv (PG_FUNCTION_ARGS)
 
static lqueryparse_lquery (const char *buf)
 
static char * deparse_lquery (const lquery *in)
 
 PG_FUNCTION_INFO_V1 (lquery_in)
 
Datum lquery_in (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (lquery_out)
 
Datum lquery_out (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (lquery_send)
 
Datum lquery_send (PG_FUNCTION_ARGS)
 
 PG_FUNCTION_INFO_V1 (lquery_recv)
 
Datum lquery_recv (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ GETVAR

#define GETVAR (   x)    ( *((nodeitem**)LQL_FIRST(x)) )

Definition at line 253 of file ltree_io.c.

Referenced by parse_lquery().

◆ ITEMSIZE

#define ITEMSIZE   MAXALIGN(LQL_HDRSIZE+sizeof(nodeitem*))

Definition at line 254 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITCLOSE

#define LQPRS_WAITCLOSE   6

Definition at line 248 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITDELIM

#define LQPRS_WAITDELIM   1

Definition at line 243 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITEND

#define LQPRS_WAITEND   7

Definition at line 249 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITFNUM

#define LQPRS_WAITFNUM   3

Definition at line 245 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITLEVEL

#define LQPRS_WAITLEVEL   0

Definition at line 242 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITND

#define LQPRS_WAITND   5

Definition at line 247 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITOPEN

#define LQPRS_WAITOPEN   2

Definition at line 244 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITSNUM

#define LQPRS_WAITSNUM   4

Definition at line 246 of file ltree_io.c.

Referenced by parse_lquery().

◆ LQPRS_WAITVAR

#define LQPRS_WAITVAR   8

Definition at line 250 of file ltree_io.c.

Referenced by parse_lquery().

◆ LTPRS_WAITDELIM

#define LTPRS_WAITDELIM   1

Definition at line 25 of file ltree_io.c.

Referenced by parse_ltree().

◆ LTPRS_WAITNAME

#define LTPRS_WAITNAME   0

Definition at line 24 of file ltree_io.c.

Referenced by parse_ltree().

◆ NEXTLEV

#define NEXTLEV (   x)    ( (lquery_level*)( ((char*)(x)) + ITEMSIZE) )

Definition at line 255 of file ltree_io.c.

Referenced by parse_lquery().

◆ UNCHAR [1/2]

#define UNCHAR
Value:
errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("ltree syntax error at character %d", \
pos))
int errcode(int sqlerrcode)
Definition: elog.c:691
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg(const char *fmt,...)
Definition: elog.c:902

Referenced by parse_lquery(), and parse_ltree().

◆ UNCHAR [2/2]

#define UNCHAR
Value:
errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("lquery syntax error at character %d", \
pos))
int errcode(int sqlerrcode)
Definition: elog.c:691
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg(const char *fmt,...)
Definition: elog.c:902

Function Documentation

◆ deparse_lquery()

static char* deparse_lquery ( const lquery in)
static

Definition at line 613 of file ltree_io.c.

References buf, lquery_variant::flag, lquery_level::flag, lquery_level::high, i, lquery_variant::len, lquery_level::low, LQL_COUNT, LQL_FIRST, LQL_NEXT, LQL_NOT, LQUERY_FIRST, lquery_in(), LTREE_MAX_LEVELS, LVAR_ANYEND, LVAR_INCASE, LVAR_NEXT, LVAR_SUBLEXEME, lquery_variant::name, lquery::numlevel, lquery_level::numvar, palloc(), PG_FUNCTION_INFO_V1(), sprintf, and lquery_level::totallen.

Referenced by lquery_out(), and lquery_send().

614 {
615  char *buf,
616  *ptr;
617  int i,
618  j,
619  totallen = 1;
620  lquery_level *curqlevel;
621  lquery_variant *curtlevel;
622 
623  curqlevel = LQUERY_FIRST(in);
624  for (i = 0; i < in->numlevel; i++)
625  {
626  totallen++;
627  if (curqlevel->numvar)
628  {
629  totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
630  if (curqlevel->flag & LQL_COUNT)
631  totallen += 2 * 11 + 3;
632  }
633  else
634  totallen += 2 * 11 + 4;
635  curqlevel = LQL_NEXT(curqlevel);
636  }
637 
638  ptr = buf = (char *) palloc(totallen);
639  curqlevel = LQUERY_FIRST(in);
640  for (i = 0; i < in->numlevel; i++)
641  {
642  if (i != 0)
643  {
644  *ptr = '.';
645  ptr++;
646  }
647  if (curqlevel->numvar)
648  {
649  if (curqlevel->flag & LQL_NOT)
650  {
651  *ptr = '!';
652  ptr++;
653  }
654  curtlevel = LQL_FIRST(curqlevel);
655  for (j = 0; j < curqlevel->numvar; j++)
656  {
657  if (j != 0)
658  {
659  *ptr = '|';
660  ptr++;
661  }
662  memcpy(ptr, curtlevel->name, curtlevel->len);
663  ptr += curtlevel->len;
664  if ((curtlevel->flag & LVAR_SUBLEXEME))
665  {
666  *ptr = '%';
667  ptr++;
668  }
669  if ((curtlevel->flag & LVAR_INCASE))
670  {
671  *ptr = '@';
672  ptr++;
673  }
674  if ((curtlevel->flag & LVAR_ANYEND))
675  {
676  *ptr = '*';
677  ptr++;
678  }
679  curtlevel = LVAR_NEXT(curtlevel);
680  }
681  }
682  else
683  {
684  *ptr = '*';
685  ptr++;
686  }
687 
688  if ((curqlevel->flag & LQL_COUNT) || curqlevel->numvar == 0)
689  {
690  if (curqlevel->low == curqlevel->high)
691  {
692  sprintf(ptr, "{%d}", curqlevel->low);
693  }
694  else if (curqlevel->low == 0)
695  {
696  if (curqlevel->high == LTREE_MAX_LEVELS)
697  {
698  if (curqlevel->numvar == 0)
699  {
700  /* This is default for '*', so print nothing */
701  *ptr = '\0';
702  }
703  else
704  sprintf(ptr, "{,}");
705  }
706  else
707  sprintf(ptr, "{,%d}", curqlevel->high);
708  }
709  else if (curqlevel->high == LTREE_MAX_LEVELS)
710  {
711  sprintf(ptr, "{%d,}", curqlevel->low);
712  }
713  else
714  sprintf(ptr, "{%d,%d}", curqlevel->low, curqlevel->high);
715  ptr = strchr(ptr, '\0');
716  }
717 
718  curqlevel = LQL_NEXT(curqlevel);
719  }
720 
721  *ptr = '\0';
722  return buf;
723 }
#define LVAR_INCASE
Definition: ltree.h:62
uint8 flag
Definition: ltree.h:49
uint16 low
Definition: ltree.h:80
#define LQUERY_FIRST(x)
Definition: ltree.h:111
uint16 len
Definition: ltree.h:48
#define LVAR_ANYEND
Definition: ltree.h:61
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:50
#define LQL_FIRST(x)
Definition: ltree.h:88
#define LQL_NEXT(x)
Definition: ltree.h:87
uint16 totallen
Definition: ltree.h:77
#define LVAR_NEXT(x)
Definition: ltree.h:59
#define sprintf
Definition: port.h:217
uint16 flag
Definition: ltree.h:78
#define LQL_COUNT
Definition: ltree.h:91
#define LQL_NOT
Definition: ltree.h:90
static char * buf
Definition: pg_test_fsync.c:68
uint16 numlevel
Definition: ltree.h:103
#define LVAR_SUBLEXEME
Definition: ltree.h:63
uint16 numvar
Definition: ltree.h:79
void * palloc(Size size)
Definition: mcxt.c:950
int i
#define LTREE_MAX_LEVELS
Definition: ltree.h:39
uint16 high
Definition: ltree.h:81

◆ deparse_ltree()

static char* deparse_ltree ( const ltree in)
static

Definition at line 142 of file ltree_io.c.

References buf, i, ltree_level::len, LEVEL_NEXT, LTREE_FIRST, ltree_in(), ltree_level::name, ltree::numlevel, palloc(), PG_FUNCTION_INFO_V1(), and VARSIZE.

Referenced by ltree_out(), and ltree_send().

143 {
144  char *buf,
145  *ptr;
146  int i;
147  ltree_level *curlevel;
148 
149  ptr = buf = (char *) palloc(VARSIZE(in));
150  curlevel = LTREE_FIRST(in);
151  for (i = 0; i < in->numlevel; i++)
152  {
153  if (i != 0)
154  {
155  *ptr = '.';
156  ptr++;
157  }
158  memcpy(ptr, curlevel->name, curlevel->len);
159  ptr += curlevel->len;
160  curlevel = LEVEL_NEXT(curlevel);
161  }
162 
163  *ptr = '\0';
164  return buf;
165 }
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:23
uint16 len
Definition: ltree.h:22
#define VARSIZE(PTR)
Definition: postgres.h:303
static char * buf
Definition: pg_test_fsync.c:68
#define LEVEL_NEXT(x)
Definition: ltree.h:27
uint16 numlevel
Definition: ltree.h:32
void * palloc(Size size)
Definition: mcxt.c:950
#define LTREE_FIRST(x)
Definition: ltree.h:38
int i

◆ finish_nodeitem()

static void finish_nodeitem ( nodeitem lptr,
const char *  ptr,
bool  is_lquery,
int  pos 
)
static

Definition at line 573 of file ltree_io.c.

References ereport, errcode(), errdetail(), errmsg(), ERROR, nodeitem::len, LTREE_LABEL_MAX_CHARS, nodeitem::start, and nodeitem::wlen.

Referenced by parse_lquery(), and parse_ltree().

574 {
575  if (is_lquery)
576  {
577  /*
578  * Back up over any flag characters, and discount them from length and
579  * position.
580  */
581  while (ptr > lptr->start && strchr("@*%", ptr[-1]) != NULL)
582  {
583  ptr--;
584  lptr->wlen--;
585  pos--;
586  }
587  }
588 
589  /* Now compute the byte length, which we weren't tracking before. */
590  lptr->len = ptr - lptr->start;
591 
592  /* Complain if it's empty or too long */
593  if (lptr->len == 0)
594  ereport(ERROR,
595  (errcode(ERRCODE_SYNTAX_ERROR),
596  is_lquery ?
597  errmsg("lquery syntax error at character %d", pos) :
598  errmsg("ltree syntax error at character %d", pos),
599  errdetail("Empty labels are not allowed.")));
600  if (lptr->wlen > LTREE_LABEL_MAX_CHARS)
601  ereport(ERROR,
602  (errcode(ERRCODE_NAME_TOO_LONG),
603  errmsg("label string is too long"),
604  errdetail("Label length is %d, must be at most %d, at character %d.",
605  lptr->wlen, LTREE_LABEL_MAX_CHARS, pos)));
606 }
int len
Definition: ltree_io.c:19
int wlen
Definition: ltree_io.c:21
int errcode(int sqlerrcode)
Definition: elog.c:691
#define ERROR
Definition: elog.h:43
#define LTREE_LABEL_MAX_CHARS
Definition: ltree.h:18
int errdetail(const char *fmt,...)
Definition: elog.c:1035
const char * start
Definition: ltree_io.c:18
#define ereport(elevel,...)
Definition: elog.h:155
int errmsg(const char *fmt,...)
Definition: elog.c:902

◆ lquery_in()

Datum lquery_in ( PG_FUNCTION_ARGS  )

Definition at line 730 of file ltree_io.c.

References buf, lquery_out(), parse_lquery(), PG_FUNCTION_INFO_V1(), PG_GETARG_POINTER, and PG_RETURN_POINTER.

Referenced by deparse_lquery().

731 {
732  char *buf = (char *) PG_GETARG_POINTER(0);
733 
735 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
static char * buf
Definition: pg_test_fsync.c:68
static lquery * parse_lquery(const char *buf)
Definition: ltree_io.c:262

◆ lquery_out()

Datum lquery_out ( PG_FUNCTION_ARGS  )

Definition at line 739 of file ltree_io.c.

References deparse_lquery(), lquery_send(), PG_FUNCTION_INFO_V1(), PG_GETARG_LQUERY_P, and PG_RETURN_POINTER.

Referenced by lquery_in().

740 {
741  lquery *in = PG_GETARG_LQUERY_P(0);
742 
744 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
static char * deparse_lquery(const lquery *in)
Definition: ltree_io.c:613
Definition: ltree.h:100
#define PG_GETARG_LQUERY_P(n)
Definition: ltree.h:209

◆ lquery_recv()

Datum lquery_recv ( PG_FUNCTION_ARGS  )

Definition at line 781 of file ltree_io.c.

References buf, StringInfoData::cursor, elog, ERROR, StringInfoData::len, parse_lquery(), pfree(), PG_GETARG_POINTER, PG_RETURN_POINTER, pq_getmsgint(), pq_getmsgtext(), and generate_unaccent_rules::str.

Referenced by lquery_send().

782 {
784  int version = pq_getmsgint(buf, 1);
785  char *str;
786  int nbytes;
787  lquery *res;
788 
789  if (version != 1)
790  elog(ERROR, "unsupported lquery version number %d", version);
791 
792  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
793  res = parse_lquery(str);
794  pfree(str);
795 
796  PG_RETURN_POINTER(res);
797 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
Definition: ltree.h:100
StringInfoData * StringInfo
Definition: stringinfo.h:44
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:68
char * pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
Definition: pqformat.c:548
#define elog(elevel,...)
Definition: elog.h:228
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417
static lquery * parse_lquery(const char *buf)
Definition: ltree_io.c:262

◆ lquery_send()

Datum lquery_send ( PG_FUNCTION_ARGS  )

Definition at line 756 of file ltree_io.c.

References buf, deparse_lquery(), lquery_recv(), pfree(), PG_FUNCTION_INFO_V1(), PG_GETARG_LQUERY_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint8(), and pq_sendtext().

Referenced by lquery_out().

757 {
758  lquery *in = PG_GETARG_LQUERY_P(0);
760  int version = 1;
761  char *res = deparse_lquery(in);
762 
763  pq_begintypsend(&buf);
764  pq_sendint8(&buf, version);
765  pq_sendtext(&buf, res, strlen(res));
766  pfree(res);
767 
769 }
static char * deparse_lquery(const lquery *in)
Definition: ltree_io.c:613
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
Definition: ltree.h:100
void pq_sendtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:174
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
#define PG_GETARG_LQUERY_P(n)
Definition: ltree.h:209
void pfree(void *pointer)
Definition: mcxt.c:1057
static char * buf
Definition: pg_test_fsync.c:68
static void pq_sendint8(StringInfo buf, uint8 i)
Definition: pqformat.h:129

◆ ltree_in()

Datum ltree_in ( PG_FUNCTION_ARGS  )

Definition at line 172 of file ltree_io.c.

References buf, ltree_out(), parse_ltree(), PG_FUNCTION_INFO_V1(), PG_GETARG_POINTER, and PG_RETURN_POINTER.

Referenced by deparse_ltree(), ltree_addtext(), ltree_textadd(), and text2ltree().

173 {
174  char *buf = (char *) PG_GETARG_POINTER(0);
175 
177 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
static char * buf
Definition: pg_test_fsync.c:68
static ltree * parse_ltree(const char *buf)
Definition: ltree_io.c:36

◆ ltree_out()

Datum ltree_out ( PG_FUNCTION_ARGS  )

Definition at line 181 of file ltree_io.c.

References deparse_ltree(), ltree_send(), PG_FUNCTION_INFO_V1(), PG_GETARG_LTREE_P, and PG_RETURN_POINTER.

Referenced by ltree_in().

182 {
183  ltree *in = PG_GETARG_LTREE_P(0);
184 
186 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:204
static char * deparse_ltree(const ltree *in)
Definition: ltree_io.c:142
Definition: ltree.h:29

◆ ltree_recv()

Datum ltree_recv ( PG_FUNCTION_ARGS  )

Definition at line 223 of file ltree_io.c.

References buf, StringInfoData::cursor, elog, ERROR, StringInfoData::len, parse_ltree(), pfree(), PG_GETARG_POINTER, PG_RETURN_POINTER, pq_getmsgint(), pq_getmsgtext(), and generate_unaccent_rules::str.

Referenced by ltree_send().

224 {
226  int version = pq_getmsgint(buf, 1);
227  char *str;
228  int nbytes;
229  ltree *res;
230 
231  if (version != 1)
232  elog(ERROR, "unsupported ltree version number %d", version);
233 
234  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
235  res = parse_ltree(str);
236  pfree(str);
237 
238  PG_RETURN_POINTER(res);
239 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
StringInfoData * StringInfo
Definition: stringinfo.h:44
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:68
Definition: ltree.h:29
char * pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
Definition: pqformat.c:548
static ltree * parse_ltree(const char *buf)
Definition: ltree_io.c:36
#define elog(elevel,...)
Definition: elog.h:228
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417

◆ ltree_send()

Datum ltree_send ( PG_FUNCTION_ARGS  )

Definition at line 198 of file ltree_io.c.

References buf, deparse_ltree(), ltree_recv(), pfree(), PG_FUNCTION_INFO_V1(), PG_GETARG_LTREE_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint8(), and pq_sendtext().

Referenced by ltree_out().

199 {
200  ltree *in = PG_GETARG_LTREE_P(0);
202  int version = 1;
203  char *res = deparse_ltree(in);
204 
205  pq_begintypsend(&buf);
206  pq_sendint8(&buf, version);
207  pq_sendtext(&buf, res, strlen(res));
208  pfree(res);
209 
211 }
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
void pq_sendtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:174
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:204
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
void pfree(void *pointer)
Definition: mcxt.c:1057
static char * buf
Definition: pg_test_fsync.c:68
static char * deparse_ltree(const ltree *in)
Definition: ltree_io.c:142
Definition: ltree.h:29
static void pq_sendint8(StringInfo buf, uint8 i)
Definition: pqformat.h:129

◆ parse_lquery()

static lquery* parse_lquery ( const char *  buf)
static

Definition at line 262 of file ltree_io.c.

References buf, cur, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, finish_nodeitem(), lquery::firstgood, nodeitem::flag, lquery_variant::flag, lquery_level::flag, lquery::flag, GETVAR, lquery_level::high, ISALNUM, ITEMSIZE, nodeitem::len, lquery_variant::len, lquery_level::low, LQL_COUNT, LQL_FIRST, LQL_HDRSIZE, LQL_NEXT, LQL_NOT, LQPRS_WAITCLOSE, LQPRS_WAITDELIM, LQPRS_WAITEND, LQPRS_WAITFNUM, LQPRS_WAITLEVEL, LQPRS_WAITND, LQPRS_WAITOPEN, LQPRS_WAITSNUM, LQPRS_WAITVAR, LQUERY_FIRST, LQUERY_HASNOT, LQUERY_HDRSIZE, LQUERY_MAX_LEVELS, ltree_crc32_sz(), LTREE_MAX_LEVELS, LVAR_ANYEND, LVAR_HDRSIZE, LVAR_INCASE, LVAR_NEXT, LVAR_SUBLEXEME, MAXALIGN, lquery_variant::name, NEXTLEV, lquery::numlevel, lquery_level::numvar, palloc0(), pfree(), pg_mblen(), SET_VARSIZE, nodeitem::start, t_isdigit(), t_iseq, lquery_level::totallen, UNCHAR, lquery_variant::val, and nodeitem::wlen.

Referenced by lquery_in(), and lquery_recv().

263 {
264  const char *ptr;
265  int num = 0,
266  totallen = 0,
267  numOR = 0;
268  int state = LQPRS_WAITLEVEL;
269  lquery *result;
270  nodeitem *lptr = NULL;
271  lquery_level *cur,
272  *curqlevel,
273  *tmpql;
274  lquery_variant *lrptr = NULL;
275  bool hasnot = false;
276  bool wasbad = false;
277  int charlen;
278  int pos = 1; /* character position for error messages */
279 
280 #define UNCHAR ereport(ERROR, \
281  errcode(ERRCODE_SYNTAX_ERROR), \
282  errmsg("lquery syntax error at character %d", \
283  pos))
284 
285  ptr = buf;
286  while (*ptr)
287  {
288  charlen = pg_mblen(ptr);
289 
290  if (t_iseq(ptr, '.'))
291  num++;
292  else if (t_iseq(ptr, '|'))
293  numOR++;
294 
295  ptr += charlen;
296  }
297 
298  num++;
299  if (num > LQUERY_MAX_LEVELS)
300  ereport(ERROR,
301  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
302  errmsg("number of lquery items (%d) exceeds the maximum allowed (%d)",
303  num, LQUERY_MAX_LEVELS)));
304  curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
305  ptr = buf;
306  while (*ptr)
307  {
308  charlen = pg_mblen(ptr);
309 
310  switch (state)
311  {
312  case LQPRS_WAITLEVEL:
313  if (ISALNUM(ptr))
314  {
315  GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
316  lptr->start = ptr;
317  state = LQPRS_WAITDELIM;
318  curqlevel->numvar = 1;
319  }
320  else if (t_iseq(ptr, '!'))
321  {
322  GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
323  lptr->start = ptr + 1;
324  lptr->wlen = -1; /* compensate for counting ! below */
325  state = LQPRS_WAITDELIM;
326  curqlevel->numvar = 1;
327  curqlevel->flag |= LQL_NOT;
328  hasnot = true;
329  }
330  else if (t_iseq(ptr, '*'))
331  state = LQPRS_WAITOPEN;
332  else
333  UNCHAR;
334  break;
335  case LQPRS_WAITVAR:
336  if (ISALNUM(ptr))
337  {
338  lptr++;
339  lptr->start = ptr;
340  state = LQPRS_WAITDELIM;
341  curqlevel->numvar++;
342  }
343  else
344  UNCHAR;
345  break;
346  case LQPRS_WAITDELIM:
347  if (t_iseq(ptr, '@'))
348  {
349  lptr->flag |= LVAR_INCASE;
350  curqlevel->flag |= LVAR_INCASE;
351  }
352  else if (t_iseq(ptr, '*'))
353  {
354  lptr->flag |= LVAR_ANYEND;
355  curqlevel->flag |= LVAR_ANYEND;
356  }
357  else if (t_iseq(ptr, '%'))
358  {
359  lptr->flag |= LVAR_SUBLEXEME;
360  curqlevel->flag |= LVAR_SUBLEXEME;
361  }
362  else if (t_iseq(ptr, '|'))
363  {
364  finish_nodeitem(lptr, ptr, true, pos);
365  state = LQPRS_WAITVAR;
366  }
367  else if (t_iseq(ptr, '{'))
368  {
369  finish_nodeitem(lptr, ptr, true, pos);
370  curqlevel->flag |= LQL_COUNT;
371  state = LQPRS_WAITFNUM;
372  }
373  else if (t_iseq(ptr, '.'))
374  {
375  finish_nodeitem(lptr, ptr, true, pos);
376  state = LQPRS_WAITLEVEL;
377  curqlevel = NEXTLEV(curqlevel);
378  }
379  else if (ISALNUM(ptr))
380  {
381  /* disallow more chars after a flag */
382  if (lptr->flag)
383  UNCHAR;
384  }
385  else
386  UNCHAR;
387  break;
388  case LQPRS_WAITOPEN:
389  if (t_iseq(ptr, '{'))
390  state = LQPRS_WAITFNUM;
391  else if (t_iseq(ptr, '.'))
392  {
393  /* We only get here for '*', so these are correct defaults */
394  curqlevel->low = 0;
395  curqlevel->high = LTREE_MAX_LEVELS;
396  curqlevel = NEXTLEV(curqlevel);
397  state = LQPRS_WAITLEVEL;
398  }
399  else
400  UNCHAR;
401  break;
402  case LQPRS_WAITFNUM:
403  if (t_iseq(ptr, ','))
404  state = LQPRS_WAITSNUM;
405  else if (t_isdigit(ptr))
406  {
407  int low = atoi(ptr);
408 
409  if (low < 0 || low > LTREE_MAX_LEVELS)
410  ereport(ERROR,
411  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
412  errmsg("lquery syntax error"),
413  errdetail("Low limit (%d) exceeds the maximum allowed (%d), at character %d.",
414  low, LTREE_MAX_LEVELS, pos)));
415 
416  curqlevel->low = (uint16) low;
417  state = LQPRS_WAITND;
418  }
419  else
420  UNCHAR;
421  break;
422  case LQPRS_WAITSNUM:
423  if (t_isdigit(ptr))
424  {
425  int high = atoi(ptr);
426 
427  if (high < 0 || high > LTREE_MAX_LEVELS)
428  ereport(ERROR,
429  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
430  errmsg("lquery syntax error"),
431  errdetail("High limit (%d) exceeds the maximum allowed (%d), at character %d.",
432  high, LTREE_MAX_LEVELS, pos)));
433  else if (curqlevel->low > high)
434  ereport(ERROR,
435  (errcode(ERRCODE_SYNTAX_ERROR),
436  errmsg("lquery syntax error"),
437  errdetail("Low limit (%d) is greater than high limit (%d), at character %d.",
438  curqlevel->low, high, pos)));
439 
440  curqlevel->high = (uint16) high;
441  state = LQPRS_WAITCLOSE;
442  }
443  else if (t_iseq(ptr, '}'))
444  {
445  curqlevel->high = LTREE_MAX_LEVELS;
446  state = LQPRS_WAITEND;
447  }
448  else
449  UNCHAR;
450  break;
451  case LQPRS_WAITCLOSE:
452  if (t_iseq(ptr, '}'))
453  state = LQPRS_WAITEND;
454  else if (!t_isdigit(ptr))
455  UNCHAR;
456  break;
457  case LQPRS_WAITND:
458  if (t_iseq(ptr, '}'))
459  {
460  curqlevel->high = curqlevel->low;
461  state = LQPRS_WAITEND;
462  }
463  else if (t_iseq(ptr, ','))
464  state = LQPRS_WAITSNUM;
465  else if (!t_isdigit(ptr))
466  UNCHAR;
467  break;
468  case LQPRS_WAITEND:
469  if (t_iseq(ptr, '.'))
470  {
471  state = LQPRS_WAITLEVEL;
472  curqlevel = NEXTLEV(curqlevel);
473  }
474  else
475  UNCHAR;
476  break;
477  default:
478  elog(ERROR, "internal error in lquery parser");
479  }
480 
481  ptr += charlen;
482  if (state == LQPRS_WAITDELIM)
483  lptr->wlen++;
484  pos++;
485  }
486 
487  if (state == LQPRS_WAITDELIM)
488  finish_nodeitem(lptr, ptr, true, pos);
489  else if (state == LQPRS_WAITOPEN)
490  curqlevel->high = LTREE_MAX_LEVELS;
491  else if (state != LQPRS_WAITEND)
492  ereport(ERROR,
493  (errcode(ERRCODE_SYNTAX_ERROR),
494  errmsg("lquery syntax error"),
495  errdetail("Unexpected end of input.")));
496 
497  curqlevel = tmpql;
498  totallen = LQUERY_HDRSIZE;
499  while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
500  {
501  totallen += LQL_HDRSIZE;
502  if (curqlevel->numvar)
503  {
504  lptr = GETVAR(curqlevel);
505  while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
506  {
507  totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
508  lptr++;
509  }
510  }
511  curqlevel = NEXTLEV(curqlevel);
512  }
513 
514  result = (lquery *) palloc0(totallen);
515  SET_VARSIZE(result, totallen);
516  result->numlevel = num;
517  result->firstgood = 0;
518  result->flag = 0;
519  if (hasnot)
520  result->flag |= LQUERY_HASNOT;
521  cur = LQUERY_FIRST(result);
522  curqlevel = tmpql;
523  while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
524  {
525  memcpy(cur, curqlevel, LQL_HDRSIZE);
526  cur->totallen = LQL_HDRSIZE;
527  if (curqlevel->numvar)
528  {
529  lrptr = LQL_FIRST(cur);
530  lptr = GETVAR(curqlevel);
531  while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
532  {
533  cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
534  lrptr->len = lptr->len;
535  lrptr->flag = lptr->flag;
536  lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
537  memcpy(lrptr->name, lptr->start, lptr->len);
538  lptr++;
539  lrptr = LVAR_NEXT(lrptr);
540  }
541  pfree(GETVAR(curqlevel));
542  if (cur->numvar > 1 || cur->flag != 0)
543  {
544  /* Not a simple match */
545  wasbad = true;
546  }
547  else if (wasbad == false)
548  {
549  /* count leading simple matches */
550  (result->firstgood)++;
551  }
552  }
553  else
554  {
555  /* '*', so this isn't a simple match */
556  wasbad = true;
557  }
558  curqlevel = NEXTLEV(curqlevel);
559  cur = LQL_NEXT(cur);
560  }
561 
562  pfree(tmpql);
563  return result;
564 
565 #undef UNCHAR
566 }
uint16 firstgood
Definition: ltree.h:104
#define GETVAR(x)
Definition: ltree_io.c:253
#define LVAR_INCASE
Definition: ltree.h:62
uint8 flag
Definition: ltree.h:49
#define LQPRS_WAITVAR
Definition: ltree_io.c:250
#define LQPRS_WAITFNUM
Definition: ltree_io.c:245
unsigned int ltree_crc32_sz(const char *buf, int size)
Definition: crc32.c:23
uint16 low
Definition: ltree.h:80
#define LQUERY_FIRST(x)
Definition: ltree.h:111
uint16 len
Definition: ltree.h:48
#define ISALNUM(x)
Definition: ltree.h:116
#define LVAR_ANYEND
Definition: ltree.h:61
#define LQPRS_WAITCLOSE
Definition: ltree_io.c:248
#define LQPRS_WAITOPEN
Definition: ltree_io.c:244
int len
Definition: ltree_io.c:19
#define NEXTLEV(x)
Definition: ltree_io.c:255
int wlen
Definition: ltree_io.c:21
Definition: ltree.h:100
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:50
#define LQL_FIRST(x)
Definition: ltree.h:88
#define LQL_NEXT(x)
Definition: ltree.h:87
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:691
uint16 flag
Definition: ltree.h:105
uint16 totallen
Definition: ltree.h:77
#define LQPRS_WAITND
Definition: ltree_io.c:247
#define LVAR_NEXT(x)
Definition: ltree.h:59
int flag
Definition: ltree_io.c:20
int t_isdigit(const char *ptr)
Definition: ts_locale.c:37
unsigned short uint16
Definition: c.h:428
void pfree(void *pointer)
Definition: mcxt.c:1057
uint16 flag
Definition: ltree.h:78
#define ERROR
Definition: elog.h:43
#define LQUERY_MAX_LEVELS
Definition: ltree.h:112
#define LQL_COUNT
Definition: ltree.h:91
#define LQPRS_WAITDELIM
Definition: ltree_io.c:243
#define LQL_NOT
Definition: ltree.h:90
static char * buf
Definition: pg_test_fsync.c:68
#define t_iseq(x, c)
Definition: ts_locale.h:46
#define UNCHAR
int errdetail(const char *fmt,...)
Definition: elog.c:1035
#define LQPRS_WAITSNUM
Definition: ltree_io.c:246
const char * start
Definition: ltree_io.c:18
#define LQUERY_HDRSIZE
Definition: ltree.h:110
void * palloc0(Size size)
Definition: mcxt.c:981
#define ITEMSIZE
Definition: ltree_io.c:254
#define LQPRS_WAITLEVEL
Definition: ltree_io.c:242
#define ereport(elevel,...)
Definition: elog.h:155
int32 val
Definition: ltree.h:47
#define LQPRS_WAITEND
Definition: ltree_io.c:249
uint16 numlevel
Definition: ltree.h:103
Definition: regguts.h:298
#define LVAR_SUBLEXEME
Definition: ltree.h:63
uint16 numvar
Definition: ltree.h:79
#define MAXALIGN(LEN)
Definition: c.h:753
int pg_mblen(const char *mbstr)
Definition: mbutils.c:907
#define LVAR_HDRSIZE
Definition: ltree.h:58
int errmsg(const char *fmt,...)
Definition: elog.c:902
#define elog(elevel,...)
Definition: elog.h:228
#define LQUERY_HASNOT
Definition: ltree.h:114
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define LTREE_MAX_LEVELS
Definition: ltree.h:39
static void finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos)
Definition: ltree_io.c:573
#define LQL_HDRSIZE
Definition: ltree.h:86
uint16 high
Definition: ltree.h:81

◆ parse_ltree()

static ltree* parse_ltree ( const char *  buf)
static

Definition at line 36 of file ltree_io.c.

References buf, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, finish_nodeitem(), ISALNUM, nodeitem::len, ltree_level::len, LEVEL_HDRSIZE, LEVEL_NEXT, sort-test::list, LTPRS_WAITDELIM, LTPRS_WAITNAME, LTREE_FIRST, LTREE_HDRSIZE, LTREE_MAX_LEVELS, MAXALIGN, ltree_level::name, ltree::numlevel, palloc(), palloc0(), pfree(), pg_mblen(), SET_VARSIZE, nodeitem::start, t_iseq, UNCHAR, and nodeitem::wlen.

Referenced by ltree_in(), and ltree_recv().

37 {
38  const char *ptr;
39  nodeitem *list,
40  *lptr;
41  int num = 0,
42  totallen = 0;
43  int state = LTPRS_WAITNAME;
44  ltree *result;
45  ltree_level *curlevel;
46  int charlen;
47  int pos = 1; /* character position for error messages */
48 
49 #define UNCHAR ereport(ERROR, \
50  errcode(ERRCODE_SYNTAX_ERROR), \
51  errmsg("ltree syntax error at character %d", \
52  pos))
53 
54  ptr = buf;
55  while (*ptr)
56  {
57  charlen = pg_mblen(ptr);
58  if (t_iseq(ptr, '.'))
59  num++;
60  ptr += charlen;
61  }
62 
63  if (num + 1 > LTREE_MAX_LEVELS)
64  ereport(ERROR,
65  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
66  errmsg("number of ltree labels (%d) exceeds the maximum allowed (%d)",
67  num + 1, LTREE_MAX_LEVELS)));
68  list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
69  ptr = buf;
70  while (*ptr)
71  {
72  charlen = pg_mblen(ptr);
73 
74  switch (state)
75  {
76  case LTPRS_WAITNAME:
77  if (ISALNUM(ptr))
78  {
79  lptr->start = ptr;
80  lptr->wlen = 0;
81  state = LTPRS_WAITDELIM;
82  }
83  else
84  UNCHAR;
85  break;
86  case LTPRS_WAITDELIM:
87  if (t_iseq(ptr, '.'))
88  {
89  finish_nodeitem(lptr, ptr, false, pos);
90  totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
91  lptr++;
92  state = LTPRS_WAITNAME;
93  }
94  else if (!ISALNUM(ptr))
95  UNCHAR;
96  break;
97  default:
98  elog(ERROR, "internal error in ltree parser");
99  }
100 
101  ptr += charlen;
102  lptr->wlen++;
103  pos++;
104  }
105 
106  if (state == LTPRS_WAITDELIM)
107  {
108  finish_nodeitem(lptr, ptr, false, pos);
109  totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
110  lptr++;
111  }
112  else if (!(state == LTPRS_WAITNAME && lptr == list))
113  ereport(ERROR,
114  (errcode(ERRCODE_SYNTAX_ERROR),
115  errmsg("ltree syntax error"),
116  errdetail("Unexpected end of input.")));
117 
118  result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
119  SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
120  result->numlevel = lptr - list;
121  curlevel = LTREE_FIRST(result);
122  lptr = list;
123  while (lptr - list < result->numlevel)
124  {
125  curlevel->len = (uint16) lptr->len;
126  memcpy(curlevel->name, lptr->start, lptr->len);
127  curlevel = LEVEL_NEXT(curlevel);
128  lptr++;
129  }
130 
131  pfree(list);
132  return result;
133 
134 #undef UNCHAR
135 }
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:23
#define ISALNUM(x)
Definition: ltree.h:116
uint16 len
Definition: ltree.h:22
int len
Definition: ltree_io.c:19
int wlen
Definition: ltree_io.c:21
#define LTREE_HDRSIZE
Definition: ltree.h:37
int errcode(int sqlerrcode)
Definition: elog.c:691
unsigned short uint16
Definition: c.h:428
void pfree(void *pointer)
Definition: mcxt.c:1057
#define ERROR
Definition: elog.h:43
#define LTPRS_WAITNAME
Definition: ltree_io.c:24
static char * buf
Definition: pg_test_fsync.c:68
#define t_iseq(x, c)
Definition: ts_locale.h:46
#define UNCHAR
int errdetail(const char *fmt,...)
Definition: elog.c:1035
#define LEVEL_NEXT(x)
Definition: ltree.h:27
Definition: ltree.h:29
const char * start
Definition: ltree_io.c:18
uint16 numlevel
Definition: ltree.h:32
void * palloc0(Size size)
Definition: mcxt.c:981
#define ereport(elevel,...)
Definition: elog.h:155
Definition: regguts.h:298
#define LTPRS_WAITDELIM
Definition: ltree_io.c:25
#define MAXALIGN(LEN)
Definition: c.h:753
int pg_mblen(const char *mbstr)
Definition: mbutils.c:907
void * palloc(Size size)
Definition: mcxt.c:950
int errmsg(const char *fmt,...)
Definition: elog.c:902
#define LTREE_FIRST(x)
Definition: ltree.h:38
#define elog(elevel,...)
Definition: elog.h:228
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define LTREE_MAX_LEVELS
Definition: ltree.h:39
static void finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos)
Definition: ltree_io.c:573
#define LEVEL_HDRSIZE
Definition: ltree.h:26

◆ PG_FUNCTION_INFO_V1() [1/8]

◆ PG_FUNCTION_INFO_V1() [2/8]

PG_FUNCTION_INFO_V1 ( ltree_out  )

◆ PG_FUNCTION_INFO_V1() [3/8]

PG_FUNCTION_INFO_V1 ( ltree_send  )

◆ PG_FUNCTION_INFO_V1() [4/8]

PG_FUNCTION_INFO_V1 ( ltree_recv  )

◆ PG_FUNCTION_INFO_V1() [5/8]

PG_FUNCTION_INFO_V1 ( lquery_in  )

◆ PG_FUNCTION_INFO_V1() [6/8]

PG_FUNCTION_INFO_V1 ( lquery_out  )

◆ PG_FUNCTION_INFO_V1() [7/8]

PG_FUNCTION_INFO_V1 ( lquery_send  )

◆ PG_FUNCTION_INFO_V1() [8/8]

PG_FUNCTION_INFO_V1 ( lquery_recv  )