[英]Is it possible to create a javascript User-defined function in sqlite
BACKGROUND: 背景:
Firefox 3 includes SQLite version 3.5.9. Firefox 3包含SQLite版本3.5.9。 Firefox also allows extensions, which are written in javascript and can call the embedded SQLite engine.
Firefox还允许使用javascript编写的扩展,并可以调用嵌入式SQLite引擎。
As expected, executing the following SQL statement 'SELECT "TEXT" REGEXP "T*";' 正如所料,执行以下SQL语句'SELECT“TEXT”REGEXP“T *”;' gives an error, since there is no REGEXP function natively included in SQLite.
由于SQLite中没有本地包含的REGEXP函数,因此会出错。
javascript includes a built in regexp function. javascript包含内置的regexp功能。
SQLite allows loadable extensions via SELECT load_extension('filename'); SQLite允许通过SELECT load_extension('filename')加载扩展;
QUESTION: Is it possible to a load an extension in SQLite which is written in javascript that can do REGEXP? 问题: 是否可以在SQLite中加载一个用javascript编写的可以执行REGEXP的扩展?
Yes. 是。 It is possible to call javascript functions
可以调用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;
}
}
};
after instantiating a SQLite instance: 在实例化SQLite实例之后:
Database.createFunction("REGEXP", 2, smDbFunctions.regexp);
What Noah is talking about has been included into SQLite Manager add-on for Firefox. 诺亚所谈论的内容已包含在Firefox的SQLite Manager插件中。
When you start this add-on, you can click the icon labeled f(x) to open the User-defined functions tab. 启动此加载项时,可以单击标记为f(x)的图标以打开“用户定义的函数”选项卡。 From there, select a directory in which you have an SQLite database named smFunctions.sqlite, with the following schema:
从那里,选择一个目录,在该目录中有一个名为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
);
Inside that table you can define custom functions. 在该表中,您可以定义自定义函数。 Parameters will be passed as an array named
aValues
. 参数将作为名为
aValues
的数组aValues
。 For example: 例如:
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, then there is no limit on the number of arguments. argLength
== -1,则参数数量没有限制。 You can get the count with aValues.numEntries
. aValues.numEntries
获取计数。 aValues.getTypeOfIndex(i)
to know the type of the argument: 0 => NULL, 1 => Integer ( aValues.getInt64(i)
), 2 => Real ( aValues.getDouble(i)
), 3 => String, see example. aValues.getTypeOfIndex(i)
来知道参数的类型:0 => NULL,1 => Integer( aValues.getInt64(i)
),2 => Real( aValues.getDouble(i)
),3 = >字符串,请参见示例。 For aggregate functions you can use this._store
as an initially empty array to push the elements during the onStepBody phase, and read from it in onStepFinal
to compute the final result. 对于聚合函数,您可以将
this._store
用作初始为空的数组,以在onStepBody阶段推送元素,并在onStepFinal
读取它以计算最终结果。
Below is a bash script that will create smFunctions.sqlite
with some custom functions (this is a .dump
of my own smFunctions.sqlite): 下面是一个bash脚本,将创建
smFunctions.sqlite
一些自定义的功能(这是一个.dump
我自己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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.