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 "varatt.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 bool finish_nodeitem (nodeitem *lptr, const char *ptr, bool is_lquery, int pos, struct Node *escontext)
 
static ltreeparse_ltree (const char *buf, struct Node *escontext)
 
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, struct Node *escontext)
 
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 260 of file ltree_io.c.

◆ ITEMSIZE

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

Definition at line 261 of file ltree_io.c.

◆ LQPRS_WAITCLOSE

#define LQPRS_WAITCLOSE   6

Definition at line 255 of file ltree_io.c.

◆ LQPRS_WAITDELIM

#define LQPRS_WAITDELIM   1

Definition at line 250 of file ltree_io.c.

◆ LQPRS_WAITEND

#define LQPRS_WAITEND   7

Definition at line 256 of file ltree_io.c.

◆ LQPRS_WAITFNUM

#define LQPRS_WAITFNUM   3

Definition at line 252 of file ltree_io.c.

◆ LQPRS_WAITLEVEL

#define LQPRS_WAITLEVEL   0

Definition at line 249 of file ltree_io.c.

◆ LQPRS_WAITND

#define LQPRS_WAITND   5

Definition at line 254 of file ltree_io.c.

◆ LQPRS_WAITOPEN

#define LQPRS_WAITOPEN   2

Definition at line 251 of file ltree_io.c.

◆ LQPRS_WAITSNUM

#define LQPRS_WAITSNUM   4

Definition at line 253 of file ltree_io.c.

◆ LQPRS_WAITVAR

#define LQPRS_WAITVAR   8

Definition at line 257 of file ltree_io.c.

◆ LTPRS_WAITDELIM

#define LTPRS_WAITDELIM   1

Definition at line 26 of file ltree_io.c.

◆ LTPRS_WAITNAME

#define LTPRS_WAITNAME   0

Definition at line 25 of file ltree_io.c.

◆ NEXTLEV

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

Definition at line 262 of file ltree_io.c.

◆ UNCHAR [1/2]

#define UNCHAR
Value:
ereturn(escontext, NULL,\
errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("ltree syntax error at character %d", \
pos))
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereturn(context, dummy_value,...)
Definition: elog.h:276

◆ UNCHAR [2/2]

#define UNCHAR
Value:
ereturn(escontext, NULL,\
errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("lquery syntax error at character %d", \
pos))

Function Documentation

◆ deparse_lquery()

static char* deparse_lquery ( const lquery in)
static

Definition at line 628 of file ltree_io.c.

