PostgreSQL Source Code  git master
test_regex.c File Reference
#include "postgres.h"
#include "funcapi.h"
#include "regex/regex.h"
#include "utils/array.h"
#include "utils/builtins.h"
Include dependency graph for test_regex.c:

Go to the source code of this file.

Data Structures

struct  test_re_flags
 
struct  test_regex_ctx
 

Typedefs

typedef struct test_re_flags test_re_flags
 
typedef struct test_regex_ctx test_regex_ctx
 

Functions

static void test_re_compile (text *text_re, int cflags, Oid collation, regex_t *result_re)
 
static void parse_test_flags (test_re_flags *flags, text *opts)
 
static test_regex_ctxsetup_test_matches (text *orig_str, regex_t *cpattern, test_re_flags *re_flags, Oid collation, bool use_subpatterns)
 
static ArrayTypebuild_test_info_result (regex_t *cpattern, test_re_flags *flags)
 
static ArrayTypebuild_test_match_result (test_regex_ctx *matchctx)
 
 PG_FUNCTION_INFO_V1 (test_regex)
 
Datum test_regex (PG_FUNCTION_ARGS)
 
static bool test_re_execute (regex_t *re, pg_wchar *data, int data_len, int start_search, rm_detail_t *details, int nmatch, regmatch_t *pmatch, int eflags)
 

Variables

 PG_MODULE_MAGIC
 

Typedef Documentation

◆ test_re_flags

typedef struct test_re_flags test_re_flags

◆ test_regex_ctx

Function Documentation

◆ build_test_info_result()

static ArrayType * build_test_info_result ( regex_t cpattern,
test_re_flags flags 
)
static

Definition at line 617 of file test_regex.c.

