是否可以在sqlite中创建javascript用户定义函数

是否可以在sqlite中创建javascript用户定义函数,javascript,sqlite,Javascript,Sqlite,背景: Firefox3包括 版本 3.5.9. Firefox还允许使用javascript和 可以调用嵌入式SQLite引擎 如预期的那样,执行以下操作 SQL语句“选择“文本”REGEXP “T*”;'给出一个错误,因为有 SQLite中没有本机包含的REGEXP函数 javascript包含一个内置的regexp函数 SQLite允许通过选择load_扩展(“文件名”)加载可加载的扩展 问题: 是否可以在SQLite中加载用javascript编写的可以执行REGEXP的扩展?是。可

背景:

  • Firefox3包括 版本 3.5.9. Firefox还允许使用javascript和 可以调用嵌入式SQLite引擎

  • 如预期的那样,执行以下操作 SQL语句“选择“文本”REGEXP “T*”;'给出一个错误,因为有 SQLite中没有本机包含的REGEXP函数

  • javascript包含一个内置的regexp函数

  • SQLite允许通过选择load_扩展(“文件名”)加载可加载的扩展

问题:
是否可以在SQLite中加载用javascript编写的可以执行REGEXP的扩展?是。可以调用javascript函数

//(thanks to Mirnal Kant, SQLManager)
//Version 2 -- Prevent Firefox crashing 
//          -- Suspect a problem with continual creation of Regex objects

var g_RegExpString = null;
var g_RegExp = null;

//functions to be created for the db
var smDbFunctions = { 
  // (0) = Regex Expression
  // (1) = Column value to test
    regexp: {
        onFunctionCall: function(val) {
            if (g_RegExp == null || val.getString(0) != g_RegExpString) 
            {
                g_RegExpString = val.getString(0);
                g_RegExp = new RegExp(g_RegExpString);
            }
            if (val.getString(1).match(g_RegExp)) return 1;
            else return 0;
        }
    }
}; 
实例化SQLite实例后:

Database.createFunction("REGEXP", 2, smDbFunctions.regexp);

Noah所说的内容已经包含在Firefox的插件中

启动此加载项时,可以单击标记为f(x)的图标打开“用户定义函数”选项卡。从中选择一个目录,其中有一个名为smFunctions.SQLite的SQLite数据库,模式如下:

CREATE TABLE "functions"          ( "name"        TEXT    PRIMARY KEY  NOT NULL
                                  , "body"        TEXT                 NOT NULL
                                  , "argLength"   INTEGER
                                  , "aggregate"   INTEGER              NOT NULL DEFAULT 0
                                  , "enabled"     INTEGER              NOT NULL DEFAULT 1
                                  , "extraInfo"   TEXT
                                  );

CREATE TABLE "aggregateFunctions" ( "name"        TEXT    PRIMARY KEY  NOT NULL
                                  , "argLength"   INTEGER
                                  , "onStepBody"  TEXT
                                  , "onFinalBody" TEXT
                                  , "enabled"     INTEGER              NOT NULL DEFAULT 1
                                  , "extraInfo"   TEXT
                                  );
在该表中,您可以定义自定义函数。参数将作为名为
aValues
的数组传递。例如:

INSERT INTO "functions" ("name", "body", "argLength", "aggregate", "enabled", "extraInfo")
VALUES('regexp_replace'
      ,'// exemple : SELECT regexp_replace(''FOOBAR'',''o+'',''a'',''gi'')
        var input      = new String(aValues.getString(0));
        var regex      = new String(aValues.getString(1));
        var substitute = new String(aValues.getString(2));
        var flags      = new String(aValues.getString(3));

        return input.replace(new RegExp(regex,flags), substitute);
       '
      ,4
      ,0
      ,1
      ,''
      );
  • 如果
    argLength
    =-1,则参数数量没有限制。您可以使用
    aValues.numEntries
    获取计数
  • 您可以使用
    aValues.getTypeOfIndex(i)
    了解参数的类型:0=>NULL,1=>Integer(
    aValues.getInt64(i)
    ),2=>Real(
    aValues.getDouble(i)
    ),3=>String,请参见示例
