mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Merge all recent trunk enhancements into the reuse-schema branch.
FossilOrigin-Name: e556f3d3819134022f72e72471976616700c4fe00fc924bfbe713a6132440fdf
This commit is contained in:
@@ -55,8 +55,8 @@ struct Fts5PhraseIter {
|
||||
** EXTENSION API FUNCTIONS
|
||||
**
|
||||
** xUserData(pFts):
|
||||
** Return a copy of the context pointer the extension function was
|
||||
** registered with.
|
||||
** Return a copy of the pUserData pointer passed to the xCreateFunction()
|
||||
** API when the extension function was registered.
|
||||
**
|
||||
** xColumnTotalSize(pFts, iCol, pnToken):
|
||||
** If parameter iCol is less than zero, set output variable *pnToken
|
||||
|
@@ -471,7 +471,7 @@ static void icuLoadCollation(
|
||||
UCollator *pUCollator; /* ICU library collation object */
|
||||
int rc; /* Return code from sqlite3_create_collation_x() */
|
||||
|
||||
assert(nArg==2);
|
||||
assert(nArg==2 || nArg==3);
|
||||
(void)nArg; /* Unused parameter */
|
||||
zLocale = (const char *)sqlite3_value_text(apArg[0]);
|
||||
zName = (const char *)sqlite3_value_text(apArg[1]);
|
||||
@@ -486,7 +486,39 @@ static void icuLoadCollation(
|
||||
return;
|
||||
}
|
||||
assert(p);
|
||||
|
||||
if(nArg==3){
|
||||
const char *zOption = (const char*)sqlite3_value_text(apArg[2]);
|
||||
static const struct {
|
||||
const char *zName;
|
||||
UColAttributeValue val;
|
||||
} aStrength[] = {
|
||||
{ "PRIMARY", UCOL_PRIMARY },
|
||||
{ "SECONDARY", UCOL_SECONDARY },
|
||||
{ "TERTIARY", UCOL_TERTIARY },
|
||||
{ "DEFAULT", UCOL_DEFAULT_STRENGTH },
|
||||
{ "QUARTERNARY", UCOL_QUATERNARY },
|
||||
{ "IDENTICAL", UCOL_IDENTICAL },
|
||||
};
|
||||
int i;
|
||||
for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
|
||||
if( sqlite3_stricmp(zOption,aStrength[i].zName)==0 ){
|
||||
ucol_setStrength(pUCollator, aStrength[i].val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i>=sizeof(aStrength)/sizeof(aStrength[0]) ){
|
||||
sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p));
|
||||
sqlite3_str_appendf(pStr,
|
||||
"unknown collation strength \"%s\" - should be one of:",
|
||||
zOption);
|
||||
for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
|
||||
sqlite3_str_appendf(pStr, " %s", aStrength[i].zName);
|
||||
}
|
||||
sqlite3_result_error(p, sqlite3_str_value(pStr), -1);
|
||||
sqlite3_free(sqlite3_str_finish(pStr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
|
||||
icuCollationColl, icuCollationDel
|
||||
);
|
||||
@@ -509,6 +541,7 @@ int sqlite3IcuInit(sqlite3 *db){
|
||||
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
||||
} scalars[] = {
|
||||
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
|
||||
{"icu_load_collation",3,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
|
||||
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
||||
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
|
||||
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
||||
|
@@ -433,40 +433,56 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
out.returnVal = ()=>opt.resultRows;
|
||||
}
|
||||
if(opt.callback || opt.resultRows){
|
||||
switch((undefined===opt.rowMode)
|
||||
? 'array' : opt.rowMode) {
|
||||
case 'object': out.cbArg = (stmt)=>stmt.get(Object.create(null)); break;
|
||||
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
|
||||
case 'stmt':
|
||||
if(Array.isArray(opt.resultRows)){
|
||||
toss3("exec(): invalid rowMode for a resultRows array: must",
|
||||
"be one of 'array', 'object',",
|
||||
"a result column number, or column name reference.");
|
||||
}
|
||||
out.cbArg = (stmt)=>stmt;
|
||||
switch((undefined===opt.rowMode) ? 'array' : opt.rowMode) {
|
||||
case 'object':
|
||||
out.cbArg = (stmt,cache)=>{
|
||||
if( !cache.columnNames ) cache.columnNames = stmt.getColumnNames([]);
|
||||
/* https://sqlite.org/forum/forumpost/3632183d2470617d:
|
||||
conversion of rows to objects (key/val pairs) is
|
||||
somewhat expensive for large data sets because of the
|
||||
native-to-JS conversion of the column names. If we
|
||||
instead cache the names and build objects from that
|
||||
list of strings, it can run twice as fast. The
|
||||
difference is not noticeable for small data sets but
|
||||
becomes human-perceivable when enough rows are
|
||||
involved. */
|
||||
const row = stmt.get([]);
|
||||
const rv = Object.create(null);
|
||||
for( const i in cache.columnNames ) rv[cache.columnNames[i]] = row[i];
|
||||
return rv;
|
||||
};
|
||||
break;
|
||||
case 'array': out.cbArg = (stmt)=>stmt.get([]); break;
|
||||
case 'stmt':
|
||||
if(Array.isArray(opt.resultRows)){
|
||||
toss3("exec(): invalid rowMode for a resultRows array: must",
|
||||
"be one of 'array', 'object',",
|
||||
"a result column number, or column name reference.");
|
||||
}
|
||||
out.cbArg = (stmt)=>stmt;
|
||||
break;
|
||||
default:
|
||||
if(util.isInt32(opt.rowMode)){
|
||||
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
|
||||
break;
|
||||
default:
|
||||
if(util.isInt32(opt.rowMode)){
|
||||
out.cbArg = (stmt)=>stmt.get(opt.rowMode);
|
||||
break;
|
||||
}else if('string'===typeof opt.rowMode
|
||||
&& opt.rowMode.length>1
|
||||
&& '$'===opt.rowMode[0]){
|
||||
/* "$X": fetch column named "X" (case-sensitive!). Prior
|
||||
to 2022-12-14 ":X" and "@X" were also permitted, but
|
||||
having so many options is unnecessary and likely to
|
||||
cause confusion. */
|
||||
const $colName = opt.rowMode.substr(1);
|
||||
out.cbArg = (stmt)=>{
|
||||
const rc = stmt.get(Object.create(null))[$colName];
|
||||
return (undefined===rc)
|
||||
? toss3(capi.SQLITE_NOTFOUND,
|
||||
"exec(): unknown result column:",$colName)
|
||||
: rc;
|
||||
};
|
||||
break;
|
||||
}
|
||||
toss3("Invalid rowMode:",opt.rowMode);
|
||||
}else if('string'===typeof opt.rowMode
|
||||
&& opt.rowMode.length>1
|
||||
&& '$'===opt.rowMode[0]){
|
||||
/* "$X": fetch column named "X" (case-sensitive!). Prior
|
||||
to 2022-12-14 ":X" and "@X" were also permitted, but
|
||||
having so many options is unnecessary and likely to
|
||||
cause confusion. */
|
||||
const $colName = opt.rowMode.substr(1);
|
||||
out.cbArg = (stmt)=>{
|
||||
const rc = stmt.get(Object.create(null))[$colName];
|
||||
return (undefined===rc)
|
||||
? toss3(capi.SQLITE_NOTFOUND,
|
||||
"exec(): unknown result column:",$colName)
|
||||
: rc;
|
||||
};
|
||||
break;
|
||||
}
|
||||
toss3("Invalid rowMode:",opt.rowMode);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
@@ -884,10 +900,15 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
and names. */) ? 0 : 1;
|
||||
evalFirstResult = false;
|
||||
if(arg.cbArg || resultRows){
|
||||
const cbArgCache = Object.create(null)
|
||||
/* 2nd arg for arg.cbArg, used by (at least) row-to-object
|
||||
converter */;
|
||||
for(; stmt.step(); stmt._lockedByExec = false){
|
||||
if(0===gotColNames++) stmt.getColumnNames(opt.columnNames);
|
||||
if(0===gotColNames++){
|
||||
stmt.getColumnNames(cbArgCache.columnNames = (opt.columnNames || []));
|
||||
}
|
||||
stmt._lockedByExec = true;
|
||||
const row = arg.cbArg(stmt);
|
||||
const row = arg.cbArg(stmt,cbArgCache);
|
||||
if(resultRows) resultRows.push(row);
|
||||
if(callback && false === callback.call(opt, row, stmt)){
|
||||
break;
|
||||
|
@@ -1272,7 +1272,7 @@ globalThis.sqlite3ApiBootstrap.initializers.push(function(sqlite3){
|
||||
return poolUtil;
|
||||
}).catch(async (e)=>{
|
||||
await thePool.removeVfs().catch(()=>{});
|
||||
return e;
|
||||
throw e;
|
||||
});
|
||||
}).catch((err)=>{
|
||||
//error("rejecting promise:",err);
|
||||
|
Reference in New Issue
Block a user