/ Check-in [7b7c8d36]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix VC++ compiler warnings.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 7b7c8d366c51e89aefc6efc9dcffe3f62c7e1d25
User & Date: drh 2011-04-06 23:39:28
Context
2011-04-06
23:40
Add a missing "extern C" terminator to the end of sqlite3session.h. check-in: 29090b69 user: drh tags: sessions
23:39
Fix VC++ compiler warnings. check-in: 7b7c8d36 user: drh tags: sessions
22:33
Merge in the latest changes from the trunk. check-in: 435b57dc user: drh tags: sessions
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/session/sqlite3session.c.

560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
...
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
...
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
...
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
....
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
....
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
....
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
....
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
....
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
....
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
....
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
....
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
....
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
....
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
  int i;
  u8 *pAlloc;
  char **azCol = 0;
  u8 *abPK;

  assert( pazCol && pabPK );

  nThis = strlen(zThis);
  zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
  if( !zPragma ) return SQLITE_NOMEM;

  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
  sqlite3_free(zPragma);
  if( rc!=SQLITE_OK ) return rc;

................................................................................
  int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
  char const *zDb,                /* Database name */
  char const *zName,              /* Table name */
  sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
  sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
){
  sqlite3_session *pSession;
  int nDb = strlen(zDb);
  int nName = strlen(zDb);

  assert( sqlite3_mutex_held(db->mutex) );

  for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
    SessionTable *pTab;

    /* If this session is attached to a different database ("main", "temp" 
................................................................................
int sqlite3session_create(
  sqlite3 *db,                    /* Database handle */
  const char *zDb,                /* Name of db (e.g. "main") */
  sqlite3_session **ppSession     /* OUT: New session object */
){
  sqlite3_session *pNew;          /* Newly allocated session object */
  sqlite3_session *pOld;          /* Session object already attached to db */
  int nDb = strlen(zDb);          /* Length of zDb in bytes */

  /* Zero the output value in case an error occurs. */
  *ppSession = 0;

  /* Allocate and populate the new session object. */
  pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
  if( !pNew ) return SQLITE_NOMEM;
................................................................................
      SessionChange *p;
      SessionChange *pNext;
      for(p=pTab->apChange[i]; p; p=pNext){
        pNext = p->pNext;
        sqlite3_free(p);
      }
    }
    sqlite3_free(pTab->azCol);
    sqlite3_free(pTab->apChange);
    sqlite3_free(pTab);
  }

  /* Free the session object itself. */
  sqlite3_free(pSession);
}
................................................................................
    pSession->bAutoAttach = 1;
  }else{
    SessionTable *pTab;           /* New table object (if required) */
    int nName;                    /* Number of bytes in string zName */

    /* First search for an existing entry. If one is found, this call is
    ** a no-op. Return early. */
    nName = strlen(zName);
    for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
      if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
    }

    if( !pTab ){
      /* Allocate new SessionTable object. */
      pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
................................................................................
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is 
** called. Otherwise, append a single varint to the buffer. 
**
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
** returning.
*/
static void sessionAppendVarint(SessionBuffer *p, sqlite3_int64 v, int *pRc){
  if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 9, pRc) ){
    p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
  }
}

/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is 
................................................................................
** returning.
*/
static void sessionAppendStr(
  SessionBuffer *p, 
  const char *zStr, 
  int *pRc
){
  int nStr = strlen(zStr);
  if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
    memcpy(&p->aBuf[p->nBuf], zStr, nStr);
    p->nBuf += nStr;
  }
}

/*
................................................................................
** returning.
*/
static void sessionAppendIdent(
  SessionBuffer *p,               /* Buffer to a append to */
  const char *zStr,               /* String to quote, escape and append */
  int *pRc                        /* IN/OUT: Error code */
){
  int nStr = strlen(zStr)*2 + 2 + 1;
  if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
    char *zOut = (char *)&p->aBuf[p->nBuf];
    const char *zIn = zStr;
    *zOut++ = '"';
    while( *zIn ){
      if( *zIn=='"' ) *zOut++ = '"';
      *zOut++ = *(zIn++);
    }
    *zOut++ = '"';
    p->nBuf = ((u8 *)zOut - p->aBuf);
  }
}