629 {
630  char *buf,
631  *ptr;
632  int i,
633  j,
634  totallen = 1;
635  lquery_level *curqlevel;
636  lquery_variant *curtlevel;
637 
638  curqlevel = LQUERY_FIRST(in);
639  for (i = 0; i < in->numlevel; i++)
640  {
641  totallen++;
642  if (curqlevel->numvar)
643  {
644  totallen += 1 + (curqlevel->numvar * 4) + curqlevel->totallen;
645  if (curqlevel->flag & LQL_COUNT)
646  totallen += 2 * 11 + 3;
647  }
648  else
649  totallen += 2 * 11 + 4;
650  curqlevel = LQL_NEXT(curqlevel);
651  }
652 
653  ptr = buf = (char *) palloc(totallen);
654  curqlevel = LQUERY_FIRST(in);
655  for (i = 0; i < in->numlevel; i++)
656  {
657  if (i != 0)
658  {
659  *ptr = '.';
660  ptr++;
661  }
662  if (curqlevel->numvar)
663  {
664  if (curqlevel->flag & LQL_NOT)
665  {
666  *ptr = '!';
667  ptr++;
668  }
669  curtlevel = LQL_FIRST(curqlevel);
670  for (j = 0; j < curqlevel->numvar; j++)
671  {
672  if (j != 0)
673  {
674  *ptr = '|';
675  ptr++;
676  }
677  memcpy(ptr, curtlevel->name, curtlevel->len);
678  ptr += curtlevel->len;
679  if ((curtlevel->flag & LVAR_SUBLEXEME))
680  {
681  *ptr = '%';
682  ptr++;
683  }
684  if ((curtlevel->flag & LVAR_INCASE))
685  {
686  *ptr = '@';
687  ptr++;
688  }
689  if ((curtlevel->flag & LVAR_ANYEND))
690  {
691  *ptr = '*';
692  ptr++;
693  }
694  curtlevel = LVAR_NEXT(curtlevel);
695  }
696  }
697  else
698  {
699  *ptr = '*';
700  ptr++;
701  }
702 
703  if ((curqlevel->flag & LQL_COUNT) || curqlevel->numvar == 0)
704  {
705  if (curqlevel->low == curqlevel->high)
706  {
707  sprintf(ptr, "{%d}", curqlevel->low);
708  }
709  else if (curqlevel->low == 0)
710  {
711  if (curqlevel->high == LTREE_MAX_LEVELS)
712  {
713  if (curqlevel->numvar == 0)
714  {
715  /* This is default for '*', so print nothing */
716  *ptr = '\0';
717  }
718  else
719  sprintf(ptr, "{,}");
720  }
721  else
722  sprintf(ptr, "{,%d}", curqlevel->high);
723  }
724  else if (curqlevel->high == LTREE_MAX_LEVELS)
725  {
726  sprintf(ptr, "{%d,}", curqlevel->low);
727  }
728  else
729  sprintf(ptr, "{%d,%d}", curqlevel->low, curqlevel->high);
730  ptr = strchr(ptr, '\0');
731  }
732 
733  curqlevel = LQL_NEXT(curqlevel);
734  }
735 
736  *ptr = '\0';
737  return buf;
738 }
int j
Definition: isn.c:74
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define LTREE_MAX_LEVELS
Definition: ltree.h:52
#define LVAR_INCASE
Definition: ltree.h:75
#define LVAR_ANYEND
Definition: ltree.h:74
#define LQL_FIRST(x)
Definition: ltree.h:101
#define LVAR_NEXT(x)
Definition: ltree.h:72
#define LQL_NEXT(x)
Definition: ltree.h:100
#define LQL_COUNT
Definition: ltree.h:104
#define LQUERY_FIRST(x)
Definition: ltree.h:124
#define LQL_NOT
Definition: ltree.h:103
#define LVAR_SUBLEXEME
Definition: ltree.h:76
void * palloc(Size size)
Definition: mcxt.c:1316
static char * buf
Definition: pg_test_fsync.c:73
#define sprintf
Definition: port.h:240
uint16 numvar
Definition: ltree.h:92
uint16 high
Definition: ltree.h:94
uint16 flag
Definition: ltree.h:91
uint16 low
Definition: ltree.h:93
uint16 totallen
Definition: ltree.h:90
uint8 flag
Definition: ltree.h:62
uint16 len
Definition: ltree.h:61
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:63
uint16 numlevel
Definition: ltree.h:116

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

Referenced by lquery_out(), and lquery_send().

◆ deparse_ltree()

static char* deparse_ltree ( const ltree in)
static

Definition at line 145 of file ltree_io.c.

146 {
147  char *buf,
148  *ptr;
149  int i;
150  ltree_level *curlevel;
151 
152  ptr = buf = (char *) palloc(VARSIZE(in));
153  curlevel = LTREE_FIRST(in);
154  for (i = 0; i < in->numlevel; i++)
155  {
156  if (i != 0)
157  {
158  *ptr = '.';
159  ptr++;
160  }
161  memcpy(ptr, curlevel->name, curlevel->len);
162  ptr += curlevel->len;
163  curlevel = LEVEL_NEXT(curlevel);
164  }
165 
166  *ptr = '\0';
167  return buf;
168 }
#define LTREE_FIRST(x)
Definition: ltree.h:51
#define LEVEL_NEXT(x)
Definition: ltree.h:40
char name[FLEXIBLE_ARRAY_MEMBER]
Definition: ltree.h:36
uint16 len
Definition: ltree.h:35
uint16 numlevel
Definition: ltree.h:45
#define VARSIZE(PTR)
Definition: varatt.h:279

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

