os/persistentdata/persistentstorage/sqlite3api/TEST/SRC/test3.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/*
sl@0
     2
** 2001 September 15
sl@0
     3
**
sl@0
     4
** The author disclaims copyright to this source code.  In place of
sl@0
     5
** a legal notice, here is a blessing:
sl@0
     6
**
sl@0
     7
**    May you do good and not evil.
sl@0
     8
**    May you find forgiveness for yourself and forgive others.
sl@0
     9
**    May you share freely, never taking more than you give.
sl@0
    10
**
sl@0
    11
*************************************************************************
sl@0
    12
** Code for testing the btree.c module in SQLite.  This code
sl@0
    13
** is not included in the SQLite library.  It is used for automated
sl@0
    14
** testing of the SQLite library.
sl@0
    15
**
sl@0
    16
** $Id: test3.c,v 1.101 2008/08/13 19:11:48 drh Exp $
sl@0
    17
*/
sl@0
    18
#include "sqliteInt.h"
sl@0
    19
#include "btreeInt.h"
sl@0
    20
#include "tcl.h"
sl@0
    21
#include <stdlib.h>
sl@0
    22
#include <string.h>
sl@0
    23
sl@0
    24
/*
sl@0
    25
** Interpret an SQLite error number
sl@0
    26
*/
sl@0
    27
static char *errorName(int rc){
sl@0
    28
  char *zName;
sl@0
    29
  switch( rc ){
sl@0
    30
    case SQLITE_OK:         zName = "SQLITE_OK";          break;
sl@0
    31
    case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
sl@0
    32
    case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
sl@0
    33
    case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
sl@0
    34
    case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
sl@0
    35
    case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
sl@0
    36
    case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
sl@0
    37
    case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
sl@0
    38
    case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
sl@0
    39
    case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
sl@0
    40
    case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
sl@0
    41
    case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
sl@0
    42
    case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
sl@0
    43
    case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
sl@0
    44
    case SQLITE_LOCKED:     zName = "SQLITE_LOCKED";      break;
sl@0
    45
    default:                zName = "SQLITE_Unknown";     break;
sl@0
    46
  }
sl@0
    47
  return zName;
sl@0
    48
}
sl@0
    49
sl@0
    50
/*
sl@0
    51
** A bogus sqlite3 connection structure for use in the btree
sl@0
    52
** tests.
sl@0
    53
*/
sl@0
    54
static sqlite3 sDb;
sl@0
    55
static int nRefSqlite3 = 0;
sl@0
    56
sl@0
    57
/*
sl@0
    58
** Usage:   btree_open FILENAME NCACHE FLAGS
sl@0
    59
**
sl@0
    60
** Open a new database
sl@0
    61
*/
sl@0
    62
static int btree_open(
sl@0
    63
  void *NotUsed,
sl@0
    64
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
    65
  int argc,              /* Number of arguments */
sl@0
    66
  const char **argv      /* Text of each argument */
sl@0
    67
){
sl@0
    68
  Btree *pBt;
sl@0
    69
  int rc, nCache, flags;
sl@0
    70
  char zBuf[100];
sl@0
    71
  if( argc!=4 ){
sl@0
    72
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
    73
       " FILENAME NCACHE FLAGS\"", 0);
sl@0
    74
    return TCL_ERROR;
sl@0
    75
  }
sl@0
    76
  if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
sl@0
    77
  if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
sl@0
    78
  nRefSqlite3++;
sl@0
    79
  if( nRefSqlite3==1 ){
sl@0
    80
    sDb.pVfs = sqlite3_vfs_find(0);
sl@0
    81
    sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
sl@0
    82
    sqlite3_mutex_enter(sDb.mutex);
sl@0
    83
  }
sl@0
    84
  rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags,
sl@0
    85
     SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
sl@0
    86
  if( rc!=SQLITE_OK ){
sl@0
    87
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
    88
    return TCL_ERROR;
sl@0
    89
  }
sl@0
    90
  sqlite3BtreeSetCacheSize(pBt, nCache);
sl@0
    91
  sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
sl@0
    92
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
    93
  return TCL_OK;
sl@0
    94
}
sl@0
    95
sl@0
    96
/*
sl@0
    97
** Usage:   btree_close ID
sl@0
    98
**
sl@0
    99
** Close the given database.
sl@0
   100
*/
sl@0
   101
static int btree_close(
sl@0
   102
  void *NotUsed,
sl@0
   103
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   104
  int argc,              /* Number of arguments */
sl@0
   105
  const char **argv      /* Text of each argument */
sl@0
   106
){
sl@0
   107
  Btree *pBt;
sl@0
   108
  int rc;
sl@0
   109
  if( argc!=2 ){
sl@0
   110
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   111
       " ID\"", 0);
sl@0
   112
    return TCL_ERROR;
sl@0
   113
  }
sl@0
   114
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   115
  rc = sqlite3BtreeClose(pBt);
sl@0
   116
  if( rc!=SQLITE_OK ){
sl@0
   117
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   118
    return TCL_ERROR;
sl@0
   119
  }
sl@0
   120
  nRefSqlite3--;
sl@0
   121
  if( nRefSqlite3==0 ){
sl@0
   122
    sqlite3_mutex_leave(sDb.mutex);
sl@0
   123
    sqlite3_mutex_free(sDb.mutex);
sl@0
   124
    sDb.mutex = 0;
sl@0
   125
    sDb.pVfs = 0;
sl@0
   126
  }
sl@0
   127
  return TCL_OK;
sl@0
   128
}
sl@0
   129
sl@0
   130
sl@0
   131
/*
sl@0
   132
** Usage:   btree_begin_transaction ID
sl@0
   133
**
sl@0
   134
** Start a new transaction
sl@0
   135
*/
sl@0
   136
static int btree_begin_transaction(
sl@0
   137
  void *NotUsed,
sl@0
   138
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   139
  int argc,              /* Number of arguments */
sl@0
   140
  const char **argv      /* Text of each argument */
sl@0
   141
){
sl@0
   142
  Btree *pBt;
sl@0
   143
  int rc;
sl@0
   144
  if( argc!=2 ){
sl@0
   145
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   146
       " ID\"", 0);
sl@0
   147
    return TCL_ERROR;
sl@0
   148
  }
sl@0
   149
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   150
  sqlite3BtreeEnter(pBt);
sl@0
   151
  rc = sqlite3BtreeBeginTrans(pBt, 1);
sl@0
   152
  sqlite3BtreeLeave(pBt);
sl@0
   153
  if( rc!=SQLITE_OK ){
sl@0
   154
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   155
    return TCL_ERROR;
sl@0
   156
  }
sl@0
   157
  return TCL_OK;
sl@0
   158
}
sl@0
   159
sl@0
   160
/*
sl@0
   161
** Usage:   btree_rollback ID
sl@0
   162
**
sl@0
   163
** Rollback changes
sl@0
   164
*/
sl@0
   165
static int btree_rollback(
sl@0
   166
  void *NotUsed,
sl@0
   167
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   168
  int argc,              /* Number of arguments */
sl@0
   169
  const char **argv      /* Text of each argument */
sl@0
   170
){
sl@0
   171
  Btree *pBt;
sl@0
   172
  int rc;
sl@0
   173
  if( argc!=2 ){
sl@0
   174
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   175
       " ID\"", 0);
sl@0
   176
    return TCL_ERROR;
sl@0
   177
  }
sl@0
   178
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   179
  sqlite3BtreeEnter(pBt);
sl@0
   180
  rc = sqlite3BtreeRollback(pBt);
sl@0
   181
  sqlite3BtreeLeave(pBt);
sl@0
   182
  if( rc!=SQLITE_OK ){
sl@0
   183
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   184
    return TCL_ERROR;
sl@0
   185
  }
sl@0
   186
  return TCL_OK;
sl@0
   187
}
sl@0
   188
sl@0
   189
/*
sl@0
   190
** Usage:   btree_commit ID
sl@0
   191
**
sl@0
   192
** Commit all changes
sl@0
   193
*/
sl@0
   194
static int btree_commit(
sl@0
   195
  void *NotUsed,
sl@0
   196
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   197
  int argc,              /* Number of arguments */
sl@0
   198
  const char **argv      /* Text of each argument */
sl@0
   199
){
sl@0
   200
  Btree *pBt;
sl@0
   201
  int rc;
sl@0
   202
  if( argc!=2 ){
sl@0
   203
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   204
       " ID\"", 0);
sl@0
   205
    return TCL_ERROR;
sl@0
   206
  }
sl@0
   207
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   208
  sqlite3BtreeEnter(pBt);
sl@0
   209
  rc = sqlite3BtreeCommit(pBt);
