PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
test_regex.c File Reference
#include "postgres.h"
#include "funcapi.h"
#include "regex/regex.h"
#include "utils/array.h"
#include "utils/builtins.h"
Include dependency graph for test_regex.c:

Go to the source code of this file.

Data Structures

struct  test_re_flags
 
struct  test_regex_ctx
 

Typedefs

typedef struct test_re_flags test_re_flags
 
typedef struct test_regex_ctx test_regex_ctx
 

Functions

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

Variables

 PG_MODULE_MAGIC
 

Typedef Documentation

◆ test_re_flags

typedef struct test_re_flags test_re_flags

◆ test_regex_ctx

Function Documentation

◆ build_test_info_result()

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

Definition at line 617 of file test_regex.c.

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

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

Referenced by test_regex().

◆ build_test_match_result()

static ArrayType * build_test_match_result ( test_regex_ctx matchctx)
static

Definition at line 691 of file test_regex.c.

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

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

Referenced by test_regex().

◆ parse_test_flags()

static void parse_test_flags ( test_re_flags flags,
text opts 
)
static

Definition at line 249 of file test_regex.c.

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

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

Referenced by test_regex().

◆ PG_FUNCTION_INFO_V1()

PG_FUNCTION_INFO_V1 ( test_regex  )

◆ setup_test_matches()

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

Definition at line 434 of file test_regex.c.

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

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

Referenced by test_regex().

◆ test_re_compile()

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

Definition at line 160 of file test_regex.c.

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

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

Referenced by test_regex().

◆ test_re_execute()

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

Definition at line 201 of file test_regex.c.

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

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

Referenced by setup_test_matches().

◆ test_regex()

Datum test_regex ( PG_FUNCTION_ARGS  )

Definition at line 79 of file test_regex.c.

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

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

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 22 of file test_regex.c.