Referenced by ltree_out(), and ltree_send().

◆ finish_nodeitem()

static bool finish_nodeitem ( nodeitem lptr,
const char *  ptr,
bool  is_lquery,
int  pos,
struct Node escontext 
)
static

Definition at line 586 of file ltree_io.c.

588 {
589  if (is_lquery)
590  {
591  /*
592  * Back up over any flag characters, and discount them from length and
593  * position.
594  */
595  while (ptr > lptr->start && strchr("@*%", ptr[-1]) != NULL)
596  {
597  ptr--;
598  lptr->wlen--;
599  pos--;
600  }
601  }
602 
603  /* Now compute the byte length, which we weren't tracking before. */
604  lptr->len = ptr - lptr->start;
605 
606  /* Complain if it's empty or too long */
607  if (lptr->len == 0)
608  ereturn(escontext, false,
609  (errcode(ERRCODE_SYNTAX_ERROR),
610  is_lquery ?
611  errmsg("lquery syntax error at character %d", pos) :
612  errmsg("ltree syntax error at character %d", pos),
613  errdetail("Empty labels are not allowed.")));
614  if (lptr->wlen > LTREE_LABEL_MAX_CHARS)
615  ereturn(escontext, false,
616  (errcode(ERRCODE_NAME_TOO_LONG),
617  errmsg("label string is too long"),
618  errdetail("Label length is %d, must be at most %d, at character %d.",
619  lptr->wlen, LTREE_LABEL_MAX_CHARS, pos)));
620  return true;
621 }
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define LTREE_LABEL_MAX_CHARS
Definition: ltree.h:18
int wlen
Definition: ltree_io.c:22
const char * start
Definition: ltree_io.c:19
int len
Definition: ltree_io.c:20

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

Referenced by parse_lquery(), and parse_ltree().

◆ lquery_in()

Datum lquery_in ( PG_FUNCTION_ARGS  )

Definition at line 745 of file ltree_io.c.

746 {
747  char *buf = (char *) PG_GETARG_POINTER(0);
748  lquery *res;
749 
750  if ((res = parse_lquery(buf, fcinfo->context)) == NULL)
751  PG_RETURN_NULL();
752 
754 }
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
static lquery * parse_lquery(const char *buf, struct Node *escontext)
Definition: ltree_io.c:269
Definition: ltree.h:114

References buf, parse_lquery(), PG_GETARG_POINTER, PG_RETURN_NULL, PG_RETURN_POINTER, and res.

◆ lquery_out()

Datum lquery_out ( PG_FUNCTION_ARGS  )

Definition at line 758 of file ltree_io.c.

759 {
760  lquery *in = PG_GETARG_LQUERY_P(0);
761 
763 }
#define PG_GETARG_LQUERY_P(n)
Definition: ltree.h:223
static char * deparse_lquery(const lquery *in)
Definition: ltree_io.c:628

References deparse_lquery(), PG_GETARG_LQUERY_P, and PG_RETURN_POINTER.

◆ lquery_recv()

Datum lquery_recv ( PG_FUNCTION_ARGS  )

Definition at line 800 of file ltree_io.c.

801 {
803  int version = pq_getmsgint(buf, 1);
804  char *str;
805  int nbytes;
806  lquery *res;
807 
808  if (version != 1)
809  elog(ERROR, "unsupported lquery version number %d", version);
810 
811  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
812  res = parse_lquery(str, NULL);
813  pfree(str);
814 
816 }
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
const char * str
void pfree(void *pointer)
Definition: mcxt.c:1520
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
char * pq_getmsgtext(StringInfo msg, int rawbytes, int *nbytes)
Definition: pqformat.c:546
StringInfoData * StringInfo
Definition: stringinfo.h:54