618 {
619  /* Translation data for flag bits in regex_t.re_info */
620  struct infoname
621  {
622  int bit;
623  const char *text;
624  };
625  static const struct infoname infonames[] = {
626  {REG_UBACKREF, "REG_UBACKREF"},
627  {REG_ULOOKAROUND, "REG_ULOOKAROUND"},
628  {REG_UBOUNDS, "REG_UBOUNDS"},
629  {REG_UBRACES, "REG_UBRACES"},
630  {REG_UBSALNUM, "REG_UBSALNUM"},
631  {REG_UPBOTCH, "REG_UPBOTCH"},
632  {REG_UBBS, "REG_UBBS"},
633  {REG_UNONPOSIX, "REG_UNONPOSIX"},
634  {REG_UUNSPEC, "REG_UUNSPEC"},
635  {REG_UUNPORT, "REG_UUNPORT"},
636  {REG_ULOCALE, "REG_ULOCALE"},
637  {REG_UEMPTYMATCH, "REG_UEMPTYMATCH"},
638  {REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"},
639  {REG_USHORTEST, "REG_USHORTEST"},
640  {0, NULL}
641  };
642  const struct infoname *inf;
643  Datum elems[lengthof(infonames) + 1];
644  int nresults = 0;
645  char buf[80];
646  int dims[1];
647  int lbs[1];
648 
649  /* Set up results: first, the number of subexpressions */
650  snprintf(buf, sizeof(buf), "%d", (int) cpattern->re_nsub);
651  elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
652 
653  /* Report individual info bit states */
654  for (inf = infonames; inf->bit != 0; inf++)
655  {
656  if (cpattern->re_info & inf->bit)
657  {
658  if (flags->info & inf->bit)
659  elems[nresults++] = PointerGetDatum(cstring_to_text(inf->text));
660  else
661  {
662  snprintf(buf, sizeof(buf), "unexpected %s!", inf->text);
663  elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
664  }
665  }
666  else
667  {
668  if (flags->info & inf->bit)
669  {
670  snprintf(buf, sizeof(buf), "missing %s!", inf->text);
671  elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
672  }
673  }
674  }
675 
676  /* And form an array */
677  dims[0] = nresults;
678  lbs[0] = 1;
679  /* XXX: this hardcodes assumptions about the text type */
680  return construct_md_array(elems, NULL, 1, dims, lbs,
681  TEXTOID, -1, false, TYPALIGN_INT);
682 }
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3494
struct varlena text
Definition: c.h:691
#define lengthof(array)
Definition: c.h:779
static char * buf
Definition: pg_test_fsync.c:73
#define snprintf
Definition: port.h:238
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
#define REG_UEMPTYMATCH
Definition: regex.h:149
#define REG_UBOUNDS
Definition: regex.h:140
#define REG_UIMPOSSIBLE
Definition: regex.h:150
#define REG_UPBOTCH
Definition: regex.h:143
#define REG_ULOOKAROUND
Definition: regex.h:139
#define REG_UBBS
Definition: regex.h:144
#define REG_UUNSPEC
Definition: regex.h:146
#define REG_UNONPOSIX
Definition: regex.h:145
#define REG_UBSALNUM
Definition: regex.h:142
#define REG_USHORTEST
Definition: regex.h:151
#define REG_ULOCALE
Definition: regex.h:148
#define REG_UUNPORT
Definition: regex.h:147
#define REG_UBRACES
Definition: regex.h:141
#define REG_UBACKREF
Definition: regex.h:138
Datum bit(PG_FUNCTION_ARGS)
Definition: varbit.c:391
text * cstring_to_text(const char *s)
Definition: varlena.c:184

References bit(), buf, construct_md_array(), cstring_to_text(), test_re_flags::info, lengthof, PointerGetDatum(), REG_UBACKREF, REG_UBBS, REG_UBOUNDS, REG_UBRACES, REG_UBSALNUM, REG_UEMPTYMATCH, REG_UIMPOSSIBLE, REG_ULOCALE, REG_ULOOKAROUND, REG_UNONPOSIX, REG_UPBOTCH, REG_USHORTEST, REG_UUNPORT, REG_UUNSPEC, and snprintf.

Referenced by test_regex().

◆ build_test_match_result()

static ArrayType * build_test_match_result ( test_regex_ctx matchctx)
static

Definition at line 691 of file test_regex.c.

692 {
693  char *buf = matchctx->conv_buf;
694  Datum *elems = matchctx->elems;
695  bool *nulls = matchctx->nulls;
696  bool indices = matchctx->re_flags.indices;
697  char bufstr[80];
698  int dims[1];
699  int lbs[1];
700  int loc;
701  int i;
702 
703  /* Extract matching substrings from the original string */
704  loc = matchctx->next_match * matchctx->npatterns * 2;
705  for (i = 0; i < matchctx->npatterns; i++)
706  {
707  int so = matchctx->match_locs[loc++];
708  int eo = matchctx->match_locs[loc++];
709 
710  if (indices)
711  {
712  /* Report eo this way for consistency with Tcl */
713  snprintf(bufstr, sizeof(bufstr), "%d %d",
714  so, so < 0 ? eo : eo - 1);
715  elems[i] = PointerGetDatum(cstring_to_text(bufstr));
716  nulls[i] = false;
717  }
718  else if (so < 0 || eo < 0)
719  {
720  elems[i] = (Datum) 0;
721  nulls[i] = true;
722  }
723  else if (buf)
724  {
725  int len = pg_wchar2mb_with_len(matchctx->wide_str + so,
726  buf,
727  eo - so);
728 
729  Assert(len < matchctx->conv_bufsiz);
731  nulls[i] = false;
732  }
733  else
734  {
736  PointerGetDatum(matchctx->orig_str),
737  Int32GetDatum(so + 1),
738  Int32GetDatum(eo - so));
739  nulls[i] = false;
740  }
741  }
742 
743  /* In EXPECT indices mode, also report the "details" */
744  if (indices && (matchctx->re_flags.cflags & REG_EXPECT))
745  {
746  int so = matchctx->details.rm_extend.rm_so;
747  int eo = matchctx->details.rm_extend.rm_eo;
748 
749  snprintf(bufstr, sizeof(bufstr), "%d %d",
750  so, so < 0 ? eo : eo - 1);
751  elems[i] = PointerGetDatum(cstring_to_text(bufstr));
752  nulls[i] = false;
753  i++;
754  }
755 
756  /* And form an array */
757  dims[0] = i;
758  lbs[0] = 1;
759  /* XXX: this hardcodes assumptions about the text type */
760  return construct_md_array(elems, nulls, 1, dims, lbs,
761  TEXTOID, -1, false, TYPALIGN_INT);
762 }
#define Assert(condition)
Definition: c.h:849
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:645
int i
Definition: isn.c:72
int pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len)
Definition: mbutils.c:1008
const void size_t len
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define REG_EXPECT
Definition: regex.h:191
pg_regoff_t rm_eo
Definition: regex.h:164
pg_regoff_t rm_so
Definition: regex.h:163
pg_regmatch_t rm_extend
Definition: regex.h:170
int * match_locs
Definition: test_regex.c:46
test_re_flags re_flags
Definition: test_regex.c:39
text * orig_str
Definition: test_regex.c:41
pg_wchar * wide_str
Definition: test_regex.c:51
bool * nulls
Definition: test_regex.c:50
rm_detail_t details
Definition: test_regex.c:40
Datum * elems
Definition: test_regex.c:49
char * conv_buf
Definition: test_regex.c:52
Datum text_substr(PG_FUNCTION_ARGS)
Definition: varlena.c:852
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196

