~ubuntu-branches/ubuntu/trusty/postgresql-8.4/trusty

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/like_match.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-11 16:59:35 UTC
  • mfrom: (5.1.1 karmic)
  • Revision ID: james.westby@ubuntu.com-20090711165935-jfwin6gfrxf0gfsi
Tags: 8.4.0-2
* debian/libpq-dev.install: Ship catalog/genbki.h. (Closes: #536139)
* debian/rules: Drop --enable-cassert for final release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
 * (UTF8 is a special case because we can use a much more efficient version
10
10
 * of NextChar than can be used for general multi-byte encodings.)
11
11
 *
12
 
 * Before the inclusion, we need to define following macros:
 
12
 * Before the inclusion, we need to define the following macros:
13
13
 *
14
14
 * NextChar
15
15
 * MatchText - to name of function wanted
19
19
 * Copyright (c) 1996-2009, PostgreSQL Global Development Group
20
20
 *
21
21
 * IDENTIFICATION
22
 
 *      $PostgreSQL: pgsql/src/backend/utils/adt/like_match.c,v 1.24 2009/01/01 17:23:49 momjian Exp $
 
22
 *      $PostgreSQL: pgsql/src/backend/utils/adt/like_match.c,v 1.26 2009/06/11 14:49:03 momjian Exp $
23
23
 *
24
24
 *-------------------------------------------------------------------------
25
25
 */
26
26
 
27
27
/*
28
 
**      Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
29
 
**      Rich $alz is now <rsalz@bbn.com>.
30
 
**      Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
31
 
**
32
 
**      This code was shamelessly stolen from the "pql" code by myself and
33
 
**      slightly modified :)
34
 
**
35
 
**      All references to the word "star" were replaced by "percent"
36
 
**      All references to the word "wild" were replaced by "like"
37
 
**
38
 
**      All the nice shell RE matching stuff was replaced by just "_" and "%"
39
 
**
40
 
**      As I don't have a copy of the SQL standard handy I wasn't sure whether
41
 
**      to leave in the '\' escape character handling.
42
 
**
43
 
**      Keith Parks. <keith@mtcc.demon.co.uk>
44
 
**
45
 
**      SQL92 lets you specify the escape character by saying
46
 
**      LIKE <pattern> ESCAPE <escape character>. We are a small operation
47
 
**      so we force you to use '\'. - ay 7/95
48
 
**
49
 
**      Now we have the like_escape() function that converts patterns with
50
 
**      any specified escape character (or none at all) to the internal
51
 
**      default escape character, which is still '\'. - tgl 9/2000
52
 
**
53
 
** The code is rewritten to avoid requiring null-terminated strings,
54
 
** which in turn allows us to leave out some memcpy() operations.
55
 
** This code should be faster and take less memory, but no promises...
56
 
** - thomas 2000-08-06
57
 
**
58
 
*/
 
28
 *      Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
 
29
 *      Rich $alz is now <rsalz@bbn.com>.
 
30
 *      Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
 
31
 *
 
32
 *      This code was shamelessly stolen from the "pql" code by myself and
 
33
 *      slightly modified :)
 
34
 *
 
35
 *      All references to the word "star" were replaced by "percent"
 
36
 *      All references to the word "wild" were replaced by "like"
 
37
 *
 
38
 *      All the nice shell RE matching stuff was replaced by just "_" and "%"
 
39
 *
 
40
 *      As I don't have a copy of the SQL standard handy I wasn't sure whether
 
41
 *      to leave in the '\' escape character handling.
 
42
 *
 
43
 *      Keith Parks. <keith@mtcc.demon.co.uk>
 
44
 *
 
45
 *      SQL92 lets you specify the escape character by saying
 
46
 *      LIKE <pattern> ESCAPE <escape character>. We are a small operation
 
47
 *      so we force you to use '\'. - ay 7/95
 
48
 *
 
49
 *      Now we have the like_escape() function that converts patterns with
 
50
 *      any specified escape character (or none at all) to the internal
 
51
 *      default escape character, which is still '\'. - tgl 9/2000
 
52
 *
 
53
 * The code is rewritten to avoid requiring null-terminated strings,
 
54
 * which in turn allows us to leave out some memcpy() operations.
 
55
 * This code should be faster and take less memory, but no promises...
 
56
 * - thomas 2000-08-06
 
57
 */
59
58
 
60
59
 
61
60
/*--------------------
62
 
 *      Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
 
61
 *      Match text and pattern, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
63
62
 *
64
63
 *      LIKE_TRUE: they match
65
64
 *      LIKE_FALSE: they don't match
80
79
MatchText(char *t, int tlen, char *p, int plen)
81
80
{
82
81
        /* Fast path for match-everything pattern */
83
 
        if ((plen == 1) && (*p == '%'))
 
82
        if (plen == 1 && *p == '%')
84
83
                return LIKE_TRUE;
85
84
 
86
85
        /*
87
86
         * In this loop, we advance by char when matching wildcards (and thus on
88
87
         * recursive entry to this function we are properly char-synced). On other
89
88
         * occasions it is safe to advance by byte, as the text and pattern will
90
 
         * be in lockstep. This allows us to perform all comparisons  between the
 
89
         * be in lockstep. This allows us to perform all comparisons between the
91
90
         * text and pattern on a byte by byte basis, even for multi-byte
92
91
         * encodings.
93
92
         */