References buf, elog, ERROR, parse_lquery(), pfree(), PG_GETARG_POINTER, PG_RETURN_POINTER, pq_getmsgint(), pq_getmsgtext(), res, and str.

◆ lquery_send()

Datum lquery_send ( PG_FUNCTION_ARGS  )

Definition at line 775 of file ltree_io.c.

776 {
777  lquery *in = PG_GETARG_LQUERY_P(0);
779  int version = 1;
780  char *res = deparse_lquery(in);
781 
783  pq_sendint8(&buf, version);
784  pq_sendtext(&buf, res, strlen(res));
785  pfree(res);
786 
788 }
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
void pq_sendtext(StringInfo buf, const char *str, int slen)
Definition: pqformat.c:172
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint8(StringInfo buf, uint8 i)
Definition: pqformat.h:128

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

◆ ltree_in()

Datum ltree_in ( PG_FUNCTION_ARGS  )

Definition at line 175 of file ltree_io.c.

176 {
177  char *buf = (char *) PG_GETARG_POINTER(0);
178  ltree *res;
179 
180  if ((res = parse_ltree(buf, fcinfo->context)) == NULL)
181  PG_RETURN_NULL();
182 
184 }
static ltree * parse_ltree(const char *buf, struct Node *escontext)
Definition: ltree_io.c:37
Definition: ltree.h:43

References buf, parse_ltree(), PG_GETARG_POINTER, PG_RETURN_NULL, PG_RETURN_POINTER, and res.

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

◆ ltree_out()

Datum ltree_out ( PG_FUNCTION_ARGS  )

Definition at line 188 of file ltree_io.c.

189 {
190  ltree *in = PG_GETARG_LTREE_P(0);
191 
193 }
#define PG_GETARG_LTREE_P(n)
Definition: ltree.h:218
static char * deparse_ltree(const ltree *in)
Definition: ltree_io.c:145

References deparse_ltree(), PG_GETARG_LTREE_P, and PG_RETURN_POINTER.

◆ ltree_recv()

Datum ltree_recv ( PG_FUNCTION_ARGS  )

Definition at line 230 of file ltree_io.c.

231 {
233  int version = pq_getmsgint(buf, 1);
234  char *str;
235  int nbytes;
236  ltree *res;
237 
238  if (version != 1)
239  elog(ERROR, "unsupported ltree version number %d", version);
240 
241  str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
242  res = parse_ltree(str, NULL);
243  pfree(str);
244 
246 }

References buf, elog, ERROR, parse_ltree(), pfree(), PG_GETARG_POINTER, PG_RETURN_POINTER, pq_getmsgint(), pq_getmsgtext(), res, and str.

◆ ltree_send()

Datum ltree_send ( PG_FUNCTION_ARGS  )

Definition at line 205 of file ltree_io.c.

206 {
207  ltree *in = PG_GETARG_LTREE_P(0);
209  int version = 1;
210  char *res = deparse_ltree(in);
211 
213  pq_sendint8(&buf, version);
214  pq_sendtext(&buf, res, strlen(res));
215  pfree(res);
216 
218 }

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

◆ parse_lquery()

static lquery* parse_lquery ( const char *  buf,
struct Node escontext 
)
static

Definition at line 269 of file ltree_io.c.

