SQLite

Check-in [825df75ba4]
Login

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

Overview
Comment:Fix a bug in changeset generation code.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 825df75ba453c853953e17ec29653e11c46f92bb
User & Date: dan 2011-03-19 18:46:16.000
Context
2011-03-19
19:19
Fix a problem involving session objects and attached databases. (check-in: ad91d30073 user: dan tags: sessions)
18:46
Fix a bug in changeset generation code. (check-in: 825df75ba4 user: dan tags: sessions)
17:07
Move session1.test from test/ to ext/session/. (check-in: c4436a936a user: dan tags: sessions)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/session/session2.test.
108
109
110
111
112
113
114





115
116
117
118
119
120
121
test_reset
do_common_sql {
  CREATE TABLE t1(a PRIMARY KEY, b);
  CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
  CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
}






foreach {tn sql} {
  1 { INSERT INTO t1 VALUES(1, 2) } 

  2 {
    INSERT INTO t2 VALUES(1, NULL);
    INSERT INTO t2 VALUES(2, NULL);
    INSERT INTO t2 VALUES(3, NULL);







>
>
>
>
>







108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
test_reset
do_common_sql {
  CREATE TABLE t1(a PRIMARY KEY, b);
  CREATE TABLE t2(a, b INTEGER PRIMARY KEY);
  CREATE TABLE t3(a, b, c, PRIMARY KEY(a, b));
}

# Execute each of the following blocks of SQL on database [db1]. Collect
# changes using a session object. Apply the resulting changeset to
# database [db2]. Then check that the contents of the two databases are
# identical.
#
foreach {tn sql} {
  1 { INSERT INTO t1 VALUES(1, 2) } 

  2 {
    INSERT INTO t2 VALUES(1, NULL);
    INSERT INTO t2 VALUES(2, NULL);
    INSERT INTO t2 VALUES(3, NULL);
146
147
148
149
150
151
152















153

154
155
156
157
158
159
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; --  256
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; --  512
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 1024
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 2048
    DELETE FROM t1 WHERE (rowid%3)==0;
  }
















} {

  do_then_apply_sql $sql
  do_test $tn { compare_db db db2 } {}
}

finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

>






151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; --  256
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; --  512
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 1024
    INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1; -- 2048
    DELETE FROM t1 WHERE (rowid%3)==0;
  }

  8 {
    BEGIN;
      INSERT INTO t1 SELECT randomblob(32), randomblob(32) FROM t1;
    ROLLBACK;
  }
  9 {
    BEGIN;
      UPDATE t1 SET b = 'xxx';
    ROLLBACK;
  }
  10 {
    BEGIN;
      DELETE FROM t1 WHERE 1;
    ROLLBACK;
  }
} {
if {$tn==9} breakpoint
  do_then_apply_sql $sql
  do_test $tn { compare_db db db2 } {}
}

finish_test

Changes to ext/session/sqlite3session.c.
1111
1112
1113
1114
1115
1116
1117

1118
1119
1120
1121
1122
1123
1124
  SessionChange *p,               /* Object containing old values */
  u8 *abPK,                       /* Boolean array - true for PK columns */
  int *pRc                        /* IN/OUT: Error code */
){
  if( *pRc==SQLITE_OK ){
    SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
    int bNoop = 1;                /* Set to zero if any values are modified */

    int i;                        /* Used to iterate through columns */
    u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */

    sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
    for(i=0; i<sqlite3_column_count(pStmt); i++){
      int bChanged = 0;
      int nAdvance;







>







1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
  SessionChange *p,               /* Object containing old values */
  u8 *abPK,                       /* Boolean array - true for PK columns */
  int *pRc                        /* IN/OUT: Error code */
){
  if( *pRc==SQLITE_OK ){
    SessionBuffer buf2 = {0,0,0}; /* Buffer to accumulate new.* record in */
    int bNoop = 1;                /* Set to zero if any values are modified */
    int nRewind = pBuf->nBuf;     /* Set to zero if any values are modified */
    int i;                        /* Used to iterate through columns */
    u8 *pCsr = p->aRecord;        /* Used to iterate through old.* values */

    sessionAppendByte(pBuf, SQLITE_UPDATE, pRc);
    for(i=0; i<sqlite3_column_count(pStmt); i++){
      int bChanged = 0;
      int nAdvance;
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187

1188
1189
1190
1191
1192
1193
1194
        sessionAppendByte(&buf2, 0, pRc);
      }

      pCsr += nAdvance;
    }

    if( bNoop ){
      pBuf->nBuf -= (1 + sqlite3_column_count(pStmt));
    }else{
      sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, pRc);
      sqlite3_free(buf2.aBuf);
    }

  }
}

