]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/like.c
pgindent run before 6.3 release, with Thomas' requested changes.
[postgresql] / src / backend / utils / adt / like.c
1 /*-------------------------------------------------------------------------
2  *
3  * like.c--
4  *        like expression handling code.
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp
11  *
12  *
13  *       NOTES
14  *              A big hack of the regexp.c code!! Contributed by
15  *              Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
16  *
17  *
18  *-------------------------------------------------------------------------
19  */
20 #include <string.h>
21 #include "postgres.h"                   /* postgres system include file */
22 #include "utils/palloc.h"
23 #include "utils/builtins.h"             /* where the function declarations go */
24
25 static int      like(char *text, char *p);
26
27 /*
28  *      interface routines called by the function manager
29  */
30
31 /*
32    fixedlen_like:
33
34    a generic fixed length like routine
35                  s              - the string to match against  (not necessarily null-terminated)
36                  p                 - the pattern
37                  charlen   - the length of the string
38 */
39 static bool
40 fixedlen_like(char *s, struct varlena * p, int charlen)
41 {
42         char       *sterm,
43                            *pterm;
44         int                     result;
45
46         if (!s || !p)
47                 return FALSE;
48
49         /* be sure sterm is null-terminated */
50         sterm = (char *) palloc(charlen + 1);
51         StrNCpy(sterm, s, charlen + 1);
52
53         /*
54          * p is a text = varlena, not a string so we have to make a string
55          * from the vl_data field of the struct.
56          */
57
58         /* palloc the length of the text + the null character */
59         pterm = (char *) palloc(VARSIZE(p) - VARHDRSZ + 1);
60         memmove(pterm, VARDATA(p), VARSIZE(p) - VARHDRSZ);
61         *(pterm + VARSIZE(p) - VARHDRSZ) = (char) NULL;
62
63         /* do the regexp matching */
64         result = like(sterm, pterm);
65
66         pfree(sterm);
67         pfree(pterm);
68
69         return ((bool) result);
70 }
71
72 bool
73 char2like(uint16 arg1, struct varlena * p)
74 {
75         char       *s = (char *) &arg1;
76
77         return (fixedlen_like(s, p, 2));
78 }
79
80 bool
81 char2nlike(uint16 arg1, struct varlena * p)
82 {
83         return (!char2like(arg1, p));
84 }
85
86 bool
87 char4like(uint32 arg1, struct varlena * p)
88 {
89         char       *s = (char *) &arg1;
90
91         return (fixedlen_like(s, p, 4));
92 }
93
94 bool
95 char4nlike(uint32 arg1, struct varlena * p)
96 {
97         return (!char4like(arg1, p));
98 }
99
100 bool
101 char8like(char *s, struct varlena * p)
102 {
103         return (fixedlen_like(s, p, 8));
104 }
105
106 bool
107 char8nlike(char *s, struct varlena * p)
108 {
109         return (!char8like(s, p));
110 }
111
112 bool
113 char16like(char *s, struct varlena * p)
114 {
115         return (fixedlen_like(s, p, 16));
116 }
117
118 bool
119 char16nlike(char *s, struct varlena * p)
120 {
121         return (!char16like(s, p));
122 }
123
124 bool
125 namelike(NameData *n, struct varlena * p)
126 {
127         if (!n)
128                 return FALSE;
129         return (fixedlen_like(n->data, p, NAMEDATALEN));
130 }
131
132 bool
133 namenlike(NameData *s, struct varlena * p)
134 {
135         return (!namelike(s, p));
136 }
137
138 bool
139 textlike(struct varlena * s, struct varlena * p)
140 {
141         if (!s)
142                 return FALSE;
143         return (fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ));
144 }
145
146 bool
147 textnlike(struct varlena * s, struct varlena * p)
148 {
149         return (!textlike(s, p));
150 }
151
152
153 /*      $Revision: 1.12 $
154 **      "like.c" A first attempt at a LIKE operator for Postgres95.
155 **
156 **      Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
157 **      Rich $alz is now <rsalz@bbn.com>.
158 **      Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
159 **
160 **      This code was shamelessly stolen from the "pql" code by myself and
161 **      slightly modified :)
162 **
163 **      All references to the word "star" were replaced by "percent"
164 **      All references to the word "wild" were replaced by "like"
165 **
166 **      All the nice shell RE matching stuff was replaced by just "_" and "%"
167 **
168 **      As I don't have a copy of the SQL standard handy I wasn't sure whether
169 **      to leave in the '\' escape character handling. (I suspect the standard
170 **      handles "%%" as a single literal percent)
171 **
172 **      Keith Parks. <keith@mtcc.demon.co.uk>
173 **
174 **      [SQL92 lets you specify the escape character by saying
175 **       LIKE <pattern> ESCAPE <escape character>. We are a small operation
176 **       so we force you to use '\'. - ay 7/95]
177 **
178 */
179
180 #define LIKE_TRUE                                               1
181 #define LIKE_FALSE                                              0
182 #define LIKE_ABORT                                              -1
183
184 /*
185 **      Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
186 */
187 static int
188 DoMatch(char *text, char *p)
189 {
190         int                     matched;
191
192         for (; *p; text ++, p++)
193         {
194                 if (*text == '\0' && *p != '%')
195                         return LIKE_ABORT;
196                 switch (*p)
197                 {
198                         case '\\':
199                                 /* Literal match with following character. */
200                                 p++;
201                                 /* FALLTHROUGH */
202                         default:
203                                 if (*text !=*p)
204                                         return LIKE_FALSE;
205                                 continue;
206                         case '_':
207                                 /* Match anything. */
208                                 continue;
209                         case '%':
210                                 while (*++p == '%')
211                                         /* Consecutive percents act just like one. */
212                                         continue;
213                                 if (*p == '\0')
214                                         /* Trailing percent matches everything. */
215                                         return LIKE_TRUE;
216                                 while (*text)
217                                         if ((matched = DoMatch(text ++, p)) != LIKE_FALSE)
218                                                 return matched;
219                                 return LIKE_ABORT;
220                 }
221         }
222
223         return *text == '\0';
224 }
225
226
227 /*
228 **      User-level routine.  Returns TRUE or FALSE.
229 */
230 static int
231 like(char *text, char *p)
232 {
233         if (p[0] == '%' && p[1] == '\0')
234                 return TRUE;
235         return (DoMatch(text, p) == LIKE_TRUE);
236 }