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