sl@0
   210
  sqlite3BtreeLeave(pBt);
sl@0
   211
  if( rc!=SQLITE_OK ){
sl@0
   212
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   213
    return TCL_ERROR;
sl@0
   214
  }
sl@0
   215
  return TCL_OK;
sl@0
   216
}
sl@0
   217
sl@0
   218
/*
sl@0
   219
** Usage:   btree_begin_statement ID
sl@0
   220
**
sl@0
   221
** Start a new statement transaction
sl@0
   222
*/
sl@0
   223
static int btree_begin_statement(
sl@0
   224
  void *NotUsed,
sl@0
   225
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   226
  int argc,              /* Number of arguments */
sl@0
   227
  const char **argv      /* Text of each argument */
sl@0
   228
){
sl@0
   229
  Btree *pBt;
sl@0
   230
  int rc;
sl@0
   231
  if( argc!=2 ){
sl@0
   232
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   233
       " ID\"", 0);
sl@0
   234
    return TCL_ERROR;
sl@0
   235
  }
sl@0
   236
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   237
  sqlite3BtreeEnter(pBt);
sl@0
   238
  rc = sqlite3BtreeBeginStmt(pBt);
sl@0
   239
  sqlite3BtreeLeave(pBt);
sl@0
   240
  if( rc!=SQLITE_OK ){
sl@0
   241
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   242
    return TCL_ERROR;
sl@0
   243
  }
sl@0
   244
  return TCL_OK;
sl@0
   245
}
sl@0
   246
sl@0
   247
/*
sl@0
   248
** Usage:   btree_rollback_statement ID
sl@0
   249
**
sl@0
   250
** Rollback changes
sl@0
   251
*/
sl@0
   252
static int btree_rollback_statement(
sl@0
   253
  void *NotUsed,
sl@0
   254
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   255
  int argc,              /* Number of arguments */
sl@0
   256
  const char **argv      /* Text of each argument */
sl@0
   257
){
sl@0
   258
  Btree *pBt;
sl@0
   259
  int rc;
sl@0
   260
  if( argc!=2 ){
sl@0
   261
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   262
       " ID\"", 0);
sl@0
   263
    return TCL_ERROR;
sl@0
   264
  }
sl@0
   265
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   266
  sqlite3BtreeEnter(pBt);
sl@0
   267
  rc = sqlite3BtreeRollbackStmt(pBt);
sl@0
   268
  sqlite3BtreeLeave(pBt);
sl@0
   269
  if( rc!=SQLITE_OK ){
sl@0
   270
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   271
    return TCL_ERROR;
sl@0
   272
  }
sl@0
   273
  return TCL_OK;
sl@0
   274
}
sl@0
   275
sl@0
   276
/*
sl@0
   277
** Usage:   btree_commit_statement ID
sl@0
   278
**
sl@0
   279
** Commit all changes
sl@0
   280
*/
sl@0
   281
static int btree_commit_statement(
sl@0
   282
  void *NotUsed,
sl@0
   283
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   284
  int argc,              /* Number of arguments */
sl@0
   285
  const char **argv      /* Text of each argument */
sl@0
   286
){
sl@0
   287
  Btree *pBt;
sl@0
   288
  int rc;
sl@0
   289
  if( argc!=2 ){
sl@0
   290
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   291
       " ID\"", 0);
sl@0
   292
    return TCL_ERROR;
sl@0
   293
  }
sl@0
   294
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   295
  sqlite3BtreeEnter(pBt);
sl@0
   296
  rc = sqlite3BtreeCommitStmt(pBt);
sl@0
   297
  sqlite3BtreeLeave(pBt);
sl@0
   298
  if( rc!=SQLITE_OK ){
sl@0
   299
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   300
    return TCL_ERROR;
sl@0
   301
  }
sl@0
   302
  return TCL_OK;
sl@0
   303
}
sl@0
   304
sl@0
   305
/*
sl@0
   306
** Usage:   btree_create_table ID FLAGS
sl@0
   307
**
sl@0
   308
** Create a new table in the database
sl@0
   309
*/
sl@0
   310
static int btree_create_table(
sl@0
   311
  void *NotUsed,
sl@0
   312
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   313
  int argc,              /* Number of arguments */
sl@0
   314
  const char **argv      /* Text of each argument */
sl@0
   315
){
sl@0
   316
  Btree *pBt;
sl@0
   317
  int rc, iTable, flags;
sl@0
   318
  char zBuf[30];
sl@0
   319
  if( argc!=3 ){
sl@0
   320
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   321
       " ID FLAGS\"", 0);
sl@0
   322
    return TCL_ERROR;
sl@0
   323
  }
sl@0
   324
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   325
  if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR;
sl@0
   326
  sqlite3BtreeEnter(pBt);
sl@0
   327
  rc = sqlite3BtreeCreateTable(pBt, &iTable, flags);
sl@0
   328
  sqlite3BtreeLeave(pBt);
sl@0
   329
  if( rc!=SQLITE_OK ){
sl@0
   330
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   331
    return TCL_ERROR;
sl@0
   332
  }
sl@0
   333
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable);
sl@0
   334
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   335
  return TCL_OK;
sl@0
   336
}
sl@0
   337
sl@0
   338
/*
sl@0
   339
** Usage:   btree_drop_table ID TABLENUM
sl@0
   340
**
sl@0
   341
** Delete an entire table from the database
sl@0
   342
*/
sl@0
   343
static int btree_drop_table(
sl@0
   344
  void *NotUsed,
sl@0
   345
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   346
  int argc,              /* Number of arguments */
sl@0
   347
  const char **argv      /* Text of each argument */
sl@0
   348
){
sl@0
   349
  Btree *pBt;
sl@0
   350
  int iTable;
sl@0
   351
  int rc;
sl@0
   352
  int notUsed1;
sl@0
   353
  if( argc!=3 ){
sl@0
   354
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   355
       " ID TABLENUM\"", 0);
sl@0
   356
    return TCL_ERROR;
sl@0
   357
  }
sl@0
   358
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   359
  if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
sl@0
   360
  sqlite3BtreeEnter(pBt);
sl@0
   361
  rc = sqlite3BtreeDropTable(pBt, iTable, &notUsed1);
sl@0
   362
  sqlite3BtreeLeave(pBt);
sl@0
   363
  if( rc!=SQLITE_OK ){
sl@0
   364
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   365
    return TCL_ERROR;
sl@0
   366
  }
sl@0
   367
  return TCL_OK;
sl@0
   368
}
sl@0
   369
sl@0
   370
/*
sl@0
   371
** Usage:   btree_clear_table ID TABLENUM
sl@0
   372
**
sl@0
   373
** Remove all entries from the given table but keep the table around.
sl@0
   374
*/
sl@0
   375
static int btree_clear_table(
sl@0
   376
  void *NotUsed,
sl@0
   377
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   378
  int argc,              /* Number of arguments */
sl@0
   379
  const char **argv      /* Text of each argument */
sl@0
   380
){
sl@0
   381
  Btree *pBt;
sl@0
   382
  int iTable;
sl@0
   383
  int rc;
sl@0
   384
  if( argc!=3 ){
sl@0
   385
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   386
       " ID TABLENUM\"", 0);
sl@0
   387
    return TCL_ERROR;
sl@0
   388
  }
sl@0
   389
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   390
  if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
sl@0
   391
  sqlite3BtreeEnter(pBt);
sl@0
   392
  rc = sqlite3BtreeClearTable(pBt, iTable);
sl@0
   393
  sqlite3BtreeLeave(pBt);
sl@0
   394
  if( rc!=SQLITE_OK ){
sl@0
   395
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   396
    return TCL_ERROR;
sl@0
   397
  }
sl@0
   398
  return TCL_OK;
sl@0
   399
}
sl@0
   400
sl@0
   401
/*
sl@0
   402
** Usage:   btree_get_meta ID
sl@0
   403
**
sl@0
   404
** Return meta data
sl@0
   405
*/
sl@0
   406
static int btree_get_meta(
sl@0
   407
  void *NotUsed,
sl@0
   408
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   409
  int argc,              /* Number of arguments */
sl@0
   410
  const char **argv      /* Text of each argument */
sl@0
   411
){
sl@0
   412
  Btree *pBt;
sl@0
   413
  int rc;
sl@0
   414
  int i;
sl@0
   415
  if( argc!=2 ){
sl@0
   416
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   417
       " ID\"", 0);
sl@0
   418
    return TCL_ERROR;
sl@0
   419
  }