References Assert, buf, test_re_flags::cflags, construct_md_array(), test_regex_ctx::conv_buf, cstring_to_text(), cstring_to_text_with_len(), test_regex_ctx::details, DirectFunctionCall3, test_regex_ctx::elems, i, test_re_flags::indices, Int32GetDatum(), len, test_regex_ctx::match_locs, test_regex_ctx::next_match, test_regex_ctx::npatterns, test_regex_ctx::nulls, test_regex_ctx::orig_str, pg_wchar2mb_with_len(), PointerGetDatum(), test_regex_ctx::re_flags, REG_EXPECT, pg_regmatch_t::rm_eo, rm_detail_t::rm_extend, pg_regmatch_t::rm_so, snprintf, text_substr(), and test_regex_ctx::wide_str.

Referenced by test_regex().

◆ parse_test_flags()

static void parse_test_flags ( test_re_flags flags,
text opts 
)
static

Definition at line 249 of file test_regex.c.

250 {
251  /* these defaults must match Tcl's */
252  int cflags = REG_ADVANCED;
253  int eflags = 0;
254  long info = 0;
255 
256  flags->glob = false;
257  flags->indices = false;
258  flags->partial = false;
259 
260  if (opts)
261  {
262  char *opt_p = VARDATA_ANY(opts);
263  int opt_len = VARSIZE_ANY_EXHDR(opts);
264  int i;
265 
266  for (i = 0; i < opt_len; i++)
267  {
268  switch (opt_p[i])
269  {
270  case '-':
271  /* allowed, no-op */
272  break;
273  case '!':
274  flags->partial = true;
275  break;
276  case '*':
277  /* test requires Unicode --- ignored here */
278  break;
279  case '0':
280  flags->indices = true;
281  break;
282 
283  /* These flags correspond to user-exposed RE options: */
284  case 'g': /* global match */
285  flags->glob = true;
286  break;
287  case 'i': /* case insensitive */
288  cflags |= REG_ICASE;
289  break;
290  case 'n': /* \n affects ^ $ . [^ */
291  cflags |= REG_NEWLINE;
292  break;
293  case 'p': /* ~Perl, \n affects . [^ */
294  cflags |= REG_NLSTOP;
295  cflags &= ~REG_NLANCH;
296  break;
297  case 'w': /* weird, \n affects ^ $ only */
298  cflags &= ~REG_NLSTOP;
299  cflags |= REG_NLANCH;
300  break;
301  case 'x': /* expanded syntax */
302  cflags |= REG_EXPANDED;
303  break;
304 
305  /* These flags correspond to Tcl's -xflags options: */
306  case 'a':
307  cflags |= REG_ADVF;
308  break;
309  case 'b':
310  cflags &= ~REG_ADVANCED;
311  break;
312  case 'c':
313 
314  /*
315  * Tcl calls this TCL_REG_CANMATCH, but it's really
316  * REG_EXPECT. In this implementation we must also set
317  * the partial and indices flags, so that
318  * setup_test_matches and build_test_match_result will
319  * emit the desired data. (They'll emit more fields than
320  * Tcl would, but that's fine.)
321  */
322  cflags |= REG_EXPECT;
323  flags->partial = true;
324  flags->indices = true;
325  break;
326  case 'e':
327  cflags &= ~REG_ADVANCED;
328  cflags |= REG_EXTENDED;
329  break;
330  case 'q':
331  cflags &= ~REG_ADVANCED;
332  cflags |= REG_QUOTE;
333  break;
334  case 'o': /* o for opaque */
335  cflags |= REG_NOSUB;
336  break;
337  case 's': /* s for start */
338  cflags |= REG_BOSONLY;
339  break;
340  case '+':
341  cflags |= REG_FAKE;
342  break;
343  case ',':
344  cflags |= REG_PROGRESS;
345  break;
346  case '.':
347  cflags |= REG_DUMP;
348  break;
349  case ':':
350  eflags |= REG_MTRACE;
351  break;
352  case ';':
353  eflags |= REG_FTRACE;
354  break;
355  case '^':
356  eflags |= REG_NOTBOL;
357  break;
358  case '$':
359  eflags |= REG_NOTEOL;
360  break;
361  case 't':
362  cflags |= REG_EXPECT;
363  break;
364  case '%':
365  eflags |= REG_SMALL;
366  break;
367 
368  /* These flags define expected info bits: */
369  case 'A':
370  info |= REG_UBSALNUM;
371  break;
372  case 'B':
373  info |= REG_UBRACES;
374  break;
375  case 'E':
376  info |= REG_UBBS;
377  break;
378  case 'H':
379  info |= REG_ULOOKAROUND;
380  break;
381  case 'I':
382  info |= REG_UIMPOSSIBLE;
383  break;
384  case 'L':
385  info |= REG_ULOCALE;
386  break;
387  case 'M':
388  info |= REG_UUNPORT;
389  break;
390  case 'N':
391  info |= REG_UEMPTYMATCH;
392  break;
393  case 'P':
394  info |= REG_UNONPOSIX;
395  break;
396  case 'Q':
397  info |= REG_UBOUNDS;
398  break;
399  case 'R':
400  info |= REG_UBACKREF;
401  break;
402  case 'S':
403  info |= REG_UUNSPEC;
404  break;
405  case 'T':
406  info |= REG_USHORTEST;
407  break;
408  case 'U':
409  info |= REG_UPBOTCH;
410  break;
411 
412  default:
413  ereport(ERROR,
414  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
415  errmsg("invalid regular expression test option: \"%.*s\"",
416  pg_mblen(opt_p + i), opt_p + i)));
417  break;
418  }
419  }
420  }
421  flags->cflags = cflags;
422  flags->eflags = eflags;
423  flags->info = info;
424 }
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1023
static AmcheckOptions opts
Definition: pg_amcheck.c:111
#define REG_ICASE
Definition: regex.h:184
#define REG_DUMP
Definition: regex.h:193
#define REG_PROGRESS
Definition: regex.h:195
#define REG_ADVANCED
Definition: regex.h:181
#define REG_MTRACE
Definition: regex.h:206
#define REG_EXPANDED
Definition: regex.h:186
#define REG_FTRACE
Definition: regex.h:205
#define REG_NLANCH
Definition: regex.h:188
#define REG_EXTENDED
Definition: regex.h:179
#define REG_NLSTOP
Definition: regex.h:187
#define REG_ADVF
Definition: regex.h:180
#define REG_SMALL
Definition: regex.h:207
#define REG_NOTEOL
Definition: regex.h:203
#define REG_NOTBOL
Definition: regex.h:202
#define REG_NEWLINE
Definition: regex.h:189
#define REG_NOSUB
Definition: regex.h:185
#define REG_BOSONLY
Definition: regex.h:192
#define REG_FAKE
Definition: regex.h:194
#define REG_QUOTE
Definition: regex.h:182
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References test_re_flags::cflags, test_re_flags::eflags, ereport, errcode(), errmsg(), ERROR, test_re_flags::glob, i, test_re_flags::indices, test_re_flags::info, opts, test_re_flags::partial, pg_mblen(), REG_ADVANCED, REG_ADVF, REG_BOSONLY, REG_DUMP, REG_EXPANDED, REG_EXPECT, REG_EXTENDED, REG_FAKE, REG_FTRACE, REG_ICASE, REG_MTRACE, REG_NEWLINE, REG_NLANCH, REG_NLSTOP, REG_NOSUB, REG_NOTBOL, REG_NOTEOL, REG_PROGRESS, REG_QUOTE, REG_SMALL, REG_UBACKREF, REG_UBBS, REG_UBOUNDS, REG_UBRACES, REG_UBSALNUM, REG_UEMPTYMATCH, REG_UIMPOSSIBLE, REG_ULOCALE, REG_ULOOKAROUND, REG_UNONPOSIX, REG_UPBOTCH, REG_USHORTEST, REG_UUNPORT, REG_UUNSPEC, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by test_regex().