/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwse, it appends the serialized version of the value stored
** in column iCol of the row that SQL statement pStmt currently points
................................................................................
        rc = SQLITE_SCHEMA;
      }

      /* Write a table header */
      sessionAppendByte(&buf, 'T', &rc);
      sessionAppendVarint(&buf, nCol, &rc);
      sessionAppendBlob(&buf, pTab->abPK, nCol, &rc);
      sessionAppendBlob(&buf, (u8 *)zName, strlen(zName)+1, &rc);

      /* Build and compile a statement to execute: */
      if( rc==SQLITE_OK ){
        rc = sessionSelectStmt(
            db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
      }

................................................................................
        }
      }

      sqlite3_finalize(pSel);
      if( buf.nBuf==nNoop ){
        buf.nBuf = nRewind;
      }
      sqlite3_free(azCol);
    }
  }

  if( rc==SQLITE_OK ){
    *pnChangeset = buf.nBuf;
    *ppChangeset = buf.aBuf;
  }else{
................................................................................
  c = *(aChange++);
  if( c=='T' ){
    int nByte;                    /* Bytes to allocate for apValue */
    aChange += sessionVarintGet(aChange, &p->nCol);
    p->abPK = (u8 *)aChange;
    aChange += p->nCol;
    p->zTab = (char *)aChange;
    aChange += (strlen((char *)aChange) + 1);
    p->op = *(aChange++);
    p->bIndirect = *(aChange++);
    sqlite3_free(p->apValue);
    nByte = sizeof(sqlite3_value *) * p->nCol * 2;
    p->apValue = (sqlite3_value **)sqlite3_malloc(nByte);
    if( !p->apValue ){
      return (p->rc = SQLITE_NOMEM);
................................................................................
        **   * A constant 'T' character,
        **   * Number of columns in said table (a varint),
        **   * An array of nCol bytes (abPK),
        **   * A nul-terminated table name.
        */
        int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol);
        nByte += nCol;
        nByte += 1 + strlen((char *)&aIn[i+nByte]);
        memcpy(&aOut[i], &aIn[i], nByte);
        i += nByte;
        break;
      }

      case SQLITE_INSERT:
      case SQLITE_DELETE: {
        int nByte;
        u8 *aEnd = &aIn[i+2];

        sessionReadRecord(&aEnd, nCol, 0);
        aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
        aOut[i+1] = aIn[i+1];
        nByte = aEnd - &aIn[i+2];
        memcpy(&aOut[i+2], &aIn[i+2], nByte);
        i += 2 + nByte;
        break;
      }

      case SQLITE_UPDATE: {
        int nByte1;              /* Size of old.* record in bytes */
        int nByte2;              /* Size of new.* record in bytes */
        u8 *aEnd = &aIn[i+2];    

        sessionReadRecord(&aEnd, nCol, 0);
        nByte1 = aEnd - &aIn[i+2];
        sessionReadRecord(&aEnd, nCol, 0);
        nByte2 = aEnd - &aIn[i+2] - nByte1;

        aOut[i] = SQLITE_UPDATE;
        aOut[i+1] = aIn[i+1];
        memcpy(&aOut[i+2], &aIn[i+2+nByte1], nByte2);
        memcpy(&aOut[i+2+nByte2], &aIn[i+2], nByte1);

        i += 2 + nByte1 + nByte2;
................................................................................
  ),
  void *pCtx                      /* First argument passed to xConflict */
){
  int schemaMismatch = 0;
  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
  int rc;                         /* Return code */
  const char *zTab = 0;           /* Name of current table */
  int nTab = 0;                   /* Result of strlen(zTab) */
  SessionApplyCtx sApply;         /* changeset_apply() context object */

  memset(&sApply, 0, sizeof(sApply));
  rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
  if( rc!=SQLITE_OK ) return rc;

  sqlite3_mutex_enter(sqlite3_db_mutex(db));
................................................................................
    
    sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);

    if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
      u8 *abPK;

      schemaMismatch = 0;
      sqlite3_free(sApply.azCol);
      sqlite3_finalize(sApply.pDelete);
      sqlite3_finalize(sApply.pUpdate); 
      sqlite3_finalize(sApply.pInsert);
      sqlite3_finalize(sApply.pSelect);
      memset(&sApply, 0, sizeof(sApply));
      sApply.db = db;

