@@ -991,6 +991,45 @@ static int addWriteStagedCatalog(
991991 return rc ;
992992}
993993
994+ /* True when the two catalogs' index schema rows for zTable differ: any
995+ ** index added, dropped, re-targeted, or redefined. Index changes carry no
996+ ** named catalog entry, so every surface that reports per-table change
997+ ** (status, the diff summary) attributes them through this comparison. */
998+ int doltliteIndexSchemaRowsDifferForTable (
999+ SchemaEntry * aA , int nA ,
1000+ SchemaEntry * aB , int nB ,
1001+ const char * zTable
1002+ ){
1003+ int i , j , nMatchA = 0 , nBForTable = 0 ;
1004+ for (i = 0 ; i < nA ; i ++ ){
1005+ int found = 0 ;
1006+ if ( !aA [i ].zType || strcmp (aA [i ].zType , "index" )!= 0
1007+ || !aA [i ].zTblName || strcmp (aA [i ].zTblName , zTable )!= 0 ){
1008+ continue ;
1009+ }
1010+ for (j = 0 ; j < nB ; j ++ ){
1011+ if ( aB [j ].zType && strcmp (aB [j ].zType , "index" )== 0
1012+ && aB [j ].zTblName && strcmp (aB [j ].zTblName , zTable )== 0
1013+ && aB [j ].zName && aA [i ].zName
1014+ && strcmp (aB [j ].zName , aA [i ].zName )== 0
1015+ && ((aB [j ].zSql == 0 )== (aA [i ].zSql == 0 ))
1016+ && (aB [j ].zSql == 0 || strcmp (aB [j ].zSql , aA [i ].zSql )== 0 ) ){
1017+ found = 1 ;
1018+ break ;
1019+ }
1020+ }
1021+ if ( !found ) return 1 ;
1022+ nMatchA ++ ;
1023+ }
1024+ for (j = 0 ; j < nB ; j ++ ){
1025+ if ( aB [j ].zType && strcmp (aB [j ].zType , "index" )== 0
1026+ && aB [j ].zTblName && strcmp (aB [j ].zTblName , zTable )== 0 ){
1027+ nBForTable ++ ;
1028+ }
1029+ }
1030+ return nMatchA != nBForTable ;
1031+ }
1032+
9941033/* True when the final staged entry list contains a table entry named
9951034** zTbl. Index entries follow their parent table through -a staging, and
9961035** the parent's presence decides whether an index entry belongs at all. */
@@ -1311,14 +1350,35 @@ static int addStageNamedTables(
13111350 SchemaEntry * aStagedSchema = 0 ;
13121351 int nWorkSchema = 0 ;
13131352 int nStagedSchema = 0 ;
1353+ /* Objects whose master rows follow WORKING in this operation: the named
1354+ ** tables (adds and staged drops) plus a staged vtab's shadows. Names are
1355+ ** borrowed from the argv values and schema arrays, which outlive use. */
1356+ char * * azTouched = 0 ;
1357+ int nTouched = 0 ;
13141358
13151359 #define ADDNAMED_FREE_ALL () do { \
1360+ int ft_; \
1361+ for(ft_=0; ft_<nTouched; ft_++) sqlite3_free(azTouched[ft_]); \
1362+ sqlite3_free((void*)azTouched); \
13161363 freeSchemaEntries(aWorkSchema, nWorkSchema); \
13171364 freeSchemaEntries(aStagedSchema, nStagedSchema); \
13181365 doltliteFreeCatalog(aWorking, nWorking); \
13191366 doltliteFreeCatalog(aStaged, nStaged); \
13201367 } while(0)
13211368
1369+ #define ADDNAMED_TOUCH (zN ) do { \
1370+ char **azNew = sqlite3_realloc((void*)azTouched, \
1371+ (nTouched+1)*(int)sizeof(char*)); \
1372+ char *zOwn_ = azNew ? sqlite3_mprintf("%s", (zN)) : 0; \
1373+ if( azNew ) azTouched = azNew; \
1374+ if( !azNew || !zOwn_ ){ \
1375+ ADDNAMED_FREE_ALL(); \
1376+ sqlite3_result_error_nomem(context); \
1377+ return SQLITE_NOMEM; \
1378+ } \
1379+ azTouched[nTouched++] = zOwn_; \
1380+ } while(0)
1381+
13221382 rc = addLoadWorkingAndStagedCatalogs (db , pWorkingHash ,
13231383 & aWorking , & nWorking ,
13241384 & aStaged , & nStaged );
@@ -1369,6 +1429,7 @@ static int addStageNamedTables(
13691429 {
13701430 Table * pLive = sqlite3FindTable (db , zTable , "main" );
13711431 if ( pLive && IsVirtual (pLive ) ){
1432+ int w ;
13721433 rc = addStageShadowTablesOf (db , context , & aStaged , & nStaged ,
13731434 aWorking , nWorking ,
13741435 aWorkSchema , nWorkSchema ,
@@ -1377,6 +1438,16 @@ static int addStageNamedTables(
13771438 ADDNAMED_FREE_ALL ();
13781439 return rc ;
13791440 }
1441+ ADDNAMED_TOUCH (zTable );
1442+ for (w = 0 ; w < nWorkSchema ; w ++ ){
1443+ if ( aWorkSchema [w ].zType
1444+ && strcmp (aWorkSchema [w ].zType , "table" )== 0
1445+ && aWorkSchema [w ].zName
1446+ && strcmp (aWorkSchema [w ].zName , zTable )!= 0
1447+ && sqlite3IsShadowTableOf (db , pLive , aWorkSchema [w ].zName ) ){
1448+ ADDNAMED_TOUCH (aWorkSchema [w ].zName );
1449+ }
1450+ }
13801451 updateMaster = 1 ;
13811452 continue ;
13821453 }
@@ -1422,6 +1493,7 @@ static int addStageNamedTables(
14221493 addRemoveShadowEntriesOfDroppedVtab (aStaged , & nStaged ,
14231494 aStagedSchema , nStagedSchema ,
14241495 aWorking , nWorking , zTable );
1496+ ADDNAMED_TOUCH (zTable );
14251497 updateMaster = 1 ;
14261498 }
14271499 if ( !found ){
@@ -1446,21 +1518,44 @@ static int addStageNamedTables(
14461518 int nameMatch = aStaged [k ].zName && aWorking [j ].zName
14471519 && strcmp (aStaged [k ].zName , aWorking [j ].zName )== 0 ;
14481520 int rootMatch = aStaged [k ].iTable == iTable ;
1449- int unnamedRootMatch = rootMatch
1450- && (!aStaged [k ].zName || !aWorking [j ].zName );
1521+ /* An unnamed staged entry on a bare number match can be a
1522+ ** cross-domain collision with an index entry; pair only when
1523+ ** the staged catalog's own schema rows say the entry at this
1524+ ** number is this very table. */
1525+ int unnamedRootMatch = 0 ;
14511526 int renameRootMatch = rootMatch
14521527 && aStaged [k ].zName && aWorking [j ].zName
14531528 && strcmp (aStaged [k ].zName , aWorking [j ].zName )!= 0
14541529 && !addFindEntryByName (aWorking , nWorking , aStaged [k ].zName )
14551530 && !addFindEntryByName (aStaged , nStaged , aWorking [j ].zName );
1531+ if ( rootMatch && !aStaged [k ].zName && aWorking [j ].zName ){
1532+ int r ;
1533+ for (r = 0 ; r < nStagedSchema ; r ++ ){
1534+ if ( aStagedSchema [r ].iRootpage == aStaged [k ].iTable
1535+ && aStagedSchema [r ].zType
1536+ && strcmp (aStagedSchema [r ].zType , "table" )== 0
1537+ && aStagedSchema [r ].zName
1538+ && strcmp (aStagedSchema [r ].zName , aWorking [j ].zName )== 0 ){
1539+ unnamedRootMatch = 1 ;
1540+ break ;
1541+ }
1542+ }
1543+ }
14561544 if ( nameMatch || unnamedRootMatch || renameRootMatch ){
14571545 int schemaChanged =
14581546 prollyHashCompare (& aStaged [k ].schemaHash , & aWorking [j ].schemaHash )!= 0 ;
14591547 int nameChanged =
14601548 (!aStaged [k ].zName ) != (!aWorking [j ].zName )
14611549 || (aStaged [k ].zName && aWorking [j ].zName
14621550 && strcmp (aStaged [k ].zName , aWorking [j ].zName )!= 0 );
1463- char * zDup = aWorking [j ].zName
1551+ char * zDup ;
1552+ /* A rename retires the old name: its rows (and its indexes'
1553+ ** rows, keyed by the old tbl_name) must follow WORKING too,
1554+ ** where they no longer exist. */
1555+ if ( nameChanged && aStaged [k ].zName ){
1556+ ADDNAMED_TOUCH (aStaged [k ].zName );
1557+ }
1558+ zDup = aWorking [j ].zName
14641559 ? sqlite3_mprintf ("%s" , aWorking [j ].zName ) : 0 ;
14651560 if ( aWorking [j ].zName && !zDup ){
14661561 ADDNAMED_FREE_ALL ();
@@ -1504,6 +1599,7 @@ static int addStageNamedTables(
15041599 ADDNAMED_FREE_ALL ();
15051600 return rc ;
15061601 }
1602+ ADDNAMED_TOUCH (zTable );
15071603 break ;
15081604 }
15091605 }
@@ -1523,6 +1619,7 @@ static int addStageNamedTables(
15231619 & pWorkingMaster -> root , pWorkingMaster -> flags ,
15241620 pStagedMaster ? & pStagedMaster -> root : 0 ,
15251621 pStagedMaster ? pStagedMaster -> flags : 0 ,
1622+ (const char * * )azTouched , nTouched ,
15261623 & composedRoot );
15271624 if ( rc != SQLITE_OK ){
15281625 ADDNAMED_FREE_ALL ();
@@ -1549,6 +1646,7 @@ static int addStageNamedTables(
15491646 addAlignStagedEntriesToWorking (aWorking , nWorking , aStaged , nStaged );
15501647 rc = addWriteStagedCatalog (db , cs , aStaged , nStaged );
15511648 ADDNAMED_FREE_ALL ();
1649+ #undef ADDNAMED_TOUCH
15521650 #undef ADDNAMED_FREE_ALL
15531651 if ( rc != SQLITE_OK ){
15541652 sqlite3_result_error_code (context , rc );
0 commit comments