对于聚合函数,您可以使用
this.\u将
存储为初始空数组,以便在onStepBody阶段推送元素,并在
onStepFinal
中从中读取以计算最终结果

下面是一个bash脚本,它将创建带有一些自定义函数的
smFunctions.sqlite
(这是我自己的smFunctions.sqlite的
.dump
):

sqlite smFunctions.sqlite
sqlite smFunctions.sqlite << EOF
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE "functions" ("name" TEXT PRIMARY KEY  NOT NULL, "body" TEXT NOT NULL, "argLength" INTEGER, "aggregate" INTEGER NOT NULL  DEFAULT 0, "enabled" INTEGER NOT NULL  DEFAULT 1, "extraInfo" TEXT);
INSERT INTO "functions" VALUES('accumulate','var sum = 0;
for (var j = 0; j < aValues.numEntries; j++) {
    sum += aValues.getInt32(j);
}
return sum;
',-1,0,1,NULL);
INSERT INTO "functions" VALUES('concatenate','var valArr = [];
var delim = new String(aValues.getString(0));
for (var j = 1; j < aValues.numEntries; j++) {
    switch (aValues.getTypeOfIndex(j)) {
    case 0:
        //NULL
        valArr.push(null);
        break;
    case 1:
        //INTEGER
        valArr.push(aValues.getInt64(j));
        break;
    case 2:
        //REAL
        valArr.push(aValues.getDouble(j));
        break;
    case 3:
        //TEXT
    default:
        valArr.push(aValues.getString(j));
    }
}
return valArr.join(delim);',-1,0,1,NULL);
INSERT INTO "functions" VALUES('regexp_match','var regExp = new RegExp(aValues.getString(0));
var strVal = new String(aValues.getString(1));

if (strVal.match(regExp)) {
    return 1;
}
else {
    return 0;
}

',2,0,1,NULL);
INSERT INTO "functions" VALUES('regexp_replace','// exemple : regexp_replace(''toto'',''o+'',''a'',''g'')
var input      = new String(aValues.getString(0));
var regex      = new String(aValues.getString(1));
var substitute = new String(aValues.getString(2));
var flags      = new String(aValues.getString(3));

return input.replace(new RegExp(regex,flags), substitute);
',4,0,1,NULL);
INSERT INTO "functions" VALUES('instr','var char = new String(aValues.getString(0));
var str  = new String(aValues.getString(1));
return str.indexOf(char, 0) + 1;',2,0,1,NULL);
INSERT INTO "functions" VALUES('rinstr','var char = new String(aValues.getString(0));
var str  = new String(aValues.getString(1));
return str.lastIndexOf(char) + 1;
',2,0,1,NULL);
CREATE TABLE "aggregateFunctions" ("name" TEXT PRIMARY KEY  NOT NULL, "argLength" INTEGER, "onStepBody" TEXT, "onFinalBody" TEXT, "enabled" INTEGER NOT NULL DEFAULT 1, "extraInfo" TEXT);
INSERT INTO "aggregateFunctions" VALUES('stdDev',1,'this._store.push(aValues.getInt32(0));','var iLength = this._store.length;
let total = 0;
this._store.forEach(function(elt) { total += elt });
let mean = total / iLength;
let data = this._store.map(function(elt) {
  let value = elt - mean;
  return value * value;
});
total = 0;
data.forEach(function(elt) { total += elt });
this._store = [];
return Math.sqrt(total / iLength);',1,NULL);
INSERT INTO "aggregateFunctions" VALUES('longest_prefix',1,'this._store.push(aValues.getString(0));','if (this._store.length == 0) {
        return "";
}
var prefix = this._store[0];
var prefixLen = prefix.length;
for (var i = 1; i < this._store.length && prefixLen > 0; i++) {
        var word = this._store[i];
        // The next line assumes 1st char of word and prefix always match.
        // Initialize matchLen to -1 to test entire word.
        var matchLen = 0;
        var maxMatchLen = Math.min(word.length, prefixLen);
        while (++matchLen < maxMatchLen) {
                if (word.charAt(matchLen) != prefix.charAt(matchLen)) {
                        break;
                }
        }
        prefixLen = matchLen;
}
return prefix.substring(0, prefixLen);',1,NULL);
COMMIT;
EOF