◆ PG_FUNCTION_INFO_V1()

PG_FUNCTION_INFO_V1 ( test_regex  )

◆ setup_test_matches()

static test_regex_ctx * setup_test_matches ( text orig_str,
regex_t cpattern,
test_re_flags re_flags,
Oid  collation,
bool  use_subpatterns 
)
static

Definition at line 434 of file test_regex.c.

438 {
439  test_regex_ctx *matchctx = palloc0(sizeof(test_regex_ctx));
441  int orig_len;
442  pg_wchar *wide_str;
443  int wide_len;
444  regmatch_t *pmatch;
445  int pmatch_len;
446  int array_len;
447  int array_idx;
448  int prev_match_end;
449  int start_search;
450  int maxlen = 0; /* largest fetch length in characters */
451 
452  /* save flags */
453  matchctx->re_flags = *re_flags;
454 
455  /* save original string --- we'll extract result substrings from it */
456  matchctx->orig_str = orig_str;
457 
458  /* convert string to pg_wchar form for matching */
459  orig_len = VARSIZE_ANY_EXHDR(orig_str);
460  wide_str = (pg_wchar *) palloc(sizeof(pg_wchar) * (orig_len + 1));
461  wide_len = pg_mb2wchar_with_len(VARDATA_ANY(orig_str), wide_str, orig_len);
462 
463  /* do we want to remember subpatterns? */
464  if (use_subpatterns && cpattern->re_nsub > 0)
465  {
466  matchctx->npatterns = cpattern->re_nsub + 1;
467  pmatch_len = cpattern->re_nsub + 1;
468  }
469  else
470  {
471  use_subpatterns = false;
472  matchctx->npatterns = 1;
473  pmatch_len = 1;
474  }
475 
476  /* temporary output space for RE package */
477  pmatch = palloc(sizeof(regmatch_t) * pmatch_len);
478 
479  /*
480  * the real output space (grown dynamically if needed)
481  *
482  * use values 2^n-1, not 2^n, so that we hit the limit at 2^28-1 rather
483  * than at 2^27
484  */
485  array_len = re_flags->glob ? 255 : 31;
486  matchctx->match_locs = (int *) palloc(sizeof(int) * array_len);
487  array_idx = 0;
488 
489  /* search for the pattern, perhaps repeatedly */
490  prev_match_end = 0;
491  start_search = 0;
492  while (test_re_execute(cpattern, wide_str, wide_len,
493  start_search,
494  &matchctx->details,
495  pmatch_len, pmatch,
496  re_flags->eflags))
497  {
498  /* enlarge output space if needed */
499  while (array_idx + matchctx->npatterns * 2 + 1 > array_len)
500  {
501  array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */
502  if (array_len > MaxAllocSize / sizeof(int))
503  ereport(ERROR,
504  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
505  errmsg("too many regular expression matches")));
506  matchctx->match_locs = (int *) repalloc(matchctx->match_locs,
507  sizeof(int) * array_len);
508  }
509 
510  /* save this match's locations */
511  for (int i = 0; i < matchctx->npatterns; i++)
512  {
513  int so = pmatch[i].rm_so;
514  int eo = pmatch[i].rm_eo;
515 
516  matchctx->match_locs[array_idx++] = so;
517  matchctx->match_locs[array_idx++] = eo;
518  if (so >= 0 && eo >= 0 && (eo - so) > maxlen)
519  maxlen = (eo - so);
520  }
521  matchctx->nmatches++;
522  prev_match_end = pmatch[0].rm_eo;
523 
524  /* if not glob, stop after one match */
525  if (!re_flags->glob)
526  break;
527 
528  /*
529  * Advance search position. Normally we start the next search at the
530  * end of the previous match; but if the match was of zero length, we
531  * have to advance by one character, or we'd just find the same match
532  * again.
533  */
534  start_search = prev_match_end;
535  if (pmatch[0].rm_so == pmatch[0].rm_eo)
536  start_search++;
537  if (start_search > wide_len)
538  break;
539  }
540 
541  /*
542  * If we had no match, but "partial" and "indices" are set, emit the
543  * details.
544  */
545  if (matchctx->nmatches == 0 && re_flags->partial && re_flags->indices)
546  {
547  /* enlarge output space if needed */
548  while (array_idx + matchctx->npatterns * 2 + 1 > array_len)
549  {
550  array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */
551  if (array_len > MaxAllocSize / sizeof(int))
552  ereport(ERROR,
553  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
554  errmsg("too many regular expression matches")));
555  matchctx->match_locs = (int *) repalloc(matchctx->match_locs,
556  sizeof(int) * array_len);
557  }
558 
559  matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_so;
560  matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_eo;
561  /* we don't have pmatch data, so emit -1 */
562  for (int i = 1; i < matchctx->npatterns; i++)
563  {
564  matchctx->match_locs[array_idx++] = -1;
565  matchctx->match_locs[array_idx++] = -1;
566  }
567  matchctx->nmatches++;
568  }
569 
570  Assert(array_idx <= array_len);
571 
572  if (eml > 1)
573  {
574  int64 maxsiz = eml * (int64) maxlen;
575  int conv_bufsiz;
576 
577  /*
578  * Make the conversion buffer large enough for any substring of
579  * interest.
580  *
581  * Worst case: assume we need the maximum size (maxlen*eml), but take
582  * advantage of the fact that the original string length in bytes is
583  * an upper bound on the byte length of any fetched substring (and we
584  * know that len+1 is safe to allocate because the varlena header is
585  * longer than 1 byte).
586  */
587  if (maxsiz > orig_len)
588  conv_bufsiz = orig_len + 1;
589  else
590  conv_bufsiz = maxsiz + 1; /* safe since maxsiz < 2^30 */
591 
592  matchctx->conv_buf = palloc(conv_bufsiz);
593  matchctx->conv_bufsiz = conv_bufsiz;
594  matchctx->wide_str = wide_str;
595  }
596  else
597  {
598  /* No need to keep the wide string if we're in a single-byte charset. */
599  pfree(wide_str);
600  matchctx->wide_str = NULL;
601  matchctx->conv_buf = NULL;
602  matchctx->conv_bufsiz = 0;
603  }
604 
605  /* Clean up temp storage */
606  pfree(pmatch);
607 
608  return matchctx;
609 }
#define MaxAllocSize
Definition: fe_memutils.h:22
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_database_encoding_max_length(void)
Definition: mbutils.c:1546
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition: mbutils.c:986
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1541
void * palloc(Size size)
Definition: mcxt.c:1317
#define regmatch_t
Definition: regex.h:246
static bool test_re_execute(regex_t *re, pg_wchar *data, int data_len, int start_search, rm_detail_t *details, int nmatch, regmatch_t *pmatch, int eflags)
Definition: test_regex.c:201