94
 
 
95
 
        while ((tlen > 0) && (plen > 0))
 
93
        while (tlen > 0 && plen > 0)
96
94
        {
97
95
                if (*p == '\\')
98
96
                {
102
100
                        if (plen <= 0)
103
101
                                ereport(ERROR,
104
102
                                                (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE),
105
 
                                                 errmsg("LIKE pattern must not end with escape character")));
106
 
                        if (TCHAR(*p) != TCHAR(*t))
 
103
                                 errmsg("LIKE pattern must not end with escape character")));
 
104
                        if (TCHAR (*p) != TCHAR (*t))
107
105
                                return LIKE_FALSE;
108
106
                }
109
107
                else if (*p == '%')
116
114
 
117
115
                        /* %% is the same as % according to the SQL standard */
118
116
                        /* Advance past all %'s */
119
 
                        while ((plen > 0) && (*p == '%'))
 
117
                        while (plen > 0 && *p == '%')
120
118
                                NextByte(p, plen);
121
119
                        /* Trailing percent matches everything. */
122
120
                        if (plen <= 0)
127
125
                         * rest of the pattern.
128
126
                         */
129
127
                        if (*p == '_')
130
 
 
131
128
                        {
132
129
                                /* %_ is the same as _% - avoid matching _ repeatedly */
133
130
 
134
 
                                NextChar(t, tlen);
135
 
                                NextByte(p, plen);
136
 
 
137
 
                                if (tlen <= 0)
138
 
                                {
139
 
                                        return (plen <= 0) ? LIKE_TRUE : LIKE_ABORT;
140
 
                                }
141
 
                                else if (plen <= 0)
142
 
                                {
143
 
                                        return LIKE_FALSE;
144
 
                                }
145
 
 
 
131
                                do
 
132
                                {
 
133
                                        NextChar(t, tlen);
 
134
                                        NextByte(p, plen);
 
135
                                } while (tlen > 0 && plen > 0 && *p == '_');
 
136
 
 
137
                                /*
 
138
                                 * If we are at the end of the pattern, succeed: % followed by
 
139
                                 * n _'s matches any string of at least n characters, and we
 
140
                                 * have now found there are at least n characters.
 
141
                                 */
 
142
                                if (plen <= 0)
 
143
                                        return LIKE_TRUE;
 
144
 
 
145
                                /* Look for a place that matches the rest of the pattern */
146
146
                                while (tlen > 0)
147
147
                                {
148
148
                                        int                     matched = MatchText(t, tlen, p, plen);
155
155
                        }
156
156
                        else
157
157
                        {
158
 
 
159
 
                                char            firstpat = TCHAR(*p);
 
158
                                char            firstpat = TCHAR (*p);
160
159
 
161
160
                                if (*p == '\\')
162
161
                                {
163
162
                                        if (plen < 2)
164
163
                                                return LIKE_FALSE;
165
 
                                        firstpat = TCHAR(p[1]);
 
164
                                        firstpat = TCHAR (p[1]);
166
165
                                }
167
166
 
168
167
                                while (tlen > 0)
171
170
                                         * Optimization to prevent most recursion: don't recurse
172
171
                                         * unless first pattern byte matches first text byte.
173
172
                                         */
174
 
                                        if (TCHAR(*t) == firstpat)
 
173
                                        if (TCHAR (*t) == firstpat)
175
174
                                        {
176
175
                                                int                     matched = MatchText(t, tlen, p, plen);
177
176
 
180
179
                                        }
181
180
 
182
181
                                        NextChar(t, tlen);
183
 
 
184
182
                                }
185
183
                        }
186
184
 
192
190
                }
193
191
                else if (*p == '_')
194
192
                {
 
193
                        /* _ matches any single character, and we know there is one */
195
194
                        NextChar(t, tlen);
196
195
                        NextByte(p, plen);
197
196
                        continue;
198
197
                }
199
 
                else if (TCHAR(*t) != TCHAR(*p))
 
198
                else if (TCHAR (*p) != TCHAR (*t))
200
199
                {
201
 
                        /*
202
 
                         * Not the single-character wildcard and no explicit match? Then
203
 
                         * time to quit...
204
 
                         */
 
200
                        /* non-wildcard pattern char fails to match text char */
205
201
                        return LIKE_FALSE;
206
202
                }
207
203
 
208
204
                /*
 
205
                 * Pattern and text match, so advance.
 
206
                 *
209
207
                 * It is safe to use NextByte instead of NextChar here, even for
210
208
                 * multi-byte character sets, because we are not following immediately
211
209
                 * after a wildcard character. If we are in the middle of a multibyte
222
220
        if (tlen > 0)
223
221
                return LIKE_FALSE;              /* end of pattern, but not of text */
224
222
 
225
 
        /* End of input string.  Do we have matching pattern remaining? */
226
 
        while ((plen > 0) && (*p == '%'))       /* allow multiple %'s at end of
 
223
        /* End of text string.  Do we have matching pattern remaining? */
 
224
        while (plen > 0 && *p == '%')           /* allow multiple %'s at end of
227
225
                                                                                 * pattern */
228
226
                NextByte(p, plen);
229
227