................................................................................
          (rc = sessionSelectRow(db, zTab, &sApply))
       || (rc = sessionUpdateRow(db, zTab, &sApply))
       || (rc = sessionDeleteRow(db, zTab, &sApply))
       || (rc = sessionInsertRow(db, zTab, &sApply))
      ){
        break;
      }
      nTab = strlen(zTab);
    }

    /* If there is a schema mismatch on the current table, proceed to the
    ** next change. A log message has already been issued. */
    if( schemaMismatch ) continue;

    rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
................................................................................
    sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
  }

  sqlite3_finalize(sApply.pInsert);
  sqlite3_finalize(sApply.pDelete);
  sqlite3_finalize(sApply.pUpdate);
  sqlite3_finalize(sApply.pSelect);
  sqlite3_free(sApply.azCol);
  sqlite3_mutex_leave(sqlite3_db_mutex(db));
  return rc;
}

#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */







|







 







|
|







 







|







 







|







 







|







 







|







 







|







 







|









|







 







|







 







|







 







|







 







|













|











|

|







 







|







 







|







 







|







 







|





560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
...
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
...
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
...
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
...
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
...
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
....
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
....
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
....
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
....
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
....
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
....
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
....
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
....
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
....
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
....
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
  int i;
  u8 *pAlloc;
  char **azCol = 0;
  u8 *abPK;

  assert( pazCol && pabPK );

  nThis = sqlite3Strlen30(zThis);
  zPragma = sqlite3_mprintf("PRAGMA '%q'.table_info('%q')", zDb, zThis);
  if( !zPragma ) return SQLITE_NOMEM;

  rc = sqlite3_prepare_v2(db, zPragma, -1, &pStmt, 0);
  sqlite3_free(zPragma);
  if( rc!=SQLITE_OK ) return rc;

................................................................................
  int op,                         /* SQLITE_UPDATE, DELETE or INSERT */
  char const *zDb,                /* Database name */
  char const *zName,              /* Table name */
  sqlite3_int64 iKey1,            /* Rowid of row about to be deleted/updated */
  sqlite3_int64 iKey2             /* New rowid value (for a rowid UPDATE) */
){
  sqlite3_session *pSession;
  int nDb = sqlite3Strlen30(zDb);
  int nName = sqlite3Strlen30(zName);

  assert( sqlite3_mutex_held(db->mutex) );

  for(pSession=(sqlite3_session *)pCtx; pSession; pSession=pSession->pNext){
    SessionTable *pTab;

    /* If this session is attached to a different database ("main", "temp" 
................................................................................
int sqlite3session_create(
  sqlite3 *db,                    /* Database handle */
  const char *zDb,                /* Name of db (e.g. "main") */
  sqlite3_session **ppSession     /* OUT: New session object */
){
  sqlite3_session *pNew;          /* Newly allocated session object */
  sqlite3_session *pOld;          /* Session object already attached to db */
  int nDb = sqlite3Strlen30(zDb); /* Length of zDb in bytes */

  /* Zero the output value in case an error occurs. */
  *ppSession = 0;

  /* Allocate and populate the new session object. */
  pNew = (sqlite3_session *)sqlite3_malloc(sizeof(sqlite3_session) + nDb + 1);
  if( !pNew ) return SQLITE_NOMEM;
................................................................................
      SessionChange *p;
      SessionChange *pNext;
      for(p=pTab->apChange[i]; p; p=pNext){
        pNext = p->pNext;
        sqlite3_free(p);
      }
    }
    sqlite3_free((char*)pTab->azCol);  /* cast works around VC++ bug */
    sqlite3_free(pTab->apChange);
    sqlite3_free(pTab);
  }

  /* Free the session object itself. */
  sqlite3_free(pSession);
}
................................................................................
    pSession->bAutoAttach = 1;
  }else{
    SessionTable *pTab;           /* New table object (if required) */
    int nName;                    /* Number of bytes in string zName */

    /* First search for an existing entry. If one is found, this call is
    ** a no-op. Return early. */
    nName = sqlite3Strlen30(zName);
    for(pTab=pSession->pTable; pTab; pTab=pTab->pNext){
      if( 0==sqlite3_strnicmp(pTab->zName, zName, nName+1) ) break;
    }

    if( !pTab ){
      /* Allocate new SessionTable object. */
      pTab = (SessionTable *)sqlite3_malloc(sizeof(SessionTable) + nName + 1);
................................................................................
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is 
** called. Otherwise, append a single varint to the buffer. 
**
** If an OOM condition is encountered, set *pRc to SQLITE_NOMEM before
** returning.
*/
static void sessionAppendVarint(SessionBuffer *p, int v, int *pRc){
  if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, 9, pRc) ){
    p->nBuf += sessionVarintPut(&p->aBuf[p->nBuf], v);
  }
}