sl@0
   420
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   421
  for(i=0; i<SQLITE_N_BTREE_META; i++){
sl@0
   422
    char zBuf[30];
sl@0
   423
    u32 v;
sl@0
   424
    sqlite3BtreeEnter(pBt);
sl@0
   425
    rc = sqlite3BtreeGetMeta(pBt, i, &v);
sl@0
   426
    sqlite3BtreeLeave(pBt);
sl@0
   427
    if( rc!=SQLITE_OK ){
sl@0
   428
      Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   429
      return TCL_ERROR;
sl@0
   430
    }
sl@0
   431
    sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v);
sl@0
   432
    Tcl_AppendElement(interp, zBuf);
sl@0
   433
  }
sl@0
   434
  return TCL_OK;
sl@0
   435
}
sl@0
   436
sl@0
   437
/*
sl@0
   438
** Usage:   btree_update_meta ID METADATA...
sl@0
   439
**
sl@0
   440
** Return meta data
sl@0
   441
*/
sl@0
   442
static int btree_update_meta(
sl@0
   443
  void *NotUsed,
sl@0
   444
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   445
  int argc,              /* Number of arguments */
sl@0
   446
  const char **argv      /* Text of each argument */
sl@0
   447
){
sl@0
   448
  Btree *pBt;
sl@0
   449
  int rc;
sl@0
   450
  int i;
sl@0
   451
  int aMeta[SQLITE_N_BTREE_META];
sl@0
   452
sl@0
   453
  if( argc!=2+SQLITE_N_BTREE_META ){
sl@0
   454
    char zBuf[30];
sl@0
   455
    sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META);
sl@0
   456
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   457
       " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
sl@0
   458
    return TCL_ERROR;
sl@0
   459
  }
sl@0
   460
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   461
  for(i=1; i<SQLITE_N_BTREE_META; i++){
sl@0
   462
    if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
sl@0
   463
  }
sl@0
   464
  for(i=1; i<SQLITE_N_BTREE_META; i++){
sl@0
   465
    sqlite3BtreeEnter(pBt);
sl@0
   466
    rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]);
sl@0
   467
    sqlite3BtreeLeave(pBt);
sl@0
   468
    if( rc!=SQLITE_OK ){
sl@0
   469
      Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   470
      return TCL_ERROR;
sl@0
   471
    }
sl@0
   472
  }
sl@0
   473
  return TCL_OK;
sl@0
   474
}
sl@0
   475
sl@0
   476
/*
sl@0
   477
** Usage:   btree_pager_stats ID
sl@0
   478
**
sl@0
   479
** Returns pager statistics
sl@0
   480
*/
sl@0
   481
static int btree_pager_stats(
sl@0
   482
  void *NotUsed,
sl@0
   483
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   484
  int argc,              /* Number of arguments */
sl@0
   485
  const char **argv      /* Text of each argument */
sl@0
   486
){
sl@0
   487
  Btree *pBt;
sl@0
   488
  int i;
sl@0
   489
  int *a;
sl@0
   490
sl@0
   491
  if( argc!=2 ){
sl@0
   492
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   493
       " ID\"", 0);
sl@0
   494
    return TCL_ERROR;
sl@0
   495
  }
sl@0
   496
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   497
 
sl@0
   498
  /* Normally in this file, with a b-tree handle opened using the 
sl@0
   499
  ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
sl@0
   500
  ** But this function is sometimes called with a btree handle obtained
sl@0
   501
  ** from an open SQLite connection (using [btree_from_db]). In this case
sl@0
   502
  ** we need to obtain the mutex for the controlling SQLite handle before
sl@0
   503
  ** it is safe to call sqlite3BtreeEnter().
sl@0
   504
  */
sl@0
   505
  sqlite3_mutex_enter(pBt->db->mutex);
sl@0
   506
sl@0
   507
  sqlite3BtreeEnter(pBt);
sl@0
   508
  a = sqlite3PagerStats(sqlite3BtreePager(pBt));
sl@0
   509
  for(i=0; i<11; i++){
sl@0
   510
    static char *zName[] = {
sl@0
   511
      "ref", "page", "max", "size", "state", "err",
sl@0
   512
      "hit", "miss", "ovfl", "read", "write"
sl@0
   513
    };
sl@0
   514
    char zBuf[100];
sl@0
   515
    Tcl_AppendElement(interp, zName[i]);
sl@0
   516
    sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
sl@0
   517
    Tcl_AppendElement(interp, zBuf);
sl@0
   518
  }
sl@0
   519
  sqlite3BtreeLeave(pBt);
sl@0
   520
sl@0
   521
  /* Release the mutex on the SQLite handle that controls this b-tree */
sl@0
   522
  sqlite3_mutex_leave(pBt->db->mutex);
sl@0
   523
  return TCL_OK;
sl@0
   524
}
sl@0
   525
sl@0
   526
/*
sl@0
   527
** Usage:   btree_integrity_check ID ROOT ...
sl@0
   528
**
sl@0
   529
** Look through every page of the given BTree file to verify correct
sl@0
   530
** formatting and linkage.  Return a line of text for each problem found.
sl@0
   531
** Return an empty string if everything worked.
sl@0
   532
*/
sl@0
   533
static int btree_integrity_check(
sl@0
   534
  void *NotUsed,
sl@0
   535
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   536
  int argc,              /* Number of arguments */
sl@0
   537
  const char **argv      /* Text of each argument */
sl@0
   538
){
sl@0
   539
  Btree *pBt;
sl@0
   540
  int nRoot;
sl@0
   541
  int *aRoot;
sl@0
   542
  int i;
sl@0
   543
  int nErr;
sl@0
   544
  char *zResult;
sl@0
   545
sl@0
   546
  if( argc<3 ){
sl@0
   547
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   548
       " ID ROOT ...\"", 0);
sl@0
   549
    return TCL_ERROR;
sl@0
   550
  }
sl@0
   551
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   552
  nRoot = argc-2;
sl@0
   553
  aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) );
sl@0
   554
  for(i=0; i<argc-2; i++){
sl@0
   555
    if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
sl@0
   556
  }
sl@0
   557
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
sl@0
   558
  sqlite3BtreeEnter(pBt);
sl@0
   559
  zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
sl@0
   560
  sqlite3BtreeLeave(pBt);
sl@0
   561
#else
sl@0
   562
  zResult = 0;
sl@0
   563
#endif
sl@0
   564
  sqlite3_free((void*)aRoot);
sl@0
   565
  if( zResult ){
sl@0
   566
    Tcl_AppendResult(interp, zResult, 0);
sl@0
   567
    sqlite3_free(zResult); 
sl@0
   568
  }
sl@0
   569
  return TCL_OK;
sl@0
   570
}
sl@0
   571
sl@0
   572
/*
sl@0
   573
** Usage:   btree_cursor_list ID
sl@0
   574
**
sl@0
   575
** Print information about all cursors to standard output for debugging.
sl@0
   576
*/
sl@0
   577
static int btree_cursor_list(
sl@0
   578
  void *NotUsed,
sl@0
   579
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   580
  int argc,              /* Number of arguments */
sl@0
   581
  const char **argv      /* Text of each argument */
sl@0
   582
){
sl@0
   583
  Btree *pBt;
sl@0
   584
sl@0
   585
  if( argc!=2 ){
sl@0
   586
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   587
       " ID\"", 0);
sl@0
   588
    return TCL_ERROR;
sl@0
   589
  }
sl@0
   590
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   591
  sqlite3BtreeEnter(pBt);
sl@0
   592
  sqlite3BtreeCursorList(pBt);
sl@0
   593
  sqlite3BtreeLeave(pBt);
sl@0
   594
  return SQLITE_OK;
sl@0
   595
}
sl@0
   596
sl@0
   597
/*
sl@0
   598
** Usage:   btree_cursor ID TABLENUM WRITEABLE
sl@0
   599
**
sl@0
   600
** Create a new cursor.  Return the ID for the cursor.
sl@0
   601
*/
sl@0
   602
static int btree_cursor(
sl@0
   603
  void *NotUsed,
sl@0
   604
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   605
  int argc,              /* Number of arguments */
sl@0
   606
  const char **argv      /* Text of each argument */
sl@0
   607
){
sl@0
   608
  Btree *pBt;
sl@0
   609
  int iTable;
sl@0
   610
  BtCursor *pCur;
sl@0
   611
  int rc;
sl@0
   612
  int wrFlag;
sl@0
   613
  char zBuf[30];
sl@0
   614
sl@0
   615
  if( argc!=4 ){
sl@0
   616
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   617
       " ID TABLENUM WRITEABLE\"", 0);
sl@0
   618
    return TCL_ERROR;
sl@0
   619
  }
sl@0
   620
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
   621
  if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
sl@0
   622
  if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
sl@0
   623
  pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