References Assert, test_regex_ctx::conv_buf, test_regex_ctx::conv_bufsiz, test_regex_ctx::details, test_re_flags::eflags, ereport, errcode(), errmsg(), ERROR, test_re_flags::glob, i, test_re_flags::indices, test_regex_ctx::match_locs, MaxAllocSize, test_regex_ctx::nmatches, test_regex_ctx::npatterns, test_regex_ctx::orig_str, palloc(), palloc0(), test_re_flags::partial, pfree(), pg_database_encoding_max_length(), pg_mb2wchar_with_len(), test_regex_ctx::re_flags, regmatch_t, repalloc(), pg_regmatch_t::rm_eo, rm_detail_t::rm_extend, pg_regmatch_t::rm_so, test_re_execute(), VARDATA_ANY, VARSIZE_ANY_EXHDR, and test_regex_ctx::wide_str.

Referenced by test_regex().

◆ test_re_compile()

static void test_re_compile ( text text_re,
int  cflags,
Oid  collation,
regex_t result_re 
)
static

Definition at line 160 of file test_regex.c.

162 {
163  int text_re_len = VARSIZE_ANY_EXHDR(text_re);
164  char *text_re_val = VARDATA_ANY(text_re);
165  pg_wchar *pattern;
166  int pattern_len;
167  int regcomp_result;
168  char errMsg[100];
169 
170  /* Convert pattern string to wide characters */
171  pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar));
172  pattern_len = pg_mb2wchar_with_len(text_re_val,
173  pattern,
174  text_re_len);
175 
176  regcomp_result = pg_regcomp(result_re,
177  pattern,
178  pattern_len,
179  cflags,
180  collation);
181 
182  pfree(pattern);
183 
184  if (regcomp_result != REG_OKAY)
185  {
186  /* re didn't compile (no need for pg_regfree, if so) */
187  pg_regerror(regcomp_result, result_re, errMsg, sizeof(errMsg));
188  ereport(ERROR,
189  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
190  errmsg("invalid regular expression: %s", errMsg)));
191  }
192 }
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition: regcomp.c:370
size_t pg_regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
Definition: regerror.c:60
#define REG_OKAY
Definition: regex.h:215