/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is 
................................................................................
** returning.
*/
static void sessionAppendStr(
  SessionBuffer *p, 
  const char *zStr, 
  int *pRc
){
  int nStr = sqlite3Strlen30(zStr);
  if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
    memcpy(&p->aBuf[p->nBuf], zStr, nStr);
    p->nBuf += nStr;
  }
}

/*
................................................................................
** returning.
*/
static void sessionAppendIdent(
  SessionBuffer *p,               /* Buffer to a append to */
  const char *zStr,               /* String to quote, escape and append */
  int *pRc                        /* IN/OUT: Error code */
){
  int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
  if( *pRc==SQLITE_OK && 0==sessionBufferGrow(p, nStr, pRc) ){
    char *zOut = (char *)&p->aBuf[p->nBuf];
    const char *zIn = zStr;
    *zOut++ = '"';
    while( *zIn ){
      if( *zIn=='"' ) *zOut++ = '"';
      *zOut++ = *(zIn++);
    }
    *zOut++ = '"';
    p->nBuf = (int)((u8 *)zOut - p->aBuf);
  }
}

/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwse, it appends the serialized version of the value stored
** in column iCol of the row that SQL statement pStmt currently points
................................................................................
        rc = SQLITE_SCHEMA;
      }

      /* Write a table header */
      sessionAppendByte(&buf, 'T', &rc);
      sessionAppendVarint(&buf, nCol, &rc);
      sessionAppendBlob(&buf, pTab->abPK, nCol, &rc);
      sessionAppendBlob(&buf, (u8 *)zName, sqlite3Strlen30(zName)+1, &rc);

      /* Build and compile a statement to execute: */
      if( rc==SQLITE_OK ){
        rc = sessionSelectStmt(
            db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
      }

................................................................................
        }
      }

      sqlite3_finalize(pSel);
      if( buf.nBuf==nNoop ){
        buf.nBuf = nRewind;
      }
      sqlite3_free((char*)azCol);  /* cast works around VC++ bug */
    }
  }

  if( rc==SQLITE_OK ){
    *pnChangeset = buf.nBuf;
    *ppChangeset = buf.aBuf;
  }else{
................................................................................
  c = *(aChange++);
  if( c=='T' ){
    int nByte;                    /* Bytes to allocate for apValue */
    aChange += sessionVarintGet(aChange, &p->nCol);
    p->abPK = (u8 *)aChange;
    aChange += p->nCol;
    p->zTab = (char *)aChange;
    aChange += (sqlite3Strlen30((char *)aChange) + 1);
    p->op = *(aChange++);
    p->bIndirect = *(aChange++);
    sqlite3_free(p->apValue);
    nByte = sizeof(sqlite3_value *) * p->nCol * 2;
    p->apValue = (sqlite3_value **)sqlite3_malloc(nByte);
    if( !p->apValue ){
      return (p->rc = SQLITE_NOMEM);
................................................................................
        **   * A constant 'T' character,
        **   * Number of columns in said table (a varint),
        **   * An array of nCol bytes (abPK),
        **   * A nul-terminated table name.
        */
        int nByte = 1 + sessionVarintGet(&aIn[i+1], &nCol);
        nByte += nCol;
        nByte += 1 + sqlite3Strlen30((char *)&aIn[i+nByte]);
        memcpy(&aOut[i], &aIn[i], nByte);
        i += nByte;
        break;
      }

      case SQLITE_INSERT:
      case SQLITE_DELETE: {
        int nByte;
        u8 *aEnd = &aIn[i+2];

        sessionReadRecord(&aEnd, nCol, 0);
        aOut[i] = (eType==SQLITE_DELETE ? SQLITE_INSERT : SQLITE_DELETE);
        aOut[i+1] = aIn[i+1];
        nByte = (int)(aEnd - &aIn[i+2]);
        memcpy(&aOut[i+2], &aIn[i+2], nByte);
        i += 2 + nByte;
        break;
      }

      case SQLITE_UPDATE: {
        int nByte1;              /* Size of old.* record in bytes */
        int nByte2;              /* Size of new.* record in bytes */
        u8 *aEnd = &aIn[i+2];    

        sessionReadRecord(&aEnd, nCol, 0);
        nByte1 = (int)(aEnd - &aIn[i+2]);
        sessionReadRecord(&aEnd, nCol, 0);
        nByte2 = (int)(aEnd - &aIn[i+2]) - nByte1;

        aOut[i] = SQLITE_UPDATE;
        aOut[i+1] = aIn[i+1];
        memcpy(&aOut[i+2], &aIn[i+2+nByte1], nByte2);
        memcpy(&aOut[i+2+nByte2], &aIn[i+2], nByte1);

        i += 2 + nByte1 + nByte2;
................................................................................
  ),
  void *pCtx                      /* First argument passed to xConflict */
){
  int schemaMismatch = 0;
  sqlite3_changeset_iter *pIter;  /* Iterator to skip through changeset */  
  int rc;                         /* Return code */
  const char *zTab = 0;           /* Name of current table */
  int nTab = 0;                   /* Result of sqlite3Strlen30(zTab) */
  SessionApplyCtx sApply;         /* changeset_apply() context object */

  memset(&sApply, 0, sizeof(sApply));
  rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
  if( rc!=SQLITE_OK ) return rc;

  sqlite3_mutex_enter(sqlite3_db_mutex(db));
................................................................................
    
    sqlite3changeset_op(pIter, &zNew, &nCol, &op, 0);

    if( zTab==0 || sqlite3_strnicmp(zNew, zTab, nTab+1) ){
      u8 *abPK;

      schemaMismatch = 0;
      sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
      sqlite3_finalize(sApply.pDelete);
      sqlite3_finalize(sApply.pUpdate); 
      sqlite3_finalize(sApply.pInsert);
      sqlite3_finalize(sApply.pSelect);
      memset(&sApply, 0, sizeof(sApply));
      sApply.db = db;

................................................................................
          (rc = sessionSelectRow(db, zTab, &sApply))
       || (rc = sessionUpdateRow(db, zTab, &sApply))
       || (rc = sessionDeleteRow(db, zTab, &sApply))
       || (rc = sessionInsertRow(db, zTab, &sApply))
      ){
        break;
      }
      nTab = sqlite3Strlen30(zTab);
    }

    /* If there is a schema mismatch on the current table, proceed to the
    ** next change. A log message has already been issued. */
    if( schemaMismatch ) continue;

    rc = sessionApplyOneOp(pIter, &sApply, xConflict, pCtx, &bReplace, &bRetry);
................................................................................
    sqlite3_exec(db, "RELEASE changeset_apply", 0, 0, 0);
  }

  sqlite3_finalize(sApply.pInsert);
  sqlite3_finalize(sApply.pDelete);
  sqlite3_finalize(sApply.pUpdate);
  sqlite3_finalize(sApply.pSelect);
  sqlite3_free((char*)sApply.azCol);  /* cast works around VC++ bug */
  sqlite3_mutex_leave(sqlite3_db_mutex(db));
  return rc;
}

#endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */

Changes to src/vdbetrace.c.

81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  if( db->vdbeExecCnt>1 ){
    while( *zRawSql ){
      const char *zStart = zRawSql;
      while( *(zRawSql++)!='\n' && *zRawSql );
      sqlite3StrAccumAppend(&out, "-- ", 3);
      sqlite3StrAccumAppend(&out, zStart, zRawSql-zStart);
    }
  }else{
    while( zRawSql[0] ){
      n = findNextHostParameter(zRawSql, &nToken);
      assert( n>0 );
      sqlite3StrAccumAppend(&out, zRawSql, n);
      zRawSql += n;







|







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
                      db->aLimit[SQLITE_LIMIT_LENGTH]);
  out.db = db;
  if( db->vdbeExecCnt>1 ){
    while( *zRawSql ){
      const char *zStart = zRawSql;
      while( *(zRawSql++)!='\n' && *zRawSql );
      sqlite3StrAccumAppend(&out, "-- ", 3);
      sqlite3StrAccumAppend(&out, zStart, (int)(zRawSql-zStart));
    }
  }else{
    while( zRawSql[0] ){
      n = findNextHostParameter(zRawSql, &nToken);
      assert( n>0 );
      sqlite3StrAccumAppend(&out, zRawSql, n);
      zRawSql += n;