PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 "regex/regex.h"
19#include "utils/array.h"
20#include "utils/builtins.h"
21
23
24
25/* all the options of interest for regex functions */
26typedef struct test_re_flags
27{
28 int cflags; /* compile flags for Spencer's regex code */
29 int eflags; /* execute flags for Spencer's regex code */
30 long info; /* expected re_info bits */
31 bool glob; /* do it globally (for each occurrence) */
32 bool indices; /* report indices not actual strings */
33 bool partial; /* expect partial match */
35
36/* cross-call state for test_regex() */
37typedef struct test_regex_ctx
38{
40 rm_detail_t details; /* "details" from execution */
41 text *orig_str; /* data string in original TEXT form */
42 int nmatches; /* number of places where pattern matched */
43 int npatterns; /* number of capturing subpatterns */
44 /* We store start char index and end+1 char index for each match */
45 /* so the number of entries in match_locs is nmatches * npatterns * 2 */
46 int *match_locs; /* 0-based character indexes */
47 int next_match; /* 0-based index of next match to process */
48 /* workspace for build_test_match_result() */
49 Datum *elems; /* has npatterns+1 elements */
50 bool *nulls; /* has npatterns+1 elements */
51 pg_wchar *wide_str; /* wide-char version of original string */
52 char *conv_buf; /* conversion buffer, if needed */
53 int conv_bufsiz; /* size thereof */
55
56/* Local functions */
57static void test_re_compile(text *text_re, int cflags, Oid collation,
59static void parse_test_flags(test_re_flags *flags, text *opts);
60static test_regex_ctx *setup_test_matches(text *orig_str,
62 test_re_flags *re_flags,
63 Oid collation,
64 bool use_subpatterns);
66 test_re_flags *flags);
68
69
70/*
71 * test_regex(pattern text, string text, flags text) returns setof text[]
72 *
73 * This is largely based on regexp.c's regexp_matches, with additions
74 * for debugging purposes.
75 */
77
80{
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;
92 MemoryContext oldcontext;
93
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 */
105 &re_flags,
106 collation,
107 true);
108
109 /* Pre-create workspace that build_test_match_result needs */
110 matchctx->elems = palloc_array(Datum, matchctx->npatterns + 1);
111 matchctx->nulls = palloc_array(bool, matchctx->npatterns + 1);
112
113 MemoryContextSwitchTo(oldcontext);
114 funcctx->user_fctx = matchctx;
115
116 /*
117 * Return the first result row, which is info equivalent to Tcl's
118 * "regexp -about" output
119 */
121
123
125 }
126 else
127 {
128 /* Each subsequent row describes one match */
130 matchctx = (test_regex_ctx *) funcctx->user_fctx;
131
132 if (matchctx->next_match < matchctx->nmatches)
133 {
135 matchctx->next_match++;
137 }
138 }
139
141}
142
143
144/*
145 * test_re_compile - compile a RE
146 *
147 * text_re --- the pattern, expressed as a TEXT object
148 * cflags --- compile options for the pattern
149 * collation --- collation to use for LC_CTYPE-dependent behavior
150 * result_re --- output, compiled RE is stored here
151 *
152 * Pattern is given in the database encoding. We internally convert to
153 * an array of pg_wchar, which is what Spencer's regex package wants.
154 *
155 * Caller must eventually pg_regfree the resulting RE to avoid memory leaks.
156 */
157static void
158test_re_compile(text *text_re, int cflags, Oid collation,
160{
163 pg_wchar *pattern;
164 int pattern_len;
165 int regcomp_result;
166 char errMsg[100];
167
168 /* Convert pattern string to wide characters */
169 pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar));
171 pattern,
173
175 pattern,
177 cflags,
178 collation);
179
180 pfree(pattern);
181
183 {
184 /* re didn't compile (no need for pg_regfree, if so) */
185 pg_regerror(regcomp_result, result_re, errMsg, sizeof(errMsg));
188 errmsg("invalid regular expression: %s", errMsg)));
189 }
190}
191
192/*
193 * test_re_execute - execute a RE on pg_wchar data
194 *
195 * Returns true on match, false on no match
196 * Arguments are as for pg_regexec
197 */
198static bool
200 int start_search,
201 rm_detail_t *details,
202 int nmatch, regmatch_t *pmatch,
203 int eflags)
204{
205 int regexec_result;
206 char errMsg[100];
207
208 /* Initialize match locations in case engine doesn't */
209 details->rm_extend.rm_so = -1;
210 details->rm_extend.rm_eo = -1;
211 for (int i = 0; i < nmatch; i++)
212 {
213 pmatch[i].rm_so = -1;
214 pmatch[i].rm_eo = -1;
215 }
216
217 /* Perform RE match and return result */
219 data,
220 data_len,
222 details,
223 nmatch,
224 pmatch,
225 eflags);
226
228 {
229 /* re failed??? */
230 pg_regerror(regexec_result, re, errMsg, sizeof(errMsg));
233 errmsg("regular expression failed: %s", errMsg)));
234 }
235
236 return (regexec_result == REG_OKAY);
237}
238
239
240/*
241 * parse_test_flags - parse the flags argument
242 *
243 * flags --- output argument, filled with desired options
244 * opts --- TEXT object, or NULL for defaults
245 */
246static void
248{
249 /* these defaults must match Tcl's */
250 int cflags = REG_ADVANCED;
251 int eflags = 0;
252 long info = 0;
253
254 flags->glob = false;
255 flags->indices = false;
256 flags->partial = false;
257
258 if (opts)
259 {
260 char *opt_p = VARDATA_ANY(opts);
262 int i;
263
264 for (i = 0; i < opt_len; i++)
265 {
266 switch (opt_p[i])
267 {
268 case '-':
269 /* allowed, no-op */
270 break;
271 case '!':
272 flags->partial = true;
273 break;
274 case '*':
275 /* test requires Unicode --- ignored here */
276 break;
277 case '0':
278 flags->indices = true;
279 break;
280
281 /* These flags correspond to user-exposed RE options: */
282 case 'g': /* global match */
283 flags->glob = true;
284 break;
285 case 'i': /* case insensitive */
286 cflags |= REG_ICASE;
287 break;
288 case 'n': /* \n affects ^ $ . [^ */
289 cflags |= REG_NEWLINE;
290 break;
291 case 'p': /* ~Perl, \n affects . [^ */
292 cflags |= REG_NLSTOP;
293 cflags &= ~REG_NLANCH;
294 break;
295 case 'w': /* weird, \n affects ^ $ only */
296 cflags &= ~REG_NLSTOP;
297 cflags |= REG_NLANCH;
298 break;
299 case 'x': /* expanded syntax */
300 cflags |= REG_EXPANDED;
301 break;
302
303 /* These flags correspond to Tcl's -xflags options: */
304 case 'a':
305 cflags |= REG_ADVF;
306 break;
307 case 'b':
308 cflags &= ~REG_ADVANCED;
309 break;
310 case 'c':
311
312 /*
313 * Tcl calls this TCL_REG_CANMATCH, but it's really
314 * REG_EXPECT. In this implementation we must also set
315 * the partial and indices flags, so that
316 * setup_test_matches and build_test_match_result will
317 * emit the desired data. (They'll emit more fields than
318 * Tcl would, but that's fine.)
319 */
320 cflags |= REG_EXPECT;
321 flags->partial = true;
322 flags->indices = true;
323 break;
324 case 'e':
325 cflags &= ~REG_ADVANCED;
326 cflags |= REG_EXTENDED;
327 break;
328 case 'q':
329 cflags &= ~REG_ADVANCED;
330 cflags |= REG_QUOTE;
331 break;
332 case 'o': /* o for opaque */
333 cflags |= REG_NOSUB;
334 break;
335 case 's': /* s for start */
336 cflags |= REG_BOSONLY;
337 break;
338 case '+':
339 cflags |= REG_FAKE;
340 break;
341 case ',':
342 cflags |= REG_PROGRESS;
343 break;
344 case '.':
345 cflags |= REG_DUMP;
346 break;
347 case ':':
348 eflags |= REG_MTRACE;
349 break;
350 case ';':
351 eflags |= REG_FTRACE;
352 break;
353 case '^':
354 eflags |= REG_NOTBOL;
355 break;
356 case '$':
357 eflags |= REG_NOTEOL;
358 break;
359 case 't':
360 cflags |= REG_EXPECT;
361 break;
362 case '%':
363 eflags |= REG_SMALL;
364 break;
365
366 /* These flags define expected info bits: */
367 case 'A':
368 info |= REG_UBSALNUM;
369 break;
370 case 'B':
371 info |= REG_UBRACES;
372 break;
373 case 'E':
374 info |= REG_UBBS;
375 break;
376 case 'H':
377 info |= REG_ULOOKAROUND;
378 break;
379 case 'I':
380 info |= REG_UIMPOSSIBLE;
381 break;
382 case 'L':
383 info |= REG_ULOCALE;
384 break;
385 case 'M':
386 info |= REG_UUNPORT;
387 break;
388 case 'N':
389 info |= REG_UEMPTYMATCH;
390 break;
391 case 'P':
392 info |= REG_UNONPOSIX;
393 break;
394 case 'Q':
395 info |= REG_UBOUNDS;
396 break;
397 case 'R':
398 info |= REG_UBACKREF;
399 break;
400 case 'S':
401 info |= REG_UUNSPEC;
402 break;
403 case 'T':
404 info |= REG_USHORTEST;
405 break;
406 case 'U':
407 info |= REG_UPBOTCH;
408 break;
409
410 default:
413 errmsg("invalid regular expression test option: \"%.*s\"",
415 opt_p + i)));
416 break;
417 }
418 }
419 }
420 flags->cflags = cflags;
421 flags->eflags = eflags;
422 flags->info = info;
423}
424
425/*
426 * setup_test_matches --- do the initial matching
427 *
428 * To simplify memory management, we do all the matching in one swoop.
429 * The returned test_regex_ctx contains the locations of all the substrings
430 * matching the pattern.
431 */
432static test_regex_ctx *
434 regex_t *cpattern, test_re_flags *re_flags,
435 Oid collation,
436 bool use_subpatterns)
437{
440 int orig_len;
441 pg_wchar *wide_str;
442 int wide_len;
443 regmatch_t *pmatch;
444 int pmatch_len;
445 int array_len;
446 int array_idx;
447 int prev_match_end;
448 int start_search;
449 int maxlen = 0; /* largest fetch length in characters */
450
451 /* save flags */
452 matchctx->re_flags = *re_flags;
453
454 /* save original string --- we'll extract result substrings from it */
455 matchctx->orig_str = orig_str;
456
457 /* convert string to pg_wchar form for matching */
458 orig_len = VARSIZE_ANY_EXHDR(orig_str);
459 wide_str = palloc_array(pg_wchar, orig_len + 1);
460 wide_len = pg_mb2wchar_with_len(VARDATA_ANY(orig_str), wide_str, orig_len);
461
462 /* do we want to remember subpatterns? */
463 if (use_subpatterns && cpattern->re_nsub > 0)
464 {
465 matchctx->npatterns = cpattern->re_nsub + 1;
466 pmatch_len = cpattern->re_nsub + 1;
467 }
468 else
469 {
470 use_subpatterns = false;
471 matchctx->npatterns = 1;
472 pmatch_len = 1;
473 }
474
475 /* temporary output space for RE package */
477
478 /*
479 * the real output space (grown dynamically if needed)
480 *
481 * use values 2^n-1, not 2^n, so that we hit the limit at 2^28-1 rather
482 * than at 2^27
483 */
484 array_len = re_flags->glob ? 255 : 31;
485 matchctx->match_locs = palloc_array(int, array_len);
486 array_idx = 0;
487
488 /* search for the pattern, perhaps repeatedly */
489 prev_match_end = 0;
490 start_search = 0;
491 while (test_re_execute(cpattern, wide_str, wide_len,
493 &matchctx->details,
494 pmatch_len, pmatch,
495 re_flags->eflags))
496 {
497 /* enlarge output space if needed */
498 while (array_idx + matchctx->npatterns * 2 + 1 > array_len)
499 {
500 array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */
501 if (array_len > MaxAllocSize / sizeof(int))
504 errmsg("too many regular expression matches")));
505 matchctx->match_locs = (int *) repalloc(matchctx->match_locs,
506 sizeof(int) * array_len);
507 }
508
509 /* save this match's locations */
510 for (int i = 0; i < matchctx->npatterns; i++)
511 {
512 int so = pmatch[i].rm_so;
513 int eo = pmatch[i].rm_eo;
514
515 matchctx->match_locs[array_idx++] = so;
516 matchctx->match_locs[array_idx++] = eo;
517 if (so >= 0 && eo >= 0 && (eo - so) > maxlen)
518 maxlen = (eo - so);
519 }
520 matchctx->nmatches++;
521 prev_match_end = pmatch[0].rm_eo;
522
523 /* if not glob, stop after one match */
524 if (!re_flags->glob)
525 break;
526
527 /*
528 * Advance search position. Normally we start the next search at the
529 * end of the previous match; but if the match was of zero length, we
530 * have to advance by one character, or we'd just find the same match
531 * again.
532 */
534 if (pmatch[0].rm_so == pmatch[0].rm_eo)
535 start_search++;
537 break;
538 }
539
540 /*
541 * If we had no match, but "partial" and "indices" are set, emit the
542 * details.
543 */
544 if (matchctx->nmatches == 0 && re_flags->partial && re_flags->indices)
545 {
546 /* enlarge output space if needed */
547 while (array_idx + matchctx->npatterns * 2 + 1 > array_len)
548 {
549 array_len += array_len + 1; /* 2^n-1 => 2^(n+1)-1 */
550 if (array_len > MaxAllocSize / sizeof(int))
553 errmsg("too many regular expression matches")));
554 matchctx->match_locs = (int *) repalloc(matchctx->match_locs,
555 sizeof(int) * array_len);
556 }
557
558 matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_so;
559 matchctx->match_locs[array_idx++] = matchctx->details.rm_extend.rm_eo;
560 /* we don't have pmatch data, so emit -1 */
561 for (int i = 1; i < matchctx->npatterns; i++)
562 {
563 matchctx->match_locs[array_idx++] = -1;
564 matchctx->match_locs[array_idx++] = -1;
565 }
566 matchctx->nmatches++;
567 }
568
569 Assert(array_idx <= array_len);
570
571 if (eml > 1)
572 {
573 int64 maxsiz = eml * (int64) maxlen;
574 int conv_bufsiz;
575
576 /*
577 * Make the conversion buffer large enough for any substring of
578 * interest.
579 *
580 * Worst case: assume we need the maximum size (maxlen*eml), but take
581 * advantage of the fact that the original string length in bytes is
582 * an upper bound on the byte length of any fetched substring (and we
583 * know that len+1 is safe to allocate because the varlena header is
584 * longer than 1 byte).
585 */
586 if (maxsiz > orig_len)
587 conv_bufsiz = orig_len + 1;
588 else
589 conv_bufsiz = maxsiz + 1; /* safe since maxsiz < 2^30 */
590
591 matchctx->conv_buf = palloc(conv_bufsiz);
592 matchctx->conv_bufsiz = conv_bufsiz;
593 matchctx->wide_str = wide_str;
594 }
595 else
596 {
597 /* No need to keep the wide string if we're in a single-byte charset. */
598 pfree(wide_str);
599 matchctx->wide_str = NULL;
600 matchctx->conv_buf = NULL;
601 matchctx->conv_bufsiz = 0;
602 }
603
604 /* Clean up temp storage */
605 pfree(pmatch);
606
607 return matchctx;
608}
609
610/*
611 * build_test_info_result - build output array describing compiled regexp
612 *
613 * This borrows some code from Tcl's TclRegAbout().
614 */
615static ArrayType *
617{
618 /* Translation data for flag bits in regex_t.re_info */
619 struct infoname
620 {
621 int bit;
622 const char *text;
623 };
624 static const struct infoname infonames[] = {
625 {REG_UBACKREF, "REG_UBACKREF"},
626 {REG_ULOOKAROUND, "REG_ULOOKAROUND"},
627 {REG_UBOUNDS, "REG_UBOUNDS"},
628 {REG_UBRACES, "REG_UBRACES"},
629 {REG_UBSALNUM, "REG_UBSALNUM"},
630 {REG_UPBOTCH, "REG_UPBOTCH"},
631 {REG_UBBS, "REG_UBBS"},
632 {REG_UNONPOSIX, "REG_UNONPOSIX"},
633 {REG_UUNSPEC, "REG_UUNSPEC"},
634 {REG_UUNPORT, "REG_UUNPORT"},
635 {REG_ULOCALE, "REG_ULOCALE"},
636 {REG_UEMPTYMATCH, "REG_UEMPTYMATCH"},
637 {REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"},
638 {REG_USHORTEST, "REG_USHORTEST"},
639 {0, NULL}
640 };
641 const struct infoname *inf;
642 Datum elems[lengthof(infonames) + 1];
643 int nresults = 0;
644 char buf[80];
645 int dims[1];
646 int lbs[1];
647
648 /* Set up results: first, the number of subexpressions */
649 snprintf(buf, sizeof(buf), "%d", (int) cpattern->re_nsub);
651
652 /* Report individual info bit states */
653 for (inf = infonames; inf->bit != 0; inf++)
654 {
655 if (cpattern->re_info & inf->bit)
656 {
657 if (flags->info & inf->bit)
658 elems[nresults++] = PointerGetDatum(cstring_to_text(inf->text));
659 else
660 {
661 snprintf(buf, sizeof(buf), "unexpected %s!", inf->text);
663 }
664 }
665 else
666 {
667 if (flags->info & inf->bit)
668 {
669 snprintf(buf, sizeof(buf), "missing %s!", inf->text);
671 }
672 }
673 }
674
675 /* And form an array */
676 dims[0] = nresults;
677 lbs[0] = 1;
678 /* XXX: this hardcodes assumptions about the text type */
679 return construct_md_array(elems, NULL, 1, dims, lbs,
680 TEXTOID, -1, false, TYPALIGN_INT);
681}
682
683/*
684 * build_test_match_result - build output array for current match
685 *
686 * Note that if the indices flag is set, we don't need any strings,
687 * just the location data.
688 */
689static ArrayType *
691{
692 char *buf = matchctx->conv_buf;
693 Datum *elems = matchctx->elems;
694 bool *nulls = matchctx->nulls;
695 bool indices = matchctx->re_flags.indices;
696 char bufstr[80];
697 int dims[1];
698 int lbs[1];
699 int loc;
700 int i;
701
702 /* Extract matching substrings from the original string */
703 loc = matchctx->next_match * matchctx->npatterns * 2;
704 for (i = 0; i < matchctx->npatterns; i++)
705 {
706 int so = matchctx->match_locs[loc++];
707 int eo = matchctx->match_locs[loc++];
708
709 if (indices)
710 {
711 /* Report eo this way for consistency with Tcl */
712 snprintf(bufstr, sizeof(bufstr), "%d %d",
713 so, so < 0 ? eo : eo - 1);
715 nulls[i] = false;
716 }
717 else if (so < 0 || eo < 0)
718 {
719 elems[i] = (Datum) 0;
720 nulls[i] = true;
721 }
722 else if (buf)
723 {
724 int len = pg_wchar2mb_with_len(matchctx->wide_str + so,
725 buf,
726 eo - so);
727
728 Assert(len < matchctx->conv_bufsiz);
730 nulls[i] = false;
731 }
732 else
733 {
735 PointerGetDatum(matchctx->orig_str),
736 Int32GetDatum(so + 1),
737 Int32GetDatum(eo - so));
738 nulls[i] = false;
739 }
740 }
741
742 /* In EXPECT indices mode, also report the "details" */
743 if (indices && (matchctx->re_flags.cflags & REG_EXPECT))
744 {
745 int so = matchctx->details.rm_extend.rm_so;
746 int eo = matchctx->details.rm_extend.rm_eo;
747
748 snprintf(bufstr, sizeof(bufstr), "%d %d",
749 so, so < 0 ? eo : eo - 1);
751 nulls[i] = false;
752 i++;
753 }
754
755 /* And form an array */
756 dims[0] = i;
757 lbs[0] = 1;
758 /* XXX: this hardcodes assumptions about the text type */
759 return construct_md_array(elems, nulls, 1, dims, lbs,
760 TEXTOID, -1, false, TYPALIGN_INT);
761}
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
struct varlena text
Definition c.h:719
#define Assert(condition)
Definition c.h:873
int64_t int64
Definition c.h:543
#define lengthof(array)
Definition c.h:803
int errcode(int sqlerrcode)
Definition elog.c:864
int errmsg(const char *fmt,...)
Definition elog.c:1081
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define MaxAllocSize
Definition fe_memutils.h:22
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_object(type)
Definition fe_memutils.h:75
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_FUNCTION_INFO_V1(funcname)
Definition fmgr.h:417
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition fmgr.h:688
#define PG_GET_COLLATION()
Definition fmgr.h:198
#define PG_GETARG_TEXT_P_COPY(n)
Definition fmgr.h:316
#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:77
unsigned int pg_wchar
Definition mbprint.c:31
int pg_wchar2mb_with_len(const pg_wchar *from, char *to, int len)
Definition mbutils.c:1019
int pg_mblen_range(const char *mbstr, const char *end)
Definition mbutils.c:1084
int pg_database_encoding_max_length(void)
Definition mbutils.c:1672
int pg_mb2wchar_with_len(const char *from, pg_wchar *to, int len)
Definition mbutils.c:997
void * repalloc(void *pointer, Size size)
Definition mcxt.c:1632
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
static AmcheckOptions opts
Definition pg_amcheck.c:112
const void size_t len
const void * data
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define snprintf
Definition port.h:260
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
uint64_t Datum
Definition postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
unsigned int Oid
static int fb(int x)
int pg_regcomp(regex_t *re, const chr *string, size_t len, int flags, Oid collation)
Definition regcomp.c:372
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:184
#define REG_DUMP
Definition regex.h:193
#define REG_UEMPTYMATCH
Definition regex.h:149
#define REG_NOMATCH
Definition regex.h:216
#define REG_PROGRESS
Definition regex.h:195
#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_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_EXPECT
Definition regex.h:191
#define REG_EXTENDED
Definition regex.h:179
#define REG_NLSTOP
Definition regex.h:187
#define REG_ADVF
Definition regex.h:180
#define REG_UUNSPEC
Definition regex.h:146
#define regmatch_t
Definition regex.h:246
#define REG_SMALL
Definition regex.h:207
#define REG_OKAY
Definition regex.h:215
#define REG_UNONPOSIX
Definition regex.h:145
#define REG_NOTEOL
Definition regex.h:203
#define REG_NOTBOL
Definition regex.h:202
#define REG_NEWLINE
Definition regex.h:189
#define REG_UBSALNUM
Definition regex.h:142
#define REG_NOSUB
Definition regex.h:185
#define REG_USHORTEST
Definition regex.h:151
#define REG_ULOCALE
Definition regex.h:148
#define regex_t
Definition regex.h:245
#define REG_UUNPORT
Definition regex.h:147
#define REG_BOSONLY
Definition regex.h:192
#define REG_UBRACES
Definition regex.h:141
#define REG_FAKE
Definition regex.h:194
#define REG_UBACKREF
Definition regex.h:138
#define REG_QUOTE
Definition regex.h:182
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
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
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
rm_detail_t details
Definition test_regex.c:40
Datum * elems
Definition test_regex.c:49
char * conv_buf
Definition test_regex.c:52
Definition c.h:706
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:433
PG_MODULE_MAGIC
Definition test_regex.c:22
static void test_re_compile(text *text_re, int cflags, Oid collation, regex_t *result_re)
Definition test_regex.c:158
static ArrayType * build_test_match_result(test_regex_ctx *matchctx)
Definition test_regex.c:690
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:199
Datum test_regex(PG_FUNCTION_ARGS)
Definition test_regex.c:79
static void parse_test_flags(test_re_flags *flags, text *opts)
Definition test_regex.c:247
static ArrayType * build_test_info_result(regex_t *cpattern, test_re_flags *flags)
Definition test_regex.c:616
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
Datum bit(PG_FUNCTION_ARGS)
Definition varbit.c:391
Datum text_substr(PG_FUNCTION_ARGS)
Definition varlena.c:550
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:193
text * cstring_to_text(const char *s)
Definition varlena.c:181