/ Check-in [6adb6078]
Login

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

Overview
Comment:Perpare to fork SQLite2.0 develop into a separate tree (CVS 183)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:6adb6078871114ba19ab601bb94d43ff9e03e43f
User & Date: drh 2001-02-11 16:56:24
Context
2001-02-11
16:58
Perpare to fork SQLite2.0 develop into a separate tree (CVS 184) check-in: 4f00e27f user: drh tags: trunk
16:56
Perpare to fork SQLite2.0 develop into a separate tree (CVS 183) check-in: 6adb6078 user: drh tags: trunk
2001-02-06
14:10
hi (CVS 1716) check-in: 5128135c user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to VERSION.

1
1.1.0
|
1
1.0.20

Deleted src/db.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: db.c,v 1.6 2001/01/31 13:28:08 drh Exp $
*/
#include "sqliteInt.h"
#include "pg.h"

/*
** Everything we need to know about an open database
*/
struct Db {
  Pgr *pPgr;            /* The pager for the database */
  DbCursor *pCursor;    /* All open cursors */
  int inTransaction;    /* True if a transaction is in progress */
  u32 freeList;         /* List of free blocks */
  int nTable;           /* Number of slots in aContent[] */
  u32 *aTable;          /* Root page numbers for all tables */
};

/*
** The maximum depth of a cursor
*/
#define MX_LEVEL 10

/*
** Within a cursor, each level off the search tree is an instance of
** this structure.
*/
typedef struct DbIdxpt DbIdxpt;
struct DbIdxpt {
  int pgno;         /* The page number */
  u32 *aPage;       /* The page data */
  int idx;          /* Index into pPage[] */
};

/*
** Everything we need to know about a cursor
*/
struct DbCursor {
  Db *pDb;                      /* The whole database */
  DbCursor *pPrev, *pNext;      /* Linked list of all cursors */
  u32 rootPgno;                 /* Root page of table for this cursor */
  int onEntry;                  /* True if pointing to a table entry */
  int nLevel;                   /* Number of levels of indexing used */
  DbIdxpt aLevel[MX_LEVEL];     /* The index levels */
};

/*
** Data layouts
**
** LEAF:
**    x[0]          Magic number: BLOCK_LEAF
**    x[1]          If root page, total number of entries in this table
**    ...           One or more entries follow the leaf.
**
** Entry:
**    x[N+0]        Number of u32-sized words in this entry
**    x[N+1]        Hash value for this entry
**    x[N+2]        Number of bytes of key in the payload
**    x[N+3]        Number of bytes of data in the payload
**    x{N+4]...     The payload area.
**
** INDEX:
**    x[0]          Magic number: BLOCK_INDEX
**    x[1]          If root page: total number of entries in this table
**    x[2]          Number of slots in this index (Max value of N)
**    x[2*N+3]      Page number containing entries with hash <= x[2*N+4]
**    x[2*N+4]      The maximum hash value for entries on page x[2*N+3].
**
** FREE:
**    x[0]          Magic number: BLOCK_FREE
**    x[1]          Page number of the next free block on the free list
**
** PAGE1:
**    x[0]          Magic number: BLOCK_PAGE1
**    x[1]          First page of the freelist
**    x[2]          Number of tables in this database
**    x[N+3]        Root page for table N

/*
** The first word of every page is some combination of these values
** used to indicate its function.
*/
#define BLOCK_PAGE1            0x24e47191
#define BLOCK_INDEX            0x7ac53b46
#define BLOCK_LEAF             0x60c45eef
#define BLOCK_FREE             0x5b2dda47

/*
** The number of u32-sized objects that will fit on one page.
*/
#define U32_PER_PAGE  (SQLITE_PAGE_SIZE/sizeof(u32))

/*
** Number of direct overflow pages per database entry
*/
#define N_DIRECT  10

/*
** The maximum amount of payload (in bytes) that will fit on on the same
** page as a leaf.  In other words, the maximum amount of payload
** that does not require any overflow pages.
**
** This size is chosen so that a least 3 entry will fit on every 
** leaf.  That guarantees it will always be possible to add a new
** entry after a page split.
*/
#define LOCAL_PAYLOAD (((U32_PER_PAGE-2)/3 - (6+N_DIRECT))*sizeof(u32))

/*
** Allocate a new page.  Return both the page number and a pointer
** to the page data.  The calling function is responsible for unref-ing
** the page when it is no longer needed.
**
** The page is obtained from the freelist if there is anything there.
** If the freelist is empty, the new page comes from the end of the
** database file.
*/
int allocPage(Db *pDb, u32 *pPgno, u32 **ppPage){
  u32 pgno;
  int rc;

  if( pDb->aTable==0 ) return SQLITE_NOMEM;

  /* Try to reuse a page from the freelist
  */
  if( pDb->freeList==0 ){
    u32 *pPage;
    rc = sqlitePgGet(pDb->pPgr, pDb->freeList, &pPage);
    if( rc==SQLITE_OK ){
      if( pPage[0]==BLOCK_FREE ){
        *pPgno = pDb->freeList;
        *ppPage = aPage;
        pDb->freeList = aPage[1];
        memset(*ppPage, 0, SQLITE_PAGE_SIZE);
        return SQLITE_OK;
      }
      /* This only happens if we have database corruption */
      sqlitePgUnref(pPage);
    }
  }

  /* If the freelist is empty, or we cannot access it,
  ** then allocate a new page from the end of the file.
  */
  if( (rc = sqlitePgCount(pDb->pPgr, &pgno))==SQLITE_OK &&
      (rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage))==SQLITE_OK ){
    *pPgno = pgno;
    memset(*ppPage, 0, SQLITE_PAGE_SIZE);
    return SQLITE_OK;
  }
  return rc;
}

/*
** Return a page to the freelist and dereference the page.
*/
static void freePage(DB *pDb, u32 pgno, u32 *aPage){
  if( pgno==0 ) return
  if( aPage==0 ){
    int rc;
    rc = sqlitePgGet(pDb->pPgr, pgno, &aPage);
    if( rc!=SQLITE_OK ) return;
  }
  assert( sqlitePgNum(aPage)==pgno );
  aPage[0] = BLOCK_FREE;
  aPage[1] = pDb->freeList;
  pDb->freeList = pgno;
  memset(&aPage[2], 0, SQLITE_PAGE_SIZE - 2*sizeof(u32));
  sqlitePgTouch(aPage);
  sqlitePgUnref(aPage);
}

/*
** Return the number of bytes of payload storage required on the leaf
** node to hold the amount of payload specified by the argument.
** Overflow pages do not count, only memory on the leaf page.
**
** Return -1 if nTotal is more than sqlite is able to store.
*/
static int payloadLocalSize(int nTotal){
  int nLocal, i;
  if( nTotal<0 ) nTotal = 0;
  if( nTotal <= LOCAL_PAYLOAD ){
    /* All the data fits on the leaf page */
    return (nTotal + 3)/4;
  }
  nLocal = LOCAL_PAYLOAD;
  nTotal -= LOCAL_PAYLOAD;
  if( nTotal < 10*SQLITE_PAGE_SIZE ){
    return nLocal + ((nTotal+SQLITE_PAGE_SIZE-1)/SQLITE_PAGE_SIZE)*sizeof(u32);
  }
  nLocal += N_DIRECT*sizeof(u32);
  nTotal -= N_DIRECT*SQLITE_PAGE_SIZE;
  if( nTotal < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    return nLocal + sizeof(u32);
  }
  nLocal += sizeof(u32);
  nTotal -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
  if( nTotal < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    return nLocal + sizeof(u32);
  }
  return -1;  /* This payload will not fit. */
}

