SQLite4
Check-in [c39156d2b8]
Not logged in

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

Overview
Comment:Add documentation for sqlite4_kvstore_methods.xGetMethod. Use the lsm pragmas in various tests instead of the file-controls.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c39156d2b827172871f70e80a50e27eaf4bd337d
User & Date: dan 2013-06-06 16:43:27
Context
2013-06-06
17:18
Change the names of some API functions to make their purposes clearer: "get_auxdata" -> "auxdata_fetch", "set_auxdata" -> "auxdata_store", "get_autocommit" -> "db_transaction_status", and "sql" -> "stmt_sql". check-in: c8d956ad1a user: dan tags: trunk
16:43
Add documentation for sqlite4_kvstore_methods.xGetMethod. Use the lsm pragmas in various tests instead of the file-controls. check-in: c39156d2b8 user: dan tags: trunk
2013-06-05
20:25
Allow key-value stores to intercept pragma commands. check-in: 0e6201380c user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/kv.h.

117
118
119
120
121
122
123




























124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
** entries is not actually deleted until the cursor moves.  In other words
** it is acceptable to xDelete an entry out from under a cursor.  Subsequent
** xNext or xPrev calls on that cursor will work the same as if the entry
** had not been deleted.  Two cursors can be pointing to the same entry and
** one cursor can xDelete and the other cursor is expected to continue
** functioning normally, including responding correctly to subsequent
** xNext and xPrev calls.




























*/

/* Typedefs of datatypes */
typedef struct sqlite4_kvstore KVStore;
typedef struct sqlite4_kv_methods KVStoreMethods;
typedef struct sqlite4_kvcursor KVCursor;
typedef unsigned char KVByteArray;
typedef sqlite4_kvsize KVSize;