sl@0
   624
  memset(pCur, 0, sqlite3BtreeCursorSize());
sl@0
   625
  sqlite3BtreeEnter(pBt);
sl@0
   626
  rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
sl@0
   627
  sqlite3BtreeLeave(pBt);
sl@0
   628
  if( rc ){
sl@0
   629
    ckfree((char *)pCur);
sl@0
   630
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   631
    return TCL_ERROR;
sl@0
   632
  }
sl@0
   633
  sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
sl@0
   634
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   635
  return SQLITE_OK;
sl@0
   636
}
sl@0
   637
sl@0
   638
/*
sl@0
   639
** Usage:   btree_close_cursor ID
sl@0
   640
**
sl@0
   641
** Close a cursor opened using btree_cursor.
sl@0
   642
*/
sl@0
   643
static int btree_close_cursor(
sl@0
   644
  void *NotUsed,
sl@0
   645
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   646
  int argc,              /* Number of arguments */
sl@0
   647
  const char **argv      /* Text of each argument */
sl@0
   648
){
sl@0
   649
  BtCursor *pCur;
sl@0
   650
  Btree *pBt;
sl@0
   651
  int rc;
sl@0
   652
sl@0
   653
  if( argc!=2 ){
sl@0
   654
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   655
       " ID\"", 0);
sl@0
   656
    return TCL_ERROR;
sl@0
   657
  }
sl@0
   658
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   659
  pBt = pCur->pBtree;
sl@0
   660
  sqlite3BtreeEnter(pBt);
sl@0
   661
  rc = sqlite3BtreeCloseCursor(pCur);
sl@0
   662
  sqlite3BtreeLeave(pBt);
sl@0
   663
  ckfree((char *)pCur);
sl@0
   664
  if( rc ){
sl@0
   665
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   666
    return TCL_ERROR;
sl@0
   667
  }
sl@0
   668
  return SQLITE_OK;
sl@0
   669
}
sl@0
   670
sl@0
   671
/*
sl@0
   672
** Usage:   btree_move_to ID KEY
sl@0
   673
**
sl@0
   674
** Move the cursor to the entry with the given key.
sl@0
   675
*/
sl@0
   676
static int btree_move_to(
sl@0
   677
  void *NotUsed,
sl@0
   678
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   679
  int argc,              /* Number of arguments */
sl@0
   680
  const char **argv      /* Text of each argument */
sl@0
   681
){
sl@0
   682
  BtCursor *pCur;
sl@0
   683
  int rc;
sl@0
   684
  int res;
sl@0
   685
  char zBuf[20];
sl@0
   686
sl@0
   687
  if( argc!=3 ){
sl@0
   688
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   689
       " ID KEY\"", 0);
sl@0
   690
    return TCL_ERROR;
sl@0
   691
  }
sl@0
   692
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   693
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   694
  if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
sl@0
   695
    int iKey;
sl@0
   696
    if( Tcl_GetInt(interp, argv[2], &iKey) ){
sl@0
   697
      sqlite3BtreeLeave(pCur->pBtree);
sl@0
   698
      return TCL_ERROR;
sl@0
   699
    }
sl@0
   700
    rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res);
sl@0
   701
  }else{
sl@0
   702
    rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);  
sl@0
   703
  }
sl@0
   704
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   705
  if( rc ){
sl@0
   706
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   707
    return TCL_ERROR;
sl@0
   708
  }
sl@0
   709
  if( res<0 ) res = -1;
sl@0
   710
  if( res>0 ) res = 1;
sl@0
   711
  sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res);
sl@0
   712
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   713
  return SQLITE_OK;
sl@0
   714
}
sl@0
   715
sl@0
   716
/*
sl@0
   717
** Usage:   btree_delete ID
sl@0
   718
**
sl@0
   719
** Delete the entry that the cursor is pointing to
sl@0
   720
*/
sl@0
   721
static int btree_delete(
sl@0
   722
  void *NotUsed,
sl@0
   723
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   724
  int argc,              /* Number of arguments */
sl@0
   725
  const char **argv      /* Text of each argument */
sl@0
   726
){
sl@0
   727
  BtCursor *pCur;
sl@0
   728
  int rc;
sl@0
   729
sl@0
   730
  if( argc!=2 ){
sl@0
   731
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   732
       " ID\"", 0);
sl@0
   733
    return TCL_ERROR;
sl@0
   734
  }
sl@0
   735
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   736
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   737
  rc = sqlite3BtreeDelete(pCur);
sl@0
   738
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   739
  if( rc ){
sl@0
   740
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   741
    return TCL_ERROR;
sl@0
   742
  }
sl@0
   743
  return SQLITE_OK;
sl@0
   744
}
sl@0
   745
sl@0
   746
/*
sl@0
   747
** Usage:   btree_insert ID KEY DATA ?NZERO?
sl@0
   748
**
sl@0
   749
** Create a new entry with the given key and data.  If an entry already
sl@0
   750
** exists with the same key the old entry is overwritten.
sl@0
   751
*/
sl@0
   752
static int btree_insert(
sl@0
   753
  void * clientData,
sl@0
   754
  Tcl_Interp *interp,
sl@0
   755
  int objc,
sl@0
   756
  Tcl_Obj *CONST objv[]
sl@0
   757
){
sl@0
   758
  BtCursor *pCur;
sl@0
   759
  int rc;
sl@0
   760
  int nZero;
sl@0
   761
sl@0
   762
  if( objc!=4 && objc!=5 ){
sl@0
   763
    Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
sl@0
   764
    return TCL_ERROR;
sl@0
   765
  }
sl@0
   766
  pCur = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
sl@0
   767
  if( objc==5 ){
sl@0
   768
    if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR;
sl@0
   769
  }else{
sl@0
   770
    nZero = 0;
sl@0
   771
  }
sl@0
   772
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   773
  if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
sl@0
   774
    i64 iKey;
sl@0
   775
    int len;
sl@0
   776
    unsigned char *pBuf;
sl@0
   777
    if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){
sl@0
   778
      sqlite3BtreeLeave(pCur->pBtree);
sl@0
   779
      return TCL_ERROR;
sl@0
   780
    }
sl@0
   781
    pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
sl@0
   782
    rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
sl@0
   783
  }else{
sl@0
   784
    int keylen;
sl@0
   785
    int dlen;
sl@0
   786
    unsigned char *pKBuf;
sl@0
   787
    unsigned char *pDBuf;
sl@0
   788
    pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
sl@0
   789
    pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
sl@0
   790
    rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0);
sl@0
   791
  }
sl@0
   792
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   793
  if( rc ){
sl@0
   794
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   795
    return TCL_ERROR;
sl@0
   796
  }
sl@0
   797
  return SQLITE_OK;
sl@0
   798
}
sl@0
   799
sl@0
   800
/*
sl@0
   801
** Usage:   btree_next ID
sl@0
   802
**
sl@0
   803
** Move the cursor to the next entry in the table.  Return 0 on success
sl@0
   804
** or 1 if the cursor was already on the last entry in the table or if
sl@0
   805
** the table is empty.
sl@0
   806
*/
sl@0
   807
static int btree_next(
sl@0
   808
  void *NotUsed,
sl@0
   809
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   810
  int argc,              /* Number of arguments */
sl@0
   811
  const char **argv      /* Text of each argument */
sl@0
   812
){
sl@0
   813
  BtCursor *pCur;
sl@0
   814
  int rc;
sl@0
   815
  int res = 0;
sl@0
   816
  char zBuf[100];
sl@0
   817
sl@0
   818
  if( argc!=2 ){
sl@0
   819
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   820
       " ID\"", 0);
sl@0
   821
    return TCL_ERROR;
sl@0
   822
  }
sl@0
   823
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   824
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   825
  rc = sqlite3BtreeNext(pCur, &res);
sl@0
   826
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   827
  if( rc ){
sl@0
   828
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   829
    return TCL_ERROR;
sl@0
   830
  }
sl@0
   831
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
sl@0
   832
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   833
  return SQLITE_OK;
sl@0
   834
}
sl@0
   835
sl@0
   836
/*
sl@0
   837
** Usage:   btree_prev ID
sl@0
   838
**
sl@0
   839
** Move the cursor to the previous entry in the table.  Return 0 on
sl@0
   840
** success and 1 if the cursor was already on the first entry in
sl@0
   841
** the table or if the table was empty.
sl@0
   842
*/
sl@0
   843
