SQLite

Check-in [343b64517d]
Login

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

Overview
Comment:Have sqlite3changeset_concat() return SQLITE_SCHEMA if an attempt is made to concatenate changesets based on incompatible database schemas.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | sessions
Files: files | file ages | folders
SHA1: 343b64517d244b75097e38342dc273eb5a52915b
User & Date: dan 2011-04-15 15:04:31.042
Context
2011-04-15
16:03
Add tests and fixes for OOM handling in sqlite3changeset_concat(). (check-in: df0b2d21dc user: dan tags: sessions)
15:04
Have sqlite3changeset_concat() return SQLITE_SCHEMA if an attempt is made to concatenate changesets based on incompatible database schemas. (check-in: 343b64517d user: dan tags: sessions)
12:04
Add documentation for sqlite3changeset_concat() to sqlite3session.h. (check-in: ada9efa53a user: dan tags: sessions)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/session/session5.test.
59
60
61
62
63
64
65



66
67
68
69
70
71
72
    set c_prev $c
    rename S s_prev
  }

  catch { s_prev delete }
}




do_execsql_test 1.0 {
  CREATE TABLE t1(a PRIMARY KEY, b);
}

do_concat_test 1.1.1 {
  INSERT INTO t1 VALUES(1, 'one');
} {







>
>
>







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
    set c_prev $c
    rename S s_prev
  }

  catch { s_prev delete }
}

#-------------------------------------------------------------------------
# Test cases session5-1.* - simple tests.
#
do_execsql_test 1.0 {
  CREATE TABLE t1(a PRIMARY KEY, b);
}

do_concat_test 1.1.1 {
  INSERT INTO t1 VALUES(1, 'one');
} {
130
131
132
133
134
135
136




137
138
139
140
141
142
143
144
145
146
147
148
149
}
do_concat_test 1.2.7 {
  UPDATE t1 SET b = 'eight' WHERE a = 'I';
} {
  DELETE FROM t1 WHERE a = 'I';
}





db function indirect indirect 
proc indirect {{x -1}} {
  S indirect $x
  s_prev indirect $x
}

do_concat_test 2.1 {
  CREATE TABLE abc(a, b, c PRIMARY KEY);
  INSERT INTO abc VALUES(NULL, NULL, 1);
  INSERT INTO abc VALUES('abcdefghijkl', NULL, 2);
} {
  DELETE FROM abc WHERE c = 1;
  UPDATE abc SET c = 1 WHERE c = 2;







>
>
>
>





<







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

149
150
151
152
153
154
155
}
do_concat_test 1.2.7 {
  UPDATE t1 SET b = 'eight' WHERE a = 'I';
} {
  DELETE FROM t1 WHERE a = 'I';
}


#-------------------------------------------------------------------------
# Test cases session5-2.* - more complex tests.
#
db function indirect indirect 
proc indirect {{x -1}} {
  S indirect $x
  s_prev indirect $x
}

do_concat_test 2.1 {
  CREATE TABLE abc(a, b, c PRIMARY KEY);
  INSERT INTO abc VALUES(NULL, NULL, 1);
  INSERT INTO abc VALUES('abcdefghijkl', NULL, 2);
} {
  DELETE FROM abc WHERE c = 1;
  UPDATE abc SET c = 1 WHERE c = 2;
180
181
182
183
184
185
186
187
















































188
} {
  SELECT indirect(1);
  UPDATE abc SET a='one point five' WHERE c = 'three';
} {
  SELECT indirect(0);
  UPDATE abc SET a='one point six' WHERE c = 'three';
}

















































finish_test








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

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
} {
  SELECT indirect(1);
  UPDATE abc SET a='one point five' WHERE c = 'three';
} {
  SELECT indirect(0);
  UPDATE abc SET a='one point six' WHERE c = 'three';
}

#-------------------------------------------------------------------------
# Test that schema incompatibilities are detected correctly.
#
#   session5-3.1: Incompatible number of columns.
#   session5-3.2: Incompatible PK definition.
#
proc sql_to_changeset {sql} {
  sqlite3session S db main 
  S attach *
  execsql $sql
  set c [S changeset]
  S delete
  return $c
}

