1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is unicode functions code.
18 * The Initial Developer of the Original Code is
19 * Mozilla Corporation.
20 * Portions created by the Initial Developer are Copyright (C) 2007
21 * the Initial Developer. All Rights Reserved.
23 * This code is based off of icu.c from the sqlite code
24 * whose original author is danielk1977
27 * Shawn Wilsher <me@shawnwilsher.com> (Original Author)
29 * Alternatively, the contents of this file may be used under the terms of
30 * either the GNU General Public License Version 2 or later (the "GPL"), or
31 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32 * in which case the provisions of the GPL or the LGPL are applicable instead
33 * of those above. If you wish to allow use of your version of this file only
34 * under the terms of either the GPL or the LGPL, and not to allow others to
35 * use your version of this file under the terms of the MPL, indicate your
36 * decision by deleting the provisions above and replace them with the notice
37 * and other provisions required by the GPL or the LGPL. If you do not delete
38 * the provisions above, a recipient may use your version of this file under
39 * the terms of any one of the MPL, the GPL or the LGPL.
41 * ***** END LICENSE BLOCK ***** */
43 #include "mozStorageUnicodeFunctions.h"
44 #include "nsUnicharUtils.h"
47 StorageUnicodeFunctions::RegisterFunctions(sqlite3
*aDB
)
54 void (*xFunc
)(sqlite3_context
*, int, sqlite3_value
**);
56 {"lower", 1, SQLITE_UTF16
, 0, caseFunction
},
57 {"lower", 1, SQLITE_UTF8
, 0, caseFunction
},
58 {"upper", 1, SQLITE_UTF16
, (void*)1, caseFunction
},
59 {"upper", 1, SQLITE_UTF8
, (void*)1, caseFunction
},
61 {"like", 2, SQLITE_UTF16
, 0, likeFunction
},
62 {"like", 2, SQLITE_UTF8
, 0, likeFunction
},
63 {"like", 3, SQLITE_UTF16
, 0, likeFunction
},
64 {"like", 3, SQLITE_UTF8
, 0, likeFunction
},
68 for (unsigned i
= 0; SQLITE_OK
== rv
&& i
< NS_ARRAY_LENGTH(functions
); ++i
) {
69 struct Functions
*p
= &functions
[i
];
70 rv
= sqlite3_create_function(aDB
, p
->zName
, p
->nArg
, p
->enc
, p
->pContext
,
71 p
->xFunc
, NULL
, NULL
);
78 StorageUnicodeFunctions::caseFunction(sqlite3_context
*p
,
80 sqlite3_value
**aArgv
)
82 NS_ASSERTION(1 == aArgc
, "Invalid number of arguments!");
84 nsAutoString
data(static_cast<const PRUnichar
*>(sqlite3_value_text16(aArgv
[0])));
85 PRBool toUpper
= sqlite3_user_data(p
) ? PR_TRUE
: PR_FALSE
;
92 // Give sqlite our result
93 sqlite3_result_text16(p
, data
.get(), -1, SQLITE_TRANSIENT
);
97 likeCompare(nsAString::const_iterator aPatternItr
,
98 nsAString::const_iterator aPatternEnd
,
99 nsAString::const_iterator aStringItr
,
100 nsAString::const_iterator aStringEnd
,
103 const PRUnichar
MATCH_ALL('%');
104 const PRUnichar
MATCH_ONE('_');
106 PRBool lastWasEscape
= PR_FALSE
;
107 while (aPatternItr
!= aPatternEnd
) {
109 * What we do in here is take a look at each character from the input
110 * pattern, and do something with it. There are 4 possibilities:
111 * 1) character is an un-escaped match-all character
112 * 2) character is an un-escaped match-one character
113 * 3) character is an un-escaped escape character
114 * 4) character is not any of the above
116 if (!lastWasEscape
&& *aPatternItr
== MATCH_ALL
) {
119 * Now we need to skip any MATCH_ALL or MATCH_ONE characters that follow a
120 * MATCH_ALL character. For each MATCH_ONE character, skip one character
121 * in the pattern string.
123 while (*aPatternItr
== MATCH_ALL
|| *aPatternItr
== MATCH_ONE
) {
124 if (*aPatternItr
== MATCH_ONE
) {
125 // If we've hit the end of the string we are testing, no match
126 if (aStringItr
== aStringEnd
)
133 // If we've hit the end of the pattern string, match
134 if (aPatternItr
== aPatternEnd
)
137 while (aStringItr
!= aStringEnd
) {
138 if (likeCompare(aPatternItr
, aPatternEnd
, aStringItr
, aStringEnd
, aEscape
)) {
139 // we've hit a match, so indicate this
147 } else if (!lastWasEscape
&& *aPatternItr
== MATCH_ONE
) {
149 if (aStringItr
== aStringEnd
) {
150 // If we've hit the end of the string we are testing, no match
154 lastWasEscape
= PR_FALSE
;
155 } else if (!lastWasEscape
&& *aPatternItr
== aEscape
) {
157 lastWasEscape
= PR_TRUE
;
160 if (ToUpperCase(*aStringItr
) != ToUpperCase(*aPatternItr
)) {
161 // If we've hit a point where the strings don't match, there is no match
165 lastWasEscape
= PR_FALSE
;
171 return aStringItr
== aStringEnd
;
175 * This implements the like() SQL function. This is used by the LIKE operator.
176 * The SQL statement 'A LIKE B' is implemented as 'like(B, A)', and if there is
177 * an escape character, say E, it is implemented as 'like(B, A, E)'.
180 StorageUnicodeFunctions::likeFunction(sqlite3_context
*p
,
182 sqlite3_value
**aArgv
)
184 NS_ASSERTION(2 == aArgc
|| 3 == aArgc
, "Invalid number of arguments!");
186 if (sqlite3_value_bytes(aArgv
[0]) > SQLITE_MAX_LIKE_PATTERN_LENGTH
) {
187 sqlite3_result_error(p
, "LIKE or GLOB pattern too complex", SQLITE_TOOBIG
);
191 if (!sqlite3_value_text16(aArgv
[0]) || !sqlite3_value_text16(aArgv
[1]))
194 nsDependentString
A(static_cast<const PRUnichar
*>(sqlite3_value_text16(aArgv
[1])));
195 nsDependentString
B(static_cast<const PRUnichar
*>(sqlite3_value_text16(aArgv
[0])));
196 NS_ASSERTION(!B
.IsEmpty(), "LIKE string must not be null!");
200 E
= static_cast<const PRUnichar
*>(sqlite3_value_text16(aArgv
[2]))[0];
202 nsAString::const_iterator itrString
, endString
;
203 A
.BeginReading(itrString
);
204 A
.EndReading(endString
);
205 nsAString::const_iterator itrPattern
, endPattern
;
206 B
.BeginReading(itrPattern
);
207 B
.EndReading(endPattern
);
208 sqlite3_result_int(p
, likeCompare(itrPattern
, endPattern
,
209 itrString
, endString
, E
));