static int btree_prev(
sl@0
   844
  void *NotUsed,
sl@0
   845
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   846
  int argc,              /* Number of arguments */
sl@0
   847
  const char **argv      /* Text of each argument */
sl@0
   848
){
sl@0
   849
  BtCursor *pCur;
sl@0
   850
  int rc;
sl@0
   851
  int res = 0;
sl@0
   852
  char zBuf[100];
sl@0
   853
sl@0
   854
  if( argc!=2 ){
sl@0
   855
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   856
       " ID\"", 0);
sl@0
   857
    return TCL_ERROR;
sl@0
   858
  }
sl@0
   859
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   860
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   861
  rc = sqlite3BtreePrevious(pCur, &res);
sl@0
   862
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   863
  if( rc ){
sl@0
   864
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   865
    return TCL_ERROR;
sl@0
   866
  }
sl@0
   867
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
sl@0
   868
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   869
  return SQLITE_OK;
sl@0
   870
}
sl@0
   871
sl@0
   872
/*
sl@0
   873
** Usage:   btree_first ID
sl@0
   874
**
sl@0
   875
** Move the cursor to the first entry in the table.  Return 0 if the
sl@0
   876
** cursor was left point to something and 1 if the table is empty.
sl@0
   877
*/
sl@0
   878
static int btree_first(
sl@0
   879
  void *NotUsed,
sl@0
   880
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   881
  int argc,              /* Number of arguments */
sl@0
   882
  const char **argv      /* Text of each argument */
sl@0
   883
){
sl@0
   884
  BtCursor *pCur;
sl@0
   885
  int rc;
sl@0
   886
  int res = 0;
sl@0
   887
  char zBuf[100];
sl@0
   888
sl@0
   889
  if( argc!=2 ){
sl@0
   890
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   891
       " ID\"", 0);
sl@0
   892
    return TCL_ERROR;
sl@0
   893
  }
sl@0
   894
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   895
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   896
  rc = sqlite3BtreeFirst(pCur, &res);
sl@0
   897
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   898
  if( rc ){
sl@0
   899
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   900
    return TCL_ERROR;
sl@0
   901
  }
sl@0
   902
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
sl@0
   903
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   904
  return SQLITE_OK;
sl@0
   905
}
sl@0
   906
sl@0
   907
/*
sl@0
   908
** Usage:   btree_last ID
sl@0
   909
**
sl@0
   910
** Move the cursor to the last entry in the table.  Return 0 if the
sl@0
   911
** cursor was left point to something and 1 if the table is empty.
sl@0
   912
*/
sl@0
   913
static int btree_last(
sl@0
   914
  void *NotUsed,
sl@0
   915
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   916
  int argc,              /* Number of arguments */
sl@0
   917
  const char **argv      /* Text of each argument */
sl@0
   918
){
sl@0
   919
  BtCursor *pCur;
sl@0
   920
  int rc;
sl@0
   921
  int res = 0;
sl@0
   922
  char zBuf[100];
sl@0
   923
sl@0
   924
  if( argc!=2 ){
sl@0
   925
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   926
       " ID\"", 0);
sl@0
   927
    return TCL_ERROR;
sl@0
   928
  }
sl@0
   929
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   930
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   931
  rc = sqlite3BtreeLast(pCur, &res);
sl@0
   932
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   933
  if( rc ){
sl@0
   934
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
   935
    return TCL_ERROR;
sl@0
   936
  }
sl@0
   937
  sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
sl@0
   938
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   939
  return SQLITE_OK;
sl@0
   940
}
sl@0
   941
sl@0
   942
/*
sl@0
   943
** Usage:   btree_eof ID
sl@0
   944
**
sl@0
   945
** Return TRUE if the given cursor is not pointing at a valid entry.
sl@0
   946
** Return FALSE if the cursor does point to a valid entry.
sl@0
   947
*/
sl@0
   948
static int btree_eof(
sl@0
   949
  void *NotUsed,
sl@0
   950
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   951
  int argc,              /* Number of arguments */
sl@0
   952
  const char **argv      /* Text of each argument */
sl@0
   953
){
sl@0
   954
  BtCursor *pCur;
sl@0
   955
  int rc;
sl@0
   956
  char zBuf[50];
sl@0
   957
sl@0
   958
  if( argc!=2 ){
sl@0
   959
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   960
       " ID\"", 0);
sl@0
   961
    return TCL_ERROR;
sl@0
   962
  }
sl@0
   963
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   964
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   965
  rc = sqlite3BtreeEof(pCur);
sl@0
   966
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   967
  sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
sl@0
   968
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   969
  return SQLITE_OK;
sl@0
   970
}
sl@0
   971
sl@0
   972
/*
sl@0
   973
** Usage:   btree_keysize ID
sl@0
   974
**
sl@0
   975
** Return the number of bytes of key.  For an INTKEY table, this
sl@0
   976
** returns the key itself.
sl@0
   977
*/
sl@0
   978
static int btree_keysize(
sl@0
   979
  void *NotUsed,
sl@0
   980
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
   981
  int argc,              /* Number of arguments */
sl@0
   982
  const char **argv      /* Text of each argument */
sl@0
   983
){
sl@0
   984
  BtCursor *pCur;
sl@0
   985
  u64 n;
sl@0
   986
  char zBuf[50];
sl@0
   987
sl@0
   988
  if( argc!=2 ){
sl@0
   989
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
   990
       " ID\"", 0);
sl@0
   991
    return TCL_ERROR;
sl@0
   992
  }
sl@0
   993
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
   994
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
   995
  sqlite3BtreeKeySize(pCur, (i64*)&n);
sl@0
   996
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
   997
  sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
sl@0
   998
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
   999
  return SQLITE_OK;
sl@0
  1000
}
sl@0
  1001
sl@0
  1002
/*
sl@0
  1003
** Usage:   btree_key ID
sl@0
  1004
**
sl@0
  1005
** Return the key for the entry at which the cursor is pointing.
sl@0
  1006
*/
sl@0
  1007
static int btree_key(
sl@0
  1008
  void *NotUsed,
sl@0
  1009
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1010
  int argc,              /* Number of arguments */
sl@0
  1011
  const char **argv      /* Text of each argument */
sl@0
  1012
){
sl@0
  1013
  BtCursor *pCur;
sl@0
  1014
  int rc;
sl@0
  1015
  u64 n;
sl@0
  1016
  char *zBuf;
sl@0
  1017
sl@0
  1018
  if( argc!=2 ){
sl@0
  1019
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1020
       " ID\"", 0);
sl@0
  1021
    return TCL_ERROR;
sl@0
  1022
  }
sl@0
  1023
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
  1024
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
  1025
  sqlite3BtreeKeySize(pCur, (i64*)&n);
sl@0
  1026
  if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
sl@0
  1027
    char zBuf2[60];
sl@0
  1028
    sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
sl@0
  1029
    Tcl_AppendResult(interp, zBuf2, 0);
sl@0
  1030
  }else{
sl@0
  1031
    zBuf = sqlite3_malloc( n+1 );
sl@0
  1032
    rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
sl@0
  1033
    if( rc ){
sl@0
  1034
      sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1035
      Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
  1036
      return TCL_ERROR;
sl@0
  1037
    }
sl@0
  1038
    zBuf[n] = 0;
sl@0
  1039
    Tcl_AppendResult(interp, zBuf, 0);
sl@0
  1040
    sqlite3_free(zBuf);
sl@0
  1041
  }
sl@0
  1042
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1043
  return SQLITE_OK;
sl@0
  1044
}
sl@0
  1045
sl@0
  1046
/*
sl@0
  1047
** Usage:   btree_data ID ?N?
sl@0
  1048
**
sl@0
  1049
** Return the data for the entry at which the cursor is pointing.
sl@0
  1050
*/
sl@0
  1051
static int btree_data(
sl@0
  1052
  void *NotUsed,
sl@0
  1053
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1054
  int argc,              /* Number of arguments */
sl@0
  1055
  const char **argv      /* Text of each argument */
sl@0
  1056
){
sl@0
  1057
  BtCursor *pCur;
sl@0
  1058
  int rc;
sl@0
  1059
  u32 n;
sl@0
  1060
  char *zBuf;
sl@0
  1061
sl@0
  1062
  if( argc!=2 && argc!=3 ){
sl@0
  1063
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1064
       " ID\"", 0);
sl@0
  1065
    return TCL_ERROR;
sl@0
  1066
  }
sl@0
  1067
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
  1068
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
  1069
  if( argc==2 ){
sl@0
  1070
    sqlite3BtreeDataSize(pCur, &n);
sl@0
  1071
  }else{
sl@0
  1072
    n = atoi(argv[2]);
sl@0
  1073
  }
sl@0
  1074
  zBuf = sqlite3_malloc( n+1 );
sl@0
  1075
  rc = sqlite3BtreeData(pCur, 0, n, zBuf);
