mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-18 10:21:03 +03:00
Store the collating sequence name for each column of a table as an
extension to the column name, for an additional savings in the heap space needed to hold the schema. FossilOrigin-Name: 832ac4c1ee384be0de72a4bdd55ed87e0f8294e7df5eefcf6b4942db3d85a69e
This commit is contained in:
@@ -532,7 +532,6 @@ void sqlite3AlterBeginAddColumn(Parse *pParse, SrcList *pSrc){
|
||||
Column *pCol = &pNew->aCol[i];
|
||||
pCol->zCnName = sqlite3DbStrDup(db, pCol->zCnName);
|
||||
pCol->hName = sqlite3StrIHash(pCol->zCnName);
|
||||
pCol->zCnColl = 0;
|
||||
}
|
||||
assert( !IsVirtual(pNew) );
|
||||
pNew->u.tab.pDfltList = sqlite3ExprListDup(db, pTab->u.tab.pDfltList, 0);
|
||||
|
||||
50
src/build.c
50
src/build.c
@@ -710,6 +710,45 @@ Expr *sqlite3ColumnExpr(Table *pTab, Column *pCol){
|
||||
return pTab->u.tab.pDfltList->a[pCol->iDflt-1].pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the collating sequence name for a column.
|
||||
*/
|
||||
void sqlite3ColumnSetColl(
|
||||
sqlite3 *db,
|
||||
Column *pCol,
|
||||
const char *zColl
|
||||
){
|
||||
int nColl;
|
||||
int n;
|
||||
char *zNew;
|
||||
assert( zColl!=0 );
|
||||
n = sqlite3Strlen30(pCol->zCnName) + 1;
|
||||
if( pCol->colFlags & COLFLAG_HASTYPE ){
|
||||
n += sqlite3Strlen30(pCol->zCnName+n) + 1;
|
||||
}
|
||||
nColl = sqlite3Strlen30(zColl) + 1;
|
||||
zNew = sqlite3DbRealloc(db, pCol->zCnName, nColl+n);
|
||||
if( zNew ){
|
||||
pCol->zCnName = zNew;
|
||||
memcpy(pCol->zCnName + n, zColl, nColl);
|
||||
pCol->colFlags |= COLFLAG_HASCOLL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the collating squence name for a column
|
||||
*/
|
||||
const char *sqlite3ColumnColl(Column *pCol){
|
||||
const char *z;
|
||||
if( (pCol->colFlags & COLFLAG_HASCOLL)==0 ) return 0;
|
||||
z = pCol->zCnName;
|
||||
while( *z ){ z++; }
|
||||
if( pCol->colFlags & COLFLAG_HASTYPE ){
|
||||
do{ z++; }while( *z );
|
||||
}
|
||||
return z+1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Delete memory allocated for the column names of a table or view (the
|
||||
** Table.aCol[] array).
|
||||
@@ -722,7 +761,6 @@ void sqlite3DeleteColumnNames(sqlite3 *db, Table *pTable){
|
||||
for(i=0; i<pTable->nCol; i++, pCol++){
|
||||
assert( pCol->zCnName==0 || pCol->hName==sqlite3StrIHash(pCol->zCnName) );
|
||||
sqlite3DbFree(db, pCol->zCnName);
|
||||
sqlite3DbFree(db, pCol->zCnColl);
|
||||
}
|
||||
sqlite3DbFree(db, pTable->aCol);
|
||||
if( !IsVirtual(pTable) ){
|
||||
@@ -1891,8 +1929,7 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
||||
|
||||
if( sqlite3LocateCollSeq(pParse, zColl) ){
|
||||
Index *pIdx;
|
||||
sqlite3DbFree(db, p->aCol[i].zCnColl);
|
||||
p->aCol[i].zCnColl = zColl;
|
||||
sqlite3ColumnSetColl(db, &p->aCol[i], zColl);
|
||||
|
||||
/* If the column is declared as "<name> PRIMARY KEY COLLATE <type>",
|
||||
** then an index may have been created on this column before the
|
||||
@@ -1901,12 +1938,11 @@ void sqlite3AddCollateType(Parse *pParse, Token *pToken){
|
||||
for(pIdx=p->pIndex; pIdx; pIdx=pIdx->pNext){
|
||||
assert( pIdx->nKeyCol==1 );
|
||||
if( pIdx->aiColumn[0]==i ){
|
||||
pIdx->azColl[0] = p->aCol[i].zCnColl;
|
||||
pIdx->azColl[0] = sqlite3ColumnColl(&p->aCol[i]);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sqlite3DbFree(db, zColl);
|
||||
}
|
||||
sqlite3DbFree(db, zColl);
|
||||
}
|
||||
|
||||
/* Change the most recently parsed column to be a GENERATED ALWAYS AS
|
||||
@@ -4066,7 +4102,7 @@ void sqlite3CreateIndex(
|
||||
zExtra += nColl;
|
||||
nExtra -= nColl;
|
||||
}else if( j>=0 ){
|
||||
zColl = pTab->aCol[j].zCnColl;
|
||||
zColl = sqlite3ColumnColl(&pTab->aCol[j]);
|
||||
}
|
||||
if( !zColl ) zColl = sqlite3StrBINARY;
|
||||
if( !db->init.busy && !sqlite3LocateCollSeq(pParse, zColl) ){
|
||||
|
||||
@@ -173,7 +173,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
|
||||
** a TK_COLUMN but was previously evaluated and cached in a register */
|
||||
int j = p->iColumn;
|
||||
if( j>=0 ){
|
||||
const char *zColl = p->y.pTab->aCol[j].zCnColl;
|
||||
const char *zColl = sqlite3ColumnColl(&p->y.pTab->aCol[j]);
|
||||
pColl = sqlite3FindCollSeq(db, ENC(db), zColl, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -259,7 +259,7 @@ int sqlite3FkLocateIndex(
|
||||
/* If the index uses a collation sequence that is different from
|
||||
** the default collation sequence for the column, this index is
|
||||
** unusable. Bail out early in this case. */
|
||||
zDfltColl = pParent->aCol[iCol].zCnColl;
|
||||
zDfltColl = sqlite3ColumnColl(&pParent->aCol[iCol]);
|
||||
if( !zDfltColl ) zDfltColl = sqlite3StrBINARY;
|
||||
if( sqlite3StrICmp(pIdx->azColl[i], zDfltColl) ) break;
|
||||
|
||||
@@ -487,7 +487,7 @@ static Expr *exprTableRegister(
|
||||
pCol = &pTab->aCol[iCol];
|
||||
pExpr->iTable = regBase + sqlite3TableColumnToStorage(pTab,iCol) + 1;
|
||||
pExpr->affExpr = pCol->affinity;
|
||||
zColl = pCol->zCnColl;
|
||||
zColl = sqlite3ColumnColl(pCol);
|
||||
if( zColl==0 ) zColl = db->pDfltColl->zName;
|
||||
pExpr = sqlite3ExprAddCollateString(pParse, pExpr, zColl);
|
||||
}else{
|
||||
|
||||
@@ -2843,7 +2843,8 @@ static int xferOptimization(
|
||||
if( pDestCol->affinity!=pSrcCol->affinity ){
|
||||
return 0; /* Affinity must be the same on all columns */
|
||||
}
|
||||
if( sqlite3_stricmp(pDestCol->zCnColl, pSrcCol->zCnColl)!=0 ){
|
||||
if( sqlite3_stricmp(sqlite3ColumnColl(pDestCol),
|
||||
sqlite3ColumnColl(pSrcCol))!=0 ){
|
||||
return 0; /* Collating sequence must be the same on all columns */
|
||||
}
|
||||
if( pDestCol->notNull && !pSrcCol->notNull ){
|
||||
|
||||
@@ -3769,7 +3769,7 @@ int sqlite3_table_column_metadata(
|
||||
*/
|
||||
if( pCol ){
|
||||
zDataType = sqlite3ColumnType(pCol,0);
|
||||
zCollSeq = pCol->zCnColl;
|
||||
zCollSeq = sqlite3ColumnColl(pCol);
|
||||
notnull = pCol->notNull!=0;
|
||||
primarykey = (pCol->colFlags & COLFLAG_PRIMKEY)!=0;
|
||||
autoinc = pTab->iPKey==iCol && (pTab->tabFlags & TF_Autoincrement)!=0;
|
||||
|
||||
@@ -2193,8 +2193,9 @@ void sqlite3SelectAddColumnTypeAndCollation(
|
||||
}
|
||||
if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff;
|
||||
pColl = sqlite3ExprCollSeq(pParse, p);
|
||||
if( pColl && pCol->zCnColl==0 ){
|
||||
pCol->zCnColl = sqlite3DbStrDup(db, pColl->zName);
|
||||
if( pColl && (pCol->colFlags & COLFLAG_HASCOLL)==0 ){
|
||||
assert( pTab->pIndex==0 );
|
||||
sqlite3ColumnSetColl(db, pCol, pColl->zName);
|
||||
}
|
||||
}
|
||||
pTab->szTabRow = 1; /* Any non-zero value works */
|
||||
|
||||
@@ -2028,10 +2028,17 @@ struct Module {
|
||||
** or equal to the table column index. It is
|
||||
** equal if and only if there are no VIRTUAL
|
||||
** columns to the left.
|
||||
**
|
||||
** Notes on zCnName:
|
||||
** The zCnName field stores the name of the column, the datatype of the
|
||||
** column, and the collating sequence for the column, in that order, all in
|
||||
** a single allocation. Each string is 0x00 terminated. The datatype
|
||||
** is only included if the COLFLAG_HASTYPE bit of colFlags is set and the
|
||||
** collating sequence name is only included if the COLFLAG_HASCOLL bit is
|
||||
** set.
|
||||
*/
|
||||
struct Column {
|
||||
char *zCnName; /* Name of this column */
|
||||
char *zCnColl; /* Collating sequence. If NULL, use the default */
|
||||
u8 notNull : 4; /* An OE_ code for handling a NOT NULL constraint */
|
||||
u8 eType : 4; /* One of the standard types */
|
||||
char affinity; /* One of the SQLITE_AFF_... values */
|
||||
@@ -2072,6 +2079,7 @@ struct Column {
|
||||
#define COLFLAG_STORED 0x0040 /* GENERATED ALWAYS AS ... STORED */
|
||||
#define COLFLAG_NOTAVAIL 0x0080 /* STORED column not yet calculated */
|
||||
#define COLFLAG_BUSY 0x0100 /* Blocks recursion on GENERATED columns */
|
||||
#define COLFLAG_HASCOLL 0x0200 /* Has collating sequence name in zCnName */
|
||||
#define COLFLAG_GENERATED 0x0060 /* Combo: _STORED, _VIRTUAL */
|
||||
#define COLFLAG_NOINSERT 0x0062 /* Combo: _HIDDEN, _STORED, _VIRTUAL */
|
||||
|
||||
@@ -4398,6 +4406,8 @@ void sqlite3CollapseDatabaseArray(sqlite3*);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
void sqlite3ColumnSetExpr(Parse*,Table*,Column*,Expr*);
|
||||
Expr *sqlite3ColumnExpr(Table*,Column*);
|
||||
void sqlite3ColumnSetColl(sqlite3*,Column*,const char*zColl);
|
||||
const char *sqlite3ColumnColl(Column*);
|
||||
void sqlite3DeleteColumnNames(sqlite3*,Table*);
|
||||
void sqlite3GenerateColumnNames(Parse *pParse, Select *pSelect);
|
||||
int sqlite3ColumnsFromExprList(Parse*,ExprList*,i16*,Column**);
|
||||
|
||||
@@ -1241,8 +1241,9 @@ static void whereIndexExprTrans(
|
||||
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
|
||||
}else if( iRef>=0
|
||||
&& (pTab->aCol[iRef].colFlags & COLFLAG_VIRTUAL)!=0
|
||||
&& (pTab->aCol[iRef].zCnColl==0
|
||||
|| sqlite3StrICmp(pTab->aCol[iRef].zCnColl, sqlite3StrBINARY)==0)
|
||||
&& ((pTab->aCol[iRef].colFlags & COLFLAG_HASCOLL)==0
|
||||
|| sqlite3StrICmp(sqlite3ColumnColl(&pTab->aCol[iRef]),
|
||||
sqlite3StrBINARY)==0)
|
||||
){
|
||||
/* Check to see if there are direct references to generated columns
|
||||
** that are contained in the index. Pulling the generated column
|
||||
|
||||
Reference in New Issue
Block a user