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