sl@0
  1076
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1077
  if( rc ){
sl@0
  1078
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
  1079
    sqlite3_free(zBuf);
sl@0
  1080
    return TCL_ERROR;
sl@0
  1081
  }
sl@0
  1082
  zBuf[n] = 0;
sl@0
  1083
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
  1084
  sqlite3_free(zBuf);
sl@0
  1085
  return SQLITE_OK;
sl@0
  1086
}
sl@0
  1087
sl@0
  1088
/*
sl@0
  1089
** Usage:   btree_fetch_key ID AMT
sl@0
  1090
**
sl@0
  1091
** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
sl@0
  1092
** If sqlite3BtreeKeyFetch() fails, return an empty string.
sl@0
  1093
*/
sl@0
  1094
static int btree_fetch_key(
sl@0
  1095
  void *NotUsed,
sl@0
  1096
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1097
  int argc,              /* Number of arguments */
sl@0
  1098
  const char **argv      /* Text of each argument */
sl@0
  1099
){
sl@0
  1100
  BtCursor *pCur;
sl@0
  1101
  int n;
sl@0
  1102
  int amt;
sl@0
  1103
  u64 nKey;
sl@0
  1104
  const char *zBuf;
sl@0
  1105
  char zStatic[1000];
sl@0
  1106
sl@0
  1107
  if( argc!=3 ){
sl@0
  1108
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1109
       " ID AMT\"", 0);
sl@0
  1110
    return TCL_ERROR;
sl@0
  1111
  }
sl@0
  1112
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
  1113
  if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
sl@0
  1114
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
  1115
  sqlite3BtreeKeySize(pCur, (i64*)&nKey);
sl@0
  1116
  zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
sl@0
  1117
  if( zBuf && amt>=n ){
sl@0
  1118
    assert( nKey<sizeof(zStatic) );
sl@0
  1119
    if( n>0 ) nKey = n;
sl@0
  1120
    memcpy(zStatic, zBuf, (int)nKey); 
sl@0
  1121
    zStatic[nKey] = 0;
sl@0
  1122
    Tcl_AppendResult(interp, zStatic, 0);
sl@0
  1123
  }
sl@0
  1124
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1125
  return TCL_OK;
sl@0
  1126
}
sl@0
  1127
sl@0
  1128
/*
sl@0
  1129
** Usage:   btree_fetch_data ID AMT
sl@0
  1130
**
sl@0
  1131
** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
sl@0
  1132
** If sqlite3BtreeDataFetch() fails, return an empty string.
sl@0
  1133
*/
sl@0
  1134
static int btree_fetch_data(
sl@0
  1135
  void *NotUsed,
sl@0
  1136
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1137
  int argc,              /* Number of arguments */
sl@0
  1138
  const char **argv      /* Text of each argument */
sl@0
  1139
){
sl@0
  1140
  BtCursor *pCur;
sl@0
  1141
  int n;
sl@0
  1142
  int amt;
sl@0
  1143
  u32 nData;
sl@0
  1144
  const char *zBuf;
sl@0
  1145
  char zStatic[1000];
sl@0
  1146
sl@0
  1147
  if( argc!=3 ){
sl@0
  1148
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1149
       " ID AMT\"", 0);
sl@0
  1150
    return TCL_ERROR;
sl@0
  1151
  }
sl@0
  1152
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
  1153
  if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
sl@0
  1154
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
  1155
  sqlite3BtreeDataSize(pCur, &nData);
sl@0
  1156
  zBuf = sqlite3BtreeDataFetch(pCur, &amt);
sl@0
  1157
  if( zBuf && amt>=n ){
sl@0
  1158
    assert( nData<sizeof(zStatic) );
sl@0
  1159
    if( n>0 ) nData = n;
sl@0
  1160
    memcpy(zStatic, zBuf, (int)nData); 
sl@0
  1161
    zStatic[nData] = 0;
sl@0
  1162
    Tcl_AppendResult(interp, zStatic, 0);
sl@0
  1163
  }
sl@0
  1164
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1165
  return TCL_OK;
sl@0
  1166
}
sl@0
  1167
sl@0
  1168
/*
sl@0
  1169
** Usage:   btree_payload_size ID
sl@0
  1170
**
sl@0
  1171
** Return the number of bytes of payload
sl@0
  1172
*/
sl@0
  1173
static int btree_payload_size(
sl@0
  1174
  void *NotUsed,
sl@0
  1175
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1176
  int argc,              /* Number of arguments */
sl@0
  1177
  const char **argv      /* Text of each argument */
sl@0
  1178
){
sl@0
  1179
  BtCursor *pCur;
sl@0
  1180
  int n2;
sl@0
  1181
  u64 n1;
sl@0
  1182
  char zBuf[50];
sl@0
  1183
sl@0
  1184
  if( argc!=2 ){
sl@0
  1185
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1186
       " ID\"", 0);
sl@0
  1187
    return TCL_ERROR;
sl@0
  1188
  }
sl@0
  1189
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
  1190
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
  1191
  if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
sl@0
  1192
    n1 = 0;
sl@0
  1193
  }else{
sl@0
  1194
    sqlite3BtreeKeySize(pCur, (i64*)&n1);
sl@0
  1195
  }
sl@0
  1196
  sqlite3BtreeDataSize(pCur, (u32*)&n2);
sl@0
  1197
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1198
  sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
sl@0
  1199
  Tcl_AppendResult(interp, zBuf, 0);
sl@0
  1200
  return SQLITE_OK;
sl@0
  1201
}
sl@0
  1202
sl@0
  1203
/*
sl@0
  1204
** Usage:   btree_cursor_info ID ?UP-CNT?
sl@0
  1205
**
sl@0
  1206
** Return integers containing information about the entry the
sl@0
  1207
** cursor is pointing to:
sl@0
  1208
**
sl@0
  1209
**   aResult[0] =  The page number
sl@0
  1210
**   aResult[1] =  The entry number
sl@0
  1211
**   aResult[2] =  Total number of entries on this page
sl@0
  1212
**   aResult[3] =  Cell size (local payload + header)
sl@0
  1213
**   aResult[4] =  Number of free bytes on this page
sl@0
  1214
**   aResult[5] =  Number of free blocks on the page
sl@0
  1215
**   aResult[6] =  Total payload size (local + overflow)
sl@0
  1216
**   aResult[7] =  Header size in bytes
sl@0
  1217
**   aResult[8] =  Local payload size
sl@0
  1218
**   aResult[9] =  Parent page number
sl@0
  1219
**   aResult[10]=  Page number of the first overflow page
sl@0
  1220
*/
sl@0
  1221
static int btree_cursor_info(
sl@0
  1222
  void *NotUsed,
sl@0
  1223
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1224
  int argc,              /* Number of arguments */
sl@0
  1225
  const char **argv      /* Text of each argument */
sl@0
  1226
){
sl@0
  1227
  BtCursor *pCur;
sl@0
  1228
  int rc;
sl@0
  1229
  int i, j;
sl@0
  1230
  int up;
sl@0
  1231
  int aResult[11];
sl@0
  1232
  char zBuf[400];
sl@0
  1233
sl@0
  1234
  if( argc!=2 && argc!=3 ){
sl@0
  1235
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1236
       " ID ?UP-CNT?\"", 0);
sl@0
  1237
    return TCL_ERROR;
sl@0
  1238
  }
sl@0
  1239
  pCur = sqlite3TestTextToPtr(argv[1]);
sl@0
  1240
  if( argc==3 ){
sl@0
  1241
    if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR;
sl@0
  1242
  }else{
sl@0
  1243
    up = 0;
sl@0
  1244
  }
sl@0
  1245
  sqlite3BtreeEnter(pCur->pBtree);
sl@0
  1246
  rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
sl@0
  1247
  if( rc ){
sl@0
  1248
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
  1249
    sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1250
    return TCL_ERROR;
sl@0
  1251
  }
sl@0
  1252
  j = 0;
sl@0
  1253
  for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
sl@0
  1254
    sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
sl@0
  1255
    j += strlen(&zBuf[j]);
sl@0
  1256
  }
sl@0
  1257
  sqlite3BtreeLeave(pCur->pBtree);
sl@0
  1258
  Tcl_AppendResult(interp, &zBuf[1], 0);
sl@0
  1259
  return SQLITE_OK;
sl@0
  1260
}
sl@0
  1261
sl@0
  1262
/*
sl@0
  1263
** Copied from btree.c:
sl@0
  1264
*/
sl@0
  1265
static u32 t4Get4byte(unsigned char *p){
sl@0
  1266
  return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
sl@0
  1267
}
sl@0
  1268
sl@0
  1269