int sqlite4KVStoreOpenMem(sqlite4_env*, KVStore**, const char *, unsigned);
int sqlite4KVStoreOpenLsm(sqlite4_env*, KVStore**, const char *, unsigned);
int sqlite4KVStoreOpen(
  sqlite4*,
  const char *zLabel, 
  const char *zUri,







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








<







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159

160
161
162
163
164
165
166
** entries is not actually deleted until the cursor moves.  In other words
** it is acceptable to xDelete an entry out from under a cursor.  Subsequent
** xNext or xPrev calls on that cursor will work the same as if the entry
** had not been deleted.  Two cursors can be pointing to the same entry and
** one cursor can xDelete and the other cursor is expected to continue
** functioning normally, including responding correctly to subsequent
** xNext and xPrev calls.
** 
** The xGetMethod method allows a key-value store to implement custom PRAGMA 
** commands, or override existing built-in PRAGMAs. Each time the user prepares
** a PRAGMA statement, the xGetMethod method of the corresponding key-value
** store is invoked with the name of the requested PRAGMA passed as the second
** argument.
** 
** If the key-value store will implement the specified PRAGMA, it should 
** populate the output variables and return SQLITE4_OK. If the named PRAGMA 
** is not one that the key-value store implements, it should return 
** SQLITE4_NOTFOUND. If an error occurs, any other SQLite error code may be 
** returned.
** 
** If the xGetMethod invocation returns SQLITE4_OK, the second of the three
** output parameters (pxFunc) should be set to point to a function that will
** be invoked when the prepared statement is executed (i.e. from within an
** sqlite4_step() call). The parameters passed to it are similar to those
** passed to [user-defined function] implementations. The sqlite4_value 
** arguments, if any, are the values specified as part of the PRAGMA 
** statement. The first of the output parameters (ppArg) is used to return
** the context pointer made available to the implementation of the *pxFunc 
** function via sqlite4_context_appdata(). If it is not set to NULL, the
** final output parameter (pxDestroy) may be used to specify a callback that
** is invoked when the SQL statement is finalized. The argument passed to
** the *pxDestroy invocation, if any, is a copy of *ppArg.
** 
** If the xGetMethod invocation returns SQLITE4_OK, then any built-in pragma
** of the same name is not executed.
*/

/* Typedefs of datatypes */
typedef struct sqlite4_kvstore KVStore;
typedef struct sqlite4_kv_methods KVStoreMethods;
typedef struct sqlite4_kvcursor KVCursor;
typedef unsigned char KVByteArray;
typedef sqlite4_kvsize KVSize;


int sqlite4KVStoreOpenMem(sqlite4_env*, KVStore**, const char *, unsigned);
int sqlite4KVStoreOpenLsm(sqlite4_env*, KVStore**, const char *, unsigned);
int sqlite4KVStoreOpen(
  sqlite4*,
  const char *zLabel, 
  const char *zUri,

Changes to src/kvlsm.c.

438
439
440
441
442
443
444

445
446

447

448


449

450
451
452

453
454

455

456
457
458
459
460
461
462
  int rc = SQLITE4_OK;

  switch( p->ePragma ){
    case KVLSM_LSM_FLUSH:
      if( nArg!=0 ) goto wrong_num_args;
      rc = lsm_flush(p->pDb);
      break;

    case KVLSM_LSM_WORK: {
      int nWrite;

      if( nArg!=1 ) goto wrong_num_args;

      rc = lsm_work(p->pDb, 0, sqlite4_value_int(apArg[0]), &nWrite);


      sqlite4_result_int(ctx, nWrite);

      break;
    }
    case KVLSM_LSM_CHECKPOINT:

      if( nArg!=0 ) goto wrong_num_args;
      lsm_checkpoint(p->pDb, 0);

      break;

  }

  if( rc!=SQLITE4_OK ){
    sqlite4_result_error_code(ctx, rc);
  }
  return;








>
|
<
>
|
>
|
>
>
|
>

|
|
>

|
>

>







438
439
440
441
442
443
444
445
446

447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
  int rc = SQLITE4_OK;

  switch( p->ePragma ){
    case KVLSM_LSM_FLUSH:
      if( nArg!=0 ) goto wrong_num_args;
      rc = lsm_flush(p->pDb);
      break;

    case KVLSM_LSM_WORK:

      if( nArg!=2 ){
        goto wrong_num_args;
      }else{
        int nMerge = sqlite4_value_int(apArg[0]);
        int nWrite = sqlite4_value_int(apArg[1]);
        rc = lsm_work(p->pDb, nMerge, nWrite, &nWrite);
        sqlite4_result_int(ctx, nWrite);
      }
      break;

    case KVLSM_LSM_CHECKPOINT: {
      int nKB;
      if( nArg!=0 ) goto wrong_num_args;
      rc = lsm_checkpoint(p->pDb, &nKB);
      sqlite4_result_int(ctx, nKB);
      break;
    }
  }

  if( rc!=SQLITE4_OK ){
    sqlite4_result_error_code(ctx, rc);
  }
  return;

Changes to src/pragma.c.

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
...
184
185
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
243
244
245
246
247
248
249
250
251
252
253
254
...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
    default:          zName = "NO ACTION";  
                      assert( action==OE_None ); break;
  }
  return zName;
}
#endif