do_test 3.1 {
  db close
  forcedelete test.db
  sqlite3 db test.db

  execsql { CREATE TABLE t1(a PRIMARY KEY, b) }
  set c1 [sql_to_changeset { INSERT INTO t1 VALUES(1, 2) }]
  execsql { 
    DROP TABLE t1;
    CREATE TABLE t1(a PRIMARY KEY, b, c);
  }
  set c2 [sql_to_changeset { INSERT INTO t1 VALUES(2, 3, 4) }]

  list [catch { sqlite3changeset_concat $c1 $c2 } msg] $msg
} {1 SQLITE_SCHEMA}

do_test 3.2 {
  db close
  forcedelete test.db
  sqlite3 db test.db

  execsql { CREATE TABLE t1(a PRIMARY KEY, b) }
  set c1 [sql_to_changeset { INSERT INTO t1 VALUES(1, 2) }]
  execsql { 
    DROP TABLE t1;
    CREATE TABLE t1(a, b PRIMARY KEY);
  }
  set c2 [sql_to_changeset { INSERT INTO t1 VALUES(2, 3) }]

  list [catch { sqlite3changeset_concat $c1 $c2 } msg] $msg
} {1 SQLITE_SCHEMA}


finish_test
Changes to ext/session/sqlite3session.c.
2858
2859
2860
2861
2862
2863
2864



2865
2866
2867
2868
2869
2870



2871
2872


2873



2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884

    assert( pIter->apValue==0 );
    sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);

    if( !pTab || zNew!=pTab->zName ){
      /* Search the list for a matching table */
      int nNew = strlen(zNew);



      for(pTab = *ppTabList; pTab; pTab=pTab->pNext){
        if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
      }
      if( !pTab ){
        pTab = sqlite3_malloc(sizeof(SessionTable));
        if( !pTab ) break;



        memset(pTab, 0, sizeof(SessionTable));
        pTab->pNext = *ppTabList;


        *ppTabList = pTab;



      }
      pTab->zName = (char *)zNew;
      pTab->nCol = nCol;
      sqlite3changeset_pk(pIter, &pTab->abPK, 0);
    }

    if( sessionGrowHash(pTab) ) break;
    iHash = sessionChangeHash(pTab, aRec, pTab->nChange);

    /* Search for existing entry. If found, remove it from the hash table. 
    ** Code below may link it back in.







>
>
>





|
>
>
>


>
>

>
>
>


<
<







2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886


2887
2888
2889
2890
2891
2892
2893

    assert( pIter->apValue==0 );
    sqlite3changeset_op(pIter, &zNew, &nCol, &op, &bIndirect);

    if( !pTab || zNew!=pTab->zName ){
      /* Search the list for a matching table */
      int nNew = strlen(zNew);
      u8 *abPK;

      sqlite3changeset_pk(pIter, &abPK, 0);
      for(pTab = *ppTabList; pTab; pTab=pTab->pNext){
        if( 0==sqlite3_strnicmp(pTab->zName, zNew, nNew+1) ) break;
      }
      if( !pTab ){
        pTab = sqlite3_malloc(sizeof(SessionTable));
        if( !pTab ){
          rc = SQLITE_NOMEM;
          break;
        }
        memset(pTab, 0, sizeof(SessionTable));
        pTab->pNext = *ppTabList;
        pTab->abPK = abPK;
        pTab->nCol = nCol;
        *ppTabList = pTab;
      }else if( pTab->nCol!=nCol || memcmp(pTab->abPK, abPK, nCol) ){
        rc = SQLITE_SCHEMA;
        break;
      }
      pTab->zName = (char *)zNew;


    }

    if( sessionGrowHash(pTab) ) break;
    iHash = sessionChangeHash(pTab, aRec, pTab->nChange);

    /* Search for existing entry. If found, remove it from the hash table. 
    ** Code below may link it back in.