/*
sl@0
  1270
**   btree_ovfl_info  BTREE  CURSOR
sl@0
  1271
**
sl@0
  1272
** Given a cursor, return the sequence of pages number that form the
sl@0
  1273
** overflow pages for the data of the entry that the cursor is point
sl@0
  1274
** to.
sl@0
  1275
*/ 
sl@0
  1276
static int btree_ovfl_info(
sl@0
  1277
  void *NotUsed,
sl@0
  1278
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1279
  int argc,              /* Number of arguments */
sl@0
  1280
  const char **argv      /* Text of each argument */
sl@0
  1281
){
sl@0
  1282
  Btree *pBt;
sl@0
  1283
  BtCursor *pCur;
sl@0
  1284
  Pager *pPager;
sl@0
  1285
  int rc;
sl@0
  1286
  int n;
sl@0
  1287
  int dataSize;
sl@0
  1288
  u32 pgno;
sl@0
  1289
  void *pPage;
sl@0
  1290
  int aResult[11];
sl@0
  1291
  char zElem[100];
sl@0
  1292
  Tcl_DString str;
sl@0
  1293
sl@0
  1294
  if( argc!=3 ){
sl@0
  1295
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
sl@0
  1296
                    " BTREE CURSOR", 0);
sl@0
  1297
    return TCL_ERROR;
sl@0
  1298
  }
sl@0
  1299
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
  1300
  pCur = sqlite3TestTextToPtr(argv[2]);
sl@0
  1301
  if( (*(void**)pCur) != (void*)pBt ){
sl@0
  1302
    Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
sl@0
  1303
       argv[1], 0);
sl@0
  1304
    return TCL_ERROR;
sl@0
  1305
  }
sl@0
  1306
  sqlite3BtreeEnter(pBt);
sl@0
  1307
  pPager = sqlite3BtreePager(pBt);
sl@0
  1308
  rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
sl@0
  1309
  if( rc ){
sl@0
  1310
    Tcl_AppendResult(interp, errorName(rc), 0);
sl@0
  1311
    sqlite3BtreeLeave(pBt);
sl@0
  1312
    return TCL_ERROR;
sl@0
  1313
  }
sl@0
  1314
  dataSize = pBt->pBt->usableSize;
sl@0
  1315
  Tcl_DStringInit(&str);
sl@0
  1316
  n = aResult[6] - aResult[8];
sl@0
  1317
  n = (n + dataSize - 1)/dataSize;
sl@0
  1318
  pgno = (u32)aResult[10];
sl@0
  1319
  while( pgno && n-- ){
sl@0
  1320
    DbPage *pDbPage;
sl@0
  1321
    sprintf(zElem, "%d", pgno);
sl@0
  1322
    Tcl_DStringAppendElement(&str, zElem);
sl@0
  1323
    if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
sl@0
  1324
      Tcl_DStringFree(&str);
sl@0
  1325
      Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
sl@0
  1326
      sqlite3BtreeLeave(pBt);
sl@0
  1327
      return TCL_ERROR;
sl@0
  1328
    }
sl@0
  1329
    pPage = sqlite3PagerGetData(pDbPage);
sl@0
  1330
    pgno = t4Get4byte((unsigned char*)pPage);
sl@0
  1331
    sqlite3PagerUnref(pDbPage);
sl@0
  1332
  }
sl@0
  1333
  sqlite3BtreeLeave(pBt);
sl@0
  1334
  Tcl_DStringResult(interp, &str);
sl@0
  1335
  return SQLITE_OK;
sl@0
  1336
}
sl@0
  1337
sl@0
  1338
/*
sl@0
  1339
** The command is provided for the purpose of setting breakpoints.
sl@0
  1340
** in regression test scripts.
sl@0
  1341
**
sl@0
  1342
** By setting a GDB breakpoint on this procedure and executing the
sl@0
  1343
** btree_breakpoint command in a test script, we can stop GDB at
sl@0
  1344
** the point in the script where the btree_breakpoint command is
sl@0
  1345
** inserted.  This is useful for debugging.
sl@0
  1346
*/
sl@0
  1347
static int btree_breakpoint(
sl@0
  1348
  void *NotUsed,
sl@0
  1349
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1350
  int argc,              /* Number of arguments */
sl@0
  1351
  const char **argv      /* Text of each argument */
sl@0
  1352
){
sl@0
  1353
  return TCL_OK;
sl@0
  1354
}
sl@0
  1355
sl@0
  1356
/*
sl@0
  1357
** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
sl@0
  1358
**
sl@0
  1359
** This command tests the putVarint() and getVarint()
sl@0
  1360
** routines, both for accuracy and for speed.
sl@0
  1361
**
sl@0
  1362
** An integer is written using putVarint() and read back with
sl@0
  1363
** getVarint() and varified to be unchanged.  This repeats COUNT
sl@0
  1364
** times.  The first integer is START*MULTIPLIER.  Each iteration
sl@0
  1365
** increases the integer by INCREMENT.
sl@0
  1366
**
sl@0
  1367
** This command returns nothing if it works.  It returns an error message
sl@0
  1368
** if something goes wrong.
sl@0
  1369
*/
sl@0
  1370
static int btree_varint_test(
sl@0
  1371
  void *NotUsed,
sl@0
  1372
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1373
  int argc,              /* Number of arguments */
sl@0
  1374
  const char **argv      /* Text of each argument */
sl@0
  1375
){
sl@0
  1376
  u32 start, mult, count, incr;
sl@0
  1377
  u64 in, out;
sl@0
  1378
  int n1, n2, i, j;
sl@0
  1379
  unsigned char zBuf[100];
sl@0
  1380
  if( argc!=5 ){
sl@0
  1381
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1382
       " START MULTIPLIER COUNT INCREMENT\"", 0);
sl@0
  1383
    return TCL_ERROR;
sl@0
  1384
  }
sl@0
  1385
  if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
sl@0
  1386
  if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
sl@0
  1387
  if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
sl@0
  1388
  if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
sl@0
  1389
  in = start;
sl@0
  1390
  in *= mult;
sl@0
  1391
  for(i=0; i<count; i++){
sl@0
  1392
    char zErr[200];
sl@0
  1393
    n1 = putVarint(zBuf, in);
sl@0
  1394
    if( n1>9 || n1<1 ){
sl@0
  1395
      sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
sl@0
  1396
      Tcl_AppendResult(interp, zErr, 0);
sl@0
  1397
      return TCL_ERROR;
sl@0
  1398
    }
sl@0
  1399
    n2 = getVarint(zBuf, &out);
sl@0
  1400
    if( n1!=n2 ){
sl@0
  1401
      sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
sl@0
  1402
      Tcl_AppendResult(interp, zErr, 0);
sl@0
  1403
      return TCL_ERROR;
sl@0
  1404
    }
sl@0
  1405
    if( in!=out ){
sl@0
  1406
      sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
sl@0
  1407
      Tcl_AppendResult(interp, zErr, 0);
sl@0
  1408
      return TCL_ERROR;
sl@0
  1409
    }
sl@0
  1410
    if( (in & 0xffffffff)==in ){
sl@0
  1411
      u32 out32;
sl@0
  1412
      n2 = getVarint32(zBuf, out32);
sl@0
  1413
      out = out32;
sl@0
  1414
      if( n1!=n2 ){
sl@0
  1415
        sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d", 
sl@0
  1416
                  n1, n2);
sl@0
  1417
        Tcl_AppendResult(interp, zErr, 0);
sl@0
  1418
        return TCL_ERROR;
sl@0
  1419
      }
sl@0
  1420
      if( in!=out ){
sl@0
  1421
        sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
sl@0
  1422
            in, out);
sl@0
  1423
        Tcl_AppendResult(interp, zErr, 0);
sl@0
  1424
        return TCL_ERROR;
sl@0
  1425
      }
sl@0
  1426
    }
sl@0
  1427
sl@0
  1428
    /* In order to get realistic timings, run getVarint 19 more times.
sl@0
  1429
    ** This is because getVarint is called about 20 times more often
sl@0
  1430
    ** than putVarint.
sl@0
  1431
    */
sl@0
  1432
    for(j=0; j<19; j++){
sl@0
  1433
      getVarint(zBuf, &out);
sl@0
  1434
    }
sl@0
  1435
    in += incr;
sl@0
  1436
  }
sl@0
  1437
  return TCL_OK;
sl@0
  1438
}
sl@0
  1439
sl@0
  1440