static int sessionSelectStmt(
  sqlite3 *db,                    /* Database handle */
  const char *zTab,               /* Table name */
  int nCol,







|


<

>







1177
1178
1179
1180
1181
1182
1183
1184
1185
1186

1187
1188
1189
1190
1191
1192
1193
1194
1195
        sessionAppendByte(&buf2, 0, pRc);
      }

      pCsr += nAdvance;
    }

    if( bNoop ){
      pBuf->nBuf = nRewind;
    }else{
      sessionAppendBlob(pBuf, buf2.aBuf, buf2.nBuf, pRc);

    }
    sqlite3_free(buf2.aBuf);
  }
}

static int sessionSelectStmt(
  sqlite3 *db,                    /* Database handle */
  const char *zTab,               /* Table name */
  int nCol,
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320

1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335

1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
  *ppChangeset = 0;
  rc = pSession->rc;

  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    if( pTab->nEntry ){
      int nCol = pTab->nCol;      /* Local copy of member variable */
      u8 *abPK = pTab->abPK;      /* Local copy of member variable */
      int i;
      sqlite3_stmt *pStmt = 0;
      int bNoop = 1;
      int nRewind = buf.nBuf;


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

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

      if( rc==SQLITE_OK && nCol!=sqlite3_column_count(pStmt) ){
        rc = SQLITE_SCHEMA;
      }


      for(i=0; i<pTab->nChange; i++){
        SessionChange *p;         /* Used to iterate through changes */

        for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
          rc = sessionSelectBind(pStmt, nCol, abPK, p->aRecord, p->nRecord);
          if( rc==SQLITE_OK ){
            if( sqlite3_step(pStmt)==SQLITE_ROW ){
              int iCol;
              if( p->bInsert ){
                sessionAppendByte(&buf, SQLITE_INSERT, &rc);
                for(iCol=0; iCol<nCol; iCol++){
                  sessionAppendCol(&buf, pStmt, iCol, &rc);
                }
              }else{
                sessionAppendUpdate(&buf, pStmt, p, abPK, &rc);
              }
              bNoop = 0;
            }else if( !p->bInsert ){
              /* A DELETE change */
              sessionAppendByte(&buf, SQLITE_DELETE, &rc);
              sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);
              bNoop = 0;
            }
            rc = sqlite3_reset(pStmt);
          }
        }
      }

      sqlite3_finalize(pStmt);

      if( bNoop ){
        buf.nBuf = nRewind;
      }
    }
  }

  if( rc==SQLITE_OK ){
    *pnChangeset = buf.nBuf;







|
|
<
|
>








|


|



>




|

|




|


|

<




<

|




|

|







1311
1312
1313
1314
1315
1316
1317
1318
1319

1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
  *ppChangeset = 0;
  rc = pSession->rc;

  for(pTab=pSession->pTable; rc==SQLITE_OK && pTab; pTab=pTab->pNext){
    if( pTab->nEntry ){
      int nCol = pTab->nCol;      /* Local copy of member variable */
      u8 *abPK = pTab->abPK;      /* Local copy of member variable */
      int i;                      /* Used to iterate through hash buckets */
      sqlite3_stmt *pSel = 0;     /* SELECT statement to query table pTab */

      int nRewind = buf.nBuf;     /* Initial size of write buffer */
      int nNoop;                  /* Size of buffer after writing tbl header */

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

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

      if( rc==SQLITE_OK && nCol!=sqlite3_column_count(pSel) ){
        rc = SQLITE_SCHEMA;
      }

      nNoop = buf.nBuf;
      for(i=0; i<pTab->nChange; i++){
        SessionChange *p;         /* Used to iterate through changes */

        for(p=pTab->apChange[i]; rc==SQLITE_OK && p; p=p->pNext){
          rc = sessionSelectBind(pSel, nCol, abPK, p->aRecord, p->nRecord);
          if( rc==SQLITE_OK ){
            if( sqlite3_step(pSel)==SQLITE_ROW ){
              int iCol;
              if( p->bInsert ){
                sessionAppendByte(&buf, SQLITE_INSERT, &rc);
                for(iCol=0; iCol<nCol; iCol++){
                  sessionAppendCol(&buf, pSel, iCol, &rc);
                }
              }else{
                sessionAppendUpdate(&buf, pSel, p, abPK, &rc);
              }

            }else if( !p->bInsert ){
              /* A DELETE change */
              sessionAppendByte(&buf, SQLITE_DELETE, &rc);
              sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc);

            }
            rc = sqlite3_reset(pSel);
          }
        }
      }

      sqlite3_finalize(pSel);

      if( buf.nBuf==nNoop ){
        buf.nBuf = nRewind;
      }
    }
  }

  if( rc==SQLITE_OK ){
    *pnChangeset = buf.nBuf;