void sqlite4Pragma(
  Parse *pParse, 
  Token *pId1,        /* First part of [database.]id field */
  Token *pId2,        /* Second part of [database.]id field, or {0, 0} */
  ExprList *pList     /* List of pragma arguments */
){
  sqlite4 *db = pParse->db;
  Vdbe *v = pParse->pVdbe = sqlite4VdbeCreate(db);
  Token *pPragma;                 /* Token containing name of PRAGMA */
  char *zPragma = 0;              /* Name of requested PRAGMA */
  char *zRight = 0;               /* Argument to built-in pragmas */
  int iDb;                        /* Index of affected database */
  const char *zDb;                /* Named database (or NULL) */
  int rc = SQLITE4_OK;            /* Error code */


  /* Interpret the [database.] part of the pragma statement. iDb is the
  ** index of the database this pragma is being applied to in db.aDb[]. */
  iDb = sqlite4TwoPartName(pParse, pId1, pId2, &pPragma);
  if( iDb<0 ) goto pragma_out;
  zPragma = sqlite4NameFromToken(db, pPragma);
  if( !zPragma ) goto pragma_out;
................................................................................
  /* If this pragma is to operate on the temp database, make sure it is open. */
  if( iDb==1 && sqlite4OpenTempDatabase(pParse) ){
    goto pragma_out;
  }

  /* If a database was named as part of the pragma command, check to see if
  ** this is a custom key-value store pragma. */
  if( pId2->n ){
    int (*xGetMethod)(sqlite4_kvstore*, const char *, void **,
        void (**)(sqlite4_context *, int, sqlite4_value **),
        void (**)(void *)
    );
    KVStore *pKV = db->aDb[iDb].pKV;
    xGetMethod = pKV->pStoreVfunc->xGetMethod;
    if( xGetMethod ){
      void (*xFunc)(sqlite4_context *, int, sqlite4_value **);
      void (*xDestroy)(void *);
      void *pArg;

      rc = xGetMethod(pKV, zPragma, &pArg, &xFunc, &xDestroy);
      if( rc==SQLITE4_OK ){
        FuncDef *pDef;
        int nByte;
        int r1 = 0;
        int regOut;               /* Result register */

        if( sqlite4AuthCheck(pParse, SQLITE4_PRAGMA, zPragma, 0, zDb) ){
          goto pragma_out;
        }

        nByte = sizeof(FuncDef) + sizeof(FuncDestructor);
        pDef = (FuncDef *)sqlite4DbMallocZero(db, nByte);
        if( !pDef ) goto pragma_out;
        pDef->flags = SQLITE4_FUNC_EPHEM;
        pDef->pUserData = pArg;
        pDef->xFunc = xFunc;
        pDef->pDestructor = (FuncDestructor *)&pDef[1];
        pDef->pDestructor->nRef = 1;
        pDef->pDestructor->xDestroy = xDestroy;
        pDef->pDestructor->pUserData = pArg;

        sqlite4VdbeSetNumCols(v, 1);
        sqlite4VdbeSetColName(v, 0, COLNAME_NAME, zPragma, SQLITE4_TRANSIENT);

        if( pList ){
          r1 = pParse->nMem+1;
          pParse->nMem += pList->nExpr;
          sqlite4ExprCodeExprList(pParse, pList, r1, 0);
          pDef->nArg = pList->nExpr;
        }

        regOut = ++pParse->nMem;
        sqlite4VdbeAddOp1(v, OP_KVMethod, iDb);
        sqlite4VdbeAddOp3(v, OP_Function, 0, r1, regOut);
        sqlite4VdbeChangeP4(v, -1, (char*)pDef, P4_FUNCDEF);
        if( pList ) sqlite4VdbeChangeP5(v, pList->nExpr);
        sqlite4VdbeAddOp2(v, OP_ResultRow, regOut, 1);
        goto pragma_out;

      }else if( rc==SQLITE4_NOTFOUND ){
        rc = SQLITE4_OK;
      }else{
        goto pragma_out;
      }
    }
  }

  pParse->nMem = 2;
  sqlite4VdbeRunOnlyOnce(v);
  if( pList && pList->nExpr>1 ) goto pragma_out;
  zRight = 0;
................................................................................
      sqlite4VdbeAddOp4(v, OP_String8, 0, iReg, 0, "error - cksum mismatch", 0);
      sqlite4VdbeJumpHere(v, iAddr);
      sqlite4VdbeAddOp2(v, OP_ResultRow, iReg, 1);

      sqlite4VdbeSetNumCols(v, 1);
    }
  }



