KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > Like


1 /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * Redistributions of source code must retain the above copyright notice, this
8  * list of conditions and the following disclaimer.
9  *
10  * Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * Neither the name of the Hypersonic SQL Group nor the names of its
15  * contributors may be used to endorse or promote products derived from this
16  * software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * This software consists of voluntary contributions made by many individuals
31  * on behalf of the Hypersonic SQL Group.
32  *
33  *
34  * For work added by the HSQL Development Group:
35  *
36  * Copyright (c) 2001-2005, The HSQL Development Group
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions are met:
41  *
42  * Redistributions of source code must retain the above copyright notice, this
43  * list of conditions and the following disclaimer.
44  *
45  * Redistributions in binary form must reproduce the above copyright notice,
46  * this list of conditions and the following disclaimer in the documentation
47  * and/or other materials provided with the distribution.
48  *
49  * Neither the name of the HSQL Development Group nor the names of its
50  * contributors may be used to endorse or promote products derived from this
51  * software without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
54  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
57  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
58  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
59  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
60  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
62  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
63  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64  */

65
66
67 package org.hsqldb;
68
69 import org.hsqldb.lib.StringUtil;
70
71 /**
72  * Reusable object for processing LIKE queries.
73  *
74  * Enhanced in successive versions of HSQLDB.
75  *
76  * @author Thomas Mueller (Hypersonic SQL Group)
77  * @version 1.8.0
78  * @since Hypersonic SQL
79  */