/*
** Read data from the payload area.
**
** aPage points directly at the beginning of the payload.  No bounds 
** checking is done on offset or amt -- it is assumed that the payload
** area is big enough to accomodate.
*/
static int payloadRead(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
  int rc;
  int tomove;
  int i;

  /* First read local data off of the leaf page itself.
  ** This is all that ever happens in 99% of accesses.
  */
  assert( offset>=0 && amt>=0 );
  if( offset < LOCAL_PAYLOAD ){
    /* Data stored directly in the leaf block of the BTree */
    if( amt+offset>LOCAL_PAYLOAD ){
      tomove = LOCAL_PAYLOAD - offset;
    }else{
      tomove = amt;
    }
    memcpy(pBuf, &((char*)aPage)[offset], tomove);
    pBuf = &((char*)pBuf)[tomove];
    offset += tomove;
    amt -= tomove;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= LOCAL_PAYLOAD;
  aPage += LOCAL_PAYLOAD/sizeof(aPage[0]);

  /* If not all of the data fits locally, read from the first
  ** ten direct-access overflow pages.
  */
  if( offset < N_DIRECT*SQLITE_PAGE_SIZE ){
    for(i=offset/SQLITE_PAGE_SIZE; i<N_DIRECT && amt>0; i++){
      char *aData;
      base = offset - i*SQLITE_PAGE_SIZE;
      rc = sqlitePgGet(pDb->pPgr, aPage[i], &aData);
      if( rc!=SQLITE_OK ) return rc;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(pBuf, &aData[base], tomove);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
  }
  offset -= N_DIRECT*SQLITE_PAGE_SIZE;
  aPage += N_DIRECT;

  /* If the first N_DIRECT overflow pages do not contain everything, then
  ** read from an overflow page that is filled with pointer to
  ** U32_PER_PAGE more overflow pages.
  */
  if( offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *indirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
    if( rc!=SQLITE_OK ) return rc;
    for(i=offset/SQLITE_PAGE_SIZE; i<U32_PER_PAGE && amt>0; i++){
      int base;
      char *aData;
      base = offset - i*SQLITE_PAGE_SIZE;
      rc = sqlitePgGet(pDb->pPgr, indirPage[idx], &aData);
      if( rc!=SQLITE_OK ) break;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(pBuf, &aData[base], tomove);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
    sqlitePgUnref(indirPage);
    if( rc!=SQLITE_OK ) return rc;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
  aPage++;

  /* If there is still more data, then read using a double-indirect
  ** overflow.  The overflow page points to U32_PER_PAGE additional
  ** overflow pages, each of which pointer to U32_PER_PAGE more overflow
  ** pages which contain data.
  **
  ** This is hard to test.  To exercise this code, you have to make
  ** a database entry of more than 273336 bytes in side, assuming a
  ** pagesize of 1024 bytes and 10 direct overflow pages.  By the 
  ** time this code runs, you have already used 267 overflow pages.
  */
  if( offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *dblIndirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
    if( rc!=SQLITE_OK ) return rc;
    i = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
    for(; i<U32_PER_PAGE && amt>0; i++){
      u32 *indirPage;
      int basis;
      int j;
      rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
      if( rc!=SQLITE_OK ) break;
      basis = i*U32_PER_PAGE*SQLITE_PAGE_SIZE;
      j = (offset - basis)/SQLITE_PAGE_SIZE;
      for(; j<U32_PER_PAGE && amt>0; j++){
        char *aData;
        base = (offset - basis) - ij*SQLITE_PAGE_SIZE;
        rc = sqlitePgGet(pDb->pPgr, indirPage[j], &aData);
        if( rc!=SQLITE_OK ) break;
        if( amt+base > SQLITE_PAGE_SIZE ){
          tomove = SQLITE_PAGE_SIZE - base;
        }else{
          tomove = amt;
        }
        memcpy(pBuf, &aData[base], tomove);
        sqlitePgUnref(aData);
        pBuf = &((char*)pBuf)[tomove];
        amt -= tomove;
      }
      sqlitePgUnref(indirPage);
      if( rc!=SQLITE_OK ) break;
    }
    sqlitePgUnref(dblIndirPage);
  }

  /* Anything beyond the double-indirect pages, just fill in with
  ** zeros.  You have to write 67382200 bytes to go past the
  ** double-indirect pages, assuming a 1024 byte page size.
  */
  if( amt>0 ) memset(pBuf, 0, amt);
  return SQLITE_OK;
}

/*
** Write data into the payload area.
**
** If pages have already been allocated for the payload, they are
** simply overwritten.  New pages are allocated as necessary to
** fill in gaps.  sqlitePgTouch() is called on all overflow pages,
** but the calling function must invoke sqlitePgTouch() for aPage
** itself.
*/
static int payloadWrite(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
  assert( offset>=0 && amt>=0 );

  /* Local data
  */
  if( offset < LOCAL_PAYLOAD ){
    if( amt+offset>LOCAL_PAYLOAD ){
      tomove = LOCAL_PAYLOAD - offset;
    }else{
      tomove = amt;
    }
    memcpy(&((char*)aPage)[offset], pBuf, tomove);
    pBuf = &((char*)pBuf)[tomove];
    offset += tomove;
    amt -= tomove;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= LOCAL_PAYLOAD;
  aPage += LOCAL_PAYLOAD/sizeof(aPage[0]);

  /* Direct overflow pages
  */
  if( offset < N_DIRECT*SQLITE_PAGE_SIZE ){
    for(i=offset/SQLITE_PAGE_SIZE; i<N_DIRECT && amt>0; i++){
      base = offset - i*SQLITE_PAGE_SIZE;
      if( aPage[i] ){
        rc = sqlitePgGet(pDb->pPgr, aPage[i], &aData);
      }else{
        rc = allocPage(pDb, &aPage[i], &aData);
      }
      if( rc!=SQLITE_OK ) return rc;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(&aData[base], pBuf, tomove);
      sqlitePgTouch(aData);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= N_DIRECT*SQLITE_PAGE_SIZE;
  aPage += N_DIRECT;

  /* Indirect overflow pages
  */
  if( offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *indirPage;
    if( aPage[0] ){
      rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
    }else{
      rc = allocPage(pDb, &aPage[0], &indirPage);
    }
    if( rc!=SQLITE_OK ) return rc;
    for(i=offset/SQLITE_PAGE_SIZE; i<U32_PER_PAGE && amt>0; i++){
      int base;
      char *aData;
      base = offset - i*SQLITE_PAGE_SIZE;
      if( indirPage[i] ){
        rc = sqlitePgGet(pDb->pPgr, indirPage[i], &aData);
      }else{
        rc = allocPage(pDb, &indirPage[i], &aData);
        sqlitePgTouch(indirPage);
      }
      if( rc!=SQLITE_OK ) break;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(&aData[base], pBuf, tomove);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
    sqlitePgUnref(indirPage);
    if( rc!=SQLITE_OK ) return rc;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
  aPage++;

  /* Double-indirect overflow pages
  */
  if( offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *dblIndirPage;
    if( aPage[0] ){
      rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
    }else{
      rc = allocPage(pDb, &aPage[0], &dblIndirPage);
    }
    if( rc!=SQLITE_OK ) return rc;
    i = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
    for(; i<U32_PER_PAGE && amt>0; i++){
      u32 *indirPage;
      int basis;
      int j;
      if( aPage[0] ){
        rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
      }else{
        rc = allocPage(pDb, &aPage[0], &dblIndirPage);
        sqlitePgTouch(dblIndirPage);
      }
      rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
      if( rc!=SQLITE_OK ) break;
      basis = i*U32_PER_PAGE*SQLITE_PAGE_SIZE;
      j = (offset - basis)/SQLITE_PAGE_SIZE;
      for(; j<U32_PER_PAGE && amt>0; j++){
        char *aData;
        base = (offset - basis) - ij*SQLITE_PAGE_SIZE;
        if( indirPage[j] ){
          rc = sqlitePgGet(pDb->pPgr, indirPage[j], &aData);
        }else{
          rc = allocPage(pDb, &indirPage[j], &aData);
          sqlitePgTouch(indirPage);
        }
        if( rc!=SQLITE_OK ) break;
        if( amt+base > SQLITE_PAGE_SIZE ){
          tomove = SQLITE_PAGE_SIZE - base;
        }else{
          tomove = amt;
        }
        memcpy(&aData[base], pBuf, tomove);
        sqlitePgTouch(aData);
        sqlitePgUnref(aData);
        pBuf = &((char*)pBuf)[tomove];
        amt -= tomove;
      }
      sqlitePgUnref(indirPage);
      if( rc!=SQLITE_OK ) break;
    }
    sqlitePgUnref(dblIndirPage);
  }

  return SQLITE_OK;
}

/*
** Resize the payload area.  If the payload area descreases in size,
** this routine deallocates unused overflow pages.  If the payload
** area increases in size, this routine is a no-op.
*/
static int payloadResize(Db *pDb, u32 *aPage, int oldSize, int newSize){
  int i, j;          /* Loop counters */
  int first, last;   /* Indices of first and last pages to be freed */
  int rc;            /* Return code from sqlitePgGet() */

  /* Skip over the local data.  We do not need to free it.
  */
  if( newSize>=oldSize ) return SQLITE_OK;
  oldSize -= LOCAL_PAYLOAD;
  if( oldSize<=0 ) return SQLITE_OK;
  newSize -= LOCAL_PAYLOAD;
  aPage += LOCAL_PAYLOAD/sizeof(u32);

  /* Compute the indices of the first and last overflow pages to
  ** be freed.
  */
  first = (newSize - 1)/SQLITE_PAGE_SIZE + 1;
  last = (oldSize - 1)/SQLITE_PAGE_SIZE;

  /* Free the direct overflow pages
  */
  if( first < N_DIRECT ){
    for(i=first; i<N_DIRECT && i<=last; i++){
      freePage(pDb, aPage[i], 0);
      aPage[i] = 0;
    }
  }
  aPage += N_DIRECT;
  first -= N_DIRECT;
  last -= N_DIRECT;
  if( last<0 ) return SQLITE_OK;
  if( first<0 ) first = 0;
  
  /* Free indirect overflow pages
  */
  if( first < U32_PER_PAGE ){
    u32 *indirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
    if( rc!=SQLITE_OK ) return rc;
    for(i=first; i<U32_PER_PAGE && i<=last; i++){
      freePage(pDb, indirPage[i], 0);
      indirPage[i] = 0;
      touch = 1;
    }
    if( first<=0 ){
      freepage(pDb, aPage[0], indirPage);
      aPage[0] = 0;
    }else{
      sqlitePgTouch(indirPage);
      sqlitePgUnref(indirPage);
    }
  }
  aPage++;
  first -= U32_PER_PAGE;
  last -= U32_PER_PAGE;
  if( last<0 ) return SQLITE_OK;
  if( first<0 ) first = 0;

  /* Free double-indirect overflow pages
  */
  if( first < U32_PER_PAGE*U32_PER_PAGE ){
    u32 *dblIndirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
    if( rc!=SQLITE_OK ) return rc;
    for(i=first/U32_PER_PAGE; i<U32_PER_PAGE; i++){
      u32 *indirPage;
      basis = i*U32_PER_PAGE;
      if( last < basis ) break;
      rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
      if( rc!=SQLITE_OK ) return rc;
      for(j=first>basis?first-basis:0 ; j<U32_PER_PAGE; j++){
        if( j + basis > last ) break;
        freePage(pDb, indirPage[j], 0);
        indirPage[j] = 0;
      }
      if( first<=basis ){
        freepage(pDb, dblIndirPage[i], 0);
        dblIndirPage[i] = 0;
      }else{
        sqlitePgTouch(indirPage);
        sqlitePgUnref(indirPage);
      }
    }
    if( first<=0 ){
      freepage(pDb, aPage[0], dblIndirPage);
      aPage[0] = 0;
    }else{
      sqlitePgTouch(dblIndirPage);
      sqlitePgUnref(dblIndirPage);
    }
  }

  return SQLITE_OK;    
}

/*
** Allocate space for the content table in the given Db structure.
** return SQLITE_OK on success and SQLITE_NOMEM if it fails.
*/
static int sqliteDbExpandTableArray(Db *pDb){
  pDb->aTable = sqliteRealloc( pDb->aTable, pDb->nTable*sizeof(u32));
  if( pDb->aTable==0 ){
    pDb->inTranaction = 0;
    return SQLITE_NOMEM;
  }
  return SQLITE_OK;
}

/*
** Open a database.
*/
int sqliteDbOpen(const char *filename, Db **ppDb){
  Db *pDb = 0;
  Pgr *pPgr = 0;
  u32 *aPage1;
  int rc;
  u32 nPage;

  rc = sqlitePgOpen(filename, &pPgr);
  if( rc!=SQLITE_OK ) goto open_err;
  pDb = sqliteMalloc( sizeof(*pDb) );
  if( pDb==0 ){
    rc = SQLITE_NOMEM;
    goto open_err;
  }
  pDb->pPgr = pPgr;
  pDb->pCursor = 0;
  pDb->inTransaction = 0;
  sqlitePgCount(pDb->pPgr, &nPage);
  rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
  if( rc!=0 ) goto open_err;
  if( nPage==0 ){
    sqlitePgBeginTransaction(pDb->pPgr);
    aPage1[0] = BLOCK_PAGE1;
    sqlitePgTouch(aPage1);
    sqlitePgCommit(pDb->pPgr);
  }
  pDb->freeList = aPage[1];
  pDb->nTable = aPage[2];
  rc = sqliteDbExpandTableArray(pDb);
  if( rc!=SQLITE_OK ) goto open_err;
  rc = payloadRead(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
  sqlitePgUnref(aPage1);
  if( rc!=SQLITE_OK ) goto open_err;
  *ppDb = pDb;
  return SQLITE_OK;

open_err:
  *ppDb = 0;
  if( pPgr ) sqlitePgClose(pPgr);
  if( pDb ){
    sqliteFree(pDb->aContent);
    sqliteFree(pDb);
  }
  return rc;
}

/*
** Close a database
*/
int sqliteDbClose(Db *pDb){
  while( pDb->pCursor ){
    sqliteDbCursorClose(pDb->pCursor);
  }
  sqlitePgClose(pDb->pPgr);
  sqliteFree(pDb->aContent);
  sqliteFree(pDb);
  return SQLITE_OK;
}

/*
** Begin a transaction
*/
int sqliteDbBeginTransaction(Db *pDb){
  int rc;
  if( pDb->aContent==0 ){
    return SQLITE_NOMEM;
  }
  if( pDb->inTransaction ){
    return SQLITE_INTERNAL;
  }
  rc = sqlitePgBeginTransaction(pDb->pPgr);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  pDb->inTransaction = 1;
  return SQLITE_OK;
}

/*
** Commit changes to the database
*/ 
int sqliteDbCommit(Db *pDb){
  u32 *aPage1;
  int rc;
  if( !pDb->inTransaction ){
    return SQLITE_OK;
  }
  rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
  if( rc!=SQLITE_OK ) return rc;
  aPage1[1] = pDb->freeList;
  aPage1[2] = pDb->nTable;
  payloadWrite(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
  sqlitePgUnref(aPage1);
  rc = sqlitePgCommit(pDb->pPgr);
  if( rc!=SQLITE_OK ) return rc;
  pDb->inTransaction = 0;
  return SQLITE_OK;
}

/*
** Rollback the database to its state prior to the beginning of
** the transaction
*/
int sqliteDbRollback(Db *pDb){
  u32 *aPage1;
  if( !pDb->inTransaction ) return SQLITE_OK;
  rc = sqlitePgRollback(pDb->pPgr);
  if( rc!=SQLITE_OK ) return rc;
  rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
  if( rc!=SQLITE_OK ) return rc;
  pDb->freeList = aPage1[1];
  pDb->nTable = aPage1[2];
  if( sqliteDbExpandTableArray(pDb)!=SQLITE_OK ){
    return SQLITE_NOMEM;
  }
  payloadRead(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
  sqlitePgUnref(aPage1);
  pDb->inTransaction = 0;
  return SQLITE_OK;
}

/*
** Create a new table in the database.  Write the table number
** that is used to open a cursor into that table into *pTblno.
*/
int sqliteDbCreateTable(Db *pDb, int *pTblno){
  u32 *aPage;
  u32 pgno;
  int rc;
  int swTblno;
  int i;

  rc = allocPage(pDb, &pgno, &aPage);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  tblno = -1;
  for(i=0; i<pDb->nTable; i++){
    if( pDb->aTable[i]==0 ){
      tblno = i;
      break;
    }
  }
  if( tblno<0 ){
    pDb->nTable++;
    rc = sqliteExpandTableArray(pDb);
    if( rc!=SQLITE_OK ){
      return rc;
    }
  }
  pDb->aTable[tblno] = pgno;
  aPage[0] = BLOCK_LEAF;
  memset(&aPage[1], 0, SQLITE_PAGE_SIZE - sizeof(u32));
  sqlitePgTouch(aPage);
  sqlitePgUnref(aPage);
  return rc;
}

/*
** Recursively add a page to the free list
*/
static int sqliteDbDropPage(Db *pDb, u32 pgno){
  u32 *aPage;
  int rc;

  rc = sqlitePgGet(pDb->pPgr, pgno, (void**)&aPage);
  if( rc!=SQLITE_OK ) return rc;
  switch(  aPage[0] ){
    case BLOCK_INDEX: {
      int n, i;
      n = aPage[2];
      for(i=0; i<n; i++){
        u32 subpgno = aPage[3 + i*2];
        if( subpgno>0 ) sqliteDbDropPage(pDb, subpgno);
      }
      freePage(pDb, pgno, aPage);
      break;
    }
    case BLOCK_LEAF: {
      int i = 2;
      while( i<U32_PER_PAGE ){
        int entrySize = aPage[i];
        if( entrySize==0 ) break;
        payloadResize(pDb, &aPage[i+4], aPage[i+2]+aPage[i+3], 0);
        i += entrySize;
      }
      freePage(pDb, pgno, aPage);
      break;
    }
    default: {
      /* Do nothing */
      break;
    }
  }
}

/*
** Delete the current associate of a cursor and release all the
** pages it holds.  Except, do not release pages at levels less
** than N.
*/
static void sqliteDbResetCursor(DbCursor *pCur, int N){
  int i;
  for(i=pCur->nLevel-1; i>=N; i--){
    sqlitePgUnref(pCur->aLevel[i].aPage);
  }
  pCur->nLevel = N;
  pCur->onEntry = 0;
}

/*
** Delete an entire table.
*/
static int sqliteDbDropTable(Db *pDb, int tblno){
  DbCursor *pCur;
  u32 pgno;

  /* Find the root page for the table to be dropped.
  */
  if( pDb->aTable==0 ){
    return SQLITE_NOMEM;
  }
  if( tblno<0 || tblno>=pDb->nTable || pDb->aTable[tblno]==0 ){
    return SQLITE_NOTFOUND;
  }
  pgno = pDb->aTable[tblno];
  pDb->aTable[tblno] = 0;
  if( tblno==pDb->nTable-1 ){
    pDb->nTable--;
  }

  /* Reset any cursors pointing to the table that is about to
  ** be dropped */
  for(pCur=pDb->pCursor; pCur; pCur=pCur->pNext){
    if( pCur->rootPgno==pgno ){
      sqliteDbResetCursor(pCur, 0);
    }
  }

  /* Move all pages associated with this table to the freelist
  */
  sqliteDbDropPage(pDb, pgno);
  return SQLITE_OK;
}

/*
** Create a new cursor
*/
int sqliteDbCursorOpen(Db *pDb, int tblno, DbCursor **ppCur){
  u32 pgno;
  DbCursor *pCur;

  /* Translate the table number into a page number
  */
  if( pDb->aTable==0 ){
    *ppCur = 0;
    return SQLITE_NOMEM;
  }
  if( tblno<0 || tblno>=pDb->nContent || pDb->aTable[tblno]==0 ){
    *ppCur = 0;
    return SQLITE_NOTFOUND;
  }
  pgno = pDb->aTable[tblno];
  
  /* Allocate the cursor
  */
  pCur = sqliteMalloc( sizeof(*pCur) );
  pCur->pgno = pgno;
  pCur->pDb = pDb;
  pCur->pNext = pDb->pCursor;
  pCur->pPrev = 0;
  if( pDb->pCursor ){
     pDb->pCursor->pPrev = pCur;
  }
  pDb->pCursor = pCur;
  *ppCur = pCur;
  return SQLITE_OK;
}

/*
** Delete a cursor
*/
int sqliteDbCursorClose(DbCursor *pCur){
  int i;
  if( pCur->pPrev ){
    pCur->pPrev->pNext = pCur->pNext;
  }else if( pCur->pDb->pCursor==pCur ){
    pCur->pDb->pCursor = pCur->pNext;
  }
  if( pCur->pNext ){
    pCur->pNext->pPrev = pCur->pPrev;
  }
  sqliteDbResetCursor(pCur, 0);
  sqliteFree(pCur);
  return SQLITE_OK; 
}

/*
** Beginning at index level "i" (the outer most index is 0), move down 
** to the first entry of the table.  Levels above i (less than i) are 
** unchanged.
*/
static int sqliteDbGotoFirst(DbCursor *pCur, int i){
  int rc = -1;

  assert( i>=0 && i<MAX_LEVEL );
  if( pCur->nLevel > i+1 ){
    sqliteDbResetCursor(pCur, i+1);
  }
  assert( pCur->nLevel==i+1 );
  while( rc < 0 ){
    u32 *aPage = pCur->aLevel[i].aPage;
    assert( aPage!=0 );
    switch( aPage[0] ){
      case BLOCK_LEAF: {
        if( aPage[2]!=0 ){
          pCur->aLevel[i].idx = 2;
          pCur->onEntry = 1;
        }else{
          sqliteDbResetCursor(pCur, 1);
        }
        rc = SQLITE_OK;
        break;
      }
      case BLOCK_INDEX: {
        int n = aPage[2];
        if( n<2 || n>=((U32_PER_PAGE - 3)/2) ){
          sqliteDbResetCur(pCur, 1);
          rc = SQLITE_CORRUPT;
          break;
        }
        pCur->nLevel++;
        i++;
        pCur->aLevel[i].pgno = aPage[3];
        rc = sqlitePgGet(pCur->pDb->pPgr, pCur->aLevel[i].pgno,
                    &pCur->aLevel[i].aPage);
        if( rc != SQLITE_OK ){
          sqliteDbResetCursor(pCur, 1);
        }else{
          rc = -1;
        }
        break;
      }
      default: {
        sqliteDbResetCursor(pCur, 1);
        rc = SQLITE_CORRUPT;
      }
    }
  }
  return rc;
}

################

/*
** Move the cursor to the first entry in the table.
*/
int sqliteDbCursorFirst(DbCursor *pCur){
  if( pCur->nLevel==0 ){
    int rc;
    pCur->aLevel[0].pgno = pCur->rootPgno;
    rc = sqlitePgGet(pCur->pDb->pPgr, pCur->rootPgno, pCur->aLevel[0].aPage);
    if( rc!=SQLITE_OK ){
      sqliteDbResetCursor(pCur, 0);
      return rc;
    }
    pCur->nLevel = 1;
  }
  return sqliteDbGotoFirst(pCur, 0);
}

/*
** Advance the cursor to the next entry in the table.
*/
int sqliteDbCursorNext(DbCursor *pCur){
  int i, idx, n, rc;
  u32 pgno, *aPage;
  if( !pCur->onEntry ){
     return sqliteDbCursorFirst(pCur);
  }
  i = pCur->nLevel-1;
  aPage = pCur->aLevel[i].aPage;
  idx = pCur->aLevel[i].idx;
  idx += SWB(aPage[idx]);
  if( idx >= SQLITE_PAGE_SIZE/sizeof(u32) ){
    sqliteDbResetCursor(pCur, 1);
    return SQLITE_CORRUPT;
  }
  if( aPage[idx]!=0 ){
    pCur->aLabel[i].idx = idx;
    return SQLITE_OK;
  }
  rc = SQLITE_OK;
  while( pCur->nLevel>1 ){
    pCur->nLevel--;
    i = pCur->nLevel-1;
    sqlitePgUnref(pCur->aLevel[pCur->nLevel].aPage);
    aPage = pCur->aLevel[i].aPage;
    idx = pCur->aLevel[i].idx;
    assert( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_INDEX );
    n = SWB(aPage[2]);
    idx += 2;
    if( (idx-3)/2 < n ){
      pCur->aLevel[i].idx = idx;
      pCur->nLevel++;
      i++;
      pgno = pCur->aLevel[i].pgno = SWB(aPage[idx+1]);
      rc = sqlitePgGet(pDb->pPgr, pgno, &pCur->aLevel[i].aPage);
      if( rc!=SQLITE_OK ) break;
      rc = sqliteDbGotoFirst(pCur, i);
      break;
    }
  }
  sqliteDbResetCursor(pCur, 0);
  return SQLITE_OK;
}

/*
** Return the amount of data on the entry that the cursor points
** to.
*/
int sqliteDbCursorDatasize(DbCursor *pCur){
  u32 *aPage;
  int idx, i;
  if( !pCur->onEntry ) return 0;
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<U32_PER_PAGE );
  return aPage[idx+3];
}

/*
** Return the number of bytes of key on the entry that the cursor points
** to.
*/
int sqliteDbCursorKeysize(DbCursor *pCur){
  u32 *aPage;
  int idx, i;
  if( !pCur->onEntry ) return 0;
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<U32_PER_PAGE );
  return aPage[idx+2];
}

/*
** Read data from the cursor.
*/
int sqliteDbCursorRead(DbCursor *pCur, int amt, int offset, void *buf){
  u32 *aPage;
  int idx, i;
  int nData;
  int nKey;
  if( !pCur->onEntry ){
    memset(cbuf, 0, amt);
    return SQLITE_OK;
  }
  if( amt<=0 || offset<0 ){
    return SQLITE_ERR;
  }
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<U32_PER_PAGE );
  nData = aPage[idx+3];
  if( offset>=nData ){
    memset(buf, 0, amt);
    return SQLITE_OK;
  }
  nKey = aPage[idx+2];
  if( nData<offset+amt ){
    memset(&((char*)buf)[nData-offset], 0, amt+offset-nData);
    amt = nData - offset;
  }
  payloadRead(pCur->pDb, &aPage[idx+4], amt, offset + nKey, buf);
  return SQLITE_OK;
}

/*
** Read the current key from the cursor.
*/
int sqliteDbCursorReadKey(DbCursor *pCur, int amt, int offset, void *buf){
  u32 *aPage;
  int idx, i;
  int nData;
  int nKey;
  if( !pCur->onEntry ){
    memset(cbuf, 0, amt);
    return SQLITE_OK;
  }
  if( amt<=0 || offset<0 ){
    return SQLITE_ERR;
  }
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<(SQLITE_PAGE_SIZE/sizeof(u32))
  nKey = aPage[idx+2];
  if( offset>=nKey ){
    memset(buf, 0, amt);
    return SQLITE_OK;
  }
  if( nKey<offset+amt ){
    memset(&((char*)buf)[nKey-offset], 0, amt+offset-nKey);
    amt = nKey - offset;
  }
  payloadRead(pCur->pDb, &aPage[idx+4], amt, offset, buf);
  return SQLITE_OK;
}

/*
** Generate a 32-bit hash from the given key.
*/
static u32 sqliteDbHash(int nKey, void *pKey){
  u32 h;
  unsigned char *key;
  if( nKey==4 ){
    return *(u32*)pKey;
  }
  key = pKey;
  h = 0;
  while( 0 < nKey-- ){
    h = (h<<13) ^ (h<<3) ^ h ^ *(key++)
  }
  return h;
}

/*
** Move the cursor so that the lowest level is the leaf page that
** contains (or might contain) the given key.
*/
static int sqliteDbFindLeaf(DbCursor *pCur, int nKey, void *pKey, u32 h;){
  int i, j, rc;
  u32 h;

  h = sqliteDbHash(nKey, pKey);
  sqliteDbResetCursor(pCur, 1);
  i = 0;
  for(;;){
    u32 nxPgno;
    u32 *aPage = pCur->aLevel[i].aPage;
    if( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_LEAF ) break;
    if( SWB(aPage[0])!=BLOCK_MAGIC|BLOCK_INDEX ){
      return SQLITE_CORRUPT;
    }
    if( i==MAX_LEVEL-1 ){
      return SQLITE_FULL;
    }
    n = SWB(aPage[2]);
    if( n<2 || n>=(SQLITE_PAGE_SIZE/2*sizeof(u32))-2 ){
      return SQLITE_CORRUPT;
    }
    for(j=0; j<n-1; j++){
      if( h < SWB(aPage[j*2+3]) ) break;
    }
    nxPgno = SWB(aPage[j*2+4]);
    pCur->aLevel[i].idx = j;
    pCur->aLevel[i].pgno = nxPgno;
    rc = sqlitePgGet(pCur->pDb->pPgr, nxPgno, &pCur->aLevel[i].aPage);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    pCur->nLevel++;
    i++;
  }
  return SQLITE_OK;
}

/*
** Position the cursor on the entry that matches the given key.
*/
int sqliteDbCursorMoveTo(DbCursor *pCur, int nKey, void *pKey){
  int rc, i;
  u32 *aPage;
  int idx;
  u32 h;

  h = sqliteDbHash(nKey, pKey);
  rc = sqliteDbFindLeaf(pCur, nKey, pKey, h);
  if( rc!=SQLITE_OK ) return rc;
  i = pCur->nLevel-1;
  aPage = pCur->aLevel[i].aPage;
  idx = 2;
  rc = SQLITE_NOTFOUND;
  while( idx>=2 && idx<(SQLITE_PAGE_SIZE/sizeof(u32))-3 && aPage[idx]!=0 ){
    if( sqliteDbKeyMatch(&aPage[idx], nKey, pKey, h) ){
      pCur->aLevel[i].idx = idx;
      pCur->onEntry = 1;
      rc = SQLITE_OK;
      break;
    }
    idx += SWB(aPage[idx]);
  }
  return rc;
}

/*
** Insert a new entry into the table.  The cursor is left pointing at
** the new entry.
*/
int sqliteDbCursorInsert(   
   DbCursor *pCur,          /* A cursor on the table in which to insert */
   int nKey, void *pKey,    /* The insertion key */
   int nData, void *pData   /* The data to be inserted */
){
  int minNeeded, maxNeeded;    /* In u32-sized objects */
  int rc;
  u32 h;
  int available;
  int i, j, k;
  int nKeyU, nDataU;
  u32 *aPage;
  int incr = 1;

  /* Null data is the same as a delete.
  */
  if( nData<=0 || pData==0 ){
    if( sqliteDbCursorMoveTo(pCur, nKey, pKey);
      return sqliteDbCursorDelete(pCur);
    }else{
      return SQLITE_OK;
    }
  }

  /* Figure out how much free space is needed on a leaf block in order
  ** to hold the new record.
  */
  minNeeded = maxNeeded = 6;
  nKeyU = (nKey+3)/4;
  nDataU = (nData+3)/4;
  if( nKeyU + maxNeeded + 2 <= SQLITE_PAGE_SIZE/sizeof(u32) ){
    maxNeeded += nKeyU;
  }
  if( nKeyU < SQLITE_PAGE_SIZE/(3*sizeof(u32)) ){
    minNeeded += nKeyU;
  }
  if( nDataU + maxNeeded + 2 <= SQLITE_PAGE_SIZE/sizeof(u32) ){
    maxNeeded += nDataU
  }
  if( nDataU < SQLITE_PAGE_SIZE/(3*sizeof(u32)) ){
    minNeeded += nDataU;
  }

  /* Move the cursor to the leaf block where the new record will be
  ** inserted.
  */
  h = sqliteDbHash(nKey, pKey);
  rc = sqliteDbFindLeaf(pCur, nKey, pKey, h);
  if( rc!=SQLITE_OK ) return rc;

  /* Walk thru the leaf once and do two things:
  **   1.  Remove any prior entry with the same key.
  **   2.  Figure out how much space is available on this leaf.
  */
  i = j = 2;
  aPage = pCur->aLevel[pCur->nLevel-1].aPage;
  for(;;){
    int entrySize = SWB(aPage[i]);
    if( entrySize<=0 || entrySize + i >= SQLITE_PAGE_SIZE/sizeof(u32) ) break;
    if( !sqliteDbKeyMatch(&aPage[i], nKey, pKey, h) ){
      if( j<i ){
        for(k=0; k<entrySize; k++){
           aPage[j+k] = aPage[i+k];
        }
      }
      j += entrySize;
    }else{
      sqliteDbClearEntry(pCur->pDb, &aPage[i]);
      incr--;
    }
    i += entrySize;
  }
  available = SQLITE_PAGE_SIZE/sizeof(u32) - j;

  /* If the new entry will not fit, try to move some of the entries
  ** from this leaf onto sibling leaves.
  */
  if( available<minNeeded ){
    int newSpace;
    newSpace = sqliteDbSpreadLoad(pCur, maxNeeded); ############
    available += newSpace;
  }

  /* If the new entry still will not fit, try to split this leaf into
  ** two adjacent leaves.
  */
  if( available<minNeeded && pCur->nLevel>1 ){
    int newAvail;
    newAvail = sqliteDbSplit(pCur, maxNeeded); ##############
    if( newAvail>0 ){
      available += newAvail;
    }
  }

  /* If the new entry does not fit after splitting, turn this leaf into
  ** and index node with one leaf, go down into the new leaf and try 
  ** to split again.
  */
  if( available<minNeeded && pCur->nLevel<MAX_LEVEL-1 ){
    int newAvail;
    sqliteDbNewIndexLevel(pCur);  ###############
    newAvail = sqliteDbSplit(pCur, maxNeeded);
    if( newAvail>0 ){
      available = newAvail;
    }
  }

  /* If the entry still will not fit, it means the database is full.
  */
  if( available<minNeeded ){
    return SQLITE_FULL;
  }

  /* Add the new entry to the leaf block.
  */
  aPage = pCur->aLevel[pCur->nLevel-1].aPage;
  i = 2;
  for(;;){
    int entrySize = SWB(aPage[i]);
    if( entrySize<=0 || entrySize + i >= SQLITE_PAGE_SIZE/sizeof(u32) ) break;
    i += entrySize;
  }
  assert( available==SQLITE_PAGE_SIZE/sizeof(u32) - i );
  aPage[i+1] = SWB(h);
  available -= 5;
  if( nKeyU <= available ){
    aPage[i+2] = SWB(nKey);
    memcpy(&aPage[i+4], pKey, nKey);
    j = i + 4 + nKeyU;
    available -= nKeyU;
  }else{
    u32 newPgno, *newPage;
    aPage[i+2] = SWB(nKey | 0x80000000);
    rc = allocPage(pCur->pDb, &newPgno, &newPage);
    if( rc!=SQLITE_OK ) goto write_err;
    aPage[i+4] = SWB(newPgno);
    newPage[0] = SWB(BLOCK_MAGIC | BLOCK_OVERFLOW);
    rc = sqliteDbWriteOvfl(pCur->pDb, newPage, nKey, pKey);
    if( rc!=SQLITE_OK ) goto write_err;
    j = i + 5;
    available -= 1;
  }
  if( nDataU <= available ){
    aPage[i+3] = SWB(nData);
    memcpy(&aPage[j], pData, nData);
    available -= nDataU;
    j += nDataU;
  }else{
    u32 newPgno, *newPage;
    aPage[i+3] = SWB(nData | 0x80000000);
    rc = allocPage(pCur->pDb, &newPgno, &newPage);
    if( rc!=SQLITE_OK ) goto write_err;
    aPage[j] = SWB(newPgno);
    newPage[0] = SWB(BLOCK_MAGIC | BLOCK_OVERFLOW);
    rc = sqliteDbWriteOvfl(pCur->pDb, newPage, nData, pData);
    if( rc!=SQLITE_OK ) goto write_err;
    available -= 1;
    j++;
  }    
  if( j<SQLITE_PAGE_SIZE/sizeof(u32) ){
    aPage[j] = 0;
  }
  sqlitePgTouch(aPage);
  pCur->aLevel[pCur->nLevel-1].idx = i;
  pCur->onEntry = 1;

  /*  Increment the entry count for this table.
  */
  if( incr!=0 ){
    pCur->aLevel[0].aPage[1] = SWB(SWB(pCur->aLevel[0].aPage[1])+incr);
    sqlitePgTouch(pCur->aLevel[0].aPage);
  }
  return SQLITE_OK;

write_err:
  aPage[i] = 0;
  pCur->onEntry = 0;
  return rc;
}

/*
** Delete the entry that the cursor points to.
*/
int sqliteDbCursorDelete(DbCursor *pCur){
  int i, idx;
  int from, to, limit, n;
  int entrySize;
  u32 *aPage;
  if( !pCur->onEntry ) return SQLITE_NOTFOUND;

  /* Delete the entry that the cursor is pointing to.
  */
  i = pCur->nLevel - 1;
  aPage = pCur->aLevel[i].aPage;
  idx = pCur->aLevel[i].idx;
  assert( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_LEAF );
  assert( idx>=2 && idx<SQLITE_PAGE_SIZE/sizeof(u32)-4 );
  entrySize = SWB(aPage[idx]);
  assert( entrySize>=6 && idx+entrySize<=SQLITE_PAGE_SIZE/sizeof(u32) );
  sqliteDbClearEntry(pCur->pDb, &aPage[idx]);
  to = idx;
  from = idx + entrySize;
  while( from<SQLITE_PAGE_SIZE/sizeof(u32) ){
    int k;
    entrySize = SWB(aPage[from]);
    if( entrySize<=0 ) break;
    for(k=0; k<entrySize; k++){
      aPage[to++] = aPage[from++]
    }
  }
  aPage[to] = 0;

  /*  Decrement the entry count for this table.
  */
  pCur->aLevel[0].aPage[1] = SWB(SWB(pCur->aLevel[0].aPage[1])-1);
  sqlitePgTouch(pCur->aLevel[0].aPage);

  /* If there are more entries on this leaf or this leaf is the root
  ** of the table,  then we are done.
  */
  if( to>2 || pCur->nLevel==1 ) return SQLITE_OK;

  /* Collapse the tree into a more compact form.
  */
  sqliteDbResetCursor(pCur, pCur->nLevel-1);

  i = pCur->nLevel-1;
  assert( i>=0 && i<MAX_LEVEL );
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_INDEX );
  assert( idx>=3 && idx<SQLITE_PAGE_SIZE/sizeof(u32) );
  n = SWB(aPage[2]);
  assert( n>=2 && n<=SQLITE_PAGE_SIZE/2*sizeof(u32)-2 );
  sqliteDbDropPage(pCur->pDb, SWB(aPage[idx+1]);
  to = idx;
  from = idx+2;
  limit = n*2 + 3;
  while( from<limit ){
    aPage[to++] = aPage[from++];
  }
  n--;
  if( n==1 ){
    u32 oldPgno, *oldPage;
    oldPgno = SWB(aPage[4]);
    rc = sqlitePgGet(pCur->pDb->pPgr, oldPgno, &oldPage);
    if( rc!=SQLITE_OK ){
      return rc;  /* Do something smarter here */
    }
    memcpy(aPage, oldPage, SQLITE_PAGE_SIZE);
    oldPage[0] = SWB(BLOCK_MAGIC|BLOCK_OVERFLOW);
    oldPage[1] = 0;
    sqliteDbDropPage(pCur->pDb, oldPgno);
    sqlitePgUnref(oldPage);
  }else{
    aPage[2] = SWB(n);
  }
  sqlitePgTouch(aPage);
  return SQLITE_OK;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<














































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/db.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: db.h,v 1.5 2001/01/31 13:28:09 drh Exp $
*/

typedef struct Db Db;
typedef struct DbCursor DbCursor;

int sqliteDbOpen(const char *filename, Db**);
int sqliteDbClose(Db*);
int sqliteDbBeginTransaction(Db*);
int sqliteDbCommit(Db*);
int sqliteDbRollback(Db*);

int sqliteDbCreateTable(Db*, int *pTblno);
int sqliteDbDropTable(Db*, int tblno);

int sqliteDbCursorOpen(Db*, int tblno, DbCursor**);
int sqliteDbCursorClose(DbCursor*);

int sqliteDbCursorFirst(DbCursor*);
int sqliteDbCursorNext(DbCursor*);
int sqliteDbCursorDatasize(DbCursor*);
int sqliteDbCursorKeysize(DbCursor*);
int sqliteDbCursorRead(DbCursor*, int amt, int offset, void *buf);
int sqliteDbCursorReadKey(DbCursor*, int amt, int offset, void *buf);
int sqliteDbCursorWrite(DbCursor*, int amt, int offset, const void *buf);

int sqliteDbCursorFind(DbCursor*, int nKey, const void *pKey, int createFlag);
int sqliteDbCursorResize(DbCursor*, int nData);
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<






































































































Added src/ex/README.



















>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
This directory is intended to hold "experimental" files.

The code in this directory does not necessary work.  It may
or may not be added to future SQLite releases.  We just need
a place to put ideas and works-in-progress and so this 
directory was created.

If you are interested in the production versions of SQLite,
you can safely ignore this directory.

Added src/ex/db.c.















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: db.c,v 1.1 2001/02/11 16:56:24 drh Exp $
*/
#include "sqliteInt.h"
#include "pg.h"

/*
** Everything we need to know about an open database
*/
struct Db {
  Pgr *pPgr;            /* The pager for the database */
  DbCursor *pCursor;    /* All open cursors */
  int inTransaction;    /* True if a transaction is in progress */
  u32 freeList;         /* List of free blocks */
  int nTable;           /* Number of slots in aContent[] */
  u32 *aTable;          /* Root page numbers for all tables */
};

/*
** The maximum depth of a cursor
*/
#define MX_LEVEL 10

/*
** Within a cursor, each level off the search tree is an instance of
** this structure.
*/
typedef struct DbIdxpt DbIdxpt;
struct DbIdxpt {
  int pgno;         /* The page number */
  u32 *aPage;       /* The page data */
  int idx;          /* Index into pPage[] */
};

/*
** Everything we need to know about a cursor
*/
struct DbCursor {
  Db *pDb;                      /* The whole database */
  DbCursor *pPrev, *pNext;      /* Linked list of all cursors */
  u32 rootPgno;                 /* Root page of table for this cursor */
  int onEntry;                  /* True if pointing to a table entry */
  int nLevel;                   /* Number of levels of indexing used */
  DbIdxpt aLevel[MX_LEVEL];     /* The index levels */
};

/*
** Data layouts
**
** LEAF:
**    x[0]          Magic number: BLOCK_LEAF
**    x[1]          If root page, total number of entries in this table
**    ...           One or more entries follow the leaf.
**
** Entry:
**    x[N+0]        Number of u32-sized words in this entry
**    x[N+1]        Hash value for this entry
**    x[N+2]        Number of bytes of key in the payload
**    x[N+3]        Number of bytes of data in the payload
**    x{N+4]...     The payload area.
**
** INDEX:
**    x[0]          Magic number: BLOCK_INDEX
**    x[1]          If root page: total number of entries in this table
**    x[2]          Number of slots in this index (Max value of N)
**    x[2*N+3]      Page number containing entries with hash <= x[2*N+4]
**    x[2*N+4]      The maximum hash value for entries on page x[2*N+3].
**
** FREE:
**    x[0]          Magic number: BLOCK_FREE
**    x[1]          Page number of the next free block on the free list
**
** PAGE1:
**    x[0]          Magic number: BLOCK_PAGE1
**    x[1]          First page of the freelist
**    x[2]          Number of tables in this database
**    x[N+3]        Root page for table N

/*
** The first word of every page is some combination of these values
** used to indicate its function.
*/
#define BLOCK_PAGE1            0x24e47191
#define BLOCK_INDEX            0x7ac53b46
#define BLOCK_LEAF             0x60c45eef
#define BLOCK_FREE             0x5b2dda47

/*
** The number of u32-sized objects that will fit on one page.
*/
#define U32_PER_PAGE  (SQLITE_PAGE_SIZE/sizeof(u32))

/*
** Number of direct overflow pages per database entry
*/
#define N_DIRECT  10

/*
** The maximum amount of payload (in bytes) that will fit on on the same
** page as a leaf.  In other words, the maximum amount of payload
** that does not require any overflow pages.
**
** This size is chosen so that a least 3 entry will fit on every 
** leaf.  That guarantees it will always be possible to add a new
** entry after a page split.
*/
#define LOCAL_PAYLOAD (((U32_PER_PAGE-2)/3 - (6+N_DIRECT))*sizeof(u32))

/*
** Allocate a new page.  Return both the page number and a pointer
** to the page data.  The calling function is responsible for unref-ing
** the page when it is no longer needed.
**
** The page is obtained from the freelist if there is anything there.
** If the freelist is empty, the new page comes from the end of the
** database file.
*/
int allocPage(Db *pDb, u32 *pPgno, u32 **ppPage){
  u32 pgno;
  int rc;

  if( pDb->aTable==0 ) return SQLITE_NOMEM;

  /* Try to reuse a page from the freelist
  */
  if( pDb->freeList==0 ){
    u32 *pPage;
    rc = sqlitePgGet(pDb->pPgr, pDb->freeList, &pPage);
    if( rc==SQLITE_OK ){
      if( pPage[0]==BLOCK_FREE ){
        *pPgno = pDb->freeList;
        *ppPage = aPage;
        pDb->freeList = aPage[1];
        memset(*ppPage, 0, SQLITE_PAGE_SIZE);
        return SQLITE_OK;
      }
      /* This only happens if we have database corruption */
      sqlitePgUnref(pPage);
    }
  }

  /* If the freelist is empty, or we cannot access it,
  ** then allocate a new page from the end of the file.
  */
  if( (rc = sqlitePgCount(pDb->pPgr, &pgno))==SQLITE_OK &&
      (rc = sqlitePgGet(pDb->pPgr, pgno, (void**)ppPage))==SQLITE_OK ){
    *pPgno = pgno;
    memset(*ppPage, 0, SQLITE_PAGE_SIZE);
    return SQLITE_OK;
  }
  return rc;
}

/*
** Return a page to the freelist and dereference the page.
*/
static void freePage(DB *pDb, u32 pgno, u32 *aPage){
  if( pgno==0 ) return
  if( aPage==0 ){
    int rc;
    rc = sqlitePgGet(pDb->pPgr, pgno, &aPage);
    if( rc!=SQLITE_OK ) return;
  }
  assert( sqlitePgNum(aPage)==pgno );
  aPage[0] = BLOCK_FREE;
  aPage[1] = pDb->freeList;
  pDb->freeList = pgno;
  memset(&aPage[2], 0, SQLITE_PAGE_SIZE - 2*sizeof(u32));
  sqlitePgTouch(aPage);
  sqlitePgUnref(aPage);
}

/*
** Return the number of bytes of payload storage required on the leaf
** node to hold the amount of payload specified by the argument.
** Overflow pages do not count, only memory on the leaf page.
**
** Return -1 if nTotal is more than sqlite is able to store.
*/
static int payloadLocalSize(int nTotal){
  int nLocal, i;
  if( nTotal<0 ) nTotal = 0;
  if( nTotal <= LOCAL_PAYLOAD ){
    /* All the data fits on the leaf page */
    return (nTotal + 3)/4;
  }
  nLocal = LOCAL_PAYLOAD;
  nTotal -= LOCAL_PAYLOAD;
  if( nTotal < 10*SQLITE_PAGE_SIZE ){
    return nLocal + ((nTotal+SQLITE_PAGE_SIZE-1)/SQLITE_PAGE_SIZE)*sizeof(u32);
  }
  nLocal += N_DIRECT*sizeof(u32);
  nTotal -= N_DIRECT*SQLITE_PAGE_SIZE;
  if( nTotal < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    return nLocal + sizeof(u32);
  }
  nLocal += sizeof(u32);
  nTotal -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
  if( nTotal < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    return nLocal + sizeof(u32);
  }
  return -1;  /* This payload will not fit. */
}

/*
** Read data from the payload area.
**
** aPage points directly at the beginning of the payload.  No bounds 
** checking is done on offset or amt -- it is assumed that the payload
** area is big enough to accomodate.
*/
static int payloadRead(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
  int rc;
  int tomove;
  int i;

  /* First read local data off of the leaf page itself.
  ** This is all that ever happens in 99% of accesses.
  */
  assert( offset>=0 && amt>=0 );
  if( offset < LOCAL_PAYLOAD ){
    /* Data stored directly in the leaf block of the BTree */
    if( amt+offset>LOCAL_PAYLOAD ){
      tomove = LOCAL_PAYLOAD - offset;
    }else{
      tomove = amt;
    }
    memcpy(pBuf, &((char*)aPage)[offset], tomove);
    pBuf = &((char*)pBuf)[tomove];
    offset += tomove;
    amt -= tomove;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= LOCAL_PAYLOAD;
  aPage += LOCAL_PAYLOAD/sizeof(aPage[0]);

  /* If not all of the data fits locally, read from the first
  ** ten direct-access overflow pages.
  */
  if( offset < N_DIRECT*SQLITE_PAGE_SIZE ){
    for(i=offset/SQLITE_PAGE_SIZE; i<N_DIRECT && amt>0; i++){
      char *aData;
      base = offset - i*SQLITE_PAGE_SIZE;
      rc = sqlitePgGet(pDb->pPgr, aPage[i], &aData);
      if( rc!=SQLITE_OK ) return rc;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(pBuf, &aData[base], tomove);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
  }
  offset -= N_DIRECT*SQLITE_PAGE_SIZE;
  aPage += N_DIRECT;

  /* If the first N_DIRECT overflow pages do not contain everything, then
  ** read from an overflow page that is filled with pointer to
  ** U32_PER_PAGE more overflow pages.
  */
  if( offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *indirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
    if( rc!=SQLITE_OK ) return rc;
    for(i=offset/SQLITE_PAGE_SIZE; i<U32_PER_PAGE && amt>0; i++){
      int base;
      char *aData;
      base = offset - i*SQLITE_PAGE_SIZE;
      rc = sqlitePgGet(pDb->pPgr, indirPage[idx], &aData);
      if( rc!=SQLITE_OK ) break;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(pBuf, &aData[base], tomove);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
    sqlitePgUnref(indirPage);
    if( rc!=SQLITE_OK ) return rc;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
  aPage++;

  /* If there is still more data, then read using a double-indirect
  ** overflow.  The overflow page points to U32_PER_PAGE additional
  ** overflow pages, each of which pointer to U32_PER_PAGE more overflow
  ** pages which contain data.
  **
  ** This is hard to test.  To exercise this code, you have to make
  ** a database entry of more than 273336 bytes in side, assuming a
  ** pagesize of 1024 bytes and 10 direct overflow pages.  By the 
  ** time this code runs, you have already used 267 overflow pages.
  */
  if( offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *dblIndirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
    if( rc!=SQLITE_OK ) return rc;
    i = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
    for(; i<U32_PER_PAGE && amt>0; i++){
      u32 *indirPage;
      int basis;
      int j;
      rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
      if( rc!=SQLITE_OK ) break;
      basis = i*U32_PER_PAGE*SQLITE_PAGE_SIZE;
      j = (offset - basis)/SQLITE_PAGE_SIZE;
      for(; j<U32_PER_PAGE && amt>0; j++){
        char *aData;
        base = (offset - basis) - ij*SQLITE_PAGE_SIZE;
        rc = sqlitePgGet(pDb->pPgr, indirPage[j], &aData);
        if( rc!=SQLITE_OK ) break;
        if( amt+base > SQLITE_PAGE_SIZE ){
          tomove = SQLITE_PAGE_SIZE - base;
        }else{
          tomove = amt;
        }
        memcpy(pBuf, &aData[base], tomove);
        sqlitePgUnref(aData);
        pBuf = &((char*)pBuf)[tomove];
        amt -= tomove;
      }
      sqlitePgUnref(indirPage);
      if( rc!=SQLITE_OK ) break;
    }
    sqlitePgUnref(dblIndirPage);
  }

  /* Anything beyond the double-indirect pages, just fill in with
  ** zeros.  You have to write 67382200 bytes to go past the
  ** double-indirect pages, assuming a 1024 byte page size.
  */
  if( amt>0 ) memset(pBuf, 0, amt);
  return SQLITE_OK;
}

/*
** Write data into the payload area.
**
** If pages have already been allocated for the payload, they are
** simply overwritten.  New pages are allocated as necessary to
** fill in gaps.  sqlitePgTouch() is called on all overflow pages,
** but the calling function must invoke sqlitePgTouch() for aPage
** itself.
*/
static int payloadWrite(Db *pDb, u32 *aPage, int offset, int amt, void *pBuf){
  assert( offset>=0 && amt>=0 );

  /* Local data
  */
  if( offset < LOCAL_PAYLOAD ){
    if( amt+offset>LOCAL_PAYLOAD ){
      tomove = LOCAL_PAYLOAD - offset;
    }else{
      tomove = amt;
    }
    memcpy(&((char*)aPage)[offset], pBuf, tomove);
    pBuf = &((char*)pBuf)[tomove];
    offset += tomove;
    amt -= tomove;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= LOCAL_PAYLOAD;
  aPage += LOCAL_PAYLOAD/sizeof(aPage[0]);

  /* Direct overflow pages
  */
  if( offset < N_DIRECT*SQLITE_PAGE_SIZE ){
    for(i=offset/SQLITE_PAGE_SIZE; i<N_DIRECT && amt>0; i++){
      base = offset - i*SQLITE_PAGE_SIZE;
      if( aPage[i] ){
        rc = sqlitePgGet(pDb->pPgr, aPage[i], &aData);
      }else{
        rc = allocPage(pDb, &aPage[i], &aData);
      }
      if( rc!=SQLITE_OK ) return rc;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(&aData[base], pBuf, tomove);
      sqlitePgTouch(aData);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= N_DIRECT*SQLITE_PAGE_SIZE;
  aPage += N_DIRECT;

  /* Indirect overflow pages
  */
  if( offset < U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *indirPage;
    if( aPage[0] ){
      rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
    }else{
      rc = allocPage(pDb, &aPage[0], &indirPage);
    }
    if( rc!=SQLITE_OK ) return rc;
    for(i=offset/SQLITE_PAGE_SIZE; i<U32_PER_PAGE && amt>0; i++){
      int base;
      char *aData;
      base = offset - i*SQLITE_PAGE_SIZE;
      if( indirPage[i] ){
        rc = sqlitePgGet(pDb->pPgr, indirPage[i], &aData);
      }else{
        rc = allocPage(pDb, &indirPage[i], &aData);
        sqlitePgTouch(indirPage);
      }
      if( rc!=SQLITE_OK ) break;
      if( amt+base > SQLITE_PAGE_SIZE ){
        tomove = SQLITE_PAGE_SIZE - base;
      }else{
        tomove = amt;
      }
      memcpy(&aData[base], pBuf, tomove);
      sqlitePgUnref(aData);
      pBuf = &((char*)pBuf)[tomove];
      amt -= tomove;
    }
    sqlitePgUnref(indirPage);
    if( rc!=SQLITE_OK ) return rc;
    if( amt<=0 ) return SQLITE_OK;
  }
  offset -= U32_PER_PAGE*SQLITE_PAGE_SIZE;
  aPage++;

  /* Double-indirect overflow pages
  */
  if( offset < U32_PER_PAGE*U32_PER_PAGE*SQLITE_PAGE_SIZE ){
    u32 *dblIndirPage;
    if( aPage[0] ){
      rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
    }else{
      rc = allocPage(pDb, &aPage[0], &dblIndirPage);
    }
    if( rc!=SQLITE_OK ) return rc;
    i = offset/(U32_PER_PAGE*SQLITE_PAGE_SIZE);
    for(; i<U32_PER_PAGE && amt>0; i++){
      u32 *indirPage;
      int basis;
      int j;
      if( aPage[0] ){
        rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
      }else{
        rc = allocPage(pDb, &aPage[0], &dblIndirPage);
        sqlitePgTouch(dblIndirPage);
      }
      rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
      if( rc!=SQLITE_OK ) break;
      basis = i*U32_PER_PAGE*SQLITE_PAGE_SIZE;
      j = (offset - basis)/SQLITE_PAGE_SIZE;
      for(; j<U32_PER_PAGE && amt>0; j++){
        char *aData;
        base = (offset - basis) - ij*SQLITE_PAGE_SIZE;
        if( indirPage[j] ){
          rc = sqlitePgGet(pDb->pPgr, indirPage[j], &aData);
        }else{
          rc = allocPage(pDb, &indirPage[j], &aData);
          sqlitePgTouch(indirPage);
        }
        if( rc!=SQLITE_OK ) break;
        if( amt+base > SQLITE_PAGE_SIZE ){
          tomove = SQLITE_PAGE_SIZE - base;
        }else{
          tomove = amt;
        }
        memcpy(&aData[base], pBuf, tomove);
        sqlitePgTouch(aData);
        sqlitePgUnref(aData);
        pBuf = &((char*)pBuf)[tomove];
        amt -= tomove;
      }
      sqlitePgUnref(indirPage);
      if( rc!=SQLITE_OK ) break;
    }
    sqlitePgUnref(dblIndirPage);
  }

  return SQLITE_OK;
}

/*
** Resize the payload area.  If the payload area descreases in size,
** this routine deallocates unused overflow pages.  If the payload
** area increases in size, this routine is a no-op.
*/
static int payloadResize(Db *pDb, u32 *aPage, int oldSize, int newSize){
  int i, j;          /* Loop counters */
  int first, last;   /* Indices of first and last pages to be freed */
  int rc;            /* Return code from sqlitePgGet() */

  /* Skip over the local data.  We do not need to free it.
  */
  if( newSize>=oldSize ) return SQLITE_OK;
  oldSize -= LOCAL_PAYLOAD;
  if( oldSize<=0 ) return SQLITE_OK;
  newSize -= LOCAL_PAYLOAD;
  aPage += LOCAL_PAYLOAD/sizeof(u32);

  /* Compute the indices of the first and last overflow pages to
  ** be freed.
  */
  first = (newSize - 1)/SQLITE_PAGE_SIZE + 1;
  last = (oldSize - 1)/SQLITE_PAGE_SIZE;

  /* Free the direct overflow pages
  */
  if( first < N_DIRECT ){
    for(i=first; i<N_DIRECT && i<=last; i++){
      freePage(pDb, aPage[i], 0);
      aPage[i] = 0;
    }
  }
  aPage += N_DIRECT;
  first -= N_DIRECT;
  last -= N_DIRECT;
  if( last<0 ) return SQLITE_OK;
  if( first<0 ) first = 0;
  
  /* Free indirect overflow pages
  */
  if( first < U32_PER_PAGE ){
    u32 *indirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &indirPage);
    if( rc!=SQLITE_OK ) return rc;
    for(i=first; i<U32_PER_PAGE && i<=last; i++){
      freePage(pDb, indirPage[i], 0);
      indirPage[i] = 0;
      touch = 1;
    }
    if( first<=0 ){
      freepage(pDb, aPage[0], indirPage);
      aPage[0] = 0;
    }else{
      sqlitePgTouch(indirPage);
      sqlitePgUnref(indirPage);
    }
  }
  aPage++;
  first -= U32_PER_PAGE;
  last -= U32_PER_PAGE;
  if( last<0 ) return SQLITE_OK;
  if( first<0 ) first = 0;

  /* Free double-indirect overflow pages
  */
  if( first < U32_PER_PAGE*U32_PER_PAGE ){
    u32 *dblIndirPage;
    rc = sqlitePgGet(pDb->pPgr, aPage[0], &dblIndirPage);
    if( rc!=SQLITE_OK ) return rc;
    for(i=first/U32_PER_PAGE; i<U32_PER_PAGE; i++){
      u32 *indirPage;
      basis = i*U32_PER_PAGE;
      if( last < basis ) break;
      rc = sqlitePgGet(pDb->pPgr, dblIndirPage[i], &indirPage);
      if( rc!=SQLITE_OK ) return rc;
      for(j=first>basis?first-basis:0 ; j<U32_PER_PAGE; j++){
        if( j + basis > last ) break;
        freePage(pDb, indirPage[j], 0);
        indirPage[j] = 0;
      }
      if( first<=basis ){
        freepage(pDb, dblIndirPage[i], 0);
        dblIndirPage[i] = 0;
      }else{
        sqlitePgTouch(indirPage);
        sqlitePgUnref(indirPage);
      }
    }
    if( first<=0 ){
      freepage(pDb, aPage[0], dblIndirPage);
      aPage[0] = 0;
    }else{
      sqlitePgTouch(dblIndirPage);
      sqlitePgUnref(dblIndirPage);
    }
  }

  return SQLITE_OK;    
}

/*
** Allocate space for the content table in the given Db structure.
** return SQLITE_OK on success and SQLITE_NOMEM if it fails.
*/
static int sqliteDbExpandTableArray(Db *pDb){
  pDb->aTable = sqliteRealloc( pDb->aTable, pDb->nTable*sizeof(u32));
  if( pDb->aTable==0 ){
    pDb->inTranaction = 0;
    return SQLITE_NOMEM;
  }
  return SQLITE_OK;
}

/*
** Open a database.
*/
int sqliteDbOpen(const char *filename, Db **ppDb){
  Db *pDb = 0;
  Pgr *pPgr = 0;
  u32 *aPage1;
  int rc;
  u32 nPage;

  rc = sqlitePgOpen(filename, &pPgr);
  if( rc!=SQLITE_OK ) goto open_err;
  pDb = sqliteMalloc( sizeof(*pDb) );
  if( pDb==0 ){
    rc = SQLITE_NOMEM;
    goto open_err;
  }
  pDb->pPgr = pPgr;
  pDb->pCursor = 0;
  pDb->inTransaction = 0;
  sqlitePgCount(pDb->pPgr, &nPage);
  rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
  if( rc!=0 ) goto open_err;
  if( nPage==0 ){
    sqlitePgBeginTransaction(pDb->pPgr);
    aPage1[0] = BLOCK_PAGE1;
    sqlitePgTouch(aPage1);
    sqlitePgCommit(pDb->pPgr);
  }
  pDb->freeList = aPage[1];
  pDb->nTable = aPage[2];
  rc = sqliteDbExpandTableArray(pDb);
  if( rc!=SQLITE_OK ) goto open_err;
  rc = payloadRead(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
  sqlitePgUnref(aPage1);
  if( rc!=SQLITE_OK ) goto open_err;
  *ppDb = pDb;
  return SQLITE_OK;

open_err:
  *ppDb = 0;
  if( pPgr ) sqlitePgClose(pPgr);
  if( pDb ){
    sqliteFree(pDb->aContent);
    sqliteFree(pDb);
  }
  return rc;
}

/*
** Close a database
*/
int sqliteDbClose(Db *pDb){
  while( pDb->pCursor ){
    sqliteDbCursorClose(pDb->pCursor);
  }
  sqlitePgClose(pDb->pPgr);
  sqliteFree(pDb->aContent);
  sqliteFree(pDb);
  return SQLITE_OK;
}

/*
** Begin a transaction
*/
int sqliteDbBeginTransaction(Db *pDb){
  int rc;
  if( pDb->aContent==0 ){
    return SQLITE_NOMEM;
  }
  if( pDb->inTransaction ){
    return SQLITE_INTERNAL;
  }
  rc = sqlitePgBeginTransaction(pDb->pPgr);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  pDb->inTransaction = 1;
  return SQLITE_OK;
}

/*
** Commit changes to the database
*/ 
int sqliteDbCommit(Db *pDb){
  u32 *aPage1;
  int rc;
  if( !pDb->inTransaction ){
    return SQLITE_OK;
  }
  rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
  if( rc!=SQLITE_OK ) return rc;
  aPage1[1] = pDb->freeList;
  aPage1[2] = pDb->nTable;
  payloadWrite(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
  sqlitePgUnref(aPage1);
  rc = sqlitePgCommit(pDb->pPgr);
  if( rc!=SQLITE_OK ) return rc;
  pDb->inTransaction = 0;
  return SQLITE_OK;
}

/*
** Rollback the database to its state prior to the beginning of
** the transaction
*/
int sqliteDbRollback(Db *pDb){
  u32 *aPage1;
  if( !pDb->inTransaction ) return SQLITE_OK;
  rc = sqlitePgRollback(pDb->pPgr);
  if( rc!=SQLITE_OK ) return rc;
  rc = sqlitePgGet(pDb->pPgr, 1, &aPage1);
  if( rc!=SQLITE_OK ) return rc;
  pDb->freeList = aPage1[1];
  pDb->nTable = aPage1[2];
  if( sqliteDbExpandTableArray(pDb)!=SQLITE_OK ){
    return SQLITE_NOMEM;
  }
  payloadRead(pDb, &aPage1[3], 0, pDb->nTable*sizeof(u32), pDb->aTable);
  sqlitePgUnref(aPage1);
  pDb->inTransaction = 0;
  return SQLITE_OK;
}

/*
** Create a new table in the database.  Write the table number
** that is used to open a cursor into that table into *pTblno.
*/
int sqliteDbCreateTable(Db *pDb, int *pTblno){
  u32 *aPage;
  u32 pgno;
  int rc;
  int swTblno;
  int i;

  rc = allocPage(pDb, &pgno, &aPage);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  tblno = -1;
  for(i=0; i<pDb->nTable; i++){
    if( pDb->aTable[i]==0 ){
      tblno = i;
      break;
    }
  }
  if( tblno<0 ){
    pDb->nTable++;
    rc = sqliteExpandTableArray(pDb);
    if( rc!=SQLITE_OK ){
      return rc;
    }
  }
  pDb->aTable[tblno] = pgno;
  aPage[0] = BLOCK_LEAF;
  memset(&aPage[1], 0, SQLITE_PAGE_SIZE - sizeof(u32));
  sqlitePgTouch(aPage);
  sqlitePgUnref(aPage);
  return rc;
}

/*
** Recursively add a page to the free list
*/
static int sqliteDbDropPage(Db *pDb, u32 pgno){
  u32 *aPage;
  int rc;

  rc = sqlitePgGet(pDb->pPgr, pgno, (void**)&aPage);
  if( rc!=SQLITE_OK ) return rc;
  switch(  aPage[0] ){
    case BLOCK_INDEX: {
      int n, i;
      n = aPage[2];
      for(i=0; i<n; i++){
        u32 subpgno = aPage[3 + i*2];
        if( subpgno>0 ) sqliteDbDropPage(pDb, subpgno);
      }
      freePage(pDb, pgno, aPage);
      break;
    }
    case BLOCK_LEAF: {
      int i = 2;
      while( i<U32_PER_PAGE ){
        int entrySize = aPage[i];
        if( entrySize==0 ) break;
        payloadResize(pDb, &aPage[i+4], aPage[i+2]+aPage[i+3], 0);
        i += entrySize;
      }
      freePage(pDb, pgno, aPage);
      break;
    }
    default: {
      /* Do nothing */
      break;
    }
  }
}

/*
** Delete the current associate of a cursor and release all the
** pages it holds.  Except, do not release pages at levels less
** than N.
*/
static void sqliteDbResetCursor(DbCursor *pCur, int N){
  int i;
  for(i=pCur->nLevel-1; i>=N; i--){
    sqlitePgUnref(pCur->aLevel[i].aPage);
  }
  pCur->nLevel = N;
  pCur->onEntry = 0;
}

/*
** Delete an entire table.
*/
static int sqliteDbDropTable(Db *pDb, int tblno){
  DbCursor *pCur;
  u32 pgno;

  /* Find the root page for the table to be dropped.
  */
  if( pDb->aTable==0 ){
    return SQLITE_NOMEM;
  }
  if( tblno<0 || tblno>=pDb->nTable || pDb->aTable[tblno]==0 ){
    return SQLITE_NOTFOUND;
  }
  pgno = pDb->aTable[tblno];
  pDb->aTable[tblno] = 0;
  if( tblno==pDb->nTable-1 ){
    pDb->nTable--;
  }

  /* Reset any cursors pointing to the table that is about to
  ** be dropped */
  for(pCur=pDb->pCursor; pCur; pCur=pCur->pNext){
    if( pCur->rootPgno==pgno ){
      sqliteDbResetCursor(pCur, 0);
    }
  }

  /* Move all pages associated with this table to the freelist
  */
  sqliteDbDropPage(pDb, pgno);
  return SQLITE_OK;
}

/*
** Create a new cursor
*/
int sqliteDbCursorOpen(Db *pDb, int tblno, DbCursor **ppCur){
  u32 pgno;
  DbCursor *pCur;

  /* Translate the table number into a page number
  */
  if( pDb->aTable==0 ){
    *ppCur = 0;
    return SQLITE_NOMEM;
  }
  if( tblno<0 || tblno>=pDb->nContent || pDb->aTable[tblno]==0 ){
    *ppCur = 0;
    return SQLITE_NOTFOUND;
  }
  pgno = pDb->aTable[tblno];
  
  /* Allocate the cursor
  */
  pCur = sqliteMalloc( sizeof(*pCur) );
  pCur->pgno = pgno;
  pCur->pDb = pDb;
  pCur->pNext = pDb->pCursor;
  pCur->pPrev = 0;
  if( pDb->pCursor ){
     pDb->pCursor->pPrev = pCur;
  }
  pDb->pCursor = pCur;
  *ppCur = pCur;
  return SQLITE_OK;
}

/*
** Delete a cursor
*/
int sqliteDbCursorClose(DbCursor *pCur){
  int i;
  if( pCur->pPrev ){
    pCur->pPrev->pNext = pCur->pNext;
  }else if( pCur->pDb->pCursor==pCur ){
    pCur->pDb->pCursor = pCur->pNext;
  }
  if( pCur->pNext ){
    pCur->pNext->pPrev = pCur->pPrev;
  }
  sqliteDbResetCursor(pCur, 0);
  sqliteFree(pCur);
  return SQLITE_OK; 
}

/*
** Beginning at index level "i" (the outer most index is 0), move down 
** to the first entry of the table.  Levels above i (less than i) are 
** unchanged.
*/
static int sqliteDbGotoFirst(DbCursor *pCur, int i){
  int rc = -1;

  assert( i>=0 && i<MAX_LEVEL );
  if( pCur->nLevel > i+1 ){
    sqliteDbResetCursor(pCur, i+1);
  }
  assert( pCur->nLevel==i+1 );
  while( rc < 0 ){
    u32 *aPage = pCur->aLevel[i].aPage;
    assert( aPage!=0 );
    switch( aPage[0] ){
      case BLOCK_LEAF: {
        if( aPage[2]!=0 ){
          pCur->aLevel[i].idx = 2;
          pCur->onEntry = 1;
        }else{
          sqliteDbResetCursor(pCur, 1);
        }
        rc = SQLITE_OK;
        break;
      }
      case BLOCK_INDEX: {
        int n = aPage[2];
        if( n<2 || n>=((U32_PER_PAGE - 3)/2) ){
          sqliteDbResetCur(pCur, 1);
          rc = SQLITE_CORRUPT;
          break;
        }
        pCur->nLevel++;
        i++;
        pCur->aLevel[i].pgno = aPage[3];
        rc = sqlitePgGet(pCur->pDb->pPgr, pCur->aLevel[i].pgno,
                    &pCur->aLevel[i].aPage);
        if( rc != SQLITE_OK ){
          sqliteDbResetCursor(pCur, 1);
        }else{
          rc = -1;
        }
        break;
      }
      default: {
        sqliteDbResetCursor(pCur, 1);
        rc = SQLITE_CORRUPT;
      }
    }
  }
  return rc;
}

################

/*
** Move the cursor to the first entry in the table.
*/
int sqliteDbCursorFirst(DbCursor *pCur){
  if( pCur->nLevel==0 ){
    int rc;
    pCur->aLevel[0].pgno = pCur->rootPgno;
    rc = sqlitePgGet(pCur->pDb->pPgr, pCur->rootPgno, pCur->aLevel[0].aPage);
    if( rc!=SQLITE_OK ){
      sqliteDbResetCursor(pCur, 0);
      return rc;
    }
    pCur->nLevel = 1;
  }
  return sqliteDbGotoFirst(pCur, 0);
}

/*
** Advance the cursor to the next entry in the table.
*/
int sqliteDbCursorNext(DbCursor *pCur){
  int i, idx, n, rc;
  u32 pgno, *aPage;
  if( !pCur->onEntry ){
     return sqliteDbCursorFirst(pCur);
  }
  i = pCur->nLevel-1;
  aPage = pCur->aLevel[i].aPage;
  idx = pCur->aLevel[i].idx;
  idx += SWB(aPage[idx]);
  if( idx >= SQLITE_PAGE_SIZE/sizeof(u32) ){
    sqliteDbResetCursor(pCur, 1);
    return SQLITE_CORRUPT;
  }
  if( aPage[idx]!=0 ){
    pCur->aLabel[i].idx = idx;
    return SQLITE_OK;
  }
  rc = SQLITE_OK;
  while( pCur->nLevel>1 ){
    pCur->nLevel--;
    i = pCur->nLevel-1;
    sqlitePgUnref(pCur->aLevel[pCur->nLevel].aPage);
    aPage = pCur->aLevel[i].aPage;
    idx = pCur->aLevel[i].idx;
    assert( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_INDEX );
    n = SWB(aPage[2]);
    idx += 2;
    if( (idx-3)/2 < n ){
      pCur->aLevel[i].idx = idx;
      pCur->nLevel++;
      i++;
      pgno = pCur->aLevel[i].pgno = SWB(aPage[idx+1]);
      rc = sqlitePgGet(pDb->pPgr, pgno, &pCur->aLevel[i].aPage);
      if( rc!=SQLITE_OK ) break;
      rc = sqliteDbGotoFirst(pCur, i);
      break;
    }
  }
  sqliteDbResetCursor(pCur, 0);
  return SQLITE_OK;
}

/*
** Return the amount of data on the entry that the cursor points
** to.
*/
int sqliteDbCursorDatasize(DbCursor *pCur){
  u32 *aPage;
  int idx, i;
  if( !pCur->onEntry ) return 0;
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<U32_PER_PAGE );
  return aPage[idx+3];
}

/*
** Return the number of bytes of key on the entry that the cursor points
** to.
*/
int sqliteDbCursorKeysize(DbCursor *pCur){
  u32 *aPage;
  int idx, i;
  if( !pCur->onEntry ) return 0;
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<U32_PER_PAGE );
  return aPage[idx+2];
}

/*
** Read data from the cursor.
*/
int sqliteDbCursorRead(DbCursor *pCur, int amt, int offset, void *buf){
  u32 *aPage;
  int idx, i;
  int nData;
  int nKey;
  if( !pCur->onEntry ){
    memset(cbuf, 0, amt);
    return SQLITE_OK;
  }
  if( amt<=0 || offset<0 ){
    return SQLITE_ERR;
  }
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<U32_PER_PAGE );
  nData = aPage[idx+3];
  if( offset>=nData ){
    memset(buf, 0, amt);
    return SQLITE_OK;
  }
  nKey = aPage[idx+2];
  if( nData<offset+amt ){
    memset(&((char*)buf)[nData-offset], 0, amt+offset-nData);
    amt = nData - offset;
  }
  payloadRead(pCur->pDb, &aPage[idx+4], amt, offset + nKey, buf);
  return SQLITE_OK;
}

/*
** Read the current key from the cursor.
*/
int sqliteDbCursorReadKey(DbCursor *pCur, int amt, int offset, void *buf){
  u32 *aPage;
  int idx, i;
  int nData;
  int nKey;
  if( !pCur->onEntry ){
    memset(cbuf, 0, amt);
    return SQLITE_OK;
  }
  if( amt<=0 || offset<0 ){
    return SQLITE_ERR;
  }
  i = pCur->nLevel-1;
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( aPage );
  assert( idx>=2 && idx+4<(SQLITE_PAGE_SIZE/sizeof(u32))
  nKey = aPage[idx+2];
  if( offset>=nKey ){
    memset(buf, 0, amt);
    return SQLITE_OK;
  }
  if( nKey<offset+amt ){
    memset(&((char*)buf)[nKey-offset], 0, amt+offset-nKey);
    amt = nKey - offset;
  }
  payloadRead(pCur->pDb, &aPage[idx+4], amt, offset, buf);
  return SQLITE_OK;
}

/*
** Generate a 32-bit hash from the given key.
*/
static u32 sqliteDbHash(int nKey, void *pKey){
  u32 h;
  unsigned char *key;
  if( nKey==4 ){
    return *(u32*)pKey;
  }
  key = pKey;
  h = 0;
  while( 0 < nKey-- ){
    h = (h<<13) ^ (h<<3) ^ h ^ *(key++)
  }
  return h;
}

/*
** Move the cursor so that the lowest level is the leaf page that
** contains (or might contain) the given key.
*/
static int sqliteDbFindLeaf(DbCursor *pCur, int nKey, void *pKey, u32 h;){
  int i, j, rc;
  u32 h;

  h = sqliteDbHash(nKey, pKey);
  sqliteDbResetCursor(pCur, 1);
  i = 0;
  for(;;){
    u32 nxPgno;
    u32 *aPage = pCur->aLevel[i].aPage;
    if( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_LEAF ) break;
    if( SWB(aPage[0])!=BLOCK_MAGIC|BLOCK_INDEX ){
      return SQLITE_CORRUPT;
    }
    if( i==MAX_LEVEL-1 ){
      return SQLITE_FULL;
    }
    n = SWB(aPage[2]);
    if( n<2 || n>=(SQLITE_PAGE_SIZE/2*sizeof(u32))-2 ){
      return SQLITE_CORRUPT;
    }
    for(j=0; j<n-1; j++){
      if( h < SWB(aPage[j*2+3]) ) break;
    }
    nxPgno = SWB(aPage[j*2+4]);
    pCur->aLevel[i].idx = j;
    pCur->aLevel[i].pgno = nxPgno;
    rc = sqlitePgGet(pCur->pDb->pPgr, nxPgno, &pCur->aLevel[i].aPage);
    if( rc!=SQLITE_OK ){
      return rc;
    }
    pCur->nLevel++;
    i++;
  }
  return SQLITE_OK;
}

/*
** Position the cursor on the entry that matches the given key.
*/
int sqliteDbCursorMoveTo(DbCursor *pCur, int nKey, void *pKey){
  int rc, i;
  u32 *aPage;
  int idx;
  u32 h;

  h = sqliteDbHash(nKey, pKey);
  rc = sqliteDbFindLeaf(pCur, nKey, pKey, h);
  if( rc!=SQLITE_OK ) return rc;
  i = pCur->nLevel-1;
  aPage = pCur->aLevel[i].aPage;
  idx = 2;
  rc = SQLITE_NOTFOUND;
  while( idx>=2 && idx<(SQLITE_PAGE_SIZE/sizeof(u32))-3 && aPage[idx]!=0 ){
    if( sqliteDbKeyMatch(&aPage[idx], nKey, pKey, h) ){
      pCur->aLevel[i].idx = idx;
      pCur->onEntry = 1;
      rc = SQLITE_OK;
      break;
    }
    idx += SWB(aPage[idx]);
  }
  return rc;
}

/*
** Insert a new entry into the table.  The cursor is left pointing at
** the new entry.
*/
int sqliteDbCursorInsert(   
   DbCursor *pCur,          /* A cursor on the table in which to insert */
   int nKey, void *pKey,    /* The insertion key */
   int nData, void *pData   /* The data to be inserted */
){
  int minNeeded, maxNeeded;    /* In u32-sized objects */
  int rc;
  u32 h;
  int available;
  int i, j, k;
  int nKeyU, nDataU;
  u32 *aPage;
  int incr = 1;

  /* Null data is the same as a delete.
  */
  if( nData<=0 || pData==0 ){
    if( sqliteDbCursorMoveTo(pCur, nKey, pKey);
      return sqliteDbCursorDelete(pCur);
    }else{
      return SQLITE_OK;
    }
  }

  /* Figure out how much free space is needed on a leaf block in order
  ** to hold the new record.
  */
  minNeeded = maxNeeded = 6;
  nKeyU = (nKey+3)/4;
  nDataU = (nData+3)/4;
  if( nKeyU + maxNeeded + 2 <= SQLITE_PAGE_SIZE/sizeof(u32) ){
    maxNeeded += nKeyU;
  }
  if( nKeyU < SQLITE_PAGE_SIZE/(3*sizeof(u32)) ){
    minNeeded += nKeyU;
  }
  if( nDataU + maxNeeded + 2 <= SQLITE_PAGE_SIZE/sizeof(u32) ){
    maxNeeded += nDataU
  }
  if( nDataU < SQLITE_PAGE_SIZE/(3*sizeof(u32)) ){
    minNeeded += nDataU;
  }

  /* Move the cursor to the leaf block where the new record will be
  ** inserted.
  */
  h = sqliteDbHash(nKey, pKey);
  rc = sqliteDbFindLeaf(pCur, nKey, pKey, h);
  if( rc!=SQLITE_OK ) return rc;

  /* Walk thru the leaf once and do two things:
  **   1.  Remove any prior entry with the same key.
  **   2.  Figure out how much space is available on this leaf.
  */
  i = j = 2;
  aPage = pCur->aLevel[pCur->nLevel-1].aPage;
  for(;;){
    int entrySize = SWB(aPage[i]);
    if( entrySize<=0 || entrySize + i >= SQLITE_PAGE_SIZE/sizeof(u32) ) break;
    if( !sqliteDbKeyMatch(&aPage[i], nKey, pKey, h) ){
      if( j<i ){
        for(k=0; k<entrySize; k++){
           aPage[j+k] = aPage[i+k];
        }
      }
      j += entrySize;
    }else{
      sqliteDbClearEntry(pCur->pDb, &aPage[i]);
      incr--;
    }
    i += entrySize;
  }
  available = SQLITE_PAGE_SIZE/sizeof(u32) - j;

  /* If the new entry will not fit, try to move some of the entries
  ** from this leaf onto sibling leaves.
  */
  if( available<minNeeded ){
    int newSpace;
    newSpace = sqliteDbSpreadLoad(pCur, maxNeeded); ############
    available += newSpace;
  }

  /* If the new entry still will not fit, try to split this leaf into
  ** two adjacent leaves.
  */
  if( available<minNeeded && pCur->nLevel>1 ){
    int newAvail;
    newAvail = sqliteDbSplit(pCur, maxNeeded); ##############
    if( newAvail>0 ){
      available += newAvail;
    }
  }

  /* If the new entry does not fit after splitting, turn this leaf into
  ** and index node with one leaf, go down into the new leaf and try 
  ** to split again.
  */
  if( available<minNeeded && pCur->nLevel<MAX_LEVEL-1 ){
    int newAvail;
    sqliteDbNewIndexLevel(pCur);  ###############
    newAvail = sqliteDbSplit(pCur, maxNeeded);
    if( newAvail>0 ){
      available = newAvail;
    }
  }

  /* If the entry still will not fit, it means the database is full.
  */
  if( available<minNeeded ){
    return SQLITE_FULL;
  }

  /* Add the new entry to the leaf block.
  */
  aPage = pCur->aLevel[pCur->nLevel-1].aPage;
  i = 2;
  for(;;){
    int entrySize = SWB(aPage[i]);
    if( entrySize<=0 || entrySize + i >= SQLITE_PAGE_SIZE/sizeof(u32) ) break;
    i += entrySize;
  }
  assert( available==SQLITE_PAGE_SIZE/sizeof(u32) - i );
  aPage[i+1] = SWB(h);
  available -= 5;
  if( nKeyU <= available ){
    aPage[i+2] = SWB(nKey);
    memcpy(&aPage[i+4], pKey, nKey);
    j = i + 4 + nKeyU;
    available -= nKeyU;
  }else{
    u32 newPgno, *newPage;
    aPage[i+2] = SWB(nKey | 0x80000000);
    rc = allocPage(pCur->pDb, &newPgno, &newPage);
    if( rc!=SQLITE_OK ) goto write_err;
    aPage[i+4] = SWB(newPgno);
    newPage[0] = SWB(BLOCK_MAGIC | BLOCK_OVERFLOW);
    rc = sqliteDbWriteOvfl(pCur->pDb, newPage, nKey, pKey);
    if( rc!=SQLITE_OK ) goto write_err;
    j = i + 5;
    available -= 1;
  }
  if( nDataU <= available ){
    aPage[i+3] = SWB(nData);
    memcpy(&aPage[j], pData, nData);
    available -= nDataU;
    j += nDataU;
  }else{
    u32 newPgno, *newPage;
    aPage[i+3] = SWB(nData | 0x80000000);
    rc = allocPage(pCur->pDb, &newPgno, &newPage);
    if( rc!=SQLITE_OK ) goto write_err;
    aPage[j] = SWB(newPgno);
    newPage[0] = SWB(BLOCK_MAGIC | BLOCK_OVERFLOW);
    rc = sqliteDbWriteOvfl(pCur->pDb, newPage, nData, pData);
    if( rc!=SQLITE_OK ) goto write_err;
    available -= 1;
    j++;
  }    
  if( j<SQLITE_PAGE_SIZE/sizeof(u32) ){
    aPage[j] = 0;
  }
  sqlitePgTouch(aPage);
  pCur->aLevel[pCur->nLevel-1].idx = i;
  pCur->onEntry = 1;

  /*  Increment the entry count for this table.
  */
  if( incr!=0 ){
    pCur->aLevel[0].aPage[1] = SWB(SWB(pCur->aLevel[0].aPage[1])+incr);
    sqlitePgTouch(pCur->aLevel[0].aPage);
  }
  return SQLITE_OK;

write_err:
  aPage[i] = 0;
  pCur->onEntry = 0;
  return rc;
}

/*
** Delete the entry that the cursor points to.
*/
int sqliteDbCursorDelete(DbCursor *pCur){
  int i, idx;
  int from, to, limit, n;
  int entrySize;
  u32 *aPage;
  if( !pCur->onEntry ) return SQLITE_NOTFOUND;

  /* Delete the entry that the cursor is pointing to.
  */
  i = pCur->nLevel - 1;
  aPage = pCur->aLevel[i].aPage;
  idx = pCur->aLevel[i].idx;
  assert( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_LEAF );
  assert( idx>=2 && idx<SQLITE_PAGE_SIZE/sizeof(u32)-4 );
  entrySize = SWB(aPage[idx]);
  assert( entrySize>=6 && idx+entrySize<=SQLITE_PAGE_SIZE/sizeof(u32) );
  sqliteDbClearEntry(pCur->pDb, &aPage[idx]);
  to = idx;
  from = idx + entrySize;
  while( from<SQLITE_PAGE_SIZE/sizeof(u32) ){
    int k;
    entrySize = SWB(aPage[from]);
    if( entrySize<=0 ) break;
    for(k=0; k<entrySize; k++){
      aPage[to++] = aPage[from++]
    }
  }
  aPage[to] = 0;

  /*  Decrement the entry count for this table.
  */
  pCur->aLevel[0].aPage[1] = SWB(SWB(pCur->aLevel[0].aPage[1])-1);
  sqlitePgTouch(pCur->aLevel[0].aPage);

  /* If there are more entries on this leaf or this leaf is the root
  ** of the table,  then we are done.
  */
  if( to>2 || pCur->nLevel==1 ) return SQLITE_OK;

  /* Collapse the tree into a more compact form.
  */
  sqliteDbResetCursor(pCur, pCur->nLevel-1);

  i = pCur->nLevel-1;
  assert( i>=0 && i<MAX_LEVEL );
  idx = pCur->aLevel[i].idx;
  aPage = pCur->aLevel[i].aPage;
  assert( SWB(aPage[0])==BLOCK_MAGIC|BLOCK_INDEX );
  assert( idx>=3 && idx<SQLITE_PAGE_SIZE/sizeof(u32) );
  n = SWB(aPage[2]);
  assert( n>=2 && n<=SQLITE_PAGE_SIZE/2*sizeof(u32)-2 );
  sqliteDbDropPage(pCur->pDb, SWB(aPage[idx+1]);
  to = idx;
  from = idx+2;
  limit = n*2 + 3;
  while( from<limit ){
    aPage[to++] = aPage[from++];
  }
  n--;
  if( n==1 ){
    u32 oldPgno, *oldPage;
    oldPgno = SWB(aPage[4]);
    rc = sqlitePgGet(pCur->pDb->pPgr, oldPgno, &oldPage);
    if( rc!=SQLITE_OK ){
      return rc;  /* Do something smarter here */
    }
    memcpy(aPage, oldPage, SQLITE_PAGE_SIZE);
    oldPage[0] = SWB(BLOCK_MAGIC|BLOCK_OVERFLOW);
    oldPage[1] = 0;
    sqliteDbDropPage(pCur->pDb, oldPgno);
    sqlitePgUnref(oldPage);
  }else{
    aPage[2] = SWB(n);
  }
  sqlitePgTouch(aPage);
  return SQLITE_OK;
}

Added src/ex/db.h.







































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: db.h,v 1.1 2001/02/11 16:56:24 drh Exp $
*/

typedef struct Db Db;
typedef struct DbCursor DbCursor;

int sqliteDbOpen(const char *filename, Db**);
int sqliteDbClose(Db*);
int sqliteDbBeginTransaction(Db*);
int sqliteDbCommit(Db*);
int sqliteDbRollback(Db*);

int sqliteDbCreateTable(Db*, int *pTblno);
int sqliteDbDropTable(Db*, int tblno);

int sqliteDbCursorOpen(Db*, int tblno, DbCursor**);
int sqliteDbCursorClose(DbCursor*);

int sqliteDbCursorFirst(DbCursor*);
int sqliteDbCursorNext(DbCursor*);
int sqliteDbCursorDatasize(DbCursor*);
int sqliteDbCursorKeysize(DbCursor*);
int sqliteDbCursorRead(DbCursor*, int amt, int offset, void *buf);
int sqliteDbCursorReadKey(DbCursor*, int amt, int offset, void *buf);
int sqliteDbCursorWrite(DbCursor*, int amt, int offset, const void *buf);

int sqliteDbCursorFind(DbCursor*, int nKey, const void *pKey, int createFlag);
int sqliteDbCursorResize(DbCursor*, int nData);

Added src/ex/dbbebdb1.c.





















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
/*
** Copyright (c) 2000 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code to implement the database backend (DBBE)
** for sqlite.  The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses Berkeley Database version 1.85 as the database backend.
**
** $Id: dbbebdb1.c,v 1.1 2001/02/11 16:56:24 drh Exp $
*/
#ifdef USE_BDB2

#include "sqliteInt.h"
#include <sys/types.h>
#include <limits.h>
#include <db.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>

/*
** Information about each open disk file is an instance of this 
** structure.  There will only be one such structure for each
** disk file.  If the VDBE opens the same file twice (as will happen
** for a self-join, for example) then two DbbeCursor structures are
** created but there is only a single BeFile structure with an
** nRef of 2.
*/
typedef struct BeFile BeFile;
struct BeFile {
  char *zName;            /* Name of the file */
  DB dbf;                 /* The file itself */
  int nRef;               /* Number of references */
  int delOnClose;         /* Delete when closing */
  int writeable;          /* Opened for writing */
  DbbeCursor *pCursor; /* Which of several DbbeCursors has the file cursor */
  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
};

/*
** The following structure contains all information used by BDB2
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  int write;         /* True for write permission */
  BeFile *pOpen;     /* List of open files */
  char *zDir;        /* Directory hold the database */
};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile.  The
** BeFile.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file.
*/
struct DbbeCursor {
  Dbbex *pBe;        /* The database of which this record is a part */
  BeFile *pFile;     /* The database file for this table */
  DBT key;           /* Most recently used key */
  DBT data;          /* Most recent data */
  int needRewind;    /* Next key should be the first */
  int readPending;   /* The fetch hasn't actually been done yet */
};

/*
** The "mkdir()" function only takes one argument under Windows.
*/
#if OS_WIN
# define mkdir(A,B) mkdir(A)
#endif

/*
** Forward declaration
*/
static void sqliteBdb1CloseCursor(DbbeCursor *pCursr);

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
static void sqliteBdb1Close(Dbbe *pDbbe){
  Dbbex *pBe = (Dbbex*)pDbbe;
  BeFile *pFile, *pNext;
  for(pFile=pBe->pOpen; pFile; pFile=pNext){
    pNext = pFile->pNext;
    (*pFile->dbf)(pFile->dbf);
    memset(pFile, 0, sizeof(*pFile));   
    sqliteFree(pFile);
  }
  sqliteDbbeCloseAllTempFiles(pDbbe);
  memset(pBe, 0, sizeof(*pBe));
  sqliteFree(pBe);
}

/*
** Translate the name of an SQL table (or index) into the name 
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
  return sqliteDbbeNameToFile(pBe->zDir, zTable, ".tbl");
}

/*
** Open a new table cursor.  Write a pointer to the corresponding
** DbbeCursor structure into *ppCursr.  Return an integer success
** code:
**
**    SQLITE_OK          It worked!
**
**    SQLITE_NOMEM       sqliteMalloc() failed
**
**    SQLITE_PERM        Attempt to access a file for which file
**                       access permission is denied
**
**    SQLITE_BUSY        Another thread or process is already using
**                       the corresponding file and has that file locked.
**
**    SQLITE_READONLY    The current thread already has this file open
**                       readonly but you are trying to open for writing.
**                       (This can happen if a SELECT callback tries to
**                       do an UPDATE or DELETE.)
**
** If zTable is 0 or "", then a temporary database file is created and
** a cursor to that temporary file is opened.  The temporary file
** will be deleted from the disk when it is closed.
*/
static int sqliteBdb1OpenCursor(
  Dbbe *pDbbe,            /* The database the table belongs to */
  const char *zTable,     /* The SQL name of the file to be opened */
  int writeable,          /* True to open for writing */
  int intKeyOnly,         /* True if only integer keys are used */
  DbbeCursor **ppCursr    /* Write the resulting table pointer here */
){
  char *zFile;            /* Name of the table file */
  DbbeCursor *pCursr;     /* The new table cursor */
  BeFile *pFile;          /* The underlying data file for this table */
  int rc = SQLITE_OK;     /* Return value */
  int open_flags;         /* Flags passed to dbopen() */
  Dbbex *pBe = (Dbbex*)pDbbe;

  *ppCursr = 0;
  pCursr = sqliteMalloc( sizeof(*pCursr) );
  if( pCursr==0 ) return SQLITE_NOMEM;
  if( zTable ){
    zFile = sqliteFileOfTable(pBe, zTable);
    for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
      if( strcmp(pFile->zName,zFile)==0 ) break;
    }
  }else{
    pFile = 0;
    zFile = 0;
  }
  if( pFile==0 ){
    if( writeable ){
      open_flags = O_RDWR|O_CREAT
    }else{
      open_flags = O_RDONLY;
    }
    pFile = sqliteMalloc( sizeof(*pFile) );
    if( pFile==0 ){
      sqliteFree(zFile);
      return SQLITE_NOMEM;
    }
    if( zFile ){
      if( !writeable || pBe->write ){
        pFile->dbf = dbopen(zFile, open_flags, DB_HASH, 0);
      }else{
        pFile->dbf = 0;
      }
    }else{
      int limit;
      char zRandom[50];
      zFile = 0;
      limit = 5;
      do {
        sqliteRandomName(zRandom, "_temp_table_");
        sqliteFree(zFile);
        zFile = sqliteFileOfTable(pBe, zRandom);
        pFile->dbf = dbopen(zFile, open_flags, DB_HASH, 0);
      }while( pFile->dbf==0 && limit-- >= 0);
      pFile->delOnClose = 1;
    }
    pFile->writeable = writeable;
    pFile->zName = zFile;
    pFile->nRef = 1;
    pFile->pPrev = 0;
    if( pBe->pOpen ){
      pBe->pOpen->pPrev = pFile;
    }
    pFile->pCursor = 0;
    pFile->pNext = pBe->pOpen;
    pBe->pOpen = pFile;
    if( pFile->dbf==0 ){
      if( !writeable && access(zFile,0) ){
        /* Trying to read a non-existant file.  This is OK.  All the
        ** reads will return empty, which is what we want. */
        rc = SQLITE_OK;   
      }else if( pBe->write==0 ){
        rc = SQLITE_READONLY;
      }else if( access(zFile,W_OK|R_OK) ){
        rc = SQLITE_PERM;
      }else{
        rc = SQLITE_BUSY;
      }
    }
  }else{
    sqliteFree(zFile);
    pFile->nRef++;
    if( writeable && !pFile->writeable ){
      rc = SQLITE_READONLY;
    }
  }
  pCursr->pBe = pBe;
  pCursr->pFile = pFile;
  pCursr->readPending = 0;
  pCursr->needRewind = 1;
  if( rc!=SQLITE_OK ){
    sqliteBdb1CloseCursor(pCursr);
    *ppCursr = 0;
  }else{
    *ppCursr = pCursr;
  }
  return rc;
}

/*
** Drop a table from the database.  The file on the disk that corresponds
** to this table is deleted.
*/
static void sqliteBdb1DropTable(Dbbe *pBe, const char *zTable){
  char *zFile;            /* Name of the table file */

  zFile = sqliteFileOfTable((Dbbex*)pBe, zTable);
  unlink(zFile);
  sqliteFree(zFile);
}

/*
** Close a cursor previously opened by sqliteBdb1OpenCursor().
**
** There can be multiple cursors pointing to the same open file.
** The underlying file is not closed until all cursors have been
** closed.  This routine decrements the BeFile.nref field of the
** underlying file and closes the file when nref reaches 0.
*/
static void sqliteBdb1CloseCursor(DbbeCursor *pCursr){
  BeFile *pFile;
  Dbbex *pBe;
  if( pCursr==0 ) return;
  pFile = pCursr->pFile;
  pBe = pCursr->pBe;
  if( pFile->pCursor==pCursr ){
    pFile->pCursor = 0;
  }
  pFile->nRef--;
  if( pFile->dbf!=NULL ){
    (*pFile->dbf->sync)(pFile->dbf, 0);
  }
  if( pFile->nRef<=0 ){
    if( pFile->dbf!=NULL ){
      (*pFile->dbf->close)(pFile->dbf);
    }
    if( pFile->pPrev ){
      pFile->pPrev->pNext = pFile->pNext;
    }else{
      pBe->pOpen = pFile->pNext;
    }
    if( pFile->pNext ){
      pFile->pNext->pPrev = pFile->pPrev;
    }
    if( pFile->delOnClose ){
      unlink(pFile->zName);
    }
    sqliteFree(pFile->zName);
    memset(pFile, 0, sizeof(*pFile));
    sqliteFree(pFile);
  }
  if( pCursr->key.dptr ) free(pCursr->key.dptr); ######
  if( pCursr->data.dptr ) free(pCursr->data.dptr); ######
  memset(pCursr, 0, sizeof(*pCursr));
  sqliteFree(pCursr);
}

/*
** Reorganize a table to reduce search times and disk usage.
*/
static int sqliteBdb1ReorganizeTable(Dbbe *pBe, const char *zTable){
  /* No-op */
  return SQLITE_OK;
}

/*
** Clear the given datum
*/
static void datumClear(datum *p){
  if( p->dptr ) free(p->dptr); ########
  p->data = 0;
  p->size = 0;
}

/*
** Fetch a single record from an open cursor.  Return 1 on success
** and 0 on failure.
*/
static int sqliteBdb1Fetch(DbbeCursor *pCursr, int nKey, char *pKey){
  DBT key;
  key.size = nKey;
  key.data = pKey;
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  if( pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, key);
  }
  return pCursr->data.dptr!=0;
}

/*
** Return 1 if the given key is already in the table.  Return 0
** if it is not.
*/
static int sqliteBdb1Test(DbbeCursor *pCursr, int nKey, char *pKey){
  DBT key;
  int result = 0;
  key.dsize = nKey;
  key.dptr = pKey;
  if( pCursr->pFile && pCursr->pFile->dbf ){
    result = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return result;
}

/*
** Copy bytes from the current key or data into a buffer supplied by
** the calling function.  Return the number of bytes copied.
*/
static
int sqliteBdb1CopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){
  int n;
  if( offset>=pCursr->key.dsize ) return 0;
  if( offset+size>pCursr->key.dsize ){
    n = pCursr->key.dsize - offset;
  }else{
    n = size;
  }
  memcpy(zBuf, &pCursr->key.dptr[offset], n);
  return n;
}
static
int sqliteBdb1CopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){
  int n;
  if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
    pCursr->readPending = 0;
  }
  if( offset>=pCursr->data.dsize ) return 0;
  if( offset+size>pCursr->data.dsize ){
    n = pCursr->data.dsize - offset;
  }else{
    n = size;
  }
  memcpy(zBuf, &pCursr->data.dptr[offset], n);
  return n;
}

/*
** Return a pointer to bytes from the key or data.  The data returned
** is ephemeral.
*/
static char *sqliteBdb1ReadKey(DbbeCursor *pCursr, int offset){
  if( offset<0 || offset>=pCursr->key.dsize ) return "";
  return &pCursr->key.dptr[offset];
}
static char *sqliteBdb1ReadData(DbbeCursor *pCursr, int offset){
  if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
    pCursr->readPending = 0;
  }
  if( offset<0 || offset>=pCursr->data.dsize ) return "";
  return &pCursr->data.dptr[offset];
}

/*
** Return the total number of bytes in either data or key.
*/
static int sqliteBdb1KeyLength(DbbeCursor *pCursr){
  return pCursr->key.dsize;
}
static int sqliteBdb1DataLength(DbbeCursor *pCursr){
  if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
    pCursr->readPending = 0;
  }
  return pCursr->data.dsize;
}

/*
** Make is so that the next call to sqliteNextKey() finds the first
** key of the table.
*/
static int sqliteBdb1Rewind(DbbeCursor *pCursr){
  pCursr->needRewind = 1;
  return SQLITE_OK;
}

/*
** Read the next key from the table.  Return 1 on success.  Return
** 0 if there are no more keys.
*/
static int sqliteBdb1NextKey(DbbeCursor *pCursr){
  DBT nextkey;
  int rc;
  if( pCursr==0 || pCursr->pFile==0 || pCursr->pFile->dbf==0 ){
    pCursr->readPending = 0;
    return 0;
  }
  if( pCursr->needRewind ){
    nextkey = gdbm_firstkey(pCursr->pFile->dbf);
    pCursr->needRewind = 0;
  }else{
    nextkey = gdbm_nextkey(pCursr->pFile->dbf, pCursr->key);
  }
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  pCursr->key = nextkey;
  if( pCursr->key.dptr ){
    pCursr->readPending = 1;
    rc = 1;
  }else{
    pCursr->needRewind = 1;
    pCursr->readPending = 0;
    rc = 0;
  }
  return rc;
}

/*
** Get a new integer key.
*/
static int sqliteBdb1New(DbbeCursor *pCursr){
  int iKey;
  DBT key;
  int go = 1;

  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  while( go ){
    iKey = sqliteRandomInteger();
    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return iKey;
}   

/*
** Write an entry into the table.  Overwrite any prior entry with the
** same key.
*/
static int sqliteBdb1Put(
  DbbeCursor *pCursr,  /* Write to the database associated with this cursor */
  int nKey,            /* Number of bytes in the key */
  char *pKey,          /* The data for the key */
  int nData,           /* Number of bytes of data */
  char *pData          /* The data */
){
  DBT data, key;
  int rc;
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  data.dsize = nData;
  data.dptr = pData;
  key.dsize = nKey;
  key.dptr = pKey;
  rc = gdbm_store(pCursr->pFile->dbf, key, data, GDBM_REPLACE);
  if( rc ) rc = SQLITE_ERROR;
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  return rc;
}

/*
** Remove an entry from a table, if the entry exists.
*/
static int sqliteBdb1Delete(DbbeCursor *pCursr, int nKey, char *pKey){
  DBT key;
  int rc;
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  key.dsize = nKey;
  key.dptr = pKey;
  rc = gdbm_delete(pCursr->pFile->dbf, key);
  if( rc ) rc = SQLITE_ERROR;
  return rc;
}

/*
** Open a temporary file.  The file is located in the same directory
** as the rest of the database.
*/
static int sqliteBdb1OpenTempFile(Dbbe *pDbbe, FILE **ppFile){
  Dbbex *pBe = (Dbbex*)pDbbe;
  return sqliteDbbeOpenTempFile(pBe->zDir, pDbbe, ppFile);
}

/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.
*/
static struct DbbeMethods gdbmMethods = {
  /* n         Close */   sqliteBdb1Close,
  /*      OpenCursor */   sqliteBdb1OpenCursor,
  /*       DropTable */   sqliteBdb1DropTable,
  /* ReorganizeTable */   sqliteBdb1ReorganizeTable,
  /*     CloseCursor */   sqliteBdb1CloseCursor,
  /*           Fetch */   sqliteBdb1Fetch,
  /*            Test */   sqliteBdb1Test,
  /*         CopyKey */   sqliteBdb1CopyKey,
  /*        CopyData */   sqliteBdb1CopyData,
  /*         ReadKey */   sqliteBdb1ReadKey,
  /*        ReadData */   sqliteBdb1ReadData,
  /*       KeyLength */   sqliteBdb1KeyLength,
  /*      DataLength */   sqliteBdb1DataLength,
  /*         NextKey */   sqliteBdb1NextKey,
  /*          Rewind */   sqliteBdb1Rewind,
  /*             New */   sqliteBdb1New,
  /*             Put */   sqliteBdb1Put,
  /*          Delete */   sqliteBdb1Delete,
  /*    OpenTempFile */   sqliteBdb1OpenTempFile,
  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
**
** If successful, a pointer to the Dbbe structure is returned.
** If there are errors, an appropriate error message is left
** in *pzErrMsg and NULL is returned.
*/
Dbbe *sqliteBdb1Open(
  const char *zName,     /* The name of the database */
  int writeFlag,         /* True if we will be writing to the database */
  int createFlag,        /* True to create database if it doesn't exist */
  char **pzErrMsg        /* Write error messages (if any) here */
){
  Dbbex *pNew;
  struct stat statbuf;
  char *zMaster;

  if( !writeFlag ) createFlag = 0;
  if( stat(zName, &statbuf)!=0 ){
    if( createFlag ) mkdir(zName, 0750);
    if( stat(zName, &statbuf)!=0 ){
      sqliteSetString(pzErrMsg, createFlag ? 
         "can't find or create directory \"" : "can't find directory \"",
         zName, "\"", 0);
      return 0;
    }
  }
  if( !S_ISDIR(statbuf.st_mode) ){
    sqliteSetString(pzErrMsg, "not a directory: \"", zName, "\"", 0);
    return 0;
  }
  if( access(zName, writeFlag ? (X_OK|W_OK|R_OK) : (X_OK|R_OK)) ){
    sqliteSetString(pzErrMsg, "access permission denied", 0);
    return 0;
  }
  zMaster = 0;
  sqliteSetString(&zMaster, zName, "/" MASTER_NAME ".tbl", 0);
  if( stat(zMaster, &statbuf)==0
   && access(zMaster, writeFlag ? (W_OK|R_OK) : R_OK)!=0 ){
    sqliteSetString(pzErrMsg, "access permission denied for ", zMaster, 0);
    sqliteFree(zMaster);
    return 0;
  }
  sqliteFree(zMaster);
  pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->dbbe.x = &gdbmMethods;
  pNew->zDir = (char*)&pNew[1];
  strcpy(pNew->zDir, zName);
  pNew->write = writeFlag;
  pNew->pOpen = 0;
  return &pNew->dbbe;
}

Added src/ex/dbbemird.c.

















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
/*
** Copyright (c) 2000 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code to implement the database backend (DBBE)
** for sqlite.  The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbemird.c,v 1.1 2001/02/11 16:56:24 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>

/*
** Information about each open disk file is an instance of this 
** structure.  There will only be one such structure for each
** disk file.  If the VDBE opens the same file twice (as will happen
** for a self-join, for example) then two DbbeCursor structures are
** created but there is only a single BeFile structure with an
** nRef of 2.
*/
typedef struct BeFile BeFile;
struct BeFile {
  char *zName;            /* Name of the file */
  GDBM_FILE dbf;          /* The file itself */
  int nRef;               /* Number of references */
  int delOnClose;         /* Delete when closing */
  int writeable;          /* Opened for writing */
  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
};

/*
** The following structure holds the current state of the RC4 algorithm.
** We use RC4 as a random number generator.  Each call to RC4 gives
** a random 8-bit number.
**
** Nothing in this file or anywhere else in SQLite does any kind of
** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device.
*/
struct rc4 {
  int i, j;
  int s[256];
};

/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  char *zDir;        /* The directory containing the database */
  int write;         /* True for write permission */
  BeFile *pOpen;     /* List of open files */
  int nTemp;         /* Number of temporary files created */
  FILE **apTemp;     /* Space to hold temporary file pointers */
  char **azTemp;     /* Names of the temporary files */
  struct rc4 rc4;    /* The random number generator */
};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile.  The
** BeFile.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file.
*/
struct DbbeCursor {
  Dbbex *pBe;        /* The database of which this record is a part */
  BeFile *pFile;     /* The database file for this table */
  datum key;         /* Most recently used key */
  datum data;        /* Most recent data */
  int needRewind;    /* Next key should be the first */
  int readPending;   /* The fetch hasn't actually been done yet */
};

/*
** Initialize the RC4 PRNG.  "seed" is a pointer to some random
** data used to initialize the PRNG.  
*/
static void rc4init(struct rc4 *p, char *seed, int seedlen){
  int i;
  char k[256];
  p->j = 0;
  p->i = 0;
  for(i=0; i<256; i++){
    p->s[i] = i;
    k[i] = seed[i%seedlen];
  }
  for(i=0; i<256; i++){
    int t;
    p->j = (p->j + p->s[i] + k[i]) & 0xff;
    t = p->s[p->j];
    p->s[p->j] = p->s[i];
    p->s[i] = t;
  }
}

/*
** Get a single 8-bit random value from the RC4 PRNG.
*/
static int rc4byte(struct rc4 *p){
  int t;
  p->i = (p->i + 1) & 0xff;
  p->j = (p->j + p->s[p->i]) & 0xff;
  t = p->s[p->i];
  p->s[p->i] = p->s[p->j];
  p->s[p->j] = t;
  t = p->s[p->i] + p->s[p->j];
  return t & 0xff;
}

/*
** The "mkdir()" function only takes one argument under Windows.
*/
#if OS_WIN
# define mkdir(A,B) mkdir(A)
#endif

/*
** Forward declaration
*/
static void sqliteGdbmCloseCursor(DbbeCursor *pCursr);

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
static void sqliteGdbmClose(Dbbe *pDbbe){
  Dbbex *pBe = (Dbbex*)pDbbe;
  BeFile *pFile, *pNext;
  int i;
  for(pFile=pBe->pOpen; pFile; pFile=pNext){
    pNext = pFile->pNext;
    gdbm_close(pFile->dbf);
    memset(pFile, 0, sizeof(*pFile));   
    sqliteFree(pFile);
  }
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]!=0 ){
      unlink(pBe->azTemp[i]);
      fclose(pBe->apTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  sqliteFree(pBe->azTemp);
  sqliteFree(pBe->apTemp);
  memset(pBe, 0, sizeof(*pBe));
  sqliteFree(pBe);
}

/*
** Translate the name of an SQL table (or index) into the name 
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
  char *zFile = 0;
  int i;
  sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
  if( zFile==0 ) return 0;
  for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
    int c = zFile[i];
    if( isupper(c) ){
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
  return zFile;
}

/*
** Generate a random filename with the given prefix.  The new filename
** is written into zBuf[].  The calling function must insure that
** zBuf[] is big enough to hold the prefix plus 20 or so extra
** characters.
**
** Very random names are chosen so that the chance of a
** collision with an existing filename is very very small.
*/
static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){
  int i, j;
  static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  strcpy(zBuf, zPrefix);
  j = strlen(zBuf);
  for(i=0; i<15; i++){
    int c = rc4byte(pRc4) % (sizeof(zRandomChars) - 1);
    zBuf[j++] = zRandomChars[c];
  }
  zBuf[j] = 0;
}

/*
** Open a new table cursor.  Write a pointer to the corresponding
** DbbeCursor structure into *ppCursr.  Return an integer success
** code:
**
**    SQLITE_OK          It worked!
**
**    SQLITE_NOMEM       sqliteMalloc() failed
**
**    SQLITE_PERM        Attempt to access a file for which file
**                       access permission is denied
**
**    SQLITE_BUSY        Another thread or process is already using
**                       the corresponding file and has that file locked.
**
**    SQLITE_READONLY    The current thread already has this file open
**                       readonly but you are trying to open for writing.
**                       (This can happen if a SELECT callback tries to
**                       do an UPDATE or DELETE.)
**
** If zTable is 0 or "", then a temporary database file is created and
** a cursor to that temporary file is opened.  The temporary file
** will be deleted from the disk when it is closed.
*/
static int sqliteGdbmOpenCursor(
  Dbbe *pDbbe,            /* The database the table belongs to */
  const char *zTable,     /* The SQL name of the file to be opened */
  int writeable,          /* True to open for writing */
  DbbeCursor **ppCursr    /* Write the resulting table pointer here */
){
  char *zFile;            /* Name of the table file */
  DbbeCursor *pCursr;     /* The new table cursor */
  BeFile *pFile;          /* The underlying data file for this table */
  int rc = SQLITE_OK;     /* Return value */
  int rw_mask;            /* Permissions mask for opening a table */
  int mode;               /* Mode for opening a table */
  Dbbex *pBe = (Dbbex*)pDbbe;

  *ppCursr = 0;
  pCursr = sqliteMalloc( sizeof(*pCursr) );
  if( pCursr==0 ) return SQLITE_NOMEM;
  if( zTable ){
    zFile = sqliteFileOfTable(pBe, zTable);
    for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
      if( strcmp(pFile->zName,zFile)==0 ) break;
    }
  }else{
    pFile = 0;
    zFile = 0;
  }
  if( pFile==0 ){
    if( writeable ){
      rw_mask = GDBM_WRCREAT | GDBM_FAST;
      mode = 0640;
    }else{
      rw_mask = GDBM_READER;
      mode = 0640;
    }
    pFile = sqliteMalloc( sizeof(*pFile) );
    if( pFile==0 ){
      sqliteFree(zFile);
      return SQLITE_NOMEM;
    }
    if( zFile ){
      if( !writeable || pBe->write ){
        pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
      }else{
        pFile->dbf = 0;
      }
    }else{
      int limit;
      struct rc4 *pRc4;
      char zRandom[50];
      pRc4 = &pBe->rc4;
      zFile = 0;
      limit = 5;
      do {
        randomName(&pBe->rc4, zRandom, "_temp_table_");
        sqliteFree(zFile);
        zFile = sqliteFileOfTable(pBe, zRandom);
        pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
      }while( pFile->dbf==0 && limit-- >= 0);
      pFile->delOnClose = 1;
    }
    pFile->writeable = writeable;
    pFile->zName = zFile;
    pFile->nRef = 1;
    pFile->pPrev = 0;
    if( pBe->pOpen ){
      pBe->pOpen->pPrev = pFile;
    }
    pFile->pNext = pBe->pOpen;
    pBe->pOpen = pFile;
    if( pFile->dbf==0 ){
      if( !writeable && access(zFile,0) ){
        /* Trying to read a non-existant file.  This is OK.  All the
        ** reads will return empty, which is what we want. */
        rc = SQLITE_OK;   
      }else if( pBe->write==0 ){
        rc = SQLITE_READONLY;
      }else if( access(zFile,W_OK|R_OK) ){
        rc = SQLITE_PERM;
      }else{
        rc = SQLITE_BUSY;
      }
    }
  }else{
    sqliteFree(zFile);
    pFile->nRef++;
    if( writeable && !pFile->writeable ){
      rc = SQLITE_READONLY;
    }
  }
  pCursr->pBe = pBe;
  pCursr->pFile = pFile;
  pCursr->readPending = 0;
  pCursr->needRewind = 1;
  if( rc!=SQLITE_OK ){
    sqliteGdbmCloseCursor(pCursr);
    *ppCursr = 0;
  }else{
    *ppCursr = pCursr;
  }
  return rc;
}

/*
** Drop a table from the database.  The file on the disk that corresponds
** to this table is deleted.
*/
static void sqliteGdbmDropTable(Dbbe *pBe, const char *zTable){
  char *zFile;            /* Name of the table file */

  zFile = sqliteFileOfTable((Dbbex*)pBe, zTable);
  unlink(zFile);
  sqliteFree(zFile);
}

/*
** Close a cursor previously opened by sqliteGdbmOpenCursor().
**
** There can be multiple cursors pointing to the same open file.
** The underlying file is not closed until all cursors have been
** closed.  This routine decrements the BeFile.nref field of the
** underlying file and closes the file when nref reaches 0.
*/
static void sqliteGdbmCloseCursor(DbbeCursor *pCursr){
  BeFile *pFile;
  Dbbex *pBe;
  if( pCursr==0 ) return;
  pFile = pCursr->pFile;
  pBe = pCursr->pBe;
  pFile->nRef--;
  if( pFile->dbf!=NULL ){
    gdbm_sync(pFile->dbf);
  }
  if( pFile->nRef<=0 ){
    if( pFile->dbf!=NULL ){
      gdbm_close(pFile->dbf);
    }
    if( pFile->pPrev ){
      pFile->pPrev->pNext = pFile->pNext;
    }else{
      pBe->pOpen = pFile->pNext;
    }
    if( pFile->pNext ){
      pFile->pNext->pPrev = pFile->pPrev;
    }
    if( pFile->delOnClose ){
      unlink(pFile->zName);
    }
    sqliteFree(pFile->zName);
    memset(pFile, 0, sizeof(*pFile));
    sqliteFree(pFile);
  }
  if( pCursr->key.dptr ) free(pCursr->key.dptr);
  if( pCursr->data.dptr ) free(pCursr->data.dptr);
  memset(pCursr, 0, sizeof(*pCursr));
  sqliteFree(pCursr);
}

/*
** Reorganize a table to reduce search times and disk usage.
*/
static int sqliteGdbmReorganizeTable(Dbbe *pBe, const char *zTable){
  DbbeCursor *pCrsr;
  int rc;

  rc = sqliteGdbmOpenCursor(pBe, zTable, 1, &pCrsr);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  if( pCrsr && pCrsr->pFile && pCrsr->pFile->dbf ){
    gdbm_reorganize(pCrsr->pFile->dbf);
  }
  if( pCrsr ){
    sqliteGdbmCloseCursor(pCrsr);
  }
  return SQLITE_OK;
}

/*
** Clear the given datum
*/
static void datumClear(datum *p){
  if( p->dptr ) free(p->dptr);
  p->dptr = 0;
  p->dsize = 0;
}

/*
** Fetch a single record from an open cursor.  Return 1 on success
** and 0 on failure.
*/
static int sqliteGdbmFetch(DbbeCursor *pCursr, int nKey, char *pKey){
  datum key;
  key.dsize = nKey;
  key.dptr = pKey;
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  if( pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, key);
  }
  return pCursr->data.dptr!=0;
}

/*
** Return 1 if the given key is already in the table.  Return 0
** if it is not.
*/
static int sqliteGdbmTest(DbbeCursor *pCursr, int nKey, char *pKey){
  datum key;
  int result = 0;
  key.dsize = nKey;
  key.dptr = pKey;
  if( pCursr->pFile && pCursr->pFile->dbf ){
    result = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return result;
}

/*
** Copy bytes from the current key or data into a buffer supplied by
** the calling function.  Return the number of bytes copied.
*/
static
int sqliteGdbmCopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){
  int n;
  if( offset>=pCursr->key.dsize ) return 0;
  if( offset+size>pCursr->key.dsize ){
    n = pCursr->key.dsize - offset;
  }else{
    n = size;
  }
  memcpy(zBuf, &pCursr->key.dptr[offset], n);
  return n;
}
static
int sqliteGdbmCopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){
  int n;
  if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
    pCursr->readPending = 0;
  }
  if( offset>=pCursr->data.dsize ) return 0;
  if( offset+size>pCursr->data.dsize ){
    n = pCursr->data.dsize - offset;
  }else{
    n = size;
  }
  memcpy(zBuf, &pCursr->data.dptr[offset], n);
  return n;
}

/*
** Return a pointer to bytes from the key or data.  The data returned
** is ephemeral.
*/
static char *sqliteGdbmReadKey(DbbeCursor *pCursr, int offset){
  if( offset<0 || offset>=pCursr->key.dsize ) return "";
  return &pCursr->key.dptr[offset];
}
static char *sqliteGdbmReadData(DbbeCursor *pCursr, int offset){
  if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
    pCursr->readPending = 0;
  }
  if( offset<0 || offset>=pCursr->data.dsize ) return "";
  return &pCursr->data.dptr[offset];
}

/*
** Return the total number of bytes in either data or key.
*/
static int sqliteGdbmKeyLength(DbbeCursor *pCursr){
  return pCursr->key.dsize;
}
static int sqliteGdbmDataLength(DbbeCursor *pCursr){
  if( pCursr->readPending && pCursr->pFile && pCursr->pFile->dbf ){
    pCursr->data = gdbm_fetch(pCursr->pFile->dbf, pCursr->key);
    pCursr->readPending = 0;
  }
  return pCursr->data.dsize;
}

/*
** Make is so that the next call to sqliteNextKey() finds the first
** key of the table.
*/
static int sqliteGdbmRewind(DbbeCursor *pCursr){
  pCursr->needRewind = 1;
  return SQLITE_OK;
}

/*
** Read the next key from the table.  Return 1 on success.  Return
** 0 if there are no more keys.
*/
static int sqliteGdbmNextKey(DbbeCursor *pCursr){
  datum nextkey;
  int rc;
  if( pCursr==0 || pCursr->pFile==0 || pCursr->pFile->dbf==0 ){
    pCursr->readPending = 0;
    return 0;
  }
  if( pCursr->needRewind ){
    nextkey = gdbm_firstkey(pCursr->pFile->dbf);
    pCursr->needRewind = 0;
  }else{
    nextkey = gdbm_nextkey(pCursr->pFile->dbf, pCursr->key);
  }
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  pCursr->key = nextkey;
  if( pCursr->key.dptr ){
    pCursr->readPending = 1;
    rc = 1;
  }else{
    pCursr->needRewind = 1;
    pCursr->readPending = 0;
    rc = 0;
  }
  return rc;
}

/*
** Get a new integer key.
*/
static int sqliteGdbmNew(DbbeCursor *pCursr){
  int iKey;
  datum key;
  int go = 1;
  int i;
  struct rc4 *pRc4;

  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  pRc4 = &pCursr->pBe->rc4;
  while( go ){
    iKey = 0;
    for(i=0; i<4; i++){
      iKey = (iKey<<8) + rc4byte(pRc4);
    }
    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return iKey;
}   

/*
** Write an entry into the table.  Overwrite any prior entry with the
** same key.
*/
static int
sqliteGdbmPut(DbbeCursor *pCursr, int nKey,char *pKey,int nData,char *pData){
  datum data, key;
  int rc;
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  data.dsize = nData;
  data.dptr = pData;
  key.dsize = nKey;
  key.dptr = pKey;
  rc = gdbm_store(pCursr->pFile->dbf, key, data, GDBM_REPLACE);
  if( rc ) rc = SQLITE_ERROR;
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  return rc;
}

/*
** Remove an entry from a table, if the entry exists.
*/
static int sqliteGdbmDelete(DbbeCursor *pCursr, int nKey, char *pKey){
  datum key;
  int rc;
  datumClear(&pCursr->key);
  datumClear(&pCursr->data);
  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return SQLITE_ERROR;
  key.dsize = nKey;
  key.dptr = pKey;
  rc = gdbm_delete(pCursr->pFile->dbf, key);
  if( rc ) rc = SQLITE_ERROR;
  return rc;
}

/*
** Open a temporary file.  The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file.  That works great
** under Unix, but fails when we try to port to Windows.
*/
static int sqliteGdbmOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
  char *zFile;         /* Full name of the temporary file */
  char zBuf[50];       /* Base name of the temporary file */
  int i;               /* Loop counter */
  int limit;           /* Prevent an infinite loop */
  int rc = SQLITE_OK;  /* Value returned by this function */
  Dbbex *pBe = (Dbbex*)pDbbe;

  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==0 ) break;
  }
  if( i>=pBe->nTemp ){
    pBe->nTemp++;
    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
    pBe->azTemp = sqliteRealloc(pBe->azTemp, pBe->nTemp*sizeof(char*) );
  }
  if( pBe->apTemp==0 ){
    *ppFile = 0;
    return SQLITE_NOMEM;
  }
  limit = 4;
  zFile = 0;
  do{
    randomName(&pBe->rc4, zBuf, "/_temp_file_");
    sqliteFree(zFile);
    zFile = 0;
    sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
  }while( access(zFile,0)==0 && limit-- >= 0 );
  *ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
  if( pBe->apTemp[i]==0 ){
    rc = SQLITE_ERROR;
    sqliteFree(zFile);
    pBe->azTemp[i] = 0;
  }else{
    pBe->azTemp[i] = zFile;
  }
  return rc;
}

/*
** Close a temporary file opened using sqliteGdbmOpenTempFile()
*/
static void sqliteGdbmCloseTempFile(Dbbe *pDbbe, FILE *f){
  int i;
  Dbbex *pBe = (Dbbex*)pDbbe;
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==f ){
      unlink(pBe->azTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  fclose(f);
}


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
**
** If successful, a pointer to the Dbbe structure is returned.
** If there are errors, an appropriate error message is left
** in *pzErrMsg and NULL is returned.
*/
Dbbe *sqliteGdbmOpen(
  const char *zName,     /* The name of the database */
  int writeFlag,         /* True if we will be writing to the database */
  int createFlag,        /* True to create database if it doesn't exist */
  char **pzErrMsg        /* Write error messages (if any) here */
){
  Dbbex *pNew;
  struct stat statbuf;
  char *zMaster;

  if( !writeFlag ) createFlag = 0;
  if( stat(zName, &statbuf)!=0 ){
    if( createFlag ) mkdir(zName, 0750);
    if( stat(zName, &statbuf)!=0 ){
      sqliteSetString(pzErrMsg, createFlag ? 
         "can't find or create directory \"" : "can't find directory \"",
         zName, "\"", 0);
      return 0;
    }
  }
  if( !S_ISDIR(statbuf.st_mode) ){
    sqliteSetString(pzErrMsg, "not a directory: \"", zName, "\"", 0);
    return 0;
  }
  if( access(zName, writeFlag ? (X_OK|W_OK|R_OK) : (X_OK|R_OK)) ){
    sqliteSetString(pzErrMsg, "access permission denied", 0);
    return 0;
  }
  zMaster = 0;
  sqliteSetString(&zMaster, zName, "/" MASTER_NAME ".tbl", 0);
  if( stat(zMaster, &statbuf)==0
   && access(zMaster, writeFlag ? (W_OK|R_OK) : R_OK)!=0 ){
    sqliteSetString(pzErrMsg, "access permission denied for ", zMaster, 0);
    sqliteFree(zMaster);
    return 0;
  }
  sqliteFree(zMaster);
  pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->dbbe.Close = sqliteGdbmClose;
  pNew->dbbe.OpenCursor = sqliteGdbmOpenCursor;
  pNew->dbbe.DropTable = sqliteGdbmDropTable;
  pNew->dbbe.ReorganizeTable = sqliteGdbmReorganizeTable;
  pNew->dbbe.CloseCursor = sqliteGdbmCloseCursor;
  pNew->dbbe.Fetch = sqliteGdbmFetch;
  pNew->dbbe.Test = sqliteGdbmTest;
  pNew->dbbe.CopyKey = sqliteGdbmCopyKey;
  pNew->dbbe.CopyData = sqliteGdbmCopyData;
  pNew->dbbe.ReadKey = sqliteGdbmReadKey;
  pNew->dbbe.ReadData = sqliteGdbmReadData;
  pNew->dbbe.KeyLength = sqliteGdbmKeyLength;
  pNew->dbbe.DataLength = sqliteGdbmDataLength;
  pNew->dbbe.NextKey = sqliteGdbmNextKey;
  pNew->dbbe.Rewind = sqliteGdbmRewind;
  pNew->dbbe.New = sqliteGdbmNew;
  pNew->dbbe.Put = sqliteGdbmPut;
  pNew->dbbe.Delete = sqliteGdbmDelete;
  pNew->dbbe.OpenTempFile = sqliteGdbmOpenTempFile;
  pNew->dbbe.CloseTempFile = sqliteGdbmCloseTempFile;
  pNew->zDir = (char*)&pNew[1];
  strcpy(pNew->zDir, zName);
  pNew->write = writeFlag;
  pNew->pOpen = 0;
  time(&statbuf.st_ctime);
  rc4init(&pNew->rc4, (char*)&statbuf, sizeof(statbuf));
  return &pNew->dbbe;
}

Added src/ex/pg.c.









































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.c,v 1.1 2001/02/11 16:56:24 drh Exp $
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "sqliteInt.h"
#include "pg.h"

/*
** Uncomment the following for a debug trace
*/
#if 1
# define TRACE(X)  printf X; fflush(stdout);
#endif  

/*
** Hash table sizes
*/
#define J_HASH_SIZE  127  /* Size of the journal page hash table */
#define PG_HASH_SIZE 349  /* Size of the database page hash table */

/*
** Forward declaration of structure
*/
typedef struct Pghdr Pghdr;

/*
** All information about a single paging file is contained in an
** instance of the following structure.
*/
struct Pgr {
  int fdMain;                    /* The main database file */
  char *zMain;                   /* Name of the database file */
  int fdJournal;                 /* The journal file */
  char *zJournal;                /* Name of the journal file */
  int nMemPg;                    /* Number of memory-resident pages */
  int nJPg;                      /* Number of pages in the journal */
  int nDbPg;                     /* Number of pages in the database */
  int nRefPg;                    /* Number of pages currently in use */
  Pghdr *pLru, *pMru;            /* Least and most recently used mem-page */
  Pghdr *pJidx;                  /* List of journal index pages */
  Pghdr *pAll;                   /* All pages, except journal index pages */
  u32 aJHash[J_HASH_SIZE];       /* Journal page hash table */
  Pghdr *aPgHash[PG_HASH_SIZE];  /* Mem-page hash table */
};

/*
** Each memory-resident page of the paging file has a header which
** is an instance of the following structure.
*/
struct Pghdr {
  Pgr *p;            /* Pointer back to the Pgr structure */
  int nRef;          /* Number of references to this page */
  int isDirty;       /* TRUE if needs to be written to disk */
  u32 dbpgno;        /* Page number in the database file */
  u32 jpgno;         /* Page number in the journal file */
  Pghdr *pNx;        /* Next page on a list of them all */
  Pghdr *pLru;       /* Less recently used pages */
  Pghdr *pMru;       /* More recently used pages */
  Pghdr *pNxHash;    /* Next with same dbpgno hash */
  Pghdr *pPvHash;    /* Previous with the same dbpgno hash */
};

/*
** For a memory-resident page, the page data comes immediately after
** the page header.  The following macros can be used to change a 
** pointer to a page header into a pointer to the data, or vice
** versa.
*/
#define PG_TO_DATA(X)  ((void*)&(X)[1])
#define DATA_TO_PG(X)  (&((Pghdr*)(X))[-1])

/*
** The number of in-memory pages that we accumulate before trying
** to reuse older pages when new ones are requested.
*/
#define MX_MEM_PAGE  100

/*
** The number of journal data pages that come between consecutive 
** journal index pages.
*/
#define N_J_DATAPAGE  (SQLITE_PAGE_SIZE/(2*sizeof(u32)))

/*
** An index page in the journal consists of an array of N_J_DATAPAGE
** of the following structures.  There is one instance of the following
** structure for each of the N_J_DATAPAGE data pages that follow the
** index.
**
** Let the journal page number that a JidxEntry describes be J.  Then
** the JidxEntry.dbpgno field is the page of the database file that
** corresponds to the J page in the journal.  The JidxEntry.next_jpgno
** field hold the number of another journal page that contains
** a database file page with the same hash as JidxEntry.dbpgno.
**
** All information is written to the journal index in big-endian
** notation.
*/
typedef struct JidxEntry JidxEntry;
struct JidxEntry {
  char dbpgno[sizeof(u32)];        /* Database page number for this entry */
  char next_jpgno[sizeof(u32)];    /* Next entry with same hash on dbpgno */
};

/*
** Read a page from a file into memory.  Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to read the page.
** The first page is 1.  Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgRead(int fd, char *zBuf, u32 pgno){
  int got = 0;
  int amt;

  assert( pgno>0 );
  assert( fd>=0 );
  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
  while( got<SQLITE_PAGE_SIZE ){
    amt = read(fd, &zBuf[got], SQLITE_PAGE_SIZE - got);
    if( amt<=0 ){
      memset(&zBuf[got], 0, SQLITE_PAGE_SIZE - got);
      return amt==0 ? SQLITE_OK : SQLITE_IOERR;
    }
    got += amt;
  }
  return SQLITE_OK;
}

/*
** Read a page from a file into memory.  Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to write the page.
** The first page is 1.  Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgWrite(int fd, char *zBuf, u32 pgno){
  int done = 0;
  int amt;

  assert( pgno>0 );
  assert( fd>=0 );
  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
  while( done<SQLITE_PAGE_SIZE ){
    amt = write(fd, &zBuf[done], SQLITE_PAGE_SIZE - done);
    if( amt<=0 ) return SQLITE_IOERR;
    done += amt;
  }
  return SQLITE_OK;
}

/*
** Turn four bytes into an integer.  The first byte is always the
** most significant 8 bits.
*/
static u32 sqlitePgGetInt(const char *p){
  return ((p[0]&0xff)<<24) | ((p[1]&0xff)<<16) | ((p[2]&0xff)<<8) | (p[3]&0xff);
}

/*
** Turn an integer into 4 bytes.  The first byte is always the
** most significant 8 bits.
*/
static void sqlitePgPutInt(u32 v, char *p){
  p[3] = v & 0xff;
  v >>= 8;
  p[2] = v & 0xff;
  v >>= 8;
  p[1] = v & 0xff;
  v >>= 8;
  p[0] = v & 0xff;
}

/*
** Check the hash table for an in-memory page.  Return a pointer to
** the page header if found.  Return NULL if the page is not in memory.
*/
static Pghdr *sqlitePgFind(Pgr *p, u32 pgno){
  int h;
  Pghdr *pPg;

  if( pgno==0 ) return 0;
  h = pgno % PG_HASH_SIZE;
  for(pPg = p->aPgHash[h]; pPg; pPg=pPg->pNxHash){
    if( pPg->dbpgno==pgno ) return pPg;
  }
  TRACE(("PG: data page %u is %#x\n", pgno, (u32)pPg));
  return 0;
}

/*
** Locate and return an index page from the journal.
**
** The first page of a journal is the primary index.  Additional
** index pages are called secondary indices.  Index pages appear
** in the journal as often as needed.  (If SQLITE_PAGE_SIZE==1024,
** then there are 1024/sizeof(int)*2 = 128 database between each
** pair of index pages.)  Journal index pages are not hashed and
** do no appear on the Pgr.pAll list.  Index pages are on the
** Pgr.pJidx list only.  Index pages have Pghdr.dbpgno==0.
**
** If the requested index page is not already in memory, then a
** new memory page is created to hold the index.
**
** This routine will return a NULL pointer if we run out of memory.
*/
static Pghdr *sqlitePgFindJidx(Pgr *p, u32 pgno){
  Pghdr *pPg;

  assert( pgno % (N_J_DATAPAGE+1) == 1 );
  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
    if( pPg->jpgno==pgno ){
      TRACE(("PG: found j-index %u at %#x\n", pgno, (u32)pPg));
      return pPg;
    }
  }
  pPg = sqliteMalloc( sizeof(Pghdr)+SQLITE_PAGE_SIZE );
  if( pPg==0 ) return 0;
  pPg->jpgno = pgno;
  pPg->pNx = p->pJidx;
  p->pJidx = pPg;
  sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pgno);
  TRACE(("PG: create j-index %u at %#x\n", pgno, (u32)pPg));
  return pPg;
}

/*
** Look in the journal to see if the given database page is stored
** in the journal.  If it is, return its journal page number.  If
** not, return 0.
*/
static u32 sqlitePgJournalPageNumber(Pgr *p, u32 dbpgno){
  u32 jpgno;
  
  if( dbpgno==0 ) return 0;
  jpgno = p->aJHash[dbpgno % J_HASH_SIZE];
  while( jpgno!=0 ){
    int idx_num;     /* Which journal index describes page jpgno */
    int ipgno;       /* Page number for the journal index */
    int idx_slot;    /* Which entry in index idx_num describes jpgno */
    Pghdr *pIdxPg;   /* The index page for jpgno */
    JidxEntry *aIdx; /* The data for the index page */

    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
    ipgno = idx_num * (N_J_DATAPAGE + 1) + 1;
    if( ipgno>p->nJPg ){
      jpgno = 0;
      break;
    }
    pIdxPg = sqlitePgFindJidx(p, ipgno);
    assert( pIdxPg!=0 );
    aIdx = PG_TO_DATA(pIdxPg);
    if( dbpgno==sqlitePgGetInt(aIdx[idx_slot].dbpgno) ){
      break;
    }
    jpgno = sqlitePgGetInt(aIdx[idx_slot].next_jpgno);
  }
  return jpgno;
}

/*
** Make a page not dirty by writing it to the journal.
*/
static int sqlitePgMakeClean(Pghdr *pPg){
  Pgr *p = pPg->p;
  int rc;

  assert( pPg->isDirty );
  assert( p->fdJournal>=0 );
  if( pPg->jpgno==0 ){
    int jpgno;       /* A newly allocate page in the journal */
    int idx_num;     /* Which journal index describes page jpgno */
    int idx_slot;    /* Which entry in index idx_num describes jpgno */
    Pghdr *pIdxPg;   /* The index page for jpgno */
    JidxEntry *aIdx; /* The data for the index page */
    int h;           /* The hash value for pPg->dbpgno */

    jpgno = p->nJPg + 1;
    if( jpgno % (N_J_DATAPAGE + 1) == 1 ){
      jpgno++;
    }
    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
    pIdxPg = sqlitePgFindJidx(p, idx_num * (N_J_DATAPAGE + 1) + 1);
    assert( pIdxPg!=0 );
    aIdx = PG_TO_DATA(pIdxPg);
    sqlitePgPutInt(pPg->dbpgno, aIdx[idx_slot].dbpgno);
    h = pPg->dbpgno % J_HASH_SIZE;
    sqlitePgPutInt(p->aJHash[h], aIdx[idx_slot].next_jpgno);
    p->aJHash[h] = jpgno;
    p->nJPg = jpgno;
    pPg->jpgno = jpgno;
    TRACE(("PG: assign d-page %u to j-page %u\n", jpgno, pPg->dbpgno));
  }
  rc = sqlitePgWrite(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
  if( rc==SQLITE_OK ){
    pPg->isDirty = 0;
  }
  return rc;
}

/*
** Find the number of pages in the given file by measuring the size
** of the file.  Return 0 if there is any problem.
*/
static int sqlitePgPageCount(int fd){
  struct stat statbuf;
  if( fstat(fd, &statbuf)!=0 ) return 0;
  return statbuf.st_size/SQLITE_PAGE_SIZE;
}

/*
** This routine reads the journal and transfers pages from the
** journal to the database.
*/
static int sqlitePgJournalPlayback(Pgr *p){
  Pghdr *pPg;
  JidxEntry *aIdx;
  int nJpg;
  int jpgno = 1;
  int i;
  int dbpgno;
  int rc;
  char idx[SQLITE_PAGE_SIZE];
  char pgbuf[SQLITE_PAGE_SIZE];
  
  assert( p->fdJournal>=0 );
  nJpg = sqlitePgPageCount(p->fdJournal);
  while( jpgno<=nJpg ){
    if( !sqlitePgRead(p->fdJournal, idx, jpgno++) ) break;
    aIdx = (JidxEntry*)idx;
    for(i=0; i<N_J_DATAPAGE; i++){
      dbpgno = sqlitePgGetInt(&idx[i]);
      if( dbpgno==0 ){
        jpgno = nJpg+1;
        break;
      }
      pPg = sqlitePgFind(p, dbpgno);
      if( pPg ){
        rc = sqlitePgWrite(p->fdMain, PG_TO_DATA(pPg), dbpgno);
        TRACE(("PG: commit j-page %u to d-page %u from memory\n",jpgno,dbpgno));
      }else{
        rc = sqlitePgRead(p->fdJournal, pgbuf, jpgno);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        rc = sqlitePgWrite(p->fdMain, pgbuf, dbpgno);
        TRACE(("PG: commit j-page %u to d-page %u from disk\n",jpgno,dbpgno));
      }
      jpgno++;
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  TRACE(("PG: commit complete. deleting the journal.\n"));
  fsync(p->fdMain);
  close(p->fdJournal);
  p->fdJournal = -1;
  unlink(p->zJournal);
  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    pPg->isDirty = 0;
    pPg->jpgno = 0;
  }
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  return SQLITE_OK;
}

/*
** Remove the given page from the LRU list.
*/
static void sqlitePgUnlinkLru(Pghdr *pPg){
  Pgr *p = pPg->p;
  if( pPg->pLru ){
    pPg->pLru->pMru = pPg->pLru;
  }
  if( pPg->pMru ){
    pPg->pMru->pLru = pPg->pMru;
  }
  if( p->pLru==pPg ){
    p->pLru = pPg->pLru;
  }
  if( p->pMru==pPg ){
    p->pMru = pPg->pMru;
  }
  pPg->pLru = pPg->pMru = 0;
}

/*
** Open the database file and make *ppPgr pointer to a structure describing it.
** Return SQLITE_OK on success or an error code if there is a failure.
**
** If there was an unfinished commit, complete it before returnning.
*/
int sqlitePgOpen(const char *zFilename, Pgr **ppPgr){
  Pgr *p;
  int n;

  n = strlen(zFilename);
  p = sqliteMalloc( sizeof(*p) + n*2 + 4 );
  if( p==0 ){
    *ppPgr = 0;
    return SQLITE_NOMEM;
  }
  p->zMain = (char*)&p[1];
  strcpy(p->zMain, zFilename);
  p->zJournal = &p->zMain[n+1];
  strcpy(p->zJournal, p->zMain);
  p->zJournal[n] = '~';
  p->zJournal[n+1] = 0;
  p->fdJournal = -1;
  p->fdMain = open(p->zMain, O_CREAT|O_RDWR, 0600);
  if( p->fdMain<0 ){
    *ppPgr = 0;
    sqliteFree(p);
    return SQLITE_PERM;
  }
  p->nDbPg = sqlitePgPageCount(p->fdMain);
  if( access(p->zJournal, R_OK)==0 ){
    sqlitePgJournalPlayback(p);
  }
  *ppPgr = p;
  return SQLITE_OK;
}

/*
** Close the database file.  Any outstanding transactions are abandoned.
*/
int sqlitePgClose(Pgr *p){
  Pghdr *pPg;

  if( p->fdMain ) close(p->fdMain);
  if( p->fdJournal ) close(p->fdJournal);
  unlink(p->zJournal);
  while( (pPg = p->pAll)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  sqliteFree(p);
  return SQLITE_OK;
}

/*
** Begin a new transaction.  Return SQLITE_OK on success or an error
** code if something goes wrong.
*/
int sqlitePgBeginTransaction(Pgr *p){
  assert( p->fdJournal<0 );
  if( p->nRefPg>0 ){
     /* release the read lock */
  }
  /* write lock the database */
  p->fdJournal = open(p->zJournal, O_CREAT|O_EXCL|O_RDWR, 0600);
  if( p->fdJournal<0 ){
    return SQLITE_PERM;
  }
  p->nJPg = 0;
  TRACE(("PG: begin transaction\n"));
  return SQLITE_OK;
}

/*
** Commit the current transaction.  Return SQLITE_OK or an error code.
*/
int sqlitePgCommit(Pgr *p){
  Pghdr *pPrimaryIdx = 0;
  Pghdr *pPg;
  int rc;

  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    if( pPg->isDirty ){
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
    if( pPg->jpgno==1 ){
      pPrimaryIdx = pPg;
    }else{
      TRACE(("PG: writing j-index %u\n", pPg->jpgno));
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  assert( pPrimaryIdx!=0 );
  fsync(p->fdJournal);
  TRACE(("PG: writing j-index %u\n", pPrimaryIdx->jpgno));
  rc = sqlitePgMakeClean(pPrimaryIdx);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  fsync(p->fdJournal);
  rc = sqlitePgJournalPlayback(p);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  /* remove write lock from database */
  if( p->nRefPg>0 ){
    /* acquire read lock on database */
  }
  return SQLITE_OK;
}

/*
** Abandon the current transaction.
*/
int sqlitePgRollback(Pgr *p){
  Pghdr *pPg;

  TRACE(("PG: begin rollback\n"));
  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    if( pPg->isDirty || pPg->jpgno!=0 ){
      pPg->isDirty = 0;
      pPg->jpgno = 0;
      if( pPg->nRef>0 ){
        TRACE(("PG: reloading d-page %u\n", pPg->dbpgno));
        sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
      }else{
        sqlitePgUnlinkLru(pPg);
      }
    }
  }
  close(p->fdJournal);
  p->fdJournal = -1;
  unlink(p->zJournal);
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  p->nDbPg = sqlitePgPageCount(p->fdMain);
  /* remove write lock from database */
  if( p->nRefPg>0 ){
    /* acquire read lock on database */
  }
  return SQLITE_OK;
}

/*
** Get a page from the database.  Return a pointer to the data for that
** page.
**
** A NULL pointer will be returned if we run out of memory.
*/
int sqlitePgGet(Pgr *p, u32 pgno, void **ppData){
  Pghdr *pPg;
  int h;

  pPg = sqlitePgFind(p, pgno);
  if( pPg ){
    pPg->nRef++;
    if( pPg->nRef==1 ){
      sqlitePgUnlinkLru(pPg);
      TRACE(("PG: d-page %u pulled from cache\n", pgno));
    }
    p->nRefPg++;
    if( p->nRefPg==1 ){
      /* Acquire a read lock */
    }
    *ppData = PG_TO_DATA(pPg);
    return SQLITE_OK;
  }
  if( p->nMemPg<MX_MEM_PAGE || p->pLru==0 ){
    pPg = sqliteMalloc( sizeof(Pghdr) + SQLITE_PAGE_SIZE );
    if( pPg==0 ) return SQLITE_NOMEM;
    p->nMemPg++;
    pPg->pNx = p->pAll;
    p->pAll = pPg;
    pPg->p = p;
    TRACE(("PG: new page %d created.\n", p->nMemPg));
  }else{
    int rc;
    pPg = p->pLru;
    if( pPg->isDirty ){
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ) return rc;
    }
    sqlitePgUnlinkLru(pPg);
    h = pPg->dbpgno % PG_HASH_SIZE;
    if( pPg->pPvHash ){
      pPg->pPvHash->pNxHash = pPg->pNxHash;
    }else{
      assert( p->aPgHash[h]==pPg );
      p->aPgHash[h] = pPg->pNxHash;
    }
    if( pPg->pNxHash ){
      pPg->pNxHash->pPvHash = pPg->pPvHash;
    }
    TRACE(("PG: recycling d-page %u to d-page %u\n", pPg->dbpgno, pgno));
  }
  pPg->dbpgno = pgno;
  if( pgno>p->nDbPg ){
    p->nDbPg = pgno;
  }
  h = pgno % PG_HASH_SIZE;
  pPg->pPvHash = 0;
  pPg->pNxHash = p->aPgHash[h];
  if( pPg->pNxHash ){
    pPg->pNxHash->pPvHash = pPg;
  }
  p->aPgHash[h] = pPg;
  pPg->jpgno = sqlitePgJournalPageNumber(p, pgno);
  if( pPg->jpgno!=0 ){
    TRACE(("PG: reading d-page %u content from j-page %u\n", pgno, pPg->jpgno));
    sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
  }else if( pPg->dbpgno!=0 ){
    TRACE(("PG: reading d-page %u from database\n", pgno));
    sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
  }else{
    TRACE(("PG: reading zero page\n");
    memset(PG_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
  }
  pPg->isDirty = 0;
  pPg->nRef = 1;
  p->nRefPg++;
  if( p->nRefPg==1 ){
    /* Acquire a read lock */
  }
  *ppData = PG_TO_DATA(pPg);
  return SQLITE_OK;
}

/*
** Release a reference to a database data page.
*/
int sqlitePgUnref(void *pData){
  Pghdr *pPg = DATA_TO_PG(pData);
  pPg->nRef--;
  assert( pPg->nRef>=0 );
  if( pPg->nRef==0 ){
    Pgr *p = pPg->p;
    pPg->pMru = 0;
    pPg->pLru = p->pLru;
    p->pLru = pPg;
    TRACE(("PG: d-page %u is unused\n", pPg->dbpgno));
    p->nRefPg--;
    if( p->nRefPg==0 ){
      /* Release the read lock */
    }
  }
  return SQLITE_OK;
}

/*
** The database page in the argument has been modified.  Write it back
** to the database file on the next commit.
*/
int sqlitePgTouch(void *pD){
  Pghdr *pPg = DATA_TO_PG(pD);
  assert( pPg->p->fdJournal>=0 );
  if( pPg->isDirty==0 ){
    pPg->isDirty = 1;
    TRACE(("PG: d-page %u is dirty\n", pPg->dbpgno));
  }
  return SQLITE_OK;
}

/*
** Return the number of the first unused page at the end of the
** database file.
*/
int sqlitePgCount(Pgr *p, u32 *pPgno){
  *pPgno = p->nDbPg;
  return SQLITE_OK;
}

/*
** Return the page number associated with the given page.
*/
u32 sqlitePgNum(void *pD){
  Pghdr *pPg = DATA_TO_PG(pD);
  return pPg->dbpgno;
}

Added src/ex/pg.h.

















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.h,v 1.1 2001/02/11 16:56:24 drh Exp $
*/

typedef struct Pgr Pgr;
#define SQLITE_PAGE_SIZE 1024


int sqlitePgOpen(const char *filename, Pgr **pp);
int sqlitePgClose(Pgr*);
int sqlitePgBeginTransaction(Pgr*);
int sqlitePgCommit(Pgr*);
int sqlitePgRollback(Pgr*);
int sqlitePgGet(Pgr*, u32 pgno, void **);
int sqlitePgUnref(void*);
int sqlitePgTouch(void*);
int sqlitePgCount(Pgr*, u32*);
u32 sqlitePgNum(void*);

Changes to src/main.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.24 2001/01/15 22:51:11 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
................................................................................
  ** The following program invokes its callback on the SQL for each
  ** table then goes back and invokes the callback on the
  ** SQL for each index.  The callback will invoke the
  ** parser to build the internal representation of the
  ** database scheme.
  */
  static VdbeOp initProg[] = {
    { OP_OpenTbl,    0, 0,  MASTER_NAME},
    { OP_Next,     0, 9,  0},           /* 1 */
    { OP_Field,    0, 0,  0},
    { OP_String,   0, 0,  "meta"},
    { OP_Ne,       0, 1,  0},
    { OP_Field,    0, 0,  0},
    { OP_Field,    0, 3,  0},
    { OP_Callback, 2, 0,  0},







|







 







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.25 2001/02/11 16:56:24 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
................................................................................
  ** The following program invokes its callback on the SQL for each
  ** table then goes back and invokes the callback on the
  ** SQL for each index.  The callback will invoke the
  ** parser to build the internal representation of the
  ** database scheme.
  */
  static VdbeOp initProg[] = {
    { OP_OpenTbl,  0, 0,  MASTER_NAME},
    { OP_Next,     0, 9,  0},           /* 1 */
    { OP_Field,    0, 0,  0},
    { OP_String,   0, 0,  "meta"},
    { OP_Ne,       0, 1,  0},
    { OP_Field,    0, 0,  0},
    { OP_Field,    0, 3,  0},
    { OP_Callback, 2, 0,  0},

Deleted src/pg.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
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
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.c,v 1.4 2001/01/25 01:45:41 drh Exp $
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "sqliteInt.h"
#include "pg.h"

/*
** Uncomment the following for a debug trace
*/
#if 1
# define TRACE(X)  printf X; fflush(stdout);
#endif  

/*
** Hash table sizes
*/
#define J_HASH_SIZE  127  /* Size of the journal page hash table */
#define PG_HASH_SIZE 349  /* Size of the database page hash table */

/*
** Forward declaration of structure
*/
typedef struct Pghdr Pghdr;

/*
** All information about a single paging file is contained in an
** instance of the following structure.
*/
struct Pgr {
  int fdMain;                    /* The main database file */
  char *zMain;                   /* Name of the database file */
  int fdJournal;                 /* The journal file */
  char *zJournal;                /* Name of the journal file */
  int nMemPg;                    /* Number of memory-resident pages */
  int nJPg;                      /* Number of pages in the journal */
  int nDbPg;                     /* Number of pages in the database */
  int nRefPg;                    /* Number of pages currently in use */
  Pghdr *pLru, *pMru;            /* Least and most recently used mem-page */
  Pghdr *pJidx;                  /* List of journal index pages */
  Pghdr *pAll;                   /* All pages, except journal index pages */
  u32 aJHash[J_HASH_SIZE];       /* Journal page hash table */
  Pghdr *aPgHash[PG_HASH_SIZE];  /* Mem-page hash table */
};

/*
** Each memory-resident page of the paging file has a header which
** is an instance of the following structure.
*/
struct Pghdr {
  Pgr *p;            /* Pointer back to the Pgr structure */
  int nRef;          /* Number of references to this page */
  int isDirty;       /* TRUE if needs to be written to disk */
  u32 dbpgno;        /* Page number in the database file */
  u32 jpgno;         /* Page number in the journal file */
  Pghdr *pNx;        /* Next page on a list of them all */
  Pghdr *pLru;       /* Less recently used pages */
  Pghdr *pMru;       /* More recently used pages */
  Pghdr *pNxHash;    /* Next with same dbpgno hash */
  Pghdr *pPvHash;    /* Previous with the same dbpgno hash */
};

/*
** For a memory-resident page, the page data comes immediately after
** the page header.  The following macros can be used to change a 
** pointer to a page header into a pointer to the data, or vice
** versa.
*/
#define PG_TO_DATA(X)  ((void*)&(X)[1])
#define DATA_TO_PG(X)  (&((Pghdr*)(X))[-1])

/*
** The number of in-memory pages that we accumulate before trying
** to reuse older pages when new ones are requested.
*/
#define MX_MEM_PAGE  100

/*
** The number of journal data pages that come between consecutive 
** journal index pages.
*/
#define N_J_DATAPAGE  (SQLITE_PAGE_SIZE/(2*sizeof(u32)))

/*
** An index page in the journal consists of an array of N_J_DATAPAGE
** of the following structures.  There is one instance of the following
** structure for each of the N_J_DATAPAGE data pages that follow the
** index.
**
** Let the journal page number that a JidxEntry describes be J.  Then
** the JidxEntry.dbpgno field is the page of the database file that
** corresponds to the J page in the journal.  The JidxEntry.next_jpgno
** field hold the number of another journal page that contains
** a database file page with the same hash as JidxEntry.dbpgno.
**
** All information is written to the journal index in big-endian
** notation.
*/
typedef struct JidxEntry JidxEntry;
struct JidxEntry {
  char dbpgno[sizeof(u32)];        /* Database page number for this entry */
  char next_jpgno[sizeof(u32)];    /* Next entry with same hash on dbpgno */
};

/*
** Read a page from a file into memory.  Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to read the page.
** The first page is 1.  Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgRead(int fd, char *zBuf, u32 pgno){
  int got = 0;
  int amt;

  assert( pgno>0 );
  assert( fd>=0 );
  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
  while( got<SQLITE_PAGE_SIZE ){
    amt = read(fd, &zBuf[got], SQLITE_PAGE_SIZE - got);
    if( amt<=0 ){
      memset(&zBuf[got], 0, SQLITE_PAGE_SIZE - got);
      return amt==0 ? SQLITE_OK : SQLITE_IOERR;
    }
    got += amt;
  }
  return SQLITE_OK;
}

/*
** Read a page from a file into memory.  Return SQLITE_OK if successful.
** The "pgno" parameter tells where in the file to write the page.
** The first page is 1.  Files do not contain a page 0 since a page
** number of 0 is used to indicate "no such page".
*/
static int sqlitePgWrite(int fd, char *zBuf, u32 pgno){
  int done = 0;
  int amt;

  assert( pgno>0 );
  assert( fd>=0 );
  lseek(fd, SEEK_SET, (pgno-1)*SQLITE_PAGE_SIZE);
  while( done<SQLITE_PAGE_SIZE ){
    amt = write(fd, &zBuf[done], SQLITE_PAGE_SIZE - done);
    if( amt<=0 ) return SQLITE_IOERR;
    done += amt;
  }
  return SQLITE_OK;
}

/*
** Turn four bytes into an integer.  The first byte is always the
** most significant 8 bits.
*/
static u32 sqlitePgGetInt(const char *p){
  return ((p[0]&0xff)<<24) | ((p[1]&0xff)<<16) | ((p[2]&0xff)<<8) | (p[3]&0xff);
}

/*
** Turn an integer into 4 bytes.  The first byte is always the
** most significant 8 bits.
*/
static void sqlitePgPutInt(u32 v, char *p){
  p[3] = v & 0xff;
  v >>= 8;
  p[2] = v & 0xff;
  v >>= 8;
  p[1] = v & 0xff;
  v >>= 8;
  p[0] = v & 0xff;
}

/*
** Check the hash table for an in-memory page.  Return a pointer to
** the page header if found.  Return NULL if the page is not in memory.
*/
static Pghdr *sqlitePgFind(Pgr *p, u32 pgno){
  int h;
  Pghdr *pPg;

  if( pgno==0 ) return 0;
  h = pgno % PG_HASH_SIZE;
  for(pPg = p->aPgHash[h]; pPg; pPg=pPg->pNxHash){
    if( pPg->dbpgno==pgno ) return pPg;
  }
  TRACE(("PG: data page %u is %#x\n", pgno, (u32)pPg));
  return 0;
}

/*
** Locate and return an index page from the journal.
**
** The first page of a journal is the primary index.  Additional
** index pages are called secondary indices.  Index pages appear
** in the journal as often as needed.  (If SQLITE_PAGE_SIZE==1024,
** then there are 1024/sizeof(int)*2 = 128 database between each
** pair of index pages.)  Journal index pages are not hashed and
** do no appear on the Pgr.pAll list.  Index pages are on the
** Pgr.pJidx list only.  Index pages have Pghdr.dbpgno==0.
**
** If the requested index page is not already in memory, then a
** new memory page is created to hold the index.
**
** This routine will return a NULL pointer if we run out of memory.
*/
static Pghdr *sqlitePgFindJidx(Pgr *p, u32 pgno){
  Pghdr *pPg;

  assert( pgno % (N_J_DATAPAGE+1) == 1 );
  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
    if( pPg->jpgno==pgno ){
      TRACE(("PG: found j-index %u at %#x\n", pgno, (u32)pPg));
      return pPg;
    }
  }
  pPg = sqliteMalloc( sizeof(Pghdr)+SQLITE_PAGE_SIZE );
  if( pPg==0 ) return 0;
  pPg->jpgno = pgno;
  pPg->pNx = p->pJidx;
  p->pJidx = pPg;
  sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pgno);
  TRACE(("PG: create j-index %u at %#x\n", pgno, (u32)pPg));
  return pPg;
}

/*
** Look in the journal to see if the given database page is stored
** in the journal.  If it is, return its journal page number.  If
** not, return 0.
*/
static u32 sqlitePgJournalPageNumber(Pgr *p, u32 dbpgno){
  u32 jpgno;
  
  if( dbpgno==0 ) return 0;
  jpgno = p->aJHash[dbpgno % J_HASH_SIZE];
  while( jpgno!=0 ){
    int idx_num;     /* Which journal index describes page jpgno */
    int ipgno;       /* Page number for the journal index */
    int idx_slot;    /* Which entry in index idx_num describes jpgno */
    Pghdr *pIdxPg;   /* The index page for jpgno */
    JidxEntry *aIdx; /* The data for the index page */

    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
    ipgno = idx_num * (N_J_DATAPAGE + 1) + 1;
    if( ipgno>p->nJPg ){
      jpgno = 0;
      break;
    }
    pIdxPg = sqlitePgFindJidx(p, ipgno);
    assert( pIdxPg!=0 );
    aIdx = PG_TO_DATA(pIdxPg);
    if( dbpgno==sqlitePgGetInt(aIdx[idx_slot].dbpgno) ){
      break;
    }
    jpgno = sqlitePgGetInt(aIdx[idx_slot].next_jpgno);
  }
  return jpgno;
}

/*
** Make a page not dirty by writing it to the journal.
*/
static int sqlitePgMakeClean(Pghdr *pPg){
  Pgr *p = pPg->p;
  int rc;

  assert( pPg->isDirty );
  assert( p->fdJournal>=0 );
  if( pPg->jpgno==0 ){
    int jpgno;       /* A newly allocate page in the journal */
    int idx_num;     /* Which journal index describes page jpgno */
    int idx_slot;    /* Which entry in index idx_num describes jpgno */
    Pghdr *pIdxPg;   /* The index page for jpgno */
    JidxEntry *aIdx; /* The data for the index page */
    int h;           /* The hash value for pPg->dbpgno */

    jpgno = p->nJPg + 1;
    if( jpgno % (N_J_DATAPAGE + 1) == 1 ){
      jpgno++;
    }
    idx_num = (jpgno - 1)/(N_J_DATAPAGE + 1);
    idx_slot = (jpgno - 1) % (N_J_DATAPAGE + 1) - 2;
    pIdxPg = sqlitePgFindJidx(p, idx_num * (N_J_DATAPAGE + 1) + 1);
    assert( pIdxPg!=0 );
    aIdx = PG_TO_DATA(pIdxPg);
    sqlitePgPutInt(pPg->dbpgno, aIdx[idx_slot].dbpgno);
    h = pPg->dbpgno % J_HASH_SIZE;
    sqlitePgPutInt(p->aJHash[h], aIdx[idx_slot].next_jpgno);
    p->aJHash[h] = jpgno;
    p->nJPg = jpgno;
    pPg->jpgno = jpgno;
    TRACE(("PG: assign d-page %u to j-page %u\n", jpgno, pPg->dbpgno));
  }
  rc = sqlitePgWrite(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
  if( rc==SQLITE_OK ){
    pPg->isDirty = 0;
  }
  return rc;
}

/*
** Find the number of pages in the given file by measuring the size
** of the file.  Return 0 if there is any problem.
*/
static int sqlitePgPageCount(int fd){
  struct stat statbuf;
  if( fstat(fd, &statbuf)!=0 ) return 0;
  return statbuf.st_size/SQLITE_PAGE_SIZE;
}

/*
** This routine reads the journal and transfers pages from the
** journal to the database.
*/
static int sqlitePgJournalPlayback(Pgr *p){
  Pghdr *pPg;
  JidxEntry *aIdx;
  int nJpg;
  int jpgno = 1;
  int i;
  int dbpgno;
  int rc;
  char idx[SQLITE_PAGE_SIZE];
  char pgbuf[SQLITE_PAGE_SIZE];
  
  assert( p->fdJournal>=0 );
  nJpg = sqlitePgPageCount(p->fdJournal);
  while( jpgno<=nJpg ){
    if( !sqlitePgRead(p->fdJournal, idx, jpgno++) ) break;
    aIdx = (JidxEntry*)idx;
    for(i=0; i<N_J_DATAPAGE; i++){
      dbpgno = sqlitePgGetInt(&idx[i]);
      if( dbpgno==0 ){
        jpgno = nJpg+1;
        break;
      }
      pPg = sqlitePgFind(p, dbpgno);
      if( pPg ){
        rc = sqlitePgWrite(p->fdMain, PG_TO_DATA(pPg), dbpgno);
        TRACE(("PG: commit j-page %u to d-page %u from memory\n",jpgno,dbpgno));
      }else{
        rc = sqlitePgRead(p->fdJournal, pgbuf, jpgno);
        if( rc!=SQLITE_OK ){
          return rc;
        }
        rc = sqlitePgWrite(p->fdMain, pgbuf, dbpgno);
        TRACE(("PG: commit j-page %u to d-page %u from disk\n",jpgno,dbpgno));
      }
      jpgno++;
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  TRACE(("PG: commit complete. deleting the journal.\n"));
  fsync(p->fdMain);
  close(p->fdJournal);
  p->fdJournal = -1;
  unlink(p->zJournal);
  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    pPg->isDirty = 0;
    pPg->jpgno = 0;
  }
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  return SQLITE_OK;
}

/*
** Remove the given page from the LRU list.
*/
static void sqlitePgUnlinkLru(Pghdr *pPg){
  Pgr *p = pPg->p;
  if( pPg->pLru ){
    pPg->pLru->pMru = pPg->pLru;
  }
  if( pPg->pMru ){
    pPg->pMru->pLru = pPg->pMru;
  }
  if( p->pLru==pPg ){
    p->pLru = pPg->pLru;
  }
  if( p->pMru==pPg ){
    p->pMru = pPg->pMru;
  }
  pPg->pLru = pPg->pMru = 0;
}

/*
** Open the database file and make *ppPgr pointer to a structure describing it.
** Return SQLITE_OK on success or an error code if there is a failure.
**
** If there was an unfinished commit, complete it before returnning.
*/
int sqlitePgOpen(const char *zFilename, Pgr **ppPgr){
  Pgr *p;
  int n;

  n = strlen(zFilename);
  p = sqliteMalloc( sizeof(*p) + n*2 + 4 );
  if( p==0 ){
    *ppPgr = 0;
    return SQLITE_NOMEM;
  }
  p->zMain = (char*)&p[1];
  strcpy(p->zMain, zFilename);
  p->zJournal = &p->zMain[n+1];
  strcpy(p->zJournal, p->zMain);
  p->zJournal[n] = '~';
  p->zJournal[n+1] = 0;
  p->fdJournal = -1;
  p->fdMain = open(p->zMain, O_CREAT|O_RDWR, 0600);
  if( p->fdMain<0 ){
    *ppPgr = 0;
    sqliteFree(p);
    return SQLITE_PERM;
  }
  p->nDbPg = sqlitePgPageCount(p->fdMain);
  if( access(p->zJournal, R_OK)==0 ){
    sqlitePgJournalPlayback(p);
  }
  *ppPgr = p;
  return SQLITE_OK;
}

/*
** Close the database file.  Any outstanding transactions are abandoned.
*/
int sqlitePgClose(Pgr *p){
  Pghdr *pPg;

  if( p->fdMain ) close(p->fdMain);
  if( p->fdJournal ) close(p->fdJournal);
  unlink(p->zJournal);
  while( (pPg = p->pAll)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  sqliteFree(p);
  return SQLITE_OK;
}

/*
** Begin a new transaction.  Return SQLITE_OK on success or an error
** code if something goes wrong.
*/
int sqlitePgBeginTransaction(Pgr *p){
  assert( p->fdJournal<0 );
  if( p->nRefPg>0 ){
     /* release the read lock */
  }
  /* write lock the database */
  p->fdJournal = open(p->zJournal, O_CREAT|O_EXCL|O_RDWR, 0600);
  if( p->fdJournal<0 ){
    return SQLITE_PERM;
  }
  p->nJPg = 0;
  TRACE(("PG: begin transaction\n"));
  return SQLITE_OK;
}

/*
** Commit the current transaction.  Return SQLITE_OK or an error code.
*/
int sqlitePgCommit(Pgr *p){
  Pghdr *pPrimaryIdx = 0;
  Pghdr *pPg;
  int rc;

  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    if( pPg->isDirty ){
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  for(pPg=p->pJidx; pPg; pPg=pPg->pNx){
    if( pPg->jpgno==1 ){
      pPrimaryIdx = pPg;
    }else{
      TRACE(("PG: writing j-index %u\n", pPg->jpgno));
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ){
        return rc;
      }
    }
  }
  assert( pPrimaryIdx!=0 );
  fsync(p->fdJournal);
  TRACE(("PG: writing j-index %u\n", pPrimaryIdx->jpgno));
  rc = sqlitePgMakeClean(pPrimaryIdx);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  fsync(p->fdJournal);
  rc = sqlitePgJournalPlayback(p);
  if( rc!=SQLITE_OK ){
    return rc;
  }
  /* remove write lock from database */
  if( p->nRefPg>0 ){
    /* acquire read lock on database */
  }
  return SQLITE_OK;
}

/*
** Abandon the current transaction.
*/
int sqlitePgRollback(Pgr *p){
  Pghdr *pPg;

  TRACE(("PG: begin rollback\n"));
  for(pPg=p->pAll; pPg; pPg=pPg->pNx){
    if( pPg->isDirty || pPg->jpgno!=0 ){
      pPg->isDirty = 0;
      pPg->jpgno = 0;
      if( pPg->nRef>0 ){
        TRACE(("PG: reloading d-page %u\n", pPg->dbpgno));
        sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
      }else{
        sqlitePgUnlinkLru(pPg);
      }
    }
  }
  close(p->fdJournal);
  p->fdJournal = -1;
  unlink(p->zJournal);
  while( (pPg = p->pJidx)!=0 ){
    p->pAll = pPg->pNx;
    sqliteFree(pPg);
  }
  p->nDbPg = sqlitePgPageCount(p->fdMain);
  /* remove write lock from database */
  if( p->nRefPg>0 ){
    /* acquire read lock on database */
  }
  return SQLITE_OK;
}

/*
** Get a page from the database.  Return a pointer to the data for that
** page.
**
** A NULL pointer will be returned if we run out of memory.
*/
int sqlitePgGet(Pgr *p, u32 pgno, void **ppData){
  Pghdr *pPg;
  int h;

  pPg = sqlitePgFind(p, pgno);
  if( pPg ){
    pPg->nRef++;
    if( pPg->nRef==1 ){
      sqlitePgUnlinkLru(pPg);
      TRACE(("PG: d-page %u pulled from cache\n", pgno));
    }
    p->nRefPg++;
    if( p->nRefPg==1 ){
      /* Acquire a read lock */
    }
    *ppData = PG_TO_DATA(pPg);
    return SQLITE_OK;
  }
  if( p->nMemPg<MX_MEM_PAGE || p->pLru==0 ){
    pPg = sqliteMalloc( sizeof(Pghdr) + SQLITE_PAGE_SIZE );
    if( pPg==0 ) return SQLITE_NOMEM;
    p->nMemPg++;
    pPg->pNx = p->pAll;
    p->pAll = pPg;
    pPg->p = p;
    TRACE(("PG: new page %d created.\n", p->nMemPg));
  }else{
    int rc;
    pPg = p->pLru;
    if( pPg->isDirty ){
      rc = sqlitePgMakeClean(pPg);
      if( rc!=SQLITE_OK ) return rc;
    }
    sqlitePgUnlinkLru(pPg);
    h = pPg->dbpgno % PG_HASH_SIZE;
    if( pPg->pPvHash ){
      pPg->pPvHash->pNxHash = pPg->pNxHash;
    }else{
      assert( p->aPgHash[h]==pPg );
      p->aPgHash[h] = pPg->pNxHash;
    }
    if( pPg->pNxHash ){
      pPg->pNxHash->pPvHash = pPg->pPvHash;
    }
    TRACE(("PG: recycling d-page %u to d-page %u\n", pPg->dbpgno, pgno));
  }
  pPg->dbpgno = pgno;
  if( pgno>p->nDbPg ){
    p->nDbPg = pgno;
  }
  h = pgno % PG_HASH_SIZE;
  pPg->pPvHash = 0;
  pPg->pNxHash = p->aPgHash[h];
  if( pPg->pNxHash ){
    pPg->pNxHash->pPvHash = pPg;
  }
  p->aPgHash[h] = pPg;
  pPg->jpgno = sqlitePgJournalPageNumber(p, pgno);
  if( pPg->jpgno!=0 ){
    TRACE(("PG: reading d-page %u content from j-page %u\n", pgno, pPg->jpgno));
    sqlitePgRead(p->fdJournal, PG_TO_DATA(pPg), pPg->jpgno);
  }else if( pPg->dbpgno!=0 ){
    TRACE(("PG: reading d-page %u from database\n", pgno));
    sqlitePgRead(p->fdMain, PG_TO_DATA(pPg), pPg->dbpgno);
  }else{
    TRACE(("PG: reading zero page\n");
    memset(PG_TO_DATA(pPg), 0, SQLITE_PAGE_SIZE);
  }
  pPg->isDirty = 0;
  pPg->nRef = 1;
  p->nRefPg++;
  if( p->nRefPg==1 ){
    /* Acquire a read lock */
  }
  *ppData = PG_TO_DATA(pPg);
  return SQLITE_OK;
}

/*
** Release a reference to a database data page.
*/
int sqlitePgUnref(void *pData){
  Pghdr *pPg = DATA_TO_PG(pData);
  pPg->nRef--;
  assert( pPg->nRef>=0 );
  if( pPg->nRef==0 ){
    Pgr *p = pPg->p;
    pPg->pMru = 0;
    pPg->pLru = p->pLru;
    p->pLru = pPg;
    TRACE(("PG: d-page %u is unused\n", pPg->dbpgno));
    p->nRefPg--;
    if( p->nRefPg==0 ){
      /* Release the read lock */
    }
  }
  return SQLITE_OK;
}

/*
** The database page in the argument has been modified.  Write it back
** to the database file on the next commit.
*/
int sqlitePgTouch(void *pD){
  Pghdr *pPg = DATA_TO_PG(pD);
  assert( pPg->p->fdJournal>=0 );
  if( pPg->isDirty==0 ){
    pPg->isDirty = 1;
    TRACE(("PG: d-page %u is dirty\n", pPg->dbpgno));
  }
  return SQLITE_OK;
}

/*
** Return the number of the first unused page at the end of the
** database file.
*/
int sqlitePgCount(Pgr *p, u32 *pPgno){
  *pPgno = p->nDbPg;
  return SQLITE_OK;
}

/*
** Return the page number associated with the given page.
*/
u32 sqlitePgNum(void *pD){
  Pghdr *pPg = DATA_TO_PG(pD);
  return pPg->dbpgno;
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































Deleted src/pg.h.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
** Copyright (c) 2001 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** $Id: pg.h,v 1.3 2001/01/21 00:58:09 drh Exp $
*/

typedef struct Pgr Pgr;
#define SQLITE_PAGE_SIZE 1024


int sqlitePgOpen(const char *filename, Pgr **pp);
int sqlitePgClose(Pgr*);
int sqlitePgBeginTransaction(Pgr*);
int sqlitePgCommit(Pgr*);
int sqlitePgRollback(Pgr*);
int sqlitePgGet(Pgr*, u32 pgno, void **);
int sqlitePgUnref(void*);
int sqlitePgTouch(void*);
int sqlitePgCount(Pgr*, u32*);
u32 sqlitePgNum(void*);
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
















































































Changes to src/tokenize.c.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.16 2000/12/10 18:23:51 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <stdlib.h>

/*
** All the keywords of the SQL language are stored as in a hash
................................................................................
  int nErr = 0;
  int i;
  void *pEngine;
  int once = 1;
  static FILE *trace = 0;
  extern void *sqliteParserAlloc(void*(*)(int));
  extern void sqliteParserFree(void*, void(*)(void*));
  extern int sqliteParser(void*, int, ...);
  extern void sqliteParserTrace(FILE*, char *);

  pParse->db->flags &= ~SQLITE_Interrupt;
  pParse->rc = SQLITE_OK;
  i = 0;
  sqliteParseInfoReset(pParse);
  pEngine = sqliteParserAlloc((void*(*)(int))malloc);







|







 







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.17 2001/02/11 16:56:24 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <stdlib.h>

/*
** All the keywords of the SQL language are stored as in a hash
................................................................................
  int nErr = 0;
  int i;
  void *pEngine;
  int once = 1;
  static FILE *trace = 0;
  extern void *sqliteParserAlloc(void*(*)(int));
  extern void sqliteParserFree(void*, void(*)(void*));
  extern int sqliteParser(void*, int, Token, Parse*);
  extern void sqliteParserTrace(FILE*, char *);

  pParse->db->flags &= ~SQLITE_Interrupt;
  pParse->rc = SQLITE_OK;
  i = 0;
  sqliteParseInfoReset(pParse);
  pEngine = sqliteParserAlloc((void*(*)(int))malloc);

Changes to www/changes.tcl.

12
13
14
15
16
17
18











19
20
21
22
23
24
25
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}












chng {2001 Jan 4 (1.0.18)} {
<li>Print the offending SQL statement when an error occurs.</li>
<li>Do not require commas between constraints in CREATE TABLE statements.</li>
<li>Added the "-echo" option to the shell.</li>
<li>Changes to comments.</li>
}







>
>
>
>
>
>
>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}

chng {2001 Feb 11 (1.0.20)} {
<li>Merge development changes into the main trunk.  Future work toward
    using a BTree file structure will use a separate CVS source tree.  This
    CVS tree will continue to support the GDBM version of SQLite only.</li>
}

chng {2001 Feb 6 (1.0.19)} {
<li>Fix a strange (but valid) C declaration that was causing problems
    for QNX.  No logical changes.</li>
}

chng {2001 Jan 4 (1.0.18)} {
<li>Print the offending SQL statement when an error occurs.</li>
<li>Do not require commas between constraints in CREATE TABLE statements.</li>
<li>Added the "-echo" option to the shell.</li>
<li>Changes to comments.</li>
}