#ifndef SQLITE4_OMIT_SCHEMA_PRAGMAS
  /*
  **   PRAGMA table_info(<table>)
  **
  ** Return a single row for each column of the named table. The columns of
  ** the returned data set are:







>
>
>

|












>







 







<
<
<
<
<
|
|
<
|
|
|

|
|
|
|
|
|

|
|
|

|
|
|
|
|
|
|
|
|
|

|
|

|
|
|
|
|
|

|
|
|
|
|
|
|

|
|
|
|
<







 







<
<







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
181
182
183
...
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
243
244

245
246
247
248
249
250
251
...
328
329
330
331
332
333
334


335
336
337
338
339
340
341
    default:          zName = "NO ACTION";  
                      assert( action==OE_None ); break;
  }
  return zName;
}
#endif

/*
** Prepare an SQL PRAGMA statement.
*/
void sqlite4Pragma(
  Parse *pParse,      /* Parse context */
  Token *pId1,        /* First part of [database.]id field */
  Token *pId2,        /* Second part of [database.]id field, or {0, 0} */
  ExprList *pList     /* List of pragma arguments */
){
  sqlite4 *db = pParse->db;
  Vdbe *v = pParse->pVdbe = sqlite4VdbeCreate(db);
  Token *pPragma;                 /* Token containing name of PRAGMA */
  char *zPragma = 0;              /* Name of requested PRAGMA */
  char *zRight = 0;               /* Argument to built-in pragmas */
  int iDb;                        /* Index of affected database */
  const char *zDb;                /* Named database (or NULL) */
  int rc = SQLITE4_OK;            /* Error code */
  KVStore *pKV;                   /* KV store corresponding to db iDb */

  /* Interpret the [database.] part of the pragma statement. iDb is the
  ** index of the database this pragma is being applied to in db.aDb[]. */
  iDb = sqlite4TwoPartName(pParse, pId1, pId2, &pPragma);
  if( iDb<0 ) goto pragma_out;
  zPragma = sqlite4NameFromToken(db, pPragma);
  if( !zPragma ) goto pragma_out;
................................................................................
  /* If this pragma is to operate on the temp database, make sure it is open. */
  if( iDb==1 && sqlite4OpenTempDatabase(pParse) ){
    goto pragma_out;
  }

  /* If a database was named as part of the pragma command, check to see if
  ** this is a custom key-value store pragma. */





  pKV = db->aDb[iDb].pKV;
  if( pKV->pStoreVfunc->xGetMethod ){

    void (*xFunc)(sqlite4_context *, int, sqlite4_value **);
    void (*xDestroy)(void *);
    void *pArg;

    rc = pKV->pStoreVfunc->xGetMethod(pKV, zPragma, &pArg, &xFunc, &xDestroy);
    if( rc==SQLITE4_OK ){
      FuncDef *pDef;
      int nByte;
      int r1 = 0;
      int regOut;               /* Result register */

      if( sqlite4AuthCheck(pParse, SQLITE4_PRAGMA, zPragma, 0, zDb) ){
        goto pragma_out;
      }

      nByte = sizeof(FuncDef) + sizeof(FuncDestructor);
      pDef = (FuncDef *)sqlite4DbMallocZero(db, nByte);
      if( !pDef ) goto pragma_out;
      pDef->flags = SQLITE4_FUNC_EPHEM;
      pDef->pUserData = pArg;
      pDef->xFunc = xFunc;
      pDef->pDestructor = (FuncDestructor *)&pDef[1];
      pDef->pDestructor->nRef = 1;
      pDef->pDestructor->xDestroy = xDestroy;
      pDef->pDestructor->pUserData = pArg;

      sqlite4VdbeSetNumCols(v, 1);
      sqlite4VdbeSetColName(v, 0, COLNAME_NAME, zPragma, SQLITE4_TRANSIENT);

      if( pList ){
        r1 = pParse->nMem+1;
        pParse->nMem += pList->nExpr;
        sqlite4ExprCodeExprList(pParse, pList, r1, 0);
        pDef->nArg = pList->nExpr;
      }

      regOut = ++pParse->nMem;
      sqlite4VdbeAddOp1(v, OP_KVMethod, iDb);
      sqlite4VdbeAddOp3(v, OP_Function, 0, r1, regOut);
      sqlite4VdbeChangeP4(v, -1, (char*)pDef, P4_FUNCDEF);
      if( pList ) sqlite4VdbeChangeP5(v, pList->nExpr);
      sqlite4VdbeAddOp2(v, OP_ResultRow, regOut, 1);
      goto pragma_out;

    }else if( rc==SQLITE4_NOTFOUND ){
      rc = SQLITE4_OK;
    }else{
      goto pragma_out;

    }
  }

  pParse->nMem = 2;
  sqlite4VdbeRunOnlyOnce(v);
  if( pList && pList->nExpr>1 ) goto pragma_out;
  zRight = 0;
................................................................................
      sqlite4VdbeAddOp4(v, OP_String8, 0, iReg, 0, "error - cksum mismatch", 0);
      sqlite4VdbeJumpHere(v, iAddr);
      sqlite4VdbeAddOp2(v, OP_ResultRow, iReg, 1);

      sqlite4VdbeSetNumCols(v, 1);
    }
  }