270 {
271  const char *ptr;
272  int num = 0,
273  totallen = 0,
274  numOR = 0;
275  int state = LQPRS_WAITLEVEL;
276  lquery *result;
277  nodeitem *lptr = NULL;
278  lquery_level *cur,
279  *curqlevel,
280  *tmpql;
281  lquery_variant *lrptr = NULL;
282  bool hasnot = false;
283  bool wasbad = false;
284  int charlen;
285  int pos = 1; /* character position for error messages */
286 
287 #define UNCHAR ereturn(escontext, NULL,\
288  errcode(ERRCODE_SYNTAX_ERROR), \
289  errmsg("lquery syntax error at character %d", \
290  pos))
291 
292  ptr = buf;
293  while (*ptr)
294  {
295  charlen = pg_mblen(ptr);
296 
297  if (t_iseq(ptr, '.'))
298  num++;
299  else if (t_iseq(ptr, '|'))
300  numOR++;
301 
302  ptr += charlen;
303  }
304 
305  num++;
306  if (num > LQUERY_MAX_LEVELS)
307  ereturn(escontext, NULL,
308  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
309  errmsg("number of lquery items (%d) exceeds the maximum allowed (%d)",
310  num, LQUERY_MAX_LEVELS)));
311  curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
312  ptr = buf;
313  while (*ptr)
314  {
315  charlen = pg_mblen(ptr);
316 
317  switch (state)
318  {
319  case LQPRS_WAITLEVEL:
320  if (ISLABEL(ptr))
321  {
322  GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
323  lptr->start = ptr;
325  curqlevel->numvar = 1;
326  }
327  else if (t_iseq(ptr, '!'))
328  {
329  GETVAR(curqlevel) = lptr = (nodeitem *) palloc0(sizeof(nodeitem) * (numOR + 1));
330  lptr->start = ptr + 1;
331  lptr->wlen = -1; /* compensate for counting ! below */
333  curqlevel->numvar = 1;
334  curqlevel->flag |= LQL_NOT;
335  hasnot = true;
336  }
337  else if (t_iseq(ptr, '*'))
339  else
340  UNCHAR;
341  break;
342  case LQPRS_WAITVAR:
343  if (ISLABEL(ptr))
344  {
345  lptr++;
346  lptr->start = ptr;
348  curqlevel->numvar++;
349  }
350  else
351  UNCHAR;
352  break;
353  case LQPRS_WAITDELIM:
354  if (t_iseq(ptr, '@'))
355  {
356  lptr->flag |= LVAR_INCASE;
357  curqlevel->flag |= LVAR_INCASE;
358  }
359  else if (t_iseq(ptr, '*'))
360  {
361  lptr->flag |= LVAR_ANYEND;
362  curqlevel->flag |= LVAR_ANYEND;
363  }
364  else if (t_iseq(ptr, '%'))
365  {
366  lptr->flag |= LVAR_SUBLEXEME;
367  curqlevel->flag |= LVAR_SUBLEXEME;
368  }
369  else if (t_iseq(ptr, '|'))
370  {
371  if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
372  return NULL;
374  }
375  else if (t_iseq(ptr, '{'))
376  {
377  if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
378  return NULL;
379  curqlevel->flag |= LQL_COUNT;
381  }
382  else if (t_iseq(ptr, '.'))
383  {
384  if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
385  return NULL;
387  curqlevel = NEXTLEV(curqlevel);
388  }
389  else if (ISLABEL(ptr))
390  {
391  /* disallow more chars after a flag */
392  if (lptr->flag)
393  UNCHAR;
394  }
395  else
396  UNCHAR;
397  break;
398  case LQPRS_WAITOPEN:
399  if (t_iseq(ptr, '{'))
401  else if (t_iseq(ptr, '.'))
402  {
403  /* We only get here for '*', so these are correct defaults */
404  curqlevel->low = 0;
405  curqlevel->high = LTREE_MAX_LEVELS;
406  curqlevel = NEXTLEV(curqlevel);
408  }
409  else
410  UNCHAR;
411  break;
412  case LQPRS_WAITFNUM:
413  if (t_iseq(ptr, ','))
415  else if (t_isdigit(ptr))
416  {
417  int low = atoi(ptr);
418 
419  if (low < 0 || low > LTREE_MAX_LEVELS)
420  ereturn(escontext, NULL,
421  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
422  errmsg("lquery syntax error"),
423  errdetail("Low limit (%d) exceeds the maximum allowed (%d), at character %d.",
424  low, LTREE_MAX_LEVELS, pos)));
425 
426  curqlevel->low = (uint16) low;
428  }
429  else
430  UNCHAR;
431  break;
432  case LQPRS_WAITSNUM:
433  if (t_isdigit(ptr))
434  {
435  int high = atoi(ptr);
436 
437  if (high < 0 || high > LTREE_MAX_LEVELS)
438  ereturn(escontext, NULL,
439  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
440  errmsg("lquery syntax error"),
441  errdetail("High limit (%d) exceeds the maximum allowed (%d), at character %d.",
442  high, LTREE_MAX_LEVELS, pos)));
443  else if (curqlevel->low > high)
444  ereturn(escontext, NULL,
445  (errcode(ERRCODE_SYNTAX_ERROR),
446  errmsg("lquery syntax error"),
447  errdetail("Low limit (%d) is greater than high limit (%d), at character %d.",
448  curqlevel->low, high, pos)));
449 
450  curqlevel->high = (uint16) high;
452  }
453  else if (t_iseq(ptr, '}'))
454  {
455  curqlevel->high = LTREE_MAX_LEVELS;
457  }
458  else
459  UNCHAR;
460  break;
461  case LQPRS_WAITCLOSE:
462  if (t_iseq(ptr, '}'))
464  else if (!t_isdigit(ptr))
465  UNCHAR;
466  break;
467  case LQPRS_WAITND:
468  if (t_iseq(ptr, '}'))
469  {
470  curqlevel->high = curqlevel->low;
472  }
473  else if (t_iseq(ptr, ','))
475  else if (!t_isdigit(ptr))
476  UNCHAR;
477  break;
478  case LQPRS_WAITEND:
479  if (t_iseq(ptr, '.'))
480  {
482  curqlevel = NEXTLEV(curqlevel);
483  }
484  else
485  UNCHAR;
486  break;
487  default:
488  elog(ERROR, "internal error in lquery parser");
489  }
490 
491  ptr += charlen;
492  if (state == LQPRS_WAITDELIM)
493  lptr->wlen++;
494  pos++;
495  }
496 
497  if (state == LQPRS_WAITDELIM)
498  {
499  if (!finish_nodeitem(lptr, ptr, true, pos, escontext))
500  return NULL;
501  }
502  else if (state == LQPRS_WAITOPEN)
503  curqlevel->high = LTREE_MAX_LEVELS;
504  else if (state != LQPRS_WAITEND)
505  ereturn(escontext, NULL,
506  (errcode(ERRCODE_SYNTAX_ERROR),
507  errmsg("lquery syntax error"),
508  errdetail("Unexpected end of input.")));
509 
510  curqlevel = tmpql;
511  totallen = LQUERY_HDRSIZE;
512  while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
513  {
514  totallen += LQL_HDRSIZE;
515  if (curqlevel->numvar)
516  {
517  lptr = GETVAR(curqlevel);
518  while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
519  {
520  totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
521  lptr++;
522  }
523  }
524  curqlevel = NEXTLEV(curqlevel);
525  }
526 
527  result = (lquery *) palloc0(totallen);
528  SET_VARSIZE(result, totallen);
529  result->numlevel = num;
530  result->firstgood = 0;
531  result->flag = 0;
532  if (hasnot)
533  result->flag |= LQUERY_HASNOT;
534  cur = LQUERY_FIRST(result);
535  curqlevel = tmpql;
536  while ((char *) curqlevel - (char *) tmpql < num * ITEMSIZE)
537  {
538  memcpy(cur, curqlevel, LQL_HDRSIZE);
539  cur->totallen = LQL_HDRSIZE;
540  if (curqlevel->numvar)
541  {
542  lrptr = LQL_FIRST(cur);
543  lptr = GETVAR(curqlevel);
544  while (lptr - GETVAR(curqlevel) < curqlevel->numvar)
545  {
546  cur->totallen += MAXALIGN(LVAR_HDRSIZE + lptr->len);
547  lrptr->len = lptr->len;
548  lrptr->flag = lptr->flag;
549  lrptr->val = ltree_crc32_sz(lptr->start, lptr->len);
550  memcpy(lrptr->name, lptr->start, lptr->len);
551  lptr++;
552  lrptr = LVAR_NEXT(lrptr);
553  }
554  pfree(GETVAR(curqlevel));
555  if (cur->numvar > 1 || cur->flag != 0)
556  {
557  /* Not a simple match */
558  wasbad = true;
559  }
560  else if (wasbad == false)
561  {
562  /* count leading simple matches */
563  (result->firstgood)++;
564  }
565  }
566  else
567  {
568  /* '*', so this isn't a simple match */
569  wasbad = true;
570  }
571  curqlevel = NEXTLEV(curqlevel);
572  cur = LQL_NEXT(cur);
573  }
574 
575  pfree(tmpql);
576  return result;
577 
578 #undef UNCHAR
579 }
unsigned short uint16
Definition: c.h:505
#define MAXALIGN(LEN)
Definition: c.h:811
unsigned int ltree_crc32_sz(const char *buf, int size)
Definition: crc32.c:24
struct cursor * cur
Definition: ecpg.c:28
#define LQUERY_MAX_LEVELS
Definition: ltree.h:125
#define LQL_HDRSIZE
Definition: ltree.h:99
#define ISLABEL(x)
Definition: ltree.h:130
#define LQUERY_HDRSIZE
Definition: ltree.h:123
#define LQUERY_HASNOT
Definition: ltree.h:127
#define LVAR_HDRSIZE
Definition: ltree.h:71
#define LQPRS_WAITSNUM
Definition: ltree_io.c:253
#define ITEMSIZE
Definition: ltree_io.c:261
#define NEXTLEV(x)
Definition: ltree_io.c:262
#define LQPRS_WAITEND
Definition: ltree_io.c:256
#define LQPRS_WAITOPEN
Definition: ltree_io.c:251
#define LQPRS_WAITVAR
Definition: ltree_io.c:257
#define LQPRS_WAITFNUM
Definition: ltree_io.c:252
#define LQPRS_WAITCLOSE
Definition: ltree_io.c:255
#define LQPRS_WAITLEVEL
Definition: ltree_io.c:249
#define LQPRS_WAITDELIM
Definition: ltree_io.c:250
#define UNCHAR
static bool finish_nodeitem(nodeitem *lptr, const char *ptr, bool is_lquery, int pos, struct Node *escontext)
Definition: ltree_io.c:586
#define LQPRS_WAITND
Definition: ltree_io.c:254
#define GETVAR(x)
Definition: ltree_io.c:260
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1023
void * palloc0(Size size)
Definition: mcxt.c:1346
int32 val
Definition: ltree.h:60
uint16 firstgood
Definition: ltree.h:117
uint16 flag
Definition: ltree.h:118
int flag
Definition: ltree_io.c:21
Definition: regguts.h:323
int t_isdigit(const char *ptr)
Definition: ts_locale.c:35
#define t_iseq(x, c)
Definition: ts_locale.h:38
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305

