]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/like.c
Move some system includes into c.h, and remove duplicates.
[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 "postgres.h"
21 #include "mb/pg_wchar.h"
22 #include "utils/builtins.h"
23
24 static int      like(pg_wchar * text, pg_wchar * p);
25
26 /*
27  *      interface routines called by the function manager
28  */
29
30 /*
31    fixedlen_like:
32
33    a generic fixed length like routine
34                  s              - the string to match against  (not necessarily null-terminated)
35                  p                 - the pattern
36                  charlen   - the length of the string
37 */
38 static bool
39 fixedlen_like(char *s, struct varlena * p, int charlen)
40 {
41         pg_wchar   *sterm,
42                            *pterm;
43         int                     result;
44         int                     len;
45
46         if (!s || !p)
47                 return FALSE;
48
49         /* be sure sterm is null-terminated */
50 #ifdef MULTIBYTE
51         sterm = (pg_wchar *) palloc((charlen + 1) * sizeof(pg_wchar));
52         (void) pg_mb2wchar_with_len((unsigned char *) s, sterm, charlen);
53 #else
54         sterm = (char *) palloc(charlen + 1);
55         StrNCpy(sterm, s, charlen + 1);
56 #endif
57
58         /*
59          * p is a text = varlena, not a string so we have to make a string
60          * from the vl_data field of the struct.
61          */
62
63         /* palloc the length of the text + the null character */
64         len = VARSIZE(p) - VARHDRSZ;
65 #ifdef MULTIBYTE
66         pterm = (pg_wchar *) palloc((len + 1) * sizeof(pg_wchar));
67         (void) pg_mb2wchar_with_len((unsigned char *) VARDATA(p), pterm, len);
68 #else
69         pterm = (char *) palloc(len + 1);
70         memmove(pterm, VARDATA(p), len);
71         *(pterm + len) = (char) NULL;
72 #endif
73
74         /* do the regexp matching */
75         result = like(sterm, pterm);
76
77         pfree(sterm);
78         pfree(pterm);
79
80         return (bool) result;
81 }
82
83 bool
84 namelike(NameData *n, struct varlena * p)
85 {
86         if (!n)
87                 return FALSE;
88         return fixedlen_like(n->data, p, NAMEDATALEN);
89 }
90
91 bool
92 namenlike(NameData *s, struct varlena * p)
93 {
94         return !namelike(s, p);
95 }
96
97 bool
98 textlike(struct varlena * s, struct varlena * p)
99 {
100         if (!s)
101                 return FALSE;
102         return fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ);
103 }
104
105 bool
106 textnlike(struct varlena * s, struct varlena * p)
107 {
108         return !textlike(s, p);
109 }
110
111
112 /*      $Revision: 1.30 $
113 **      "like.c" A first attempt at a LIKE operator for Postgres95.
114 **
115 **      Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
116 **      Rich $alz is now <rsalz@bbn.com>.
117 **      Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
118 **
119 **      This code was shamelessly stolen from the "pql" code by myself and
120 **      slightly modified :)
121 **
122 **      All references to the word "star" were replaced by "percent"
123 **      All references to the word "wild" were replaced by "like"
124 **
125 **      All the nice shell RE matching stuff was replaced by just "_" and "%"
126 **
127 **      As I don't have a copy of the SQL standard handy I wasn't sure whether
128 **      to leave in the '\' escape character handling. (I suspect the standard
129 **      handles "%%" as a single literal percent)
130 **
131 **      Keith Parks. <keith@mtcc.demon.co.uk>
132 **
133 **      [SQL92 lets you specify the escape character by saying
134 **       LIKE <pattern> ESCAPE <escape character>. We are a small operation
135 **       so we force you to use '\'. - ay 7/95]
136 **
137 */
138
139 #define LIKE_TRUE                                               1
140 #define LIKE_FALSE                                              0
141 #define LIKE_ABORT                                              -1
142
143 /*
144 **      Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
145 */
146 static int
147 DoMatch(pg_wchar * text, pg_wchar * p)
148 {
149         int                     matched;
150
151         for (; *p && *text; text ++, p++)
152         {
153                 switch (*p)
154                 {
155                         case '\\':
156                                 /* Literal match with following character. */
157                                 p++;
158                                 /* FALLTHROUGH */
159                         default:
160                                 if (*text !=*p)
161                                         return LIKE_FALSE;
162                                 break;
163                         case '_':
164                                 /* Match anything. */
165                                 break;
166                         case '%':
167                                 /* %% is the same as % according to the SQL standard */
168                                 /* Advance past all %'s */
169                                 while (*p == '%')
170                                         p++;
171                                 if (*p == '\0')
172                                         /* Trailing percent matches everything. */
173                                         return LIKE_TRUE;
174                                 while (*text)
175                                 {
176                                         /* Optimization to prevent most recursion */
177                                         if ((*text == *p ||
178                                                  *p == '\\' || *p == '%' || *p == '_') &&
179                                                 (matched = DoMatch(text, p)) != LIKE_FALSE)
180                                                 return matched;
181                                         text      ++;
182                                 }
183                                 return LIKE_ABORT;
184                 }
185         }
186
187         if (*text !='\0')
188                 return LIKE_ABORT;
189         else
190         {
191                 /* End of input string.  Do we have matching string remaining? */
192                 while (*p == '%')               /* allow multiple %'s at end of pattern */
193                         p++;
194                 if (*p == '\0')
195                         return LIKE_TRUE;
196                 else
197                         return LIKE_ABORT;
198         }
199 }
200
201
202 /*
203 **      User-level routine.  Returns TRUE or FALSE.
204 */
205 static int
206 like(pg_wchar * text, pg_wchar * p)
207 {
208         if (p[0] == '%' && p[1] == '\0')
209                 return TRUE;
210         return DoMatch(text, p) == LIKE_TRUE;
211 }