Source Code Cross Referenced for Like.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » iapi » types » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.iapi.types 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Derby - Class org.apache.derby.iapi.types.Like
004:
005:           Licensed to the Apache Software Foundation (ASF) under one or more
006:           contributor license agreements.  See the NOTICE file distributed with
007:           this work for additional information regarding copyright ownership.
008:           The ASF licenses this file to you under the Apache License, Version 2.0
009:           (the "License"); you may not use this file except in compliance with
010:           the License.  You may obtain a copy of the License at
011:
012:              http://www.apache.org/licenses/LICENSE-2.0
013:
014:           Unless required by applicable law or agreed to in writing, software
015:           distributed under the License is distributed on an "AS IS" BASIS,
016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017:           See the License for the specific language governing permissions and
018:           limitations under the License.
019:
020:         */
021:
022:        package org.apache.derby.iapi.types;
023:
024:        // RESOLVE: MOVE THIS CLASS TO PROTOCOL (See LikeOperatorNode)
025:
026:        import org.apache.derby.iapi.services.sanity.SanityManager;
027:
028:        import org.apache.derby.iapi.error.StandardException;
029:        import org.apache.derby.iapi.reference.SQLState;
030:
031:        import java.text.CollationElementIterator;
032:        import java.text.Collator;
033:        import java.text.RuleBasedCollator;
034:        import java.util.Locale;
035:
036:        /**
037:         Like matching algorithm. Not too speedy for %s.
038:
039:         SQL92 says the escape character can only and must be followed
040:         by itself, %, or _.  So if you choose % or _ as the escape character,
041:         you can no longer do that sort of matching.
042:
043:         Not the most recent Like -- missing the unit tests
044:
045:         @author ames
046:         */
047:        public class Like {
048:            private static final char anyChar = '_';
049:            private static final char anyString = '%';
050:
051:            private static final String SUPER_STRING = "\uffff";
052:
053:            private Like() { // do not instantiate
054:            }
055:
056:            /**
057:            	@param val value to compare. if null, result is null.
058:            	@param valLength length of val
059:            	@param pat pattern to compare. if null, result is null.
060:            	@param patLength length of pat
061:            	@param escape escape character. Must be 1 char long.
062:            		if null, no escape character is used.
063:            	@param escapeLength length of escape
064:
065:            	@return null if val or pat null, otherwise true if match
066:            	and false if not.
067:            	@exception StandardException thrown if data invalid
068:             */
069:            public static Boolean like(char[] val, int valLength, char[] pat,
070:                    int patLength, char[] escape, int escapeLength)
071:                    throws StandardException {
072:                return like(val, 0, valLength, pat, 0, patLength, escape,
073:                        escapeLength);
074:            }
075:
076:            /**
077:            	For national chars.
078:            	@param val value to compare. if null, result is null.
079:            	@param valLength length of val
080:            	@param pat pattern to compare. if null, result is null.
081:            	@param patLength length of pat
082:            	@param escape escape character. Must be 1 char long.
083:            		if null, no escape character is used.
084:            	@param escapeLength length of escape
085:            	@param collator	The collator to use.
086:
087:            	@return null if val or pat null, otherwise true if match
088:            	and false if not.
089:            	@exception StandardException thrown if data invalid
090:             */
091:            public static Boolean like(int[] val, int valLength, int[] pat,
092:                    int patLength, int[] escape, int escapeLength,
093:                    RuleBasedCollator collator) throws StandardException {
094:                return like(val, 0, valLength, pat, 0, patLength, escape,
095:                        escapeLength, collator);
096:            }
097:
098:            /* non-national chars */
099:            private static Boolean like(char[] val, int vLoc, // start at val[vLoc]
100:                    int vEnd, // end at val[vEnd]
101:                    char[] pat, int pLoc, // start at pat[pLoc]
102:                    int pEnd, // end at pat[pEnd]
103:                    char[] escape, int escapeLength) throws StandardException {
104:                char escChar = ' ';
105:                boolean haveEsc = true;
106:
107:                if (val == null)
108:                    return null;
109:                if (pat == null)
110:                    return null;
111:
112:                if (escape == null) {
113:                    haveEsc = false;
114:                } else {
115:                    escChar = escape[0];
116:                }
117:
118:                Boolean result;
119:
120:                while (true) {
121:
122:                    if ((result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd)) != null) {
123:                        return result;
124:                    }
125:
126:                    // go until we get a special char in the pattern or hit EOS
127:                    while (pat[pLoc] != anyChar && pat[pLoc] != anyString
128:                            && ((!haveEsc) || pat[pLoc] != escChar)) {
129:                        if (val[vLoc] == pat[pLoc]) {
130:                            vLoc++;
131:                            pLoc++;
132:
133:                            result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd);
134:                            if (result != null)
135:                                return result;
136:                        } else {
137:                            return Boolean.FALSE;
138:                        }
139:                    }
140:
141:                    // deal with escChar first, as it can be escaping a special char
142:                    // and can be a special char itself.
143:                    if (haveEsc && pat[pLoc] == escChar) {
144:                        pLoc++;
145:                        if (pLoc == pEnd) {
146:                            throw StandardException
147:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
148:                        }
149:                        if (pat[pLoc] != escChar && pat[pLoc] != anyChar
150:                                && pat[pLoc] != anyString) {
151:                            throw StandardException
152:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
153:                        }
154:                        // regardless of the char in pat, it must match exactly:
155:                        if (val[vLoc] == pat[pLoc]) {
156:                            vLoc++;
157:                            pLoc++;
158:
159:                            result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd);
160:                            if (result != null)
161:                                return result;
162:                        } else
163:                            return Boolean.FALSE;
164:                    } else if (pat[pLoc] == anyChar) {
165:                        // regardless of the char, it matches
166:                        vLoc++;
167:                        pLoc++;
168:
169:                        result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd);
170:                        if (result != null)
171:                            return result;
172:                    } else if (pat[pLoc] == anyString) {
173:                        // catch the simple cases -- end of the pattern or of the string
174:                        if (pLoc + 1 == pEnd)
175:                            return Boolean.TRUE;
176:
177:                        // would return true, but caught in checkLengths above
178:                        if (SanityManager.DEBUG)
179:                            SanityManager.ASSERT(vLoc != vEnd,
180:                                    "Should have been found already");
181:
182:                        //if (vLoc == vEnd) // caught in checkLengths
183:                        //return Boolean.TRUE;
184:                        // check if remainder of pattern is anyString's
185:                        // if escChar == anyString, we couldn't be here
186:                        boolean anys = true;
187:                        for (int i = pLoc + 1; i < pEnd; i++)
188:                            if (pat[i] != anyString) {
189:                                anys = false;
190:                                break;
191:                            }
192:                        if (anys)
193:                            return Boolean.TRUE;
194:
195:                        // pattern can match 0 or more chars in value.
196:                        // to test that, we take the remainder of pattern and
197:                        // apply it to ever-shorter  remainders of value until
198:                        // we hit a match.
199:
200:                        // the loop never continues from this point -- we will
201:                        // always generate an answer here.
202:
203:                        // REMIND: there are smarter ways to pick the remainders
204:                        // and do this matching.
205:
206:                        // num chars left in value includes current char
207:                        int vRem = vEnd - vLoc;
208:
209:                        int n = 0;
210:
211:                        // num chars left in pattern excludes the anychar
212:                        int minLen = getMinLen(pat, pLoc + 1, pEnd, haveEsc,
213:                                escChar);
214:                        for (int i = vRem; i >= minLen; i--) {
215:                            Boolean restResult = Like.like(val, vLoc + n, vLoc
216:                                    + n + i, pat, pLoc + 1, pEnd, escape,
217:                                    escapeLength);
218:                            if (SanityManager.DEBUG) {
219:                                if (restResult == null) {
220:                                    String vStr = new String(val, vLoc + n, i);
221:                                    String pStr = new String(pat, pLoc + 1,
222:                                            pEnd - (pLoc + 1));
223:                                    SanityManager
224:                                            .THROWASSERT("null result on like(value = "
225:                                                    + vStr
226:                                                    + ", pat = "
227:                                                    + pStr
228:                                                    + ")");
229:                                }
230:                            }
231:                            if (restResult.booleanValue())
232:                                return restResult;
233:
234:                            n++;
235:                        }
236:                        // none of the possibilities worked 
237:                        return Boolean.FALSE;
238:                    }
239:                }
240:            }
241:
242:            /* national chars */
243:            private static Boolean like(int[] val, int vLoc, // start at val[vLoc]
244:                    int vEnd, // end at val[vEnd]
245:                    int[] pat, int pLoc, // start at pat[pLoc]
246:                    int pEnd, // end at pat[pEnd]
247:                    int[] escape, int escapeLength, RuleBasedCollator collator)
248:                    throws StandardException {
249:                int[] escCharInts = null;
250:                boolean haveEsc = true;
251:                int[] anyCharInts = new int[1]; // assume only 1 int
252:                int[] anyStringInts = new int[1]; // assume only 1 int
253:
254:                if (val == null)
255:                    return null;
256:                if (pat == null)
257:                    return null;
258:
259:                if (escape == null) {
260:                    haveEsc = false;
261:                } else {
262:                    escCharInts = escape;
263:                }
264:
265:                Boolean result;
266:
267:                // get the collation integer representing "_"
268:                CollationElementIterator cei = collator
269:                        .getCollationElementIterator("_");
270:                anyCharInts[0] = cei.next();
271:                {
272:                    int nextInt;
273:
274:                    // There may be multiple ints representing this character
275:                    while ((nextInt = cei.next()) != CollationElementIterator.NULLORDER) {
276:                        int[] temp = new int[anyCharInts.length + 1];
277:                        for (int index = 0; index < anyCharInts.length; index++) {
278:                            temp[index] = anyCharInts[index];
279:                        }
280:                        temp[anyCharInts.length] = nextInt;
281:                        anyCharInts = temp;
282:                    }
283:                }
284:                // get the collation integer representing "%"
285:                cei = collator.getCollationElementIterator("%");
286:                anyStringInts[0] = cei.next();
287:                {
288:                    int nextInt;
289:
290:                    // There may be multiple ints representing this character
291:                    while ((nextInt = cei.next()) != CollationElementIterator.NULLORDER) {
292:                        int[] temp = new int[anyStringInts.length + 1];
293:                        for (int index = 0; index < anyStringInts.length; index++) {
294:                            temp[index] = anyStringInts[index];
295:                        }
296:                        temp[anyStringInts.length] = nextInt;
297:                        anyStringInts = temp;
298:                    }
299:                }
300:
301:                while (true) {
302:                    // returns null if more work to do, otherwise match Boolean
303:                    result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd,
304:                            anyStringInts);
305:                    if (result != null)
306:                        return result;
307:
308:                    // go until we get a special char in the pattern or hit EOS
309:                    while ((!matchSpecial(pat, pLoc, pEnd, anyCharInts))
310:                            && (!matchSpecial(pat, pLoc, pEnd, anyStringInts))
311:                            && ((!haveEsc) || (!matchSpecial(pat, pLoc, pEnd,
312:                                    escCharInts)))) {
313:                        if (val[vLoc] == pat[pLoc]) {
314:                            vLoc++;
315:                            pLoc++;
316:
317:                            result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd,
318:                                    anyStringInts);
319:                            if (result != null) {
320:                                return result;
321:                            }
322:                        } else {
323:                            return Boolean.FALSE;
324:                        }
325:                    }
326:
327:                    // deal with escCharInt first, as it can be escaping a special char
328:                    // and can be a special char itself.
329:                    if (haveEsc && matchSpecial(pat, pLoc, pEnd, escCharInts)) {
330:                        pLoc += escCharInts.length;
331:                        if (pLoc == pEnd) {
332:                            throw StandardException
333:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
334:                        }
335:
336:                        int[] specialInts = null;
337:                        if (matchSpecial(pat, pLoc, pEnd, escCharInts)) {
338:                            specialInts = escCharInts;
339:                        }
340:                        if (matchSpecial(pat, pLoc, pEnd, anyCharInts)) {
341:                            specialInts = anyCharInts;
342:                        }
343:                        if (matchSpecial(pat, pLoc, pEnd, anyStringInts)) {
344:                            specialInts = anyStringInts;
345:                        }
346:                        if (specialInts == null) {
347:                            throw StandardException
348:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
349:                        }
350:                        // regardless of the char in pat, it must match exactly:
351:                        for (int index = 0; index < specialInts.length; index++) {
352:                            if (val[vLoc + index] != pat[pLoc + index]) {
353:                                return Boolean.FALSE;
354:                            }
355:                        }
356:
357:                        vLoc += specialInts.length;
358:                        pLoc += specialInts.length;
359:
360:                        // returns null if more work to do, otherwise match Boolean
361:                        result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd,
362:                                anyStringInts);
363:
364:                        if (result != null)
365:                            return result;
366:                    } else if (matchSpecial(pat, pLoc, pEnd, anyCharInts)) {
367:                        // regardless of the char, it matches
368:                        vLoc += anyCharInts.length;
369:                        pLoc += anyCharInts.length;
370:
371:                        result = checkLengths(vLoc, vEnd, pLoc, pat, pEnd,
372:                                anyStringInts);
373:                        if (result != null)
374:                            return result;
375:                    } else if (matchSpecial(pat, pLoc, pEnd, anyStringInts)) {
376:                        // catch the simple cases -- end of the pattern or of the string
377:                        if (pLoc + 1 == pEnd)
378:                            return Boolean.TRUE;
379:
380:                        // would return true, but caught in checkLengths above
381:                        if (SanityManager.DEBUG)
382:                            SanityManager.ASSERT(vLoc != vEnd,
383:                                    "Should have been found already");
384:
385:                        if (vLoc == vEnd)
386:                            return Boolean.TRUE;
387:
388:                        // check if remainder of pattern is anyString's
389:                        // if escChar == anyString, we couldn't be here
390:                        // If there is an escape in the pattern we break
391:                        boolean allPercentChars = true;
392:                        for (int i = pLoc + 1; i < pEnd; i++) {
393:                            if (!matchSpecial(pat, i, pEnd, anyStringInts)) {
394:                                allPercentChars = false;
395:                                break;
396:                            }
397:                        }
398:                        if (allPercentChars)
399:                            return Boolean.TRUE;
400:
401:                        // pattern can match 0 or more chars in value.
402:                        // to test that, we take the remainder of pattern and
403:                        // apply it to ever-shorter  remainders of value until
404:                        // we hit a match.
405:
406:                        // the loop never continues from this point -- we will
407:                        // always generate an answer here.
408:
409:                        // REMIND: there are smarter ways to pick the remainders
410:                        // and do this matching.
411:
412:                        // num chars left in value includes current char
413:                        int vRem = vEnd - vLoc;
414:
415:                        int n = 0;
416:
417:                        // num chars left in pattern excludes the anyString
418:                        int minLen = getMinLen(pat, pLoc + 1, pEnd, haveEsc,
419:                                escCharInts, anyStringInts);
420:                        for (int i = vRem; i >= minLen; i--) {
421:                            Boolean restResult = Like.like(val, vLoc + n, vLoc
422:                                    + n + i, pat, pLoc + 1, pEnd, escape,
423:                                    escapeLength, collator);
424:                            if (SanityManager.DEBUG) {
425:                                if (restResult == null) {
426:                                    SanityManager
427:                                            .THROWASSERT("null result on like(vLoc+n = "
428:                                                    + (vLoc + n)
429:                                                    + ", i = "
430:                                                    + i
431:                                                    + ", pLoc+1 = "
432:                                                    + (pLoc + 1)
433:                                                    + ", pEnd-(pLoc+1) = "
434:                                                    + (pEnd - (pLoc + 1)) + ")");
435:                                }
436:                            }
437:                            if (restResult.booleanValue())
438:                                return restResult;
439:
440:                            n++;
441:                        }
442:                        // none of the possibilities worked 
443:                        return Boolean.FALSE;
444:                    }
445:                }
446:            }
447:
448:            /**
449:            	Calculate the shortest length string that could match this pattern for non-national chars
450:             */
451:            static int getMinLen(char[] pattern, int pStart, int pEnd,
452:                    boolean haveEsc, char escChar) {
453:                int m = 0;
454:                for (int l = pStart; l < pEnd;) {
455:                    if (haveEsc && pattern[l] == escChar) { // need one char
456:                        l += 2;
457:                        m++;
458:                    } else if (pattern[l] == anyString) {
459:                        l++; // anyString, nothing needed
460:                    } else { // anyChar or other chars, need one char
461:                        l++;
462:                        m++;
463:                    }
464:                }
465:                return m;
466:            }
467:
468:            /**
469:            	Calculate the shortest length string that could match this pattern for national chars
470:             */
471:            static int getMinLen(int[] pattern, int pStart, int pEnd,
472:                    boolean haveEsc, int[] escCharInts, int[] anyStringInts) {
473:                int m = 0;
474:                for (int l = pStart; l < pEnd;) {
475:                    if (haveEsc && matchSpecial(pattern, l, pEnd, escCharInts)) {
476:                        l += escCharInts.length + 1;
477:                        m += escCharInts.length;
478:                    } else if (matchSpecial(pattern, l, pEnd, anyStringInts)) {
479:                        l += anyStringInts.length; // anyString, nothing needed
480:                    } else { // anyChar or other chars, need one char
481:                        l++;
482:                        m++;
483:                    }
484:                }
485:                return m;
486:            }
487:
488:            /**
489:             * checkLengths -- non-national chars 
490:             *
491:             * Returns null if we are not done.
492:             * Returns true if we are at the end of our value and pattern
493:             * Returns false if there is more pattern left but out of input value
494:             *
495:             * @param vLoc current index into char[] val
496:             * @param vEnd end index or our value
497:             * @param pLoc current index into our char[] pattern
498:             * @param pat  pattern char []
499:             * @param pEnd end index of our pattern []
500:             */
501:
502:            static Boolean checkLengths(int vLoc, int vEnd, int pLoc,
503:                    char[] pat, int pEnd) {
504:                if (vLoc == vEnd) {
505:                    if (pLoc == pEnd) {
506:                        return Boolean.TRUE;
507:                    } else {
508:                        // if remainder of pattern is anyString chars, ok
509:                        for (int i = pLoc; i < pEnd; i++) {
510:                            if (pat[i] != anyString) {
511:                                return Boolean.FALSE; // more to match
512:                            }
513:                        }
514:                        return Boolean.TRUE;
515:                    }
516:                } else if (pLoc == pEnd) {
517:                    return Boolean.FALSE; // ran out of pattern
518:                } else
519:                    return null; // still have strings to match, not done
520:            }
521:
522:            /**
523:             * checkLengths -- national chars 
524:             *
525:             * Returns null if we are not done.
526:             * Returns true if we are at the end of our value and pattern
527:             * Returns false if there is more pattern left but out of input value
528:             *
529:             * @param vLoc current index into int[] val
530:             * @param vEnd end index or our value
531:             * @param pLoc current index into our int[] pattern
532:             * @param pat  pattern int []
533:             * @param pEnd end index of our pattern []
534:             */
535:
536:            static Boolean checkLengths(int vLoc, int vEnd, int pLoc,
537:                    int[] pat, int pEnd, int[] anyStringInts) {
538:                if (vLoc == vEnd) {
539:                    if (pLoc == pEnd) {
540:                        return Boolean.TRUE;
541:                    } else {
542:                        // if remainder of pattern is anyString chars, ok
543:                        for (int i = pLoc; i < pEnd; i += anyStringInts.length) {
544:                            if (!matchSpecial(pat, i, pEnd, anyStringInts)) {
545:                                return Boolean.FALSE;
546:                            }
547:                        }
548:                        return Boolean.TRUE;
549:                    }
550:                } else if (pLoc == pEnd) {
551:                    return Boolean.FALSE; // ran out of pattern
552:                } else
553:                    return null; // still have strings to match, not done
554:            }
555:
556:            /**
557:             * matchSpecial
558:             *
559:             *	check the pattern against the various special character arrays.
560:             *  The array can be anyStringInts, anyCharInts or anyEscChars (always 1)
561:             */
562:
563:            private static boolean matchSpecial(int[] pat, int patStart,
564:                    int patEnd, int[] specialInts) {
565:                //
566:                // multi-collation units per char can exceed the pattern length
567:                // and we fall around the 2nd if statement and falsely return true.
568:                //
569:                if (specialInts.length > patEnd - patStart)
570:                    return false;
571:                if (specialInts.length <= patEnd - patStart) {
572:                    for (int index = 0; index < specialInts.length; index++) {
573:                        if (pat[patStart + index] != specialInts[index]) {
574:                            return false; // more to match
575:                        }
576:                    }
577:                }
578:                return true;
579:            }
580:
581:            /*
582:            	Most typical interface for non-national chars
583:             */
584:            public static Boolean like(char[] value, int valueLength,
585:                    char[] pattern, int patternLength) throws StandardException {
586:                if (value == null || pattern == null)
587:                    return null;
588:                return like(value, valueLength, pattern, patternLength, null, 0);
589:            }
590:
591:            /*
592:            	Most typical interface for national chars
593:             */
594:            public static Boolean like(int[] value, int valueLength,
595:                    int[] pattern, int patternLength, RuleBasedCollator collator)
596:                    throws StandardException {
597:                if (value == null || pattern == null)
598:                    return null;
599:                return like(value, valueLength, pattern, patternLength, null,
600:                        0, collator);
601:            }
602:
603:            // Methods for LIKE transformation at preprocess time:
604:
605:            /**
606:             * Determine whether or not this LIKE can be transformed into optimizable
607:             * clauses.  It can if the pattern is non-null and if the length == 0 or
608:             * the first character is not a wild card.
609:             *
610:             * @param pattern	The right side of the LIKE
611:             *
612:             * @return	Whether or not the LIKE can be transformed
613:             */
614:
615:            public static boolean isOptimizable(String pattern) {
616:                if (pattern == null) {
617:                    return false;
618:                }
619:
620:                if (pattern.length() == 0) {
621:                    return true;
622:                }
623:
624:                // if we have pattern matching at start of string, no optimization
625:                char firstChar = pattern.charAt(0);
626:
627:                return (firstChar != anyChar && firstChar != anyString);
628:            }
629:
630:            public static String greaterEqualStringFromParameter(
631:                    String pattern, int maxWidth) throws StandardException {
632:
633:                if (pattern == null)
634:                    return null;
635:
636:                return greaterEqualString(pattern, (String) null, maxWidth);
637:            }
638:
639:            public static String greaterEqualStringFromParameterWithEsc(
640:                    String pattern, String escape, int maxWidth)
641:                    throws StandardException {
642:
643:                if (pattern == null)
644:                    return null;
645:
646:                return greaterEqualString(pattern, escape, maxWidth);
647:            }
648:
649:            /**
650:             * Return the substring from the pattern for the optimization >= clause.
651:             *
652:             * @param pattern	The right side of the LIKE
653:             * @param escape	The escape clause
654:             * @param maxWidth	Maximum length of column, for null padding
655:             *
656:             * @return	The String for the >= clause
657:             */
658:            public static String greaterEqualString(String pattern,
659:                    String escape, int maxWidth) throws StandardException {
660:
661:                int firstAnyChar = pattern.indexOf(anyChar);
662:                int firstAnyString = pattern.indexOf(anyString);
663:
664:                // 
665:                // For Escape we don't utilize any of the stylish code
666:                // below but brute force walk the pattern to find out
667:                // what is there, while stripping escapes
668:                //
669:
670:                if ((escape != null) && (escape.length() != 0)) {
671:                    char escChar = escape.charAt(0);
672:                    if (pattern.indexOf(escChar) != -1) {
673:                        // we return a string stripping out the escape char
674:                        // leaving the _? in place as normal chars.
675:
676:                        return padWithNulls(
677:                                greaterEqualString(pattern, escChar), maxWidth);
678:                    }
679:                    // drop through if no escape found
680:                }
681:
682:                if (firstAnyChar == -1) {
683:                    if (firstAnyString != -1) // no _, found %
684:                    {
685:                        pattern = pattern.substring(0, firstAnyString);
686:                    }
687:                } else if (firstAnyString == -1) {
688:                    pattern = pattern.substring(0, firstAnyChar);
689:                } else {
690:                    pattern = pattern.substring(0,
691:                            (firstAnyChar > firstAnyString) ? firstAnyString
692:                                    : firstAnyChar);
693:                }
694:                return padWithNulls(pattern, maxWidth);
695:            }
696:
697:            /** 
698:             *  greaterEqualString -- for Escape clause only
699:             *  
700:             *  Walk the pattern character by character
701:             *  @param pattern like pattern to build from
702:             *  @param escChar the escape character in the pattern
703:             */
704:
705:            private static String greaterEqualString(String pattern,
706:                    char escChar) throws StandardException {
707:                int patternLen = pattern.length();
708:                char[] patternChars = new char[patternLen];
709:                char[] result = new char[patternLen];
710:                pattern.getChars(0, patternLen, patternChars, 0);
711:
712:                int r = 0;
713:                for (int p = 0; p < patternLen && r < patternLen; p++) {
714:                    char c = patternChars[p];
715:                    if (c == escChar) {
716:                        p++; // don't copy the escape char
717:
718:                        // run out?
719:                        if (p >= patternLen)
720:                            throw StandardException
721:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
722:                        result[r++] = patternChars[p];
723:                        continue;
724:                    }
725:
726:                    // stop on first pattern matching char
727:                    if (c == anyChar || c == anyString) {
728:                        return new String(result, 0, r);
729:                    }
730:
731:                    result[r++] = patternChars[p];
732:                }
733:
734:                // no pattern chars
735:                return new String(result, 0, r);
736:            }
737:
738:            /**
739:             * stripEscapesNoPatternChars
740:             *
741:             * @param pattern	pattern String to search
742:             * @param escChar	the escape character
743:             *
744:             * @return a stripped of ESC char string if no pattern chars, null otherwise
745:             * @exception StandardException thrown if data invalid
746:             */
747:
748:            public static String stripEscapesNoPatternChars(String pattern,
749:                    char escChar) throws StandardException {
750:                int patternLen = pattern.length();
751:                char[] patternChars = new char[patternLen];
752:                char[] result = new char[patternLen];
753:                pattern.getChars(0, patternLen, patternChars, 0);
754:
755:                int r = 0;
756:                for (int p = 0; p < patternLen && r < patternLen; p++) {
757:                    char c = pattern.charAt(p);
758:                    if (c == escChar) {
759:                        p++; // don't copy the escape char
760:
761:                        // run out?
762:                        if (p >= patternLen)
763:                            throw StandardException
764:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
765:                        result[r++] = patternChars[p];
766:                        continue;
767:                    }
768:
769:                    // die on first pattern matching char
770:                    if (c == anyChar || c == anyString) {
771:                        return null;
772:                    }
773:
774:                    result[r++] = patternChars[p];
775:                }
776:                return new String(result, 0, r);
777:            }
778:
779:            public static String lessThanStringFromParameter(String pattern,
780:                    int maxWidth) throws StandardException {
781:                if (pattern == null)
782:                    return null;
783:                return lessThanString(pattern, null, maxWidth);
784:            }
785:
786:            public static String lessThanStringFromParameterWithEsc(
787:                    String pattern, String escape, int maxWidth)
788:                    throws StandardException {
789:                if (pattern == null)
790:                    return null;
791:                return lessThanString(pattern, escape, maxWidth);
792:            }
793:
794:            /**
795:             * Return the substring from the pattern for the < clause.
796:             *
797:             * @param pattern	The right side of the LIKE
798:             * @param escape	The escape clause
799:             * @param maxWidth	Maximum length of column, for null padding
800:             *
801:             * @return	The String for the < clause
802:             * @exception StandardException thrown if data invalid
803:             */
804:            public static String lessThanString(String pattern, String escape,
805:                    int maxWidth) throws StandardException {
806:                int lastUsableChar;
807:                char oldLastChar;
808:                char newLastChar;
809:                final int escChar;
810:
811:                if ((escape != null) && (escape.length() != 0)) {
812:                    escChar = escape.charAt(0);
813:                } else {
814:                    // Set escape character to a value outside the char range,
815:                    // so that comparison with a char always evaluates to false.
816:                    escChar = -1;
817:                }
818:
819:                /* Find the last non-wildcard character in the pattern
820:                 * and increment it.  In the most common case,
821:                 * "asdf%" becomes "asdg".  However, we need to 
822:                 * handle the following:
823:                 *
824:                 *	pattern			return
825:                 *	-------			------
826:                 *	""				SUPER_STRING (match against super string)
827:                 *	"%..."			SUPER_STRING (match against super string)
828:                 *	"_..."			SUPER_STRING (match against super string)
829:                 *	"asdf%"			"asdg"
830:                 */
831:
832:                StringBuffer upperLimit = new StringBuffer(maxWidth);
833:
834:                // Extract the string leading up to the first wildcard.
835:                for (int i = 0; i < pattern.length(); i++) {
836:                    char c = pattern.charAt(i);
837:                    if (c == escChar) {
838:                        if (++i >= pattern.length()) {
839:                            throw StandardException
840:                                    .newException(SQLState.LANG_INVALID_ESCAPE_SEQUENCE);
841:                        }
842:                        c = pattern.charAt(i);
843:                    } else if (c == anyChar || c == anyString) {
844:                        break;
845:                    }
846:                    upperLimit.append(c);
847:                }
848:
849:                // Pattern is empty or starts with wildcard.
850:                if (upperLimit.length() == 0) {
851:                    return SUPER_STRING;
852:                }
853:
854:                // Increment the last non-wildcard character.
855:                lastUsableChar = upperLimit.length() - 1;
856:                oldLastChar = upperLimit.charAt(lastUsableChar);
857:                newLastChar = oldLastChar;
858:                newLastChar++;
859:
860:                // Check for degenerate roll over
861:                if (newLastChar < oldLastChar) {
862:                    return SUPER_STRING;
863:                }
864:
865:                upperLimit.setCharAt(lastUsableChar, newLastChar);
866:
867:                // Pad the string with nulls.
868:                if (upperLimit.length() < maxWidth) {
869:                    upperLimit.setLength(maxWidth);
870:                }
871:
872:                return upperLimit.toString();
873:            }
874:
875:            /**
876:             * Return whether or not the like comparison is still needed after
877:             * performing the like transformation on a constant string.  The
878:             * comparison is not needed if the constant string is of the form:
879:             *		CONSTANT%  (constant followed by a trailing %)
880:             *
881:             * @param pattern	The right side of the LIKE
882:             *
883:             * @return Whether or not the like comparison is still needed.
884:             */
885:            public static boolean isLikeComparisonNeeded(String pattern) {
886:                int firstAnyChar = pattern.indexOf(anyChar);
887:                int firstAnyString = pattern.indexOf(anyString);
888:
889:                if (SanityManager.DEBUG) {
890:                    SanityManager.ASSERT(pattern.length() != 0,
891:                            "pattern expected to be non-zero length");
892:                }
893:
894:                // if no pattern matching characters, no LIKE needed
895:                if (firstAnyChar == -1 && firstAnyString == -1)
896:                    return false;
897:
898:                /* Needed if string containts anyChar */
899:                if (firstAnyChar != -1) {
900:                    return true;
901:                }
902:
903:                /* Needed if string contains and anyString in any place
904:                 * other than the last character.
905:                 */
906:                if (firstAnyString != pattern.length() - 1) {
907:                    return true;
908:                }
909:
910:                return false;
911:            }
912:
913:            /**
914:             * Pad a string with null characters, in order to make it &gt; and &lt;
915:             * comparable with SQLChar.
916:             * 
917:             * @param string	The string to pad
918:             * @param len		Max number of characters to pad to
919:             * @return the string padded with 0s up to the given length
920:             */
921:            private static String padWithNulls(String string, int len) {
922:                if (string.length() >= len)
923:                    return string;
924:
925:                StringBuffer buf = new StringBuffer(len).append(string);
926:                buf.setLength(len);
927:
928:                return buf.toString();
929:            }
930:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.