#include "sqliteInt.h"
static void callCollNeeded(sqlite3 *db, int enc, const char *zName){
assert( !db->xCollNeeded || !db->xCollNeeded16 );
if( db->xCollNeeded ){
char *zExternal = sqlite3DbStrDup(db, zName);
if( !zExternal ) return;
db->xCollNeeded(db->pCollNeededArg, db, enc, zExternal);
sqlite3DbFree(db, zExternal);
}
#ifndef SQLITE_OMIT_UTF16
if( db->xCollNeeded16 ){
char const *zExternal;
sqlite3_value *pTmp = sqlite3ValueNew(db);
sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC);
zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE);
if( zExternal ){
db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal);
}
sqlite3ValueFree(pTmp);
}
#endif
}
static int synthCollSeq(sqlite3 *db, CollSeq *pColl){
CollSeq *pColl2;
char *z = pColl->zName;
int i;
static const u8 aEnc[] = { SQLITE_UTF16BE, SQLITE_UTF16LE, SQLITE_UTF8 };
for(i=0; i<3; i++){
pColl2 = sqlite3FindCollSeq(db, aEnc[i], z, 0);
if( pColl2->xCmp!=0 ){
memcpy(pColl, pColl2, sizeof(CollSeq));
pColl->xDel = 0;
return SQLITE_OK;
}
}
return SQLITE_ERROR;
}
int sqlite3CheckCollSeq(Parse *pParse, CollSeq *pColl){
if( pColl && pColl->xCmp==0 ){
const char *zName = pColl->zName;
sqlite3 *db = pParse->db;
CollSeq *p = sqlite3GetCollSeq(pParse, ENC(db), pColl, zName);
if( !p ){
return SQLITE_ERROR;
}
assert( p==pColl );
}
return SQLITE_OK;
}
static CollSeq *findCollSeqEntry(
sqlite3 *db,
const char *zName,
int create
){
CollSeq *pColl;
pColl = sqlite3HashFind(&db->aCollSeq, zName);
if( 0==pColl && create ){
int nName = sqlite3Strlen30(zName) + 1;
pColl = sqlite3DbMallocZero(db, 3*sizeof(*pColl) + nName);
if( pColl ){
CollSeq *pDel = 0;
pColl[0].zName = (char*)&pColl[3];
pColl[0].enc = SQLITE_UTF8;
pColl[1].zName = (char*)&pColl[3];
pColl[1].enc = SQLITE_UTF16LE;
pColl[2].zName = (char*)&pColl[3];
pColl[2].enc = SQLITE_UTF16BE;
memcpy(pColl[0].zName, zName, nName);
pDel = sqlite3HashInsert(&db->aCollSeq, pColl[0].zName, pColl);
assert( pDel==0 || pDel==pColl );
if( pDel!=0 ){
sqlite3OomFault(db);
sqlite3DbFree(db, pDel);
pColl = 0;
}
}
}
return pColl;
}
CollSeq *sqlite3FindCollSeq(
sqlite3 *db,
u8 enc,
const char *zName,
int create
){
CollSeq *pColl;
assert( SQLITE_UTF8==1 && SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
assert( enc>=SQLITE_UTF8 && enc<=SQLITE_UTF16BE );
if( zName ){
pColl = findCollSeqEntry(db, zName, create);
if( pColl ) pColl += enc-1;
}else{
pColl = db->pDfltColl;
}
return pColl;
}
void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
db->enc = enc;
db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
sqlite3ExpirePreparedStatements(db, 1);
}
CollSeq *sqlite3GetCollSeq(
Parse *pParse,
u8 enc,
CollSeq *pColl,
const char *zName
){
CollSeq *p;
sqlite3 *db = pParse->db;
p = pColl;
if( !p ){
p = sqlite3FindCollSeq(db, enc, zName, 0);
}
if( !p || !p->xCmp ){
callCollNeeded(db, enc, zName);
p = sqlite3FindCollSeq(db, enc, zName, 0);
}
if( p && !p->xCmp && synthCollSeq(db, p) ){
p = 0;
}
assert( !p || p->xCmp );
if( p==0 ){
sqlite3ErrorMsg(pParse, "no such collation sequence: %s", zName);
pParse->rc = SQLITE_ERROR_MISSING_COLLSEQ;
}
return p;
}
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName){
sqlite3 *db = pParse->db;
u8 enc = ENC(db);
u8 initbusy = db->init.busy;
CollSeq *pColl;
pColl = sqlite3FindCollSeq(db, enc, zName, initbusy);
if( !initbusy && (!pColl || !pColl->xCmp) ){
pColl = sqlite3GetCollSeq(pParse, enc, pColl, zName);
}
return pColl;
}
#define FUNC_PERFECT_MATCH 6
static int matchQuality(
FuncDef *p,
int nArg,
u8 enc
){
int match;
assert( p->nArg>=-1 );
if( p->nArg!=nArg ){
if( nArg==(-2) ) return (p->xSFunc==0) ? 0 : FUNC_PERFECT_MATCH;
if( p->nArg>=0 ) return 0;
}
if( p->nArg==nArg ){
match = 4;
}else{
match = 1;
}
if( enc==(p->funcFlags & SQLITE_FUNC_ENCMASK) ){
match += 2;
}else if( (enc & p->funcFlags & 2)!=0 ){
match += 1;
}
return match;
}
FuncDef *sqlite3FunctionSearch(
int h,
const char *zFunc
){
FuncDef *p;
for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){
assert( p->funcFlags & SQLITE_FUNC_BUILTIN );
if( sqlite3StrICmp(p->zName, zFunc)==0 ){
return p;
}
}
return 0;
}
void sqlite3InsertBuiltinFuncs(
FuncDef *aDef,
int nDef
){
int i;
for(i=0; i<nDef; i++){
FuncDef *pOther;
const char *zName = aDef[i].zName;
int nName = sqlite3Strlen30(zName);
int h = SQLITE_FUNC_HASH(zName[0], nName);
assert( aDef[i].funcFlags & SQLITE_FUNC_BUILTIN );
pOther = sqlite3FunctionSearch(h, zName);
if( pOther ){
assert( pOther!=&aDef[i] && pOther->pNext!=&aDef[i] );
aDef[i].pNext = pOther->pNext;
pOther->pNext = &aDef[i];
}else{
aDef[i].pNext = 0;
aDef[i].u.pHash = sqlite3BuiltinFunctions.a[h];
sqlite3BuiltinFunctions.a[h] = &aDef[i];
}
}
}
FuncDef *sqlite3FindFunction(
sqlite3 *db,
const char *zName,
int nArg,
u8 enc,
u8 createFlag
){
FuncDef *p;
FuncDef *pBest = 0;
int bestScore = 0;
int h;
int nName;
assert( nArg>=(-2) );
assert( nArg>=(-1) || createFlag==0 );
nName = sqlite3Strlen30(zName);
p = (FuncDef*)sqlite3HashFind(&db->aFunc, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
pBest = p;
bestScore = score;
}
p = p->pNext;
}
if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){
bestScore = 0;
h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName);
p = sqlite3FunctionSearch(h, zName);
while( p ){
int score = matchQuality(p, nArg, enc);
if( score>bestScore ){
pBest = p;
bestScore = score;
}
p = p->pNext;
}
}
if( createFlag && bestScore<FUNC_PERFECT_MATCH &&
(pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
FuncDef *pOther;
u8 *z;
pBest->zName = (const char*)&pBest[1];
pBest->nArg = (u16)nArg;
pBest->funcFlags = enc;
memcpy((char*)&pBest[1], zName, nName+1);
for(z=(u8*)pBest->zName; *z; z++) *z = sqlite3UpperToLower[*z];
pOther = (FuncDef*)sqlite3HashInsert(&db->aFunc, pBest->zName, pBest);
if( pOther==pBest ){
sqlite3DbFree(db, pBest);
sqlite3OomFault(db);
return 0;
}else{
pBest->pNext = pOther;
}
}
if( pBest && (pBest->xSFunc || createFlag) ){
return pBest;
}
return 0;
}
void sqlite3SchemaClear(void *p){
Hash temp1;
Hash temp2;
HashElem *pElem;
Schema *pSchema = (Schema *)p;
sqlite3 xdb;
memset(&xdb, 0, sizeof(xdb));
temp1 = pSchema->tblHash;
temp2 = pSchema->trigHash;
sqlite3HashInit(&pSchema->trigHash);
sqlite3HashClear(&pSchema->idxHash);
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
sqlite3DeleteTrigger(&xdb, (Trigger*)sqliteHashData(pElem));
}
sqlite3HashClear(&temp2);
sqlite3HashInit(&pSchema->tblHash);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
sqlite3DeleteTable(&xdb, pTab);
}
sqlite3HashClear(&temp1);
sqlite3HashClear(&pSchema->fkeyHash);
pSchema->pSeqTab = 0;
if( pSchema->schemaFlags & DB_SchemaLoaded ){
pSchema->iGeneration++;
}
pSchema->schemaFlags &= ~(DB_SchemaLoaded|DB_ResetWanted);
}
Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){
Schema * p;
if( pBt ){
p = (Schema *)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear);
}else{
p = (Schema *)sqlite3DbMallocZero(0, sizeof(Schema));
}
if( !p ){
sqlite3OomFault(db);
}else if ( 0==p->file_format ){
sqlite3HashInit(&p->tblHash);
sqlite3HashInit(&p->idxHash);
sqlite3HashInit(&p->trigHash);
sqlite3HashInit(&p->fkeyHash);
p->enc = SQLITE_UTF8;
}
return p;
}