PostgreSQL Source Code  git master
test_regex.c File Reference
#include "postgres.h"
#include "funcapi.h"
#include "miscadmin.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 618 of file test_regex.c.

619 {
620  /* Translation data for flag bits in regex_t.re_info */
621  struct infoname
622  {
623  int bit;
624  const char *text;
625  };
626  static const struct infoname infonames[] = {
627  {REG_UBACKREF, "REG_UBACKREF"},
628  {REG_ULOOKAROUND, "REG_ULOOKAROUND"},
629  {REG_UBOUNDS, "REG_UBOUNDS"},
630  {REG_UBRACES, "REG_UBRACES"},
631  {REG_UBSALNUM, "REG_UBSALNUM"},
632  {REG_UPBOTCH, "REG_UPBOTCH"},
633  {REG_UBBS, "REG_UBBS"},
634  {REG_UNONPOSIX, "REG_UNONPOSIX"},
635  {REG_UUNSPEC, "REG_UUNSPEC"},
636  {REG_UUNPORT, "REG_UUNPORT"},
637  {REG_ULOCALE, "REG_ULOCALE"},
638  {REG_UEMPTYMATCH, "REG_UEMPTYMATCH"},
639  {REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"},
640  {REG_USHORTEST, "REG_USHORTEST"},
641  {0, NULL}
642  };
643  const struct infoname *inf;
644  Datum elems[lengthof(infonames) + 1];
645  int nresults = 0;
646  char buf[80];
647  int dims[1];
648  int lbs[1];
649 
650  /* Set up results: first, the number of subexpressions */
651  snprintf(buf, sizeof(buf), "%d", (int) cpattern->re_nsub);
652  elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
653 
654  /* Report individual info bit states */
655  for (inf = infonames; inf->bit != 0; inf++)
656  {
657  if (cpattern->re_info & inf->bit)
658  {
659  if (flags->info & inf->bit)
660  elems[nresults++] = PointerGetDatum(cstring_to_text(inf->text));
661  else
662  {
663  snprintf(buf, sizeof(buf), "unexpected %s!", inf->text);
664  elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
665  }
666  }
667  else
668  {
669  if (flags->info & inf->bit)
670  {
671  snprintf(buf, sizeof(buf), "missing %s!", inf->text);
672  elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
673  }
674  }
675  }
676 
677  /* And form an array */
678  dims[0] = nresults;
679  lbs[0] = 1;
680  /* XXX: this hardcodes assumptions about the text type */
681  return construct_md_array(elems, NULL, 1, dims, lbs,
682  TEXTOID, -1, false, TYPALIGN_INT);
683 }
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:3475
struct varlena text
Definition: c.h:687
#define lengthof(array)
Definition: c.h:775
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:71
#define REG_UBOUNDS
Definition: regex.h:62
#define REG_UIMPOSSIBLE
Definition: regex.h:72
#define REG_UPBOTCH
Definition: regex.h:65
#define REG_ULOOKAROUND
Definition: regex.h:61
#define REG_UBBS
Definition: regex.h:66
#define REG_UUNSPEC
Definition: regex.h:68
#define REG_UNONPOSIX
Definition: regex.h:67
#define REG_UBSALNUM
Definition: regex.h:64
#define REG_USHORTEST
Definition: regex.h:73
#define REG_ULOCALE
Definition: regex.h:70
#define REG_UUNPORT
Definition: regex.h:69
#define REG_UBRACES
Definition: regex.h:63
#define REG_UBACKREF
Definition: regex.h:60
long re_info
Definition: regex.h:59
size_t re_nsub
Definition: regex.h:58
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(), regex_t::re_info, regex_t::re_nsub, 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 692 of file test_regex.c.

693 {
694  char *buf = matchctx->conv_buf;
695  Datum *elems = matchctx->elems;
696  bool *nulls = matchctx->nulls;
697  bool indices = matchctx->re_flags.indices;
698  char bufstr[80];
699  int dims[1];
700  int lbs[1];
701  int loc;
702  int i;
703 
704  /* Extract matching substrings from the original string */
705  loc = matchctx->next_match * matchctx->npatterns * 2;
706  for (i = 0; i < matchctx->npatterns; i++)
707  {
708  int so = matchctx->match_locs[loc++];
709  int eo = matchctx->match_locs[loc++];
710 
711  if (indices)
712  {
713  /* Report eo this way for consistency with Tcl */
714  snprintf(bufstr, sizeof(bufstr), "%d %d",
715  so, so < 0 ? eo : eo - 1);
716  elems[i] = PointerGetDatum(cstring_to_text(bufstr));
717  nulls[i] = false;
718  }
719  else if (so < 0 || eo < 0)
720  {
721  elems[i] = (Datum) 0;
722  nulls[i] = true;
723  }
724  else if (buf)
725  {
726  int len = pg_wchar2mb_with_len(matchctx->wide_str + so,
727  buf,
728  eo - so);
729 
730  Assert(len < matchctx->conv_bufsiz);
732  nulls[i] = false;
733  }
734  else
735  {
737  PointerGetDatum(matchctx->orig_str),
738  Int32GetDatum(so + 1),
739  Int32GetDatum(eo - so));
740  nulls[i] = false;
741  }
742  }
743 
744  /* In EXPECT indices mode, also report the "details" */
745  if (indices && (matchctx->re_flags.cflags & REG_EXPECT))
746  {
747  int so = matchctx->details.rm_extend.rm_so;
748  int eo = matchctx->details.rm_extend.rm_eo;
749 
750  snprintf(bufstr, sizeof(bufstr), "%d %d",
751  so, so < 0 ? eo : eo - 1);
752  elems[i] = PointerGetDatum(cstring_to_text(bufstr));
753  nulls[i] = false;
754  i++;
755  }
756 
757  /* And form an array */
758  dims[0] = i;
759  lbs[0] = 1;
760  /* XXX: this hardcodes assumptions about the text type */
761  return construct_md_array(elems, nulls, 1, dims, lbs,
762  TEXTOID, -1, false, TYPALIGN_INT);
763 }
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
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:113
regoff_t rm_eo
Definition: regex.h:86
regoff_t rm_so
Definition: regex.h:85
regmatch_t rm_extend
Definition: regex.h:92
int * match_locs
Definition: test_regex.c:47
test_re_flags re_flags
Definition: test_regex.c:40
text * orig_str
Definition: test_regex.c:42
pg_wchar * wide_str
Definition: test_regex.c:52
bool * nulls
Definition: test_regex.c:51
rm_detail_t details
Definition: test_regex.c:41
Datum * elems
Definition: test_regex.c:50
char * conv_buf
Definition: test_regex.c:53
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, regmatch_t::rm_eo, rm_detail_t::rm_extend, 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 250 of file test_regex.c.

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

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

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, regex_t::re_nsub, repalloc(), regmatch_t::rm_eo, rm_detail_t::rm_extend, 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 161 of file test_regex.c.

163 {
164  int text_re_len = VARSIZE_ANY_EXHDR(text_re);
165  char *text_re_val = VARDATA_ANY(text_re);
166  pg_wchar *pattern;
167  int pattern_len;
168  int regcomp_result;
169  char errMsg[100];
170 
171  /* Convert pattern string to wide characters */
172  pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar));
173  pattern_len = pg_mb2wchar_with_len(text_re_val,
174  pattern,
175  text_re_len);
176 
177  regcomp_result = pg_regcomp(result_re,
178  pattern,
179  pattern_len,
180  cflags,
181  collation);
182 
183  pfree(pattern);
184 
185  if (regcomp_result != REG_OKAY)
186  {
187  /* re didn't compile (no need for pg_regfree, if so) */
188  pg_regerror(regcomp_result, result_re, errMsg, sizeof(errMsg));
189  ereport(ERROR,
190  (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
191  errmsg("invalid regular expression: %s", errMsg)));
192  }
193 }
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:137

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 202 of file test_regex.c.

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

Referenced by setup_test_matches().

◆ test_regex()

Datum test_regex ( PG_FUNCTION_ARGS  )

Definition at line 80 of file test_regex.c.

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

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(), 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 23 of file test_regex.c.