PostgreSQL Source Code git master
Loading...
Searching...
No Matches
regis.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * regis.c
4 * Fast regex subset
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 *
8 *
9 * IDENTIFICATION
10 * src/backend/tsearch/regis.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include "tsearch/dicts/regis.h"
18#include "tsearch/ts_locale.h"
19
20#define RS_IN_ONEOF 1
21#define RS_IN_ONEOF_IN 2
22#define RS_IN_NONEOF 3
23#define RS_IN_WAIT 4
24
25
26/*
27 * Test whether a regex is of the subset supported here.
28 * Keep this in sync with RS_compile!
29 */
30bool
31RS_isRegis(const char *str)
32{
33 int state = RS_IN_WAIT;
34 const char *c = str;
35
36 while (*c)
37 {
38 if (state == RS_IN_WAIT)
39 {
40 if (t_isalpha_cstr(c))
41 /* okay */ ;
42 else if (t_iseq(c, '['))
44 else
45 return false;
46 }
47 else if (state == RS_IN_ONEOF)
48 {
49 if (t_iseq(c, '^'))
51 else if (t_isalpha_cstr(c))
53 else
54 return false;
55 }
56 else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
57 {
58 if (t_isalpha_cstr(c))
59 /* okay */ ;
60 else if (t_iseq(c, ']'))
62 else
63 return false;
64 }
65 else
66 elog(ERROR, "internal error in RS_isRegis: state %d", state);
67 c += pg_mblen_cstr(c);
68 }
69
70 return (state == RS_IN_WAIT);
71}
72
73static RegisNode *
75{
76 RegisNode *ptr;
77
78 ptr = (RegisNode *) palloc0(RNHDRSZ + len + 1);
79 if (prev)
80 prev->next = ptr;
81 return ptr;
82}
83
84void
85RS_compile(Regis *r, bool issuffix, const char *str)
86{
87 int len = strlen(str);
88 int state = RS_IN_WAIT;
89 const char *c = str;
90 RegisNode *ptr = NULL;
91
92 memset(r, 0, sizeof(Regis));
93 r->issuffix = (issuffix) ? 1 : 0;
94
95 while (*c)
96 {
97 if (state == RS_IN_WAIT)
98 {
99 if (t_isalpha_cstr(c))
100 {
101 if (ptr)
102 ptr = newRegisNode(ptr, len);
103 else
104 ptr = r->node = newRegisNode(NULL, len);
105 ptr->type = RSF_ONEOF;
106 ptr->len = ts_copychar_cstr(ptr->data, c);
107 }
108 else if (t_iseq(c, '['))
109 {
110 if (ptr)
111 ptr = newRegisNode(ptr, len);
112 else
113 ptr = r->node = newRegisNode(NULL, len);
114 ptr->type = RSF_ONEOF;
116 }
117 else /* shouldn't get here */
118 elog(ERROR, "invalid regis pattern: \"%s\"", str);
119 }
120 else if (state == RS_IN_ONEOF)
121 {
122 if (t_iseq(c, '^'))
123 {
124 ptr->type = RSF_NONEOF;
126 }
127 else if (t_isalpha_cstr(c))
128 {
129 ptr->len = ts_copychar_cstr(ptr->data, c);
131 }
132 else /* shouldn't get here */
133 elog(ERROR, "invalid regis pattern: \"%s\"", str);
134 }
135 else if (state == RS_IN_ONEOF_IN || state == RS_IN_NONEOF)
136 {
137 if (t_isalpha_cstr(c))
138 ptr->len += ts_copychar_cstr(ptr->data + ptr->len, c);
139 else if (t_iseq(c, ']'))
141 else /* shouldn't get here */
142 elog(ERROR, "invalid regis pattern: \"%s\"", str);
143 }
144 else
145 elog(ERROR, "internal error in RS_compile: state %d", state);
146 c += pg_mblen_cstr(c);
147 }
148
149 if (state != RS_IN_WAIT) /* shouldn't get here */
150 elog(ERROR, "invalid regis pattern: \"%s\"", str);
151
152 ptr = r->node;
153 while (ptr)
154 {
155 r->nchar++;
156 ptr = ptr->next;
157 }
158}
159
160void
162{
163 RegisNode *ptr = r->node,
164 *tmp;
165
166 while (ptr)
167 {
168 tmp = ptr->next;
169 pfree(ptr);
170 ptr = tmp;
171 }
172
173 r->node = NULL;
174}
175
176static bool
177mb_strchr(char *str, char *c)
178{
179 int clen,
180 plen,
181 i;
182 char *ptr = str;
183 bool res = false;
184
186 while (*ptr && !res)
187 {
188 plen = pg_mblen_cstr(ptr);
189 if (plen == clen)
190 {
191 i = plen;
192 res = true;
193 while (i--)
194 if (*(ptr + i) != *(c + i))
195 {
196 res = false;
197 break;
198 }
199 }
200
201 ptr += plen;
202 }
203
204 return res;
205}
206
207bool
209{
210 RegisNode *ptr = r->node;
211 char *c = str;
212 int len = 0;
213
214 while (*c)
215 {
216 len++;
217 c += pg_mblen_cstr(c);
218 }
219
220 if (len < r->nchar)
221 return 0;
222
223 c = str;
224 if (r->issuffix)
225 {
226 len -= r->nchar;
227 while (len-- > 0)
228 c += pg_mblen_cstr(c);
229 }
230
231
232 while (ptr)
233 {
234 switch (ptr->type)
235 {
236 case RSF_ONEOF:
237 if (!mb_strchr((char *) ptr->data, c))
238 return false;
239 break;
240 case RSF_NONEOF:
241 if (mb_strchr((char *) ptr->data, c))
242 return false;
243 break;
244 default:
245 elog(ERROR, "unrecognized regis node type: %d", ptr->type);
246 }
247 ptr = ptr->next;
248 c += pg_mblen_cstr(c);
249 }
250
251 return true;
252}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
const char * str
int i
Definition isn.c:77
int pg_mblen_cstr(const char *mbstr)
Definition mbutils.c:1045
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
const void size_t len
char * c
static int fb(int x)
static RegisNode * newRegisNode(RegisNode *prev, int len)
Definition regis.c:74
#define RS_IN_WAIT
Definition regis.c:23
void RS_compile(Regis *r, bool issuffix, const char *str)
Definition regis.c:85
bool RS_execute(Regis *r, char *str)
Definition regis.c:208
bool RS_isRegis(const char *str)
Definition regis.c:31
static bool mb_strchr(char *str, char *c)
Definition regis.c:177
#define RS_IN_ONEOF_IN
Definition regis.c:21
void RS_free(Regis *r)
Definition regis.c:161
#define RS_IN_ONEOF
Definition regis.c:20
#define RS_IN_NONEOF
Definition regis.c:22
#define RNHDRSZ
Definition regis.h:27
#define RSF_ONEOF
Definition regis.h:29
#define RSF_NONEOF
Definition regis.h:30
unsigned char data[FLEXIBLE_ARRAY_MEMBER]
Definition regis.h:24
uint32 len
Definition regis.h:21
struct RegisNode * next
Definition regis.h:23
uint32 type
Definition regis.h:20
Definition regis.h:33
uint32 issuffix
Definition regis.h:36
RegisNode * node
Definition regis.h:34
uint32 nchar
Definition regis.h:37
static int ts_copychar_cstr(void *dest, const void *src)
Definition ts_locale.h:50
#define t_iseq(x, c)
Definition ts_locale.h:38