commit 643376769adac3de2531db6e56eabb60846eadaf
parent 2d619ff561c2aed4cbcc76a9c5c9fda01a34c108
Author: Dan Stillman <dstillman@zotero.org>
Date: Sun, 17 May 2009 07:52:05 +0000
Automatically hard-code NULL bound parameters (e.g., convert "WHERE foo=?" to "WHERE foo IS NULL" and "SET foo=?" to "SET foo=NULL")
Diffstat:
1 file changed, 68 insertions(+), 12 deletions(-)
diff --git a/chrome/content/zotero/xpcom/db.js b/chrome/content/zotero/xpcom/db.js
@@ -213,6 +213,65 @@ Zotero.DBConnection.prototype.columnQuery = function (sql,params) {
Zotero.DBConnection.prototype.getStatement = function (sql, params, checkParams) {
var db = this._getDBConnection();
+ // First, determine the type of query using first word
+ var matches = sql.match(/^[^\s\(]*/);
+ queryMethod = matches[0].toLowerCase();
+
+ if (params) {
+ // If single scalar value or single non-array object, wrap in an array
+ if (typeof params != 'object' || params === null ||
+ (params && typeof params == 'object' && !params.length)) {
+ var params = [params];
+ }
+
+ // Since we might make changes, only work on a copy of the array
+ var params = params.concat();
+
+ // Replace NULL bound parameters with hard-coded NULLs
+ var nullRE = /\s*=?\s*\?/g;
+ // Reset lastIndex, since regexp isn't recompiled dynamically
+ nullRE.lastIndex = 0;
+ var lastNullParamIndex = -1;
+ for (var i=0; i<params.length; i++) {
+ if (typeof params[i] != 'object' || params[i] !== null) {
+ continue;
+ }
+
+ // Find index of this parameter, skipping previous ones
+ do {
+ var matches = nullRE.exec(sql);
+ lastNullParamIndex++;
+ }
+ while (lastNullParamIndex < i);
+ lastNullParamIndex = i;
+
+ if (matches[0].indexOf('=') == -1) {
+ // mozStorage supports null bound parameters in value lists (e.g., "(?,?)") natively
+ continue;
+ //var repl = 'NULL';
+ }
+ else if (queryMethod == 'select') {
+ var repl = ' IS NULL';
+ }
+ else {
+ var repl = '=NULL';
+ }
+
+ var subpos = matches.index;
+ var sublen = matches[0].length;
+ sql = sql.substring(0, subpos) + repl + sql.substr(subpos + sublen);
+
+ //Zotero.debug("Hard-coding null bound parameter " + i);
+
+ params.splice(i, 1);
+ i--;
+ continue;
+ }
+ if (!params.length) {
+ params = undefined;
+ }
+ }
+
try {
this._debug(sql,5);
var statement = db.createStatement(sql);
@@ -226,12 +285,6 @@ Zotero.DBConnection.prototype.getStatement = function (sql, params, checkParams)
var numParams = statement.parameterCount;
if (params) {
- // If single scalar value or single non-array object, wrap in an array
- if (typeof params != 'object' || params === null ||
- (params && typeof params == 'object' && !params.length)) {
- params = [params];
- }
-
if (checkParams) {
if (numParams == 0) {
throw ("Parameters provided for query without placeholders");
@@ -243,6 +296,14 @@ Zotero.DBConnection.prototype.getStatement = function (sql, params, checkParams)
}
for (var i=0; i<params.length; i++) {
+ if (params[i] === undefined) {
+ Zotero.debug(params);
+ var msg = 'Parameter ' + i + ' is undefined in Zotero.DB.getStatement() [QUERY: ' + sql + ']';
+ Zotero.debug(msg);
+ Components.utils.reportError(msg);
+ throw (msg);
+ }
+
// Integer
if (params[i]!==null && typeof params[i]['int'] != 'undefined') {
var type = 'int';
@@ -253,10 +314,6 @@ Zotero.DBConnection.prototype.getStatement = function (sql, params, checkParams)
var type = 'string';
var value = params[i]['string'];
}
- // Null
- else if (params[i]!==null && typeof params[i]['null'] != 'undefined') {
- var type = 'null';
- }
// Automatic (trust the JS type)
else {
switch (typeof params[i]) {
@@ -316,8 +373,7 @@ Zotero.DBConnection.prototype.getStatement = function (sql, params, checkParams)
break;
case 'null':
- this._debug('Binding parameter ' + (i+1)
- + ' of type NULL', 5);
+ this._debug('Binding parameter ' + (i+1) + ' of type NULL', 5);
statement.bindNullParameter(i);
break;
}