#ifndef SQLITE4_OMIT_SCHEMA_PRAGMAS
  /*
  **   PRAGMA table_info(<table>)
  **
  ** Return a single row for each column of the named table. The columns of
  ** the returned data set are:

Changes to src/sqlite.h.in.

4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
  int (*xCommitPhaseTwo)(sqlite4_kvstore*, int);
  int (*xRollback)(sqlite4_kvstore*, int);
  int (*xRevert)(sqlite4_kvstore*, int);
  int (*xClose)(sqlite4_kvstore*);
  int (*xControl)(sqlite4_kvstore*, int, void*);
  int (*xGetMeta)(sqlite4_kvstore*, unsigned int *);
  int (*xPutMeta)(sqlite4_kvstore*, unsigned int);

  int (*xGetMethod)(sqlite4_kvstore*, const char *, void **ppArg,
      void (**pxFunc)(sqlite4_context *, int, sqlite4_value **),
      void (**pxDestroy)(void *)
  );
};
typedef struct sqlite4_kv_methods sqlite4_kv_methods;








<







4067
4068
4069
4070
4071
4072
4073

4074
4075
4076
4077
4078
4079
4080
  int (*xCommitPhaseTwo)(sqlite4_kvstore*, int);
  int (*xRollback)(sqlite4_kvstore*, int);
  int (*xRevert)(sqlite4_kvstore*, int);
  int (*xClose)(sqlite4_kvstore*);
  int (*xControl)(sqlite4_kvstore*, int, void*);
  int (*xGetMeta)(sqlite4_kvstore*, unsigned int *);
  int (*xPutMeta)(sqlite4_kvstore*, unsigned int);

  int (*xGetMethod)(sqlite4_kvstore*, const char *, void **ppArg,
      void (**pxFunc)(sqlite4_context *, int, sqlite4_value **),
      void (**pxDestroy)(void *)
  );
};
typedef struct sqlite4_kv_methods sqlite4_kv_methods;

Changes to test/permutations.test.

130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
...
227
228
229
230
231
232
233

234
235
236
237
238
239
240
#   full
#
lappend ::testsuitelist xxx

test_suite "src4" -prefix "" -description {
} -files {
  simple.test simple2.test
  log3.test 
  lsm1.test lsm2.test lsm3.test lsm4.test lsm5.test
  csr1.test
  ckpt1.test
  mc1.test
  fts5expr1.test fts5query1.test fts5rnd1.test fts5create.test
  fts5snippet.test

................................................................................
  tkt3201.test tkt3292.test tkt3298.test tkt3334.test tkt3346.test
  tkt3419.test tkt3424.test tkt3442.test tkt3461.test tkt3493.test
  tkt3508.test tkt3522.test tkt3527.test tkt3541.test tkt3554.test
  tkt3581.test tkt35xx.test tkt3630.test tkt3718.test tkt3761.test
  tkt3773.test tkt3841.test tkt3871.test tkt3879.test tkt3911.test
  tkt3918.test tkt3922.test tkt3929.test tkt3935.test tkt3997.test
}


test_suite "veryquick" -prefix "" -description {
  "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*    \







<







 







>







130
131
132
133
134
135
136

137
138
139
140
141
142
143
...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#   full
#
lappend ::testsuitelist xxx

test_suite "src4" -prefix "" -description {
} -files {
  simple.test simple2.test

  lsm1.test lsm2.test lsm3.test lsm4.test lsm5.test
  csr1.test
  ckpt1.test
  mc1.test
  fts5expr1.test fts5query1.test fts5rnd1.test fts5create.test
  fts5snippet.test

................................................................................
  tkt3201.test tkt3292.test tkt3298.test tkt3334.test tkt3346.test
  tkt3419.test tkt3424.test tkt3442.test tkt3461.test tkt3493.test
  tkt3508.test tkt3522.test tkt3527.test tkt3541.test tkt3554.test
  tkt3581.test tkt35xx.test tkt3630.test tkt3718.test tkt3761.test
  tkt3773.test tkt3841.test tkt3871.test tkt3879.test tkt3911.test
  tkt3918.test tkt3922.test tkt3929.test tkt3935.test tkt3997.test
}
#  log3.test 

test_suite "veryquick" -prefix "" -description {
  "Very" quick test suite. Runs in less than 5 minutes on a workstation. 
  This test suite is the same as the "quick" tests, except that some files
  that test malloc and IO errors are omitted.
} -files [
  test_set $allquicktests -exclude *malloc* *ioerr* *fault*    \

Changes to test/pragma3.test.

20
21
22
23
24
25
26
27
28
29
30

ifcapable !pragma {
  finish_test
  return
}

do_execsql_test 1.0 { CREATE TABLE t1(x) }
explain { PRAGMA main.lsm_work(1) }
do_execsql_test 1.1 { PRAGMA main.lsm_work(1); } {0}

finish_test







<
|


20
21
22
23
24
25
26

27
28
29

ifcapable !pragma {
  finish_test
  return
}

do_execsql_test 1.0 { CREATE TABLE t1(x) }

do_execsql_test 1.1 { PRAGMA main.lsm_work(1,1); } {0}

finish_test

Changes to test/tester.tcl.

1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585

1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
# Flush the in-memory tree to disk and merge all runs together into
# a single b-tree structure. Because this annihilates all delete keys,
# the next rowid allocated for each table with an IPK will be as expected
# by SQLite 3 tests.
#
proc optimize_db {} { 
  #catch { 
    set af [sqlite4_lsm_config db main autoflush]
    sqlite4_lsm_config db main autoflush 0
    db eval { BEGIN EXCLUSIVE; COMMIT; }
    sqlite4_lsm_config db main autoflush $af
    

    sqlite4_lsm_work db main -nmerge 1 -npage 100000 
    execsql { PRAGMA main.lsm_checkpoint }
  #}
  return ""
}


# If the library is compiled with the SQLITE4_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

source $testdir/malloc_common.tcl







|
|
<
|

>
|











1574
1575
1576
1577
1578
1579
1580
1581
1582

1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
# Flush the in-memory tree to disk and merge all runs together into
# a single b-tree structure. Because this annihilates all delete keys,
# the next rowid allocated for each table with an IPK will be as expected
# by SQLite 3 tests.
#
proc optimize_db {} { 
  #catch { 
    #set af [sqlite4_lsm_config db main autoflush]
    #sqlite4_lsm_config db main autoflush 0

    #sqlite4_lsm_config db main autoflush $af
    
    execsql { PRAGMA main.lsm_flush }
    execsql { PRAGMA main.lsm_work(1,100000) }
    execsql { PRAGMA main.lsm_checkpoint }
  #}
  return ""
}


# If the library is compiled with the SQLITE4_DEFAULT_AUTOVACUUM macro set
# to non-zero, then set the global variable $AUTOVACUUM to 1.
set AUTOVACUUM $sqlite_options(default_autovacuum)

source $testdir/malloc_common.tcl