/*
sl@0
  1441
** usage:   btree_from_db  DB-HANDLE
sl@0
  1442
**
sl@0
  1443
** This command returns the btree handle for the main database associated
sl@0
  1444
** with the database-handle passed as the argument. Example usage:
sl@0
  1445
**
sl@0
  1446
** sqlite3 db test.db
sl@0
  1447
** set bt [btree_from_db db]
sl@0
  1448
*/
sl@0
  1449
static int btree_from_db(
sl@0
  1450
  void *NotUsed,
sl@0
  1451
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1452
  int argc,              /* Number of arguments */
sl@0
  1453
  const char **argv      /* Text of each argument */
sl@0
  1454
){
sl@0
  1455
  char zBuf[100];
sl@0
  1456
  Tcl_CmdInfo info;
sl@0
  1457
  sqlite3 *db;
sl@0
  1458
  Btree *pBt;
sl@0
  1459
  int iDb = 0;
sl@0
  1460
sl@0
  1461
  if( argc!=2 && argc!=3 ){
sl@0
  1462
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1463
       " DB-HANDLE ?N?\"", 0);
sl@0
  1464
    return TCL_ERROR;
sl@0
  1465
  }
sl@0
  1466
sl@0
  1467
  if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
sl@0
  1468
    Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
sl@0
  1469
    return TCL_ERROR;
sl@0
  1470
  }
sl@0
  1471
  if( argc==3 ){
sl@0
  1472
    iDb = atoi(argv[2]);
sl@0
  1473
  }
sl@0
  1474
sl@0
  1475
  db = *((sqlite3 **)info.objClientData);
sl@0
  1476
  assert( db );
sl@0
  1477
sl@0
  1478
  pBt = db->aDb[iDb].pBt;
sl@0
  1479
  sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
sl@0
  1480
  Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
sl@0
  1481
  return TCL_OK;
sl@0
  1482
}
sl@0
  1483
sl@0
  1484
sl@0
  1485
/*
sl@0
  1486
** usage:   btree_set_cache_size ID NCACHE
sl@0
  1487
**
sl@0
  1488
** Set the size of the cache used by btree $ID.
sl@0
  1489
*/
sl@0
  1490
static int btree_set_cache_size(
sl@0
  1491
  void *NotUsed,
sl@0
  1492
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1493
  int argc,              /* Number of arguments */
sl@0
  1494
  const char **argv      /* Text of each argument */
sl@0
  1495
){
sl@0
  1496
  int nCache;
sl@0
  1497
  Btree *pBt;
sl@0
  1498
sl@0
  1499
  if( argc!=3 ){
sl@0
  1500
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1501
       " BT NCACHE\"", 0);
sl@0
  1502
    return TCL_ERROR;
sl@0
  1503
  }
sl@0
  1504
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
  1505
  if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
sl@0
  1506
sl@0
  1507
  sqlite3_mutex_enter(pBt->db->mutex);
sl@0
  1508
  sqlite3BtreeEnter(pBt);
sl@0
  1509
  sqlite3BtreeSetCacheSize(pBt, nCache);
sl@0
  1510
  sqlite3BtreeLeave(pBt);
sl@0
  1511
  sqlite3_mutex_leave(pBt->db->mutex);
sl@0
  1512
sl@0
  1513
  return TCL_OK;
sl@0
  1514
}
sl@0
  1515
sl@0
  1516
/*
sl@0
  1517
** Usage:   btree_ismemdb ID
sl@0
  1518
**
sl@0
  1519
** Return true if the B-Tree is in-memory.
sl@0
  1520
*/
sl@0
  1521
static int btree_ismemdb(
sl@0
  1522
  void *NotUsed,
sl@0
  1523
  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
sl@0
  1524
  int argc,              /* Number of arguments */
sl@0
  1525
  const char **argv      /* Text of each argument */
sl@0
  1526
){
sl@0
  1527
  Btree *pBt;
sl@0
  1528
  int res;
sl@0
  1529
sl@0
  1530
  if( argc!=2 ){
sl@0
  1531
    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
sl@0
  1532
       " ID\"", 0);
sl@0
  1533
    return TCL_ERROR;
sl@0
  1534
  }
sl@0
  1535
  pBt = sqlite3TestTextToPtr(argv[1]);
sl@0
  1536
  sqlite3_mutex_enter(pBt->db->mutex);
sl@0
  1537
  sqlite3BtreeEnter(pBt);
sl@0
  1538
  res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
sl@0
  1539
  sqlite3BtreeLeave(pBt);
sl@0
  1540
  sqlite3_mutex_leave(pBt->db->mutex);
sl@0
  1541
  Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
sl@0
  1542
  return SQLITE_OK;
sl@0
  1543
}
sl@0
  1544
sl@0
  1545
sl@0
  1546
/*
sl@0
  1547
** Register commands with the TCL interpreter.
sl@0
  1548
*/
sl@0
  1549
int Sqlitetest3_Init(Tcl_Interp *interp){
sl@0
  1550
  static struct {
sl@0
  1551
     char *zName;
sl@0
  1552
     Tcl_CmdProc *xProc;
sl@0
  1553
  } aCmd[] = {
sl@0
  1554
     { "btree_open",               (Tcl_CmdProc*)btree_open               },
sl@0
  1555
     { "btree_close",              (Tcl_CmdProc*)btree_close              },
sl@0
  1556
     { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
sl@0
  1557
     { "btree_commit",             (Tcl_CmdProc*)btree_commit             },
sl@0
  1558
     { "btree_rollback",           (Tcl_CmdProc*)btree_rollback           },
sl@0
  1559
     { "btree_create_table",       (Tcl_CmdProc*)btree_create_table       },
sl@0
  1560
     { "btree_drop_table",         (Tcl_CmdProc*)btree_drop_table         },
sl@0
  1561
     { "btree_clear_table",        (Tcl_CmdProc*)btree_clear_table        },
sl@0
  1562
     { "btree_get_meta",           (Tcl_CmdProc*)btree_get_meta           },
sl@0
  1563
     { "btree_update_meta",        (Tcl_CmdProc*)btree_update_meta        },
sl@0
  1564
     { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
sl@0
  1565
     { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
sl@0
  1566
     { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
sl@0
  1567
     { "btree_move_to",            (Tcl_CmdProc*)btree_move_to            },
sl@0
  1568
     { "btree_delete",             (Tcl_CmdProc*)btree_delete             },
sl@0
  1569
     { "btree_next",               (Tcl_CmdProc*)btree_next               },
sl@0
  1570
     { "btree_prev",               (Tcl_CmdProc*)btree_prev               },
sl@0
  1571
     { "btree_eof",                (Tcl_CmdProc*)btree_eof                },
sl@0
  1572
     { "btree_keysize",            (Tcl_CmdProc*)btree_keysize            },
sl@0
  1573
     { "btree_key",                (Tcl_CmdProc*)btree_key                },
sl@0
  1574
     { "btree_data",               (Tcl_CmdProc*)btree_data               },
sl@0
  1575
     { "btree_fetch_key",          (Tcl_CmdProc*)btree_fetch_key          },
sl@0
  1576
     { "btree_fetch_data",         (Tcl_CmdProc*)btree_fetch_data         },
sl@0
  1577
     { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
sl@0
  1578
     { "btree_first",              (Tcl_CmdProc*)btree_first              },
sl@0
  1579
     { "btree_last",               (Tcl_CmdProc*)btree_last               },
sl@0
  1580
     { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
sl@0
  1581
     { "btree_breakpoint",         (Tcl_CmdProc*)btree_breakpoint         },
sl@0
  1582
     { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
sl@0
  1583
     { "btree_begin_statement",    (Tcl_CmdProc*)btree_begin_statement    },
sl@0
  1584
     { "btree_commit_statement",   (Tcl_CmdProc*)btree_commit_statement   },
sl@0
  1585
     { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
sl@0
  1586
     { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },
sl@0
  1587
     { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     },
sl@0
  1588
     { "btree_cursor_info",        (Tcl_CmdProc*)btree_cursor_info        },
sl@0
  1589
     { "btree_ovfl_info",          (Tcl_CmdProc*)btree_ovfl_info          },
sl@0
  1590
     { "btree_cursor_list",        (Tcl_CmdProc*)btree_cursor_list        },
sl@0
  1591
     { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            },
sl@0
  1592
  };
sl@0
  1593
  int i;
sl@0
  1594
sl@0
  1595
  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
sl@0
  1596
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
sl@0
  1597
  }
sl@0
  1598
sl@0
  1599
  /* The btree_insert command is implemented using the tcl 'object'
sl@0
  1600
  ** interface, not the string interface like the other commands in this
sl@0
  1601
  ** file. This is so binary data can be inserted into btree tables.
sl@0
  1602
  */
sl@0
  1603
  Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
sl@0
  1604
  return TCL_OK;
sl@0
  1605
}