References ereport, errcode(), errmsg(), ERROR, palloc(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), REG_OKAY, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by test_regex().

◆ test_re_execute()

static bool test_re_execute ( regex_t re,
pg_wchar data,
int  data_len,
int  start_search,
rm_detail_t details,
int  nmatch,
regmatch_t pmatch,
int  eflags 
)
static

Definition at line 201 of file test_regex.c.

206 {
207  int regexec_result;
208  char errMsg[100];
209 
210  /* Initialize match locations in case engine doesn't */
211  details->rm_extend.rm_so = -1;
212  details->rm_extend.rm_eo = -1;
213  for (int i = 0; i < nmatch; i++)
214  {
215  pmatch[i].rm_so = -1;
216  pmatch[i].rm_eo = -1;
217  }
218 
219  /* Perform RE match and return result */
220  regexec_result = pg_regexec(re,
221  data,
222  data_len,
223  start_search,
224  details,
225  nmatch,
226  pmatch,
227  eflags);
228 
229  if (regexec_result != REG_OKAY && regexec_result != REG_NOMATCH)
230  {
231  /* re failed??? */
232  pg_regerror(regexec_result, re, errMsg, sizeof(errMsg));
233  ereport(ERROR,
234  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
235  errmsg("regular expression failed: %s", errMsg)));
236  }
237 
238  return (regexec_result == REG_OKAY);
239 }
const void * data
#define REG_NOMATCH
Definition: regex.h:216
int pg_regexec(regex_t *re, const chr *string, size_t len, size_t search_start, rm_detail_t *details, size_t nmatch, regmatch_t pmatch[], int flags)
Definition: regexec.c:185

