PostgreSQL Source Code  git master
test_regex.c
Go to the documentation of this file.
1 /*--------------------------------------------------------------------------
2  *
3  * test_regex.c
4  * Test harness for the regular expression package.
5  *
6  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  * src/test/modules/test_regex/test_regex.c
11  *
12  * -------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "funcapi.h"
18 #include "miscadmin.h"
19 #include "regex/regex.h"
20 #include "utils/array.h"
21 #include "utils/builtins.h"
22 
24 
25 
26 /* all the options of interest for regex functions */
27 typedef struct test_re_flags
28 {
29  int cflags; /* compile flags for Spencer's regex code */
30  int eflags; /* execute flags for Spencer's regex code */
31  long info; /* expected re_info bits */
32  bool glob; /* do it globally (for each occurrence) */
33  bool indices; /* report indices not actual strings */
34  bool partial; /* expect partial match */
36 
37 /* cross-call state for test_regex() */
38 typedef struct test_regex_ctx
39 {
40  test_re_flags re_flags; /* flags */
41  rm_detail_t details; /* "details" from execution */
42  text *orig_str; /* data string in original TEXT form */
43  int nmatches; /* number of places where pattern matched */
44  int npatterns; /* number of capturing subpatterns */
45  /* We store start char index and end+1 char index for each match */
46  /* so the number of entries in match_locs is nmatches * npatterns * 2 */
47  int *match_locs; /* 0-based character indexes */
48  int next_match; /* 0-based index of next match to process */
49  /* workspace for build_test_match_result() */
50  Datum *elems; /* has npatterns+1 elements */
51  bool *nulls; /* has npatterns+1 elements */
52  pg_wchar *wide_str; /* wide-char version of original string */
53  char *conv_buf; /* conversion buffer, if needed */
54  int conv_bufsiz; /* size thereof */
56 
57 /* Local functions */
58 static void test_re_compile(text *text_re, int cflags, Oid collation,
59  regex_t *result_re);
60 static void parse_test_flags(test_re_flags *flags, text *opts);
61 static test_regex_ctx *setup_test_matches(text *orig_str,
62  regex_t *cpattern,
63  test_re_flags *re_flags,
64  Oid collation,
65  bool use_subpatterns);
66 static ArrayType *build_test_info_result(regex_t *cpattern,
67  test_re_flags *flags);
69 
70 
71 /*
72  * test_regex(pattern text, string text, flags text) returns setof text[]
73  *
74  * This is largely based on regexp.c's regexp_matches, with additions
75  * for debugging purposes.
76  */
78 
79 Datum
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 }
145 
146 
147 /*
148  * test_re_compile - compile a RE
149  *
150  * text_re --- the pattern, expressed as a TEXT object
151  * cflags --- compile options for the pattern
152  * collation --- collation to use for LC_CTYPE-dependent behavior
153  * result_re --- output, compiled RE is stored here
154  *
155  * Pattern is given in the database encoding. We internally convert to
156  * an array of pg_wchar, which is what Spencer's regex package wants.
157  *
158  * Caller must eventually pg_regfree the resulting RE to avoid memory leaks.
159  */
160 static void
161 test_re_compile(text *text_re, int cflags, Oid collation,
162  regex_t *result_re)
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 }
194 
195 /*
196  * test_re_execute - execute a RE on pg_wchar data
197  *
198  * Returns true on match, false on no match
199  * Arguments are as for pg_regexec
200  */
201 static bool
202 test_re_execute(regex_t *re, pg_wchar *data, int data_len,
203  int start_search,
204  rm_detail_t *details,
205  int nmatch, regmatch_t *pmatch,
206  int eflags)
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 }
241 
242 
243 /*
244  * parse_test_flags - parse the flags argument
245  *
246  * flags --- output argument, filled with desired options
247  * opts --- TEXT object, or NULL for defaults
248  */
249 static void
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 }
426 
427 /*
428  * setup_test_matches --- do the initial matching
429  *
430  * To simplify memory management, we do all the matching in one swoop.
431  * The returned test_regex_ctx contains the locations of all the substrings
432  * matching the pattern.
433  */
434 static test_regex_ctx *
436  regex_t *cpattern, test_re_flags *re_flags,
437  Oid collation,
438  bool use_subpatterns)
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 }
611 
612 /*
613  * build_test_info_result - build output array describing compiled regexp
614  *
615  * This borrows some code from Tcl's TclRegAbout().
616  */
617 static ArrayType *
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 }
684 
685 /*
686  * build_test_match_result - build output array for current match
687  *
688  * Note that if the indices flag is set, we don't need any strings,
689  * just the location data.
690  */
691 static ArrayType *
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 }
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
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
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define PG_GETARG_TEXT_P_COPY(n)
Definition: fmgr.h:315
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#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
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Assert(fmt[strlen(fmt) - 1] !='\n')
unsigned int pg_wchar
Definition: mbprint.c:31
int pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len)
Definition: mbutils.c:1008
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
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1023
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 AmcheckOptions opts
Definition: pg_amcheck.c:111
const void size_t len
const void * data
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
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
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_ICASE
Definition: regex.h:106
#define REG_DUMP
Definition: regex.h:115
#define REG_UEMPTYMATCH
Definition: regex.h:71
#define REG_NOMATCH
Definition: regex.h:138
#define REG_PROGRESS
Definition: regex.h:117
#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_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_EXPECT
Definition: regex.h:113
#define REG_EXTENDED
Definition: regex.h:101
#define REG_NLSTOP
Definition: regex.h:109
#define REG_ADVF
Definition: regex.h:102
#define REG_UUNSPEC
Definition: regex.h:68
#define REG_SMALL
Definition: regex.h:129
#define REG_OKAY
Definition: regex.h:137
#define REG_UNONPOSIX
Definition: regex.h:67
#define REG_NOTEOL
Definition: regex.h:125
#define REG_NOTBOL
Definition: regex.h:124
#define REG_NEWLINE
Definition: regex.h:111
#define REG_UBSALNUM
Definition: regex.h:64
#define REG_NOSUB
Definition: regex.h:107
#define REG_USHORTEST
Definition: regex.h:73
#define REG_ULOCALE
Definition: regex.h:70
#define REG_UUNPORT
Definition: regex.h:69
#define REG_BOSONLY
Definition: regex.h:114
#define REG_UBRACES
Definition: regex.h:63
#define REG_FAKE
Definition: regex.h:116
#define REG_UBACKREF
Definition: regex.h:60
#define REG_QUOTE
Definition: regex.h:104
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
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
long re_info
Definition: regex.h:59
size_t re_nsub
Definition: regex.h:58
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
Definition: c.h:674
PG_FUNCTION_INFO_V1(test_regex)
struct test_re_flags test_re_flags
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
PG_MODULE_MAGIC
Definition: test_regex.c:23
static void test_re_compile(text *text_re, int cflags, Oid collation, regex_t *result_re)
Definition: test_regex.c:161
struct test_regex_ctx test_regex_ctx
static ArrayType * build_test_match_result(test_regex_ctx *matchctx)
Definition: test_regex.c:692
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
Datum test_regex(PG_FUNCTION_ARGS)
Definition: test_regex.c:80
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
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
Datum bit(PG_FUNCTION_ARGS)
Definition: varbit.c:391
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
text * cstring_to_text(const char *s)
Definition: varlena.c:184