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 "catalog/pg_type_d.h"
18#include "funcapi.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 */
27typedef 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() */
38typedef struct test_regex_ctx
39{
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 */
58static void test_re_compile(text *text_re, int cflags, Oid collation,
60static void parse_test_flags(test_re_flags *flags, text *opts);
61static test_regex_ctx *setup_test_matches(text *orig_str,
63 test_re_flags *re_flags,
64 Oid collation,
65 bool use_subpatterns);
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
81{
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;
93 MemoryContext oldcontext;
94
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 */
106 &re_flags,
107 collation,
108 true);
109
110 /* Pre-create workspace that build_test_match_result needs */
111 matchctx->elems = palloc_array(Datum, matchctx->npatterns + 1);
112 matchctx->nulls = palloc_array(bool, matchctx->npatterns + 1);
113
114 MemoryContextSwitchTo(oldcontext);
115 funcctx->user_fctx = matchctx;
116
117 /*
118 * Return the first result row, which is info equivalent to Tcl's
119 * "regexp -about" output
120 */
122
124
126 }
127 else
128 {
129 /* Each subsequent row describes one match */
131 matchctx = (test_regex_ctx *) funcctx->user_fctx;
132
133 if (matchctx->next_match < matchctx->nmatches)
134 {
136 matchctx->next_match++;
138 }
139 }
140
142}
143
144
145/*
146 * test_re_compile - compile a RE
147 *
148 * text_re --- the pattern, expressed as a TEXT object
149 * cflags --- compile options for the pattern
150 * collation --- collation to use for LC_CTYPE-dependent behavior
151 * result_re --- output, compiled RE is stored here
152 *
153 * Pattern is given in the database encoding. We internally convert to
154 * an array of pg_wchar, which is what Spencer's regex package wants.
155 *
156 * Caller must eventually pg_regfree the resulting RE to avoid memory leaks.
157 */
158static void
159test_re_compile(text *text_re, int cflags, Oid collation,
161{
164 pg_wchar *pattern;
165 int pattern_len;
166 int regcomp_result;
167 char errMsg[100];
168
169 /* Convert pattern string to wide characters */
170 pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar));
172 pattern,
174
176 pattern,
178 cflags,
179 collation);
180
181 pfree(pattern);
182
184 {
185 /* re didn't compile (no need for pg_regfree, if so) */
186 pg_regerror(regcomp_result, result_re, errMsg, sizeof(errMsg));
189 errmsg("invalid regular expression: %s", errMsg)));
190 }
191}
192
193/*
194 * test_re_execute - execute a RE on pg_wchar data
195 *
196 * Returns true on match, false on no match
197 * Arguments are as for pg_regexec
198 */
199static bool
201 int start_search,
202 rm_detail_t *details,
203 int nmatch, regmatch_t *pmatch,
204 int eflags)
205{
206 int regexec_result;
207 char errMsg[100];
208
209 /* Initialize match locations in case engine doesn't */
210 details->rm_extend.rm_so = -1;
211 details->rm_extend.rm_eo = -1;
212 for (int i = 0; i < nmatch; i++)
213 {
214 pmatch[i].rm_so = -1;
215 pmatch[i].rm_eo = -1;
216 }
217
218 /* Perform RE match and return result */
220 data,
221 data_len,
223 details,
224 nmatch,
225 pmatch,
226 eflags);
227
229 {
230 /* re failed??? */
231 pg_regerror(regexec_result, re, errMsg, sizeof(errMsg));
234 errmsg("regular expression failed: %s", errMsg)));
235 }
236
237 return (regexec_result == REG_OKAY);
238}
239
240
241/*
242 * parse_test_flags - parse the flags argument
243 *
244 * flags --- output argument, filled with desired options
245 * opts --- TEXT object, or NULL for defaults
246 */
247static void
249{
250 /* these defaults must match Tcl's */
251 int cflags = REG_ADVANCED;
252 int eflags = 0;
253 long info = 0;
254
255 flags->glob = false;
256 flags->indices = false;
257 flags->partial = false;
258
259 if (opts)
260 {
261 char *opt_p = VARDATA_ANY(opts);
263 int i;
264
265 for (i = 0; i < opt_len; i++)
266 {
267 switch (opt_p[i])
268 {
269 case '-':
270 /* allowed, no-op */
271 break;
272 case '!':
273 flags->partial = true;
274 break;
275 case '*':
276 /* test requires Unicode --- ignored here */
277 break;
278 case '0':
279 flags->indices = true;
280 break;
281
282 /* These flags correspond to user-exposed RE options: */
283 case 'g': /* global match */
284 flags->glob = true;
285 break;
286 case 'i': /* case insensitive */
287 cflags |= REG_ICASE;
288 break;
289 case 'n': /* \n affects ^ $ . [^ */
290 cflags |= REG_NEWLINE;
291 break;
292 case 'p': /* ~Perl, \n affects . [^ */
293 cflags |= REG_NLSTOP;
294 cflags &= ~REG_NLANCH;
295 break;
296 case 'w': /* weird, \n affects ^ $ only */
297 cflags &= ~REG_NLSTOP;
298 cflags |= REG_NLANCH;
299 break;
300 case 'x': /* expanded syntax */
301 cflags |= REG_EXPANDED;
302 break;
303
304 /* These flags correspond to Tcl's -xflags options: */
305 case 'a':
306 cflags |= REG_ADVF;
307 break;
308 case 'b':
309 cflags &= ~REG_ADVANCED;
310 break;
311 case 'c':
312
313 /*
314 * Tcl calls this TCL_REG_CANMATCH, but it's really
315 * REG_EXPECT. In this implementation we must also set
316 * the partial and indices flags, so that
317 * setup_test_matches and build_test_match_result will
318 * emit the desired data. (They'll emit more fields than
319 * Tcl would, but that's fine.)
320 */
321 cflags |= REG_EXPECT;
322 flags->partial = true;
323 flags->indices = true;
324 break;
325 case 'e':
326 cflags &= ~REG_ADVANCED;
327 cflags |= REG_EXTENDED;
328 break;
329 case 'q':
330 cflags &= ~REG_ADVANCED;
331 cflags |= REG_QUOTE;
332 break;
333 case 'o': /* o for opaque */
334 cflags |= REG_NOSUB;
335 break;
336 case 's': /* s for start */
337 cflags |= REG_BOSONLY;
338 break;
339 case '+':
340 cflags |= REG_FAKE;
341 break;
342 case ',':
343 cflags |= REG_PROGRESS;
344 break;
345 case '.':
346 cflags |= REG_DUMP;
347 break;
348 case ':':
349 eflags |= REG_MTRACE;
350 break;
351 case ';':
352 eflags |= REG_FTRACE;
353 break;
354 case '^':
355 eflags |= REG_NOTBOL;
356 break;
357 case '$':
358 eflags |= REG_NOTEOL;
359 break;
360 case 't':
361 cflags |= REG_EXPECT;
362 break;
363 case '%':
364 eflags |= REG_SMALL;
365 break;
366
367 /* These flags define expected info bits: */
368 case 'A':
369 info |= REG_UBSALNUM;
370 break;
371 case 'B':
372 info |= REG_UBRACES;
373 break;
374 case 'E':
375 info |= REG_UBBS;
376 break;
377 case 'H':
378 info |= REG_ULOOKAROUND;
379 break;
380 case 'I':
381 info |= REG_UIMPOSSIBLE;
382 break;
383 case 'L':
384 info |= REG_ULOCALE;
385 break;
386 case 'M':
387 info |= REG_UUNPORT;
388 break;
389 case 'N':
390 info |= REG_UEMPTYMATCH;
391 break;
392 case 'P':
393 info |= REG_UNONPOSIX;
394 break;
395 case 'Q':
396 info |= REG_UBOUNDS;
397 break;
398 case 'R':
399 info |= REG_UBACKREF;
400 break;
401 case 'S':
402 info |= REG_UUNSPEC;
403 break;
404 case 'T':
405 info |= REG_USHORTEST;
406 break;
407 case 'U':
408 info |= REG_UPBOTCH;
409 break;
410
411 default:
414 errmsg("invalid regular expression test option: \"%.*s\"",
416 opt_p + i)));
417 break;
418 }
419 }
420 }
421 flags->cflags = cflags;
422 flags->eflags = eflags;
423 flags->info = info;
424}
425
426/*
427 * setup_test_matches --- do the initial matching
428 *
429 * To simplify memory management, we do all the matching in one swoop.
430 * The returned test_regex_ctx contains the locations of all the substrings
431 * matching the pattern.
432 */
433static test_regex_ctx *
435 regex_t *cpattern, test_re_flags *re_flags,
436 Oid collation,
437 bool use_subpatterns)
438{
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 = palloc_array(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 */
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 = palloc_array(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,
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))
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 */
535 if (pmatch[0].rm_so == pmatch[0].rm_eo)
536 start_search++;
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))
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}
610
611/*
612 * build_test_info_result - build output array describing compiled regexp
613 *
614 * This borrows some code from Tcl's TclRegAbout().
615 */
616static ArrayType *
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);
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);
664 }
665 }
666 else
667 {
668 if (flags->info & inf->bit)
669 {
670 snprintf(buf, sizeof(buf), "missing %s!", inf->text);
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}
683
684/*
685 * build_test_match_result - build output array for current match
686 *
687 * Note that if the indices flag is set, we don't need any strings,
688 * just the location data.
689 */
690static ArrayType *
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);
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);
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}
ArrayType * construct_md_array(Datum *elems, bool *nulls, int ndims, int *dims, int *lbs, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
#define lengthof(array)
Definition c.h:875
varlena text
Definition c.h:791
int errcode(int sqlerrcode)
Definition elog.c:874
#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:1674
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 char * errmsg
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:342
uint64_t Datum
Definition postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
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:40
text * orig_str
Definition test_regex.c:42
pg_wchar * wide_str
Definition test_regex.c:52
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:778
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
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:159
static ArrayType * build_test_match_result(test_regex_ctx *matchctx)
Definition test_regex.c:691
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:200
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:248
static ArrayType * build_test_info_result(regex_t *cpattern, test_re_flags *flags)
Definition test_regex.c:617
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:553
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