References buf, cur, elog, ereturn, errcode(), errdetail(), errmsg(), ERROR, finish_nodeitem(), lquery::firstgood, lquery_variant::flag, lquery_level::flag, lquery::flag, nodeitem::flag, GETVAR, lquery_level::high, ISLABEL, ITEMSIZE, lquery_variant::len, nodeitem::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, UNCHAR, lquery_variant::val, and nodeitem::wlen.

Referenced by lquery_in(), and lquery_recv().

◆ parse_ltree()

static ltree* parse_ltree ( const char *  buf,
struct Node escontext 
)
static

Definition at line 37 of file ltree_io.c.

38 {
39  const char *ptr;
40  nodeitem *list,
41  *lptr;
42  int num = 0,
43  totallen = 0;
44  int state = LTPRS_WAITNAME;
45  ltree *result;
46  ltree_level *curlevel;
47  int charlen;
48  int pos = 1; /* character position for error messages */
49 
50 #define UNCHAR ereturn(escontext, NULL,\
51  errcode(ERRCODE_SYNTAX_ERROR), \
52  errmsg("ltree syntax error at character %d", \
53  pos))
54 
55  ptr = buf;
56  while (*ptr)
57  {
58  charlen = pg_mblen(ptr);
59  if (t_iseq(ptr, '.'))
60  num++;
61  ptr += charlen;
62  }
63 
64  if (num + 1 > LTREE_MAX_LEVELS)
65  ereturn(escontext, NULL,
66  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
67  errmsg("number of ltree labels (%d) exceeds the maximum allowed (%d)",
68  num + 1, LTREE_MAX_LEVELS)));
69  list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
70  ptr = buf;
71  while (*ptr)
72  {
73  charlen = pg_mblen(ptr);
74 
75  switch (state)
76  {
77  case LTPRS_WAITNAME:
78  if (ISLABEL(ptr))
79  {
80  lptr->start = ptr;
81  lptr->wlen = 0;
83  }
84  else
85  UNCHAR;
86  break;
87  case LTPRS_WAITDELIM:
88  if (t_iseq(ptr, '.'))
89  {
90  if (!finish_nodeitem(lptr, ptr, false, pos, escontext))
91  return NULL;
92  totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
93  lptr++;
95  }
96  else if (!ISLABEL(ptr))
97  UNCHAR;
98  break;
99  default:
100  elog(ERROR, "internal error in ltree parser");
101  }
102 
103  ptr += charlen;
104  lptr->wlen++;
105  pos++;
106  }
107 
108  if (state == LTPRS_WAITDELIM)
109  {
110  if (!finish_nodeitem(lptr, ptr, false, pos, escontext))
111  return NULL;
112  totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
113  lptr++;
114  }
115  else if (!(state == LTPRS_WAITNAME && lptr == list))
116  ereturn(escontext, NULL,
117  (errcode(ERRCODE_SYNTAX_ERROR),
118  errmsg("ltree syntax error"),
119  errdetail("Unexpected end of input.")));
120 
121  result = (ltree *) palloc0(LTREE_HDRSIZE + totallen);
122  SET_VARSIZE(result, LTREE_HDRSIZE + totallen);
123  result->numlevel = lptr - list;
124  curlevel = LTREE_FIRST(result);
125  lptr = list;
126  while (lptr - list < result->numlevel)
127  {
128  curlevel->len = (uint16) lptr->len;
129  memcpy(curlevel->name, lptr->start, lptr->len);
130  curlevel = LEVEL_NEXT(curlevel);
131  lptr++;
132  }
133 
134  pfree(list);
135  return result;
136 
137 #undef UNCHAR
138 }
#define LEVEL_HDRSIZE
Definition: ltree.h:39
#define LTREE_HDRSIZE
Definition: ltree.h:50
#define LTPRS_WAITDELIM
Definition: ltree_io.c:26
#define LTPRS_WAITNAME
Definition: ltree_io.c:25

References buf, elog, ereturn, errcode(), errdetail(), errmsg(), ERROR, finish_nodeitem(), ISLABEL, ltree_level::len, nodeitem::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().

◆ PG_FUNCTION_INFO_V1() [1/8]

PG_FUNCTION_INFO_V1 ( lquery_in  )

◆ PG_FUNCTION_INFO_V1() [2/8]

PG_FUNCTION_INFO_V1 ( lquery_out  )

◆ PG_FUNCTION_INFO_V1() [3/8]

PG_FUNCTION_INFO_V1 ( lquery_recv  )

◆ PG_FUNCTION_INFO_V1() [4/8]

PG_FUNCTION_INFO_V1 ( lquery_send  )

◆ PG_FUNCTION_INFO_V1() [5/8]

PG_FUNCTION_INFO_V1 ( ltree_in  )

◆ PG_FUNCTION_INFO_V1() [6/8]

PG_FUNCTION_INFO_V1 ( ltree_out  )

◆ PG_FUNCTION_INFO_V1() [7/8]

PG_FUNCTION_INFO_V1 ( ltree_recv  )

◆ PG_FUNCTION_INFO_V1() [8/8]

PG_FUNCTION_INFO_V1 ( ltree_send  )