80
81 // boucherb@users 20030930 - patch 1.7.2 - optimize into joins if possible
82
// fredt@users 20031006 - patch 1.7.2 - reuse Like objects for all rows
83
class Like {
84
85     private char[] cLike;
86     private int[] wildCardType;
87     private int iLen;
88     private boolean isIgnoreCase;
89     private int iFirstWildCard;
90     private boolean isNull;
91     Character JavaDoc escapeChar;
92     boolean hasCollation;
93     boolean optimised;
94     static final int UNDERSCORE_CHAR = 1;
95     static final int PERCENT_CHAR = 2;
96
97     Like(Character JavaDoc escape, boolean collation) {
98         escapeChar = escape;
99         hasCollation = collation;
100     }
101
102     /**
103      * param setter
104      *
105      * @param s
106      * @param ignorecase
107      */

108     void setParams(Session session, String JavaDoc s, boolean ignorecase) {
109
110         isIgnoreCase = ignorecase;
111
112         normalize(session, s);
113
114         optimised = true;
115     }
116
117     /**
118      * Resets the search pattern;
119      */

120     void resetPattern(Session session, String JavaDoc s) {
121         normalize(session, s);
122     }
123
124     private String JavaDoc getStartsWith() {
125
126         if (iLen == 0) {
127             return "";
128         }
129
130         StringBuffer JavaDoc s = new StringBuffer JavaDoc();
131         int i = 0;
132
133         for (; (i < iLen) && (wildCardType[i] == 0); i++) {
134             s.append(cLike[i]);
135         }
136
137         if (i == 0) {
138             return null;
139         }
140
141         return s.toString();
142     }
143
144     /**
145      * Method declaration
146      *
147      *
148      * @param o
149      *
150      * @return
151      */

152     Boolean JavaDoc compare(Session session, String JavaDoc s) {
153
154         if (s == null) {
155             return null;
156         }
157
158         if (isIgnoreCase) {
159             s = session.database.collation.toUpperCase(s);
160         }
161
162         return compareAt(s, 0, 0, s.length()) ? Boolean.TRUE
163                                               : Boolean.FALSE;
164     }
165
166     /**
167      * Method declaration
168      *
169      *
170      * @param s
171      * @param i
172      * @param j
173      * @param jLen
174      *
175      * @return
176      */

177     private boolean compareAt(String JavaDoc s, int i, int j, int jLen) {
178
179         for (; i < iLen; i++) {
180             switch (wildCardType[i]) {
181
182                 case 0 : // general character
183
if ((j >= jLen) || (cLike[i] != s.charAt(j++))) {
184                         return false;
185                     }
186                     break;
187
188                 case UNDERSCORE_CHAR : // underscore: do not test this character
189
if (j++ >= jLen) {
190                         return false;
191                     }
192                     break;
193
194                 case PERCENT_CHAR : // percent: none or any character(s)
195
if (++i >= iLen) {
196                         return true;
197                     }
198
199                     while (j < jLen) {
200                         if ((cLike[i] == s.charAt(j))
201                                 && compareAt(s, i, j, jLen)) {
202                             return true;
203                         }
204
205                         j++;
206                     }
207
208                     return false;
209             }
210         }
211
212         if (j != jLen) {
213             return false;
214         }
215
216         return true;
217     }
218
219     /**
220      * Method declaration
221      *
222      *
223      * @param pattern
224      * @param b
225      */

226     private void normalize(Session session, String JavaDoc pattern) {
227
228         isNull = pattern == null;
229
230         if (!isNull && isIgnoreCase) {
231             pattern = session.database.collation.toUpperCase(pattern);
232         }
233
234         iLen = 0;
235         iFirstWildCard = -1;
236
237         int l = pattern == null ? 0
238                                 : pattern.length();
239
240         cLike = new char[l];
241         wildCardType = new int[l];
242
243         boolean bEscaping = false,
244                 bPercent = false;
245
246         for (int i = 0; i < l; i++) {
247             char c = pattern.charAt(i);
248
249             if (bEscaping == false) {
250                 if (escapeChar != null && escapeChar.charValue() == c) {
251                     bEscaping = true;
252
253                     continue;
254                 } else if (c == '_') {
255                     wildCardType[iLen] = UNDERSCORE_CHAR;
256
257                     if (iFirstWildCard == -1) {
258                         iFirstWildCard = iLen;
259                     }
260                 } else if (c == '%') {
261                     if (bPercent) {
262                         continue;
263                     }
264
265                     bPercent = true;
266                     wildCardType[iLen] = PERCENT_CHAR;
267
268                     if (iFirstWildCard == -1) {
269                         iFirstWildCard = iLen;
270                     }
271                 } else {
272                     bPercent = false;
273                 }
274             } else {
275                 bPercent = false;
276                 bEscaping = false;
277             }
278
279             cLike[iLen++] = c;
280         }
281
282         for (int i = 0; i < iLen - 1; i++) {
283             if ((wildCardType[i] == PERCENT_CHAR)
284                     && (wildCardType[i + 1] == UNDERSCORE_CHAR)) {
285                 wildCardType[i] = UNDERSCORE_CHAR;
286                 wildCardType[i + 1] = PERCENT_CHAR;
287             }
288         }
289     }
290
291     boolean hasWildcards() {
292         return iFirstWildCard != -1;
293     }
294
295     boolean isEquivalentToFalsePredicate() {
296         return isNull;
297     }
298
299     boolean isEquivalentToEqualsPredicate() {
300         return iFirstWildCard == -1;
301     }
302
303     boolean isEquivalentToNotNullPredicate() {
304
305         if (isNull ||!hasWildcards()) {
306             return false;
307         }
308
309         for (int i = 0; i < wildCardType.length; i++) {
310             if (wildCardType[i] != PERCENT_CHAR) {
311                 return false;
312             }
313         }
314
315         return true;
316     }
317
318     boolean isEquivalentToBetweenPredicate() {
319
320         return iFirstWildCard > 0
321                && iFirstWildCard == wildCardType.length - 1
322                && cLike[iFirstWildCard] == '%';
323     }
324
325     boolean isEquivalentToBetweenPredicateAugmentedWithLike() {
326         return iFirstWildCard > 0 && cLike[iFirstWildCard] == '%';
327     }
328
329     String JavaDoc getRangeLow() {
330         return getStartsWith();
331     }
332
333     String JavaDoc getRangeHigh() {
334
335         String JavaDoc s = getStartsWith();
336
337         return s == null ? null
338                          : s.concat("\uffff");
339     }
340
341     public String JavaDoc describe(Session session) {
342
343         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
344
345         sb.append(super.toString()).append("[\n");
346         sb.append("escapeChar=").append(escapeChar).append('\n');
347         sb.append("isNull=").append(isNull).append('\n');
348         sb.append("optimised=").append(optimised).append('\n');
349         sb.append("isIgnoreCase=").append(isIgnoreCase).append('\n');
350         sb.append("iLen=").append(iLen).append('\n');
351         sb.append("iFirstWildCard=").append(iFirstWildCard).append('\n');
352         sb.append("cLike=");
353         sb.append(StringUtil.arrayToString(cLike));
354         sb.append('\n');
355         sb.append("wildCardType=");
356         sb.append(StringUtil.arrayToString(wildCardType));
357         sb.append(']');
358
359         return sb.toString();
360     }
361 }
362
Popular Tags