References data, ereport, errcode(), errmsg(), ERROR, i, pg_regerror(), pg_regexec(), REG_NOMATCH, REG_OKAY, pg_regmatch_t::rm_eo, rm_detail_t::rm_extend, and pg_regmatch_t::rm_so.

Referenced by setup_test_matches().

◆ test_regex()

Datum test_regex ( PG_FUNCTION_ARGS  )

Definition at line 79 of file test_regex.c.

80 {
81  FuncCallContext *funcctx;
82  test_regex_ctx *matchctx;
83  ArrayType *result_ary;
84 
85  if (SRF_IS_FIRSTCALL())
86  {
87  text *pattern = PG_GETARG_TEXT_PP(0);
88  text *flags = PG_GETARG_TEXT_PP(2);
89  Oid collation = PG_GET_COLLATION();
90  test_re_flags re_flags;
91  regex_t cpattern;
92  MemoryContext oldcontext;
93 
94  funcctx = SRF_FIRSTCALL_INIT();
95  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
96 
97  /* Determine options */
98  parse_test_flags(&re_flags, flags);
99 
100  /* set up the compiled pattern */
101  test_re_compile(pattern, re_flags.cflags, collation, &cpattern);
102 
103  /* be sure to copy the input string into the multi-call ctx */
104  matchctx = setup_test_matches(PG_GETARG_TEXT_P_COPY(1), &cpattern,
105  &re_flags,
106  collation,
107  true);
108 
109  /* Pre-create workspace that build_test_match_result needs */
110  matchctx->elems = (Datum *) palloc(sizeof(Datum) *
111  (matchctx->npatterns + 1));
112  matchctx->nulls = (bool *) palloc(sizeof(bool) *
113  (matchctx->npatterns + 1));
114 
115  MemoryContextSwitchTo(oldcontext);
116  funcctx->user_fctx = (void *) matchctx;
117 
118  /*
119  * Return the first result row, which is info equivalent to Tcl's
120  * "regexp -about" output
121  */
122  result_ary = build_test_info_result(&cpattern, &re_flags);
123 
124  pg_regfree(&cpattern);
125 
126  SRF_RETURN_NEXT(funcctx, PointerGetDatum(result_ary));
127  }
128  else
129  {
130  /* Each subsequent row describes one match */
131  funcctx = SRF_PERCALL_SETUP();
132  matchctx = (test_regex_ctx *) funcctx->user_fctx;
133 
134  if (matchctx->next_match < matchctx->nmatches)
135  {
136  result_ary = build_test_match_result(matchctx);
137  matchctx->next_match++;
138  SRF_RETURN_NEXT(funcctx, PointerGetDatum(result_ary));
139  }
140  }
141 
142  SRF_RETURN_DONE(funcctx);
143 }
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define PG_GETARG_TEXT_P_COPY(n)
Definition: fmgr.h:315
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
#define regex_t
Definition: regex.h:245
void pg_regfree(regex_t *re)
Definition: regfree.c:49
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
Definition: c.h:678
static test_regex_ctx * setup_test_matches(text *orig_str, regex_t *cpattern, test_re_flags *re_flags, Oid collation, bool use_subpatterns)
Definition: test_regex.c:434
static void test_re_compile(text *text_re, int cflags, Oid collation, regex_t *result_re)
Definition: test_regex.c:160
static ArrayType * build_test_match_result(test_regex_ctx *matchctx)
Definition: test_regex.c:691
static void parse_test_flags(test_re_flags *flags, text *opts)
Definition: test_regex.c:249
static ArrayType * build_test_info_result(regex_t *cpattern, test_re_flags *flags)
Definition: test_regex.c:617

References build_test_info_result(), build_test_match_result(), test_re_flags::cflags, test_regex_ctx::elems, if(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, test_regex_ctx::next_match, test_regex_ctx::nmatches, test_regex_ctx::npatterns, test_regex_ctx::nulls, palloc(), parse_test_flags(), PG_GET_COLLATION, PG_GETARG_TEXT_P_COPY, PG_GETARG_TEXT_PP, pg_regfree(), PointerGetDatum(), regex_t, setup_test_matches(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, test_re_compile(), and FuncCallContext::user_fctx.

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 22 of file test_regex.c.