1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Refactoring. Split btreeInt.h off from btree.c. Split malloc.c off from

util.c.  Expect much more to follow. (CVS 3925)

FossilOrigin-Name: 16041116aaaa2d52a289aa02a24bef579ba60896
This commit is contained in:
drh
2007-05-05 11:48:52 +00:00
parent 4500c430b0
commit a315289571
12 changed files with 1578 additions and 1483 deletions

View File

@@ -123,7 +123,7 @@ TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1
LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \ LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \
callback.lo complete.lo date.lo \ callback.lo complete.lo date.lo \
delete.lo expr.lo func.lo hash.lo insert.lo loadext.lo \ delete.lo expr.lo func.lo hash.lo insert.lo loadext.lo \
main.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \ main.lo malloc.lo opcodes.lo os.lo os_unix.lo os_win.lo os_os2.lo \
pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \ pager.lo parse.lo pragma.lo prepare.lo printf.lo random.lo \
select.lo table.lo tokenize.lo trigger.lo update.lo \ select.lo table.lo tokenize.lo trigger.lo update.lo \
util.lo vacuum.lo \ util.lo vacuum.lo \
@@ -152,6 +152,7 @@ SRC = \
$(TOP)/src/legacy.c \ $(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \ $(TOP)/src/loadext.c \
$(TOP)/src/main.c \ $(TOP)/src/main.c \
$(TOP)/src/mallo.c \
$(TOP)/src/os.c \ $(TOP)/src/os.c \
$(TOP)/src/os_unix.c \ $(TOP)/src/os_unix.c \
$(TOP)/src/os_win.c \ $(TOP)/src/os_win.c \
@@ -204,6 +205,7 @@ TESTSRC = \
$(TOP)/src/date.c \ $(TOP)/src/date.c \
$(TOP)/src/func.c \ $(TOP)/src/func.c \
$(TOP)/src/insert.c \ $(TOP)/src/insert.c \
$(TOP)/src/malloc.c \
$(TOP)/src/os.c \ $(TOP)/src/os.c \
$(TOP)/src/os_os2.c \ $(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \ $(TOP)/src/os_unix.c \
@@ -238,6 +240,7 @@ TESTSRC = \
HDR = \ HDR = \
sqlite3.h \ sqlite3.h \
$(TOP)/src/btree.h \ $(TOP)/src/btree.h \
$(TOP)/src/btreeInt.h \
$(TOP)/src/hash.h \ $(TOP)/src/hash.h \
opcodes.h \ opcodes.h \
$(TOP)/src/os.h \ $(TOP)/src/os.h \
@@ -366,6 +369,9 @@ loadext.lo: $(TOP)/src/loadext.c $(HDR)
main.lo: $(TOP)/src/main.c $(HDR) main.lo: $(TOP)/src/main.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/main.c $(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/main.c
malloc.lo: $(TOP)/src/malloc.c $(HDR)
$(LTCOMPILE) $(TEMP_STORE) -c $(TOP)/src/malloc.c
pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h pager.lo: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
$(LTCOMPILE) -c $(TOP)/src/pager.c $(LTCOMPILE) -c $(TOP)/src/pager.c

View File

@@ -58,7 +58,7 @@ TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src
LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \ LIBOBJ+= alter.o analyze.o attach.o auth.o btree.o build.o \
callback.o complete.o date.o delete.o \ callback.o complete.o date.o delete.o \
expr.o func.o hash.o insert.o loadext.o \ expr.o func.o hash.o insert.o loadext.o \
main.o opcodes.o os.o os_os2.o os_unix.o os_win.o \ main.o malloc.o opcodes.o os.o os_os2.o os_unix.o os_win.o \
pager.o parse.o pragma.o prepare.o printf.o random.o \ pager.o parse.o pragma.o prepare.o printf.o random.o \
select.o table.o tclsqlite.o tokenize.o trigger.o \ select.o table.o tclsqlite.o tokenize.o trigger.o \
update.o util.o vacuum.o \ update.o util.o vacuum.o \
@@ -87,6 +87,7 @@ SRC = \
$(TOP)/src/legacy.c \ $(TOP)/src/legacy.c \
$(TOP)/src/loadext.c \ $(TOP)/src/loadext.c \
$(TOP)/src/main.c \ $(TOP)/src/main.c \
$(TOP)/src/malloc.c \
$(TOP)/src/os.c \ $(TOP)/src/os.c \
$(TOP)/src/os_os2.c \ $(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \ $(TOP)/src/os_unix.c \
@@ -160,6 +161,7 @@ TESTSRC = \
$(TOP)/src/func.c \ $(TOP)/src/func.c \
$(TOP)/src/insert.c \ $(TOP)/src/insert.c \
$(TOP)/src/main.c \ $(TOP)/src/main.c \
$(TOP)/src/malloc.c \
$(TOP)/src/os.c \ $(TOP)/src/os.c \
$(TOP)/src/os_os2.c \ $(TOP)/src/os_os2.c \
$(TOP)/src/os_unix.c \ $(TOP)/src/os_unix.c \
@@ -194,6 +196,7 @@ TESTSRC = \
HDR = \ HDR = \
sqlite3.h \ sqlite3.h \
$(TOP)/src/btree.h \ $(TOP)/src/btree.h \
$(TOP)/src/btreeInt.h \
$(TOP)/src/hash.h \ $(TOP)/src/hash.h \
opcodes.h \ opcodes.h \
$(TOP)/src/os.h \ $(TOP)/src/os.h \
@@ -319,6 +322,9 @@ loadext.o: $(TOP)/src/loadext.c $(HDR)
main.o: $(TOP)/src/main.c $(HDR) main.o: $(TOP)/src/main.c $(HDR)
$(TCCX) -c $(TOP)/src/main.c $(TCCX) -c $(TOP)/src/main.c
malloc.o: $(TOP)/src/malloc.c $(HDR)
$(TCCX) -c $(TOP)/src/malloc.c
pager.o: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h pager.o: $(TOP)/src/pager.c $(HDR) $(TOP)/src/pager.h
$(TCCX) -c $(TOP)/src/pager.c $(TCCX) -c $(TOP)/src/pager.c

View File

@@ -1,6 +1,6 @@
C Add\sdocumentation\son\sthe\sincremental\svacuum\sfeature.\s(CVS\s3924) C Refactoring.\s\sSplit\sbtreeInt.h\soff\sfrom\sbtree.c.\s\sSplit\smalloc.c\soff\sfrom\nutil.c.\s\sExpect\smuch\smore\sto\sfollow.\s(CVS\s3925)
D 2007-05-04T19:16:30 D 2007-05-05T11:48:53
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 F Makefile.in 80d63bf2c61619ae0e29795948ec19e79f91acc3
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F VERSION 6de5e9812c227f00155cb59af3535017aef3e258 F VERSION 6de5e9812c227f00155cb59af3535017aef3e258
@@ -44,7 +44,7 @@ F ext/fts2/fts2_tokenizer1.c 5c979fe8815f95396beb22b627571da895a025af
F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977 F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387
F main.mk 2bc462dba2a8332a8a831f5ddd718b4ad7aac6c8 F main.mk b9fd506a8ff3abd83b01dff9abdb98948a207f26
F mkdll.sh ed62756baf44babf562a7843588790c02fee2106 F mkdll.sh ed62756baf44babf562a7843588790c02fee2106
F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d
F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5
@@ -59,8 +59,9 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
F src/attach.c f088f8155541ff75542239ec40cf05f3d81390ba F src/attach.c f088f8155541ff75542239ec40cf05f3d81390ba
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
F src/btree.c 1bd7820b84e93ecd7b4364faeb58565c76cf3cad F src/btree.c 7311696faf137cb37421c8e1d0e22e2d3a15de51
F src/btree.h a9cd72b05a14f6be22e057daf954ae548d2bcbe4 F src/btree.h a9cd72b05a14f6be22e057daf954ae548d2bcbe4
F src/btreeInt.h 2de5f19abb59fcc5e87474fe59ef8110cfa0d343
F src/build.c 0dd6f0d0a5d304be91374f4c7228a3e9b00ff7f1 F src/build.c 0dd6f0d0a5d304be91374f4c7228a3e9b00ff7f1
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
@@ -75,6 +76,7 @@ F src/insert.c e595ca26805dfb3a9ebaabc28e7947c479f3b14d
F src/legacy.c 388c71ad7fbcd898ba1bcbfc98a3ac954bfa5d01 F src/legacy.c 388c71ad7fbcd898ba1bcbfc98a3ac954bfa5d01
F src/loadext.c afe4f4755dc49c36ef505748bbdddecb9f1d02a2 F src/loadext.c afe4f4755dc49c36ef505748bbdddecb9f1d02a2
F src/main.c e6eb036c3580ba9116fedfe4a8b58ed63d5abb37 F src/main.c e6eb036c3580ba9116fedfe4a8b58ed63d5abb37
F src/malloc.c b89e31258a85158d15795bf87ae3ba007e56329b
F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217
F src/os.c 4650e98aadd27abfe1698ff58edf6893c58d4881 F src/os.c 4650e98aadd27abfe1698ff58edf6893c58d4881
F src/os.h 9240adf088fd55732f8926f9017601ba3430ead8 F src/os.h 9240adf088fd55732f8926f9017601ba3430ead8
@@ -87,7 +89,7 @@ F src/os_unix.c cb1fb044b84870c7b1b8b2902e9d7be779f8b7ce
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c 5e9e3d2aeed4d6f1b6ae81e866919f4f43b4a23d F src/os_win.c 5e9e3d2aeed4d6f1b6ae81e866919f4f43b4a23d
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c f01e0e577b7b54c3cdba24a30ecc585a805f23fa F src/pager.c 9c9a9df78636f4b9c8e18f90e93337a1231aaef7
F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c
F src/parse.y a5bdc301e970ceb3826b56a84898b8966d5353f8 F src/parse.y a5bdc301e970ceb3826b56a84898b8966d5353f8
F src/pragma.c 3f16c1274bc25afb630b61a3630ea19a2fd0b5dc F src/pragma.c 3f16c1274bc25afb630b61a3630ea19a2fd0b5dc
@@ -99,10 +101,10 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
F src/shell.c d07ae326b3815d80f71c69b3c7584382e47f6447 F src/shell.c d07ae326b3815d80f71c69b3c7584382e47f6447
F src/sqlite.h.in a666300976897eced975b448f722a722b362c6b1 F src/sqlite.h.in a666300976897eced975b448f722a722b362c6b1
F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
F src/sqliteInt.h 93ac1a9f1c8facfd861cf548845d2abc36039670 F src/sqliteInt.h 3ffe2f9c801575e315451e7d2831c4a90a165aa8
F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d
F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b
F src/test1.c ed62a5f1e319bb85232b98b97a438011b96da5a8 F src/test1.c 9fb5a4300897c01add79ff8691114e54e5a83ff0
F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86 F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
@@ -123,7 +125,7 @@ F src/tokenize.c 7d611fc942ca0b12514eea2e1fbb148a65af23f2
F src/trigger.c 420192efe3e6f03addf7897c60c3c8bf913d3493 F src/trigger.c 420192efe3e6f03addf7897c60c3c8bf913d3493
F src/update.c 3359041db390a8f856d67272f299600e2104f350 F src/update.c 3359041db390a8f856d67272f299600e2104f350
F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528 F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528
F src/util.c 9f9fec5dc7ffab8ff982508d03af37269a59ff91 F src/util.c 5eff5cec4ae43490ca3fb97f10a25aac1a5f9b55
F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
F src/vdbe.c 725a808e9bdc317aba963f33054db2dbebdfeecd F src/vdbe.c 725a808e9bdc317aba963f33054db2dbebdfeecd
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
@@ -409,7 +411,7 @@ F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8
F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf
F tool/mkkeywordhash.c fe15d1cbc61c2b0375634b6d8c1ef24520799ea0 F tool/mkkeywordhash.c fe15d1cbc61c2b0375634b6d8c1ef24520799ea0
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
F tool/mksqlite3c.tcl fa0429d32cb0756b23def531ec863bc0e216f375 F tool/mksqlite3c.tcl 3664556f06f7e4acd81552195ea2a9f16b887dcc
F tool/mksqlite3internalh.tcl a85bb0c812db1a060e6e6dfab4e4c817f53d194b F tool/mksqlite3internalh.tcl a85bb0c812db1a060e6e6dfab4e4c817f53d194b
F tool/omittest.tcl e6b3d6a1285f9813bc1dea53bb522b4b72774710 F tool/omittest.tcl e6b3d6a1285f9813bc1dea53bb522b4b72774710
F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
@@ -475,7 +477,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P a0f8adc692839d0645daf0630533a87b0543f6e8 P b3e2cdaed3638f033437b5561705cb253449c392
R 2ab54f3f4a04566149d9fc08dd42a530 R f966d62a9229ee8e5f7295776797e7fa
U drh U drh
Z d993c75ec553297a4f21ca68fdcc08cc Z 93ccb6a5bb856df574c55be8b837f833

View File

@@ -1 +1 @@
b3e2cdaed3638f033437b5561705cb253449c392 16041116aaaa2d52a289aa02a24bef579ba60896

View File

@@ -9,431 +9,27 @@
** May you share freely, never taking more than you give. ** May you share freely, never taking more than you give.
** **
************************************************************************* *************************************************************************
** $Id: btree.c,v 1.375 2007/05/04 19:03:03 danielk1977 Exp $ ** $Id: btree.c,v 1.376 2007/05/05 11:48:54 drh Exp $
** **
** This file implements a external (disk-based) database using BTrees. ** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to ** See the header comment on "btreeInt.h" for additional information.
** ** Including a description of file format and an overview of operation.
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
** "Sorting And Searching", pages 473-480. Addison-Wesley
** Publishing Company, Reading, Massachusetts.
**
** The basic idea is that each page of the file contains N database
** entries and N+1 pointers to subpages.
**
** ----------------------------------------------------------------
** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
** ----------------------------------------------------------------
**
** All of the keys on the page that Ptr(0) points to have values less
** than Key(0). All of the keys on page Ptr(1) and its subpages have
** values greater than Key(0) and less than Key(1). All of the keys
** on Ptr(N) and its subpages have values greater than Key(N-1). And
** so forth.
**
** Finding a particular key requires reading O(log(M)) pages from the
** disk where M is the number of entries in the tree.
**
** In this implementation, a single file can hold one or more separate
** BTrees. Each BTree is identified by the index of its root page. The
** key and data for any entry are combined to form the "payload". A
** fixed amount of payload can be carried directly on the database
** page. If the payload is larger than the preset amount then surplus
** bytes are stored on overflow pages. The payload for an entry
** and the preceding pointer are combined to form a "Cell". Each
** page has a small header which contains the Ptr(N) pointer and other
** information such as the size of key and data.
**
** FORMAT DETAILS
**
** The file is divided into pages. The first page is called page 1,
** the second is page 2, and so forth. A page number of zero indicates
** "no such page". The page size can be anything between 512 and 65536.
** Each page can be either a btree page, a freelist page or an overflow
** page.
**
** The first page is always a btree page. The first 100 bytes of the first
** page contain a special header (the "file header") that describes the file.
** The format of the file header is as follows:
**
** OFFSET SIZE DESCRIPTION
** 0 16 Header string: "SQLite format 3\000"
** 16 2 Page size in bytes.
** 18 1 File format write version
** 19 1 File format read version
** 20 1 Bytes of unused space at the end of each page
** 21 1 Max embedded payload fraction
** 22 1 Min embedded payload fraction
** 23 1 Min leaf payload fraction
** 24 4 File change counter
** 28 4 Reserved for future use
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
**
** All of the integer values are big-endian (most significant byte first).
**
** The file change counter is incremented when the database is changed more
** than once within the same second. This counter, together with the
** modification time of the file, allows other processes to know
** when the file has changed and thus when they need to flush their
** cache.
**
** The max embedded payload fraction is the amount of the total usable
** space in a page that can be consumed by a single cell for standard
** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
** is to limit the maximum cell size so that at least 4 cells will fit
** on one page. Thus the default max embedded payload fraction is 64.
**
** If the payload for a cell is larger than the max payload, then extra
** payload is spilled to overflow pages. Once an overflow page is allocated,
** as many bytes as possible are moved into the overflow pages without letting
** the cell size drop below the min embedded payload fraction.
**
** The min leaf payload fraction is like the min embedded payload fraction
** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
** not specified in the header.
**
** Each btree pages is divided into three sections: The header, the
** cell pointer array, and the cell area area. Page 1 also has a 100-byte
** file header that occurs before the page header.
**
** |----------------|
** | file header | 100 bytes. Page 1 only.
** |----------------|
** | page header | 8 bytes for leaves. 12 bytes for interior nodes
** |----------------|
** | cell pointer | | 2 bytes per cell. Sorted order.
** | array | | Grows downward
** | | v
** |----------------|
** | unallocated |
** | space |
** |----------------| ^ Grows upwards
** | cell content | | Arbitrary order interspersed with freeblocks.
** | area | | and free space fragments.
** |----------------|
**
** The page headers looks like this:
**
** OFFSET SIZE DESCRIPTION
** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
** 1 2 byte offset to the first freeblock
** 3 2 number of cells on this page
** 5 2 first byte of the cell content area
** 7 1 number of fragmented free bytes
** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
**
** The flags define the format of this btree page. The leaf flag means that
** this page has no children. The zerodata flag means that this page carries
** only keys and no data. The intkey flag means that the key is a integer
** which is stored in the key size entry of the cell header rather than in
** the payload area.
**
** The cell pointer array begins on the first byte after the page header.
** The cell pointer array contains zero or more 2-byte numbers which are
** offsets from the beginning of the page to the cell content in the cell
** content area. The cell pointers occur in sorted order. The system strives
** to keep free space after the last cell pointer so that new cells can
** be easily added without having to defragment the page.
**
** Cell content is stored at the very end of the page and grows toward the
** beginning of the page.
**
** Unused space within the cell content area is collected into a linked list of
** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
** to the first freeblock is given in the header. Freeblocks occur in
** increasing order. Because a freeblock must be at least 4 bytes in size,
** any group of 3 or fewer unused bytes in the cell content area cannot
** exist on the freeblock chain. A group of 3 or fewer free bytes is called
** a fragment. The total number of bytes in all fragments is recorded.
** in the page header at offset 7.
**
** SIZE DESCRIPTION
** 2 Byte offset of the next freeblock
** 2 Bytes in this freeblock
**
** Cells are of variable length. Cells are stored in the cell content area at
** the end of the page. Pointers to the cells are in the cell pointer array
** that immediately follows the page header. Cells is not necessarily
** contiguous or in order, but cell pointers are contiguous and in order.
**
** Cell content makes use of variable length integers. A variable
** length integer is 1 to 9 bytes where the lower 7 bits of each
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
** As a special case, all 8 bytes of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
** 0x7f becomes 0x0000007f
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
**
** Variable length integers are used for rowids and to hold the number of
** bytes of key and data in a btree cell.
**
** The content of a cell looks like this:
**
** SIZE DESCRIPTION
** 4 Page number of the left child. Omitted if leaf flag is set.
** var Number of bytes of data. Omitted if the zerodata flag is set.
** var Number of bytes of key. Or the key itself if intkey flag is set.
** * Payload
** 4 First page of the overflow chain. Omitted if no overflow
**
** Overflow pages form a linked list. Each page except the last is completely
** filled with data (pagesize - 4 bytes). The last page can have as little
** as 1 byte of data.
**
** SIZE DESCRIPTION
** 4 Page number of next overflow page
** * Data
**
** Freelist pages come in two subtypes: trunk pages and leaf pages. The
** file header points to first in a linked list of trunk page. Each trunk
** page points to multiple leaf pages. The content of a leaf page is
** unspecified. A trunk page looks like this:
**
** SIZE DESCRIPTION
** 4 Page number of next trunk page
** 4 Number of leaf pointers on this page
** * zero or more pages numbers of leaves
*/ */
#include "sqliteInt.h" #include "btreeInt.h"
#include "pager.h"
#include "btree.h"
#include "os.h"
#include <assert.h>
/* Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x) ((x+7)&~7)
/* The following value is the maximum cell size assuming a maximum page
** size give above.
*/
#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
/* The maximum number of cells on a single page of the database. This
** assumes a minimum cell size of 3 bytes. Such small cells will be
** exceedingly rare, but they are possible.
*/
#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
/* Forward declarations */
typedef struct MemPage MemPage;
typedef struct BtLock BtLock;
/* /*
** This is a magic string that appears at the beginning of every ** The header string that appears at the beginning of every
** SQLite database in order to identify the file as a real database. ** SQLite database.
**
** You can change this value at compile-time by specifying a
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long. If you change
** the header, then your custom library will not be able to read
** databases generated by the standard tools and the standard tools
** will not be able to read databases created by your custom library.
*/ */
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
# define SQLITE_FILE_HEADER "SQLite format 3"
#endif
static const char zMagicHeader[] = SQLITE_FILE_HEADER; static const char zMagicHeader[] = SQLITE_FILE_HEADER;
/*
** Page type flags. An ORed combination of these flags appear as the
** first byte of every BTree page.
*/
#define PTF_INTKEY 0x01
#define PTF_ZERODATA 0x02
#define PTF_LEAFDATA 0x04
#define PTF_LEAF 0x08
/* /*
** As each page of the file is loaded into memory, an instance of the following ** Set this global variable to 1 to enable tracing using the TRACE
** structure is appended and initialized to zero. This structure stores ** macro.
** information about the page that is decoded from the raw file page.
**
** The pParent field points back to the parent page. This allows us to
** walk up the BTree from any leaf to the root. Care must be taken to
** unref() the parent page pointer when this page is no longer referenced.
** The pageDestructor() routine handles that chore.
*/
struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
u8 idxShift; /* True if Cell indices have changed */
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u8 intKey; /* True if intkey flag is set */
u8 leaf; /* True if leaf flag is set */
u8 zeroData; /* True if table stores keys only */
u8 leafData; /* True if tables stores data on leaves only */
u8 hasData; /* True if this page stores data */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u16 maxLocal; /* Copy of Btree.maxLocal or Btree.maxLeaf */
u16 minLocal; /* Copy of Btree.minLocal or Btree.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
u16 idxParent; /* Index in parent of this node */
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
struct _OvflCell { /* Cells that will not fit on aData[] */
u8 *pCell; /* Pointers to the body of the overflow cell */
u16 idx; /* Insert this cell before idx-th non-overflow cell */
} aOvfl[5];
BtShared *pBt; /* Pointer back to BTree structure */
u8 *aData; /* Pointer back to the start of the page */
DbPage *pDbPage; /* Pager page handle */
Pgno pgno; /* Page number for this page */
MemPage *pParent; /* The parent of this page. NULL for root */
};
/*
** The in-memory image of a disk page has the auxiliary information appended
** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
** that extra information.
*/
#define EXTRA_SIZE sizeof(MemPage)
/* Btree handle */
struct Btree {
sqlite3 *pSqlite;
BtShared *pBt;
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
};
/*
** Btree.inTrans may take one of the following values.
**
** If the shared-data extension is enabled, there may be multiple users
** of the Btree structure. At most one of these may open a write transaction,
** but any number may have active read transactions. Variable Btree.pDb
** points to the handle that owns any current write-transaction.
*/
#define TRANS_NONE 0
#define TRANS_READ 1
#define TRANS_WRITE 2
/*
** Everything we need to know about an open database
*/
struct BtShared {
Pager *pPager; /* The page cache */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 maxEmbedFrac; /* Maximum payload as % of total page size */
u8 minEmbedFrac; /* Minimum payload as % of total page size */
u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
#endif
u16 pageSize; /* Total number of bytes on a page */
u16 usableSize; /* Number of usable bytes on each page */
int maxLocal; /* Maximum local payload in non-LEAFDATA tables */
int minLocal; /* Minimum local payload in non-LEAFDATA tables */
int maxLeaf; /* Maximum local payload in a LEAFDATA table */
int minLeaf; /* Minimum local payload in a LEAFDATA table */
BusyHandler *pBusyHandler; /* Callback for when there is lock contention */
u8 inTransaction; /* Transaction state */
int nRef; /* Number of references to this structure */
int nTransaction; /* Number of open transactions (read + write) */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
#ifndef SQLITE_OMIT_SHARED_CACHE
BtLock *pLock; /* List of locks held on this shared-btree struct */
BtShared *pNext; /* Next in ThreadData.pBtree linked list */
#endif
};
/*
** An instance of the following structure is used to hold information
** about a cell. The parseCellPtr() function fills in this structure
** based on information extract from the raw disk page.
*/
typedef struct CellInfo CellInfo;
struct CellInfo {
u8 *pCell; /* Pointer to the start of cell content */
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
u32 nData; /* Number of bytes of data */
u32 nPayload; /* Total amount of payload */
u16 nHeader; /* Size of the cell content header in bytes */
u16 nLocal; /* Amount of payload held locally */
u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
u16 nSize; /* Size of the cell content on the main b-tree page */
};
/*
** A cursor is a pointer to a particular entry in the BTree.
** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
void *pArg; /* First arg to xCompare() */
Pgno pgnoRoot; /* The root page of this tree */
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->aCell[] */
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#ifndef SQLITE_OMIT_INCRBLOB
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */
#endif
};
/*
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
**
** CURSOR_INVALID:
** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
**
** CURSOR_REQUIRESEEK:
** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreOrClearCursorPosition() can be called to attempt to
** seek the cursor to the saved position.
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
#define CURSOR_REQUIRESEEK 2
/*
** The TRACE macro will print high-level status information about the
** btree operation when the global variable sqlite3_btree_trace is
** enabled.
*/ */
#if SQLITE_TEST #if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace )\
/* { sqlite3DebugPrintf X; fflush(stdout); } */ \
{ printf X; fflush(stdout); }
int sqlite3_btree_trace=0; /* True to enable tracing */ int sqlite3_btree_trace=0; /* True to enable tracing */
#else
# define TRACE(X)
#endif #endif
/* /*
@@ -441,66 +37,6 @@ int sqlite3_btree_trace=0; /* True to enable tracing */
*/ */
static int checkReadLocks(Btree*,Pgno,BtCursor*); static int checkReadLocks(Btree*,Pgno,BtCursor*);
/*
** Read or write a two- and four-byte big-endian integer values.
*/
static u32 get2byte(unsigned char *p){
return (p[0]<<8) | p[1];
}
static u32 get4byte(unsigned char *p){
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}
static void put2byte(unsigned char *p, u32 v){
p[0] = v>>8;
p[1] = v;
}
static void put4byte(unsigned char *p, u32 v){
p[0] = v>>24;
p[1] = v>>16;
p[2] = v>>8;
p[3] = v;
}
/*
** Routines to read and write variable-length integers. These used to
** be defined locally, but now we use the varint routines in the util.c
** file.
*/
#define getVarint sqlite3GetVarint
/* #define getVarint32 sqlite3GetVarint32 */
#define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))
#define putVarint sqlite3PutVarint
/* The database page the PENDING_BYTE occupies. This page is never used.
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
** should possibly be consolidated (presumably in pager.h).
**
** If disk I/O is omitted (meaning that the database is stored purely
** in memory) then there is no pending byte.
*/
#ifdef SQLITE_OMIT_DISKIO
# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
#else
# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
#endif
/*
** A linked list of the following structures is stored at BtShared.pLock.
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
** from this list when a transaction is committed or rolled back, or when
** a btree handle is closed.
*/
struct BtLock {
Btree *pBtree; /* Btree handle holding this lock */
Pgno iTable; /* Root page of table */
u8 eLock; /* READ_LOCK or WRITE_LOCK */
BtLock *pNext; /* Next in BtShared.pLock list */
};
/* Candidate values for BtLock.eLock */
#define READ_LOCK 1
#define WRITE_LOCK 2
#ifdef SQLITE_OMIT_SHARED_CACHE #ifdef SQLITE_OMIT_SHARED_CACHE
/* /*
@@ -785,24 +321,10 @@ static int restoreOrClearCursorPositionX(BtCursor *pCur){
#ifndef SQLITE_OMIT_AUTOVACUUM #ifndef SQLITE_OMIT_AUTOVACUUM
/* /*
** These macros define the location of the pointer-map entry for a ** Given a page number of a regular database page, return the page
** database page. The first argument to each is the number of usable ** number for the pointer-map page that contains the entry for the
** bytes on each page of the database (often 1024). The second is the ** input page number.
** page number to look up in the pointer map.
**
** PTRMAP_PAGENO returns the database page number of the pointer-map
** page that stores the required pointer. PTRMAP_PTROFFSET returns
** the offset of the requested map entry.
**
** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
** this test.
*/ */
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
int nPagesPerMapPage = (pBt->usableSize/5)+1; int nPagesPerMapPage = (pBt->usableSize/5)+1;
int iPtrMap = (pgno-2)/nPagesPerMapPage; int iPtrMap = (pgno-2)/nPagesPerMapPage;
@@ -813,43 +335,6 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
return ret; return ret;
} }
/*
** The pointer map is a lookup table that identifies the parent page for
** each child page in the database file. The parent page is the page that
** contains a pointer to the child. Every page in the database contains
** 0 or 1 parent pages. (In this context 'database page' refers
** to any page that is not part of the pointer map itself.) Each pointer map
** entry consists of a single byte 'type' and a 4 byte parent page number.
** The PTRMAP_XXX identifiers below are the valid types.
**
** The purpose of the pointer map is to facility moving pages from one
** position in the file to another as part of autovacuum. When a page
** is moved, the pointer in its parent must be updated to point to the
** new location. The pointer map is used to locate the parent page quickly.
**
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
** used in this case.
**
** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
** is not used in this case.
**
** PTRMAP_OVERFLOW1: The database page is the first page in a list of
** overflow pages. The page number identifies the page that
** contains the cell with a pointer to this overflow page.
**
** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
** overflow pages. The page-number identifies the previous
** page in the overflow page list.
**
** PTRMAP_BTREE: The database page is a non-root btree page. The page number
** identifies the parent page in the btree.
*/
#define PTRMAP_ROOTPAGE 1
#define PTRMAP_FREEPAGE 2
#define PTRMAP_OVERFLOW1 3
#define PTRMAP_OVERFLOW2 4
#define PTRMAP_BTREE 5
/* /*
** Write an entry into the pointer map. ** Write an entry into the pointer map.
** **
@@ -1090,15 +575,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){
#endif #endif
/* A bunch of assert() statements to check the transaction state variables
** of handle p (type Btree*) are internally consistent.
*/
#define btreeIntegrity(p) \
assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \
assert( p->pBt->nTransaction<=p->pBt->nRef ); \
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
assert( p->pBt->inTransaction>=p->inTrans );
/* /*
** Defragment the page given. All Cells are moved to the ** Defragment the page given. All Cells are moved to the
** end of the page and all free space is collected into one ** end of the page and all free space is collected into one
@@ -4767,19 +4243,6 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
} }
#endif /* SQLITE_OMIT_QUICKBALANCE */ #endif /* SQLITE_OMIT_QUICKBALANCE */
/*
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
** if the database supports auto-vacuum or not. Because it is used
** within an expression that is an argument to another macro
** (sqliteMallocRaw), it is not possible to use conditional compilation.
** So, this macro is defined instead.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
#define ISAUTOVACUUM (pBt->autoVacuum)
#else
#define ISAUTOVACUUM 0
#endif
/* /*
** This routine redistributes Cells on pPage and up to NN*2 siblings ** This routine redistributes Cells on pPage and up to NN*2 siblings
** of pPage so that all pages have about the same amount of free space. ** of pPage so that all pages have about the same amount of free space.
@@ -6379,21 +5842,6 @@ Pager *sqlite3BtreePager(Btree *p){
return p->pBt->pPager; return p->pBt->pPager;
} }
/*
** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information.
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */
int mxErr; /* Stop accumulating errors when this reaches zero */
char *zErrMsg; /* An error message. NULL if no errors seen. */
int nErr; /* Number of messages written to zErrMsg so far */
};
#ifndef SQLITE_OMIT_INTEGRITY_CHECK #ifndef SQLITE_OMIT_INTEGRITY_CHECK
/* /*
** Append a message to the error message string. ** Append a message to the error message string.

576
src/btreeInt.h Normal file
View File

@@ -0,0 +1,576 @@
/*
** 2004 April 6
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btreeInt.h,v 1.1 2007/05/05 11:48:54 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
**
** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3:
** "Sorting And Searching", pages 473-480. Addison-Wesley
** Publishing Company, Reading, Massachusetts.
**
** The basic idea is that each page of the file contains N database
** entries and N+1 pointers to subpages.
**
** ----------------------------------------------------------------
** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
** ----------------------------------------------------------------
**
** All of the keys on the page that Ptr(0) points to have values less
** than Key(0). All of the keys on page Ptr(1) and its subpages have
** values greater than Key(0) and less than Key(1). All of the keys
** on Ptr(N) and its subpages have values greater than Key(N-1). And
** so forth.
**
** Finding a particular key requires reading O(log(M)) pages from the
** disk where M is the number of entries in the tree.
**
** In this implementation, a single file can hold one or more separate
** BTrees. Each BTree is identified by the index of its root page. The
** key and data for any entry are combined to form the "payload". A
** fixed amount of payload can be carried directly on the database
** page. If the payload is larger than the preset amount then surplus
** bytes are stored on overflow pages. The payload for an entry
** and the preceding pointer are combined to form a "Cell". Each
** page has a small header which contains the Ptr(N) pointer and other
** information such as the size of key and data.
**
** FORMAT DETAILS
**
** The file is divided into pages. The first page is called page 1,
** the second is page 2, and so forth. A page number of zero indicates
** "no such page". The page size can be anything between 512 and 65536.
** Each page can be either a btree page, a freelist page or an overflow
** page.
**
** The first page is always a btree page. The first 100 bytes of the first
** page contain a special header (the "file header") that describes the file.
** The format of the file header is as follows:
**
** OFFSET SIZE DESCRIPTION
** 0 16 Header string: "SQLite format 3\000"
** 16 2 Page size in bytes.
** 18 1 File format write version
** 19 1 File format read version
** 20 1 Bytes of unused space at the end of each page
** 21 1 Max embedded payload fraction
** 22 1 Min embedded payload fraction
** 23 1 Min leaf payload fraction
** 24 4 File change counter
** 28 4 Reserved for future use
** 32 4 First freelist page
** 36 4 Number of freelist pages in the file
** 40 60 15 4-byte meta values passed to higher layers
**
** All of the integer values are big-endian (most significant byte first).
**
** The file change counter is incremented when the database is changed more
** than once within the same second. This counter, together with the
** modification time of the file, allows other processes to know
** when the file has changed and thus when they need to flush their
** cache.
**
** The max embedded payload fraction is the amount of the total usable
** space in a page that can be consumed by a single cell for standard
** B-tree (non-LEAFDATA) tables. A value of 255 means 100%. The default
** is to limit the maximum cell size so that at least 4 cells will fit
** on one page. Thus the default max embedded payload fraction is 64.
**
** If the payload for a cell is larger than the max payload, then extra
** payload is spilled to overflow pages. Once an overflow page is allocated,
** as many bytes as possible are moved into the overflow pages without letting
** the cell size drop below the min embedded payload fraction.
**
** The min leaf payload fraction is like the min embedded payload fraction
** except that it applies to leaf nodes in a LEAFDATA tree. The maximum
** payload fraction for a LEAFDATA tree is always 100% (or 255) and it
** not specified in the header.
**
** Each btree pages is divided into three sections: The header, the
** cell pointer array, and the cell area area. Page 1 also has a 100-byte
** file header that occurs before the page header.
**
** |----------------|
** | file header | 100 bytes. Page 1 only.
** |----------------|
** | page header | 8 bytes for leaves. 12 bytes for interior nodes
** |----------------|
** | cell pointer | | 2 bytes per cell. Sorted order.
** | array | | Grows downward
** | | v
** |----------------|
** | unallocated |
** | space |
** |----------------| ^ Grows upwards
** | cell content | | Arbitrary order interspersed with freeblocks.
** | area | | and free space fragments.
** |----------------|
**
** The page headers looks like this:
**
** OFFSET SIZE DESCRIPTION
** 0 1 Flags. 1: intkey, 2: zerodata, 4: leafdata, 8: leaf
** 1 2 byte offset to the first freeblock
** 3 2 number of cells on this page
** 5 2 first byte of the cell content area
** 7 1 number of fragmented free bytes
** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
**
** The flags define the format of this btree page. The leaf flag means that
** this page has no children. The zerodata flag means that this page carries
** only keys and no data. The intkey flag means that the key is a integer
** which is stored in the key size entry of the cell header rather than in
** the payload area.
**
** The cell pointer array begins on the first byte after the page header.
** The cell pointer array contains zero or more 2-byte numbers which are
** offsets from the beginning of the page to the cell content in the cell
** content area. The cell pointers occur in sorted order. The system strives
** to keep free space after the last cell pointer so that new cells can
** be easily added without having to defragment the page.
**
** Cell content is stored at the very end of the page and grows toward the
** beginning of the page.
**
** Unused space within the cell content area is collected into a linked list of
** freeblocks. Each freeblock is at least 4 bytes in size. The byte offset
** to the first freeblock is given in the header. Freeblocks occur in
** increasing order. Because a freeblock must be at least 4 bytes in size,
** any group of 3 or fewer unused bytes in the cell content area cannot
** exist on the freeblock chain. A group of 3 or fewer free bytes is called
** a fragment. The total number of bytes in all fragments is recorded.
** in the page header at offset 7.
**
** SIZE DESCRIPTION
** 2 Byte offset of the next freeblock
** 2 Bytes in this freeblock
**
** Cells are of variable length. Cells are stored in the cell content area at
** the end of the page. Pointers to the cells are in the cell pointer array
** that immediately follows the page header. Cells is not necessarily
** contiguous or in order, but cell pointers are contiguous and in order.
**
** Cell content makes use of variable length integers. A variable
** length integer is 1 to 9 bytes where the lower 7 bits of each
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
** As a special case, all 8 bytes of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
** 0x7f becomes 0x0000007f
** 0x81 0x00 becomes 0x00000080
** 0x82 0x00 becomes 0x00000100
** 0x80 0x7f becomes 0x0000007f
** 0x8a 0x91 0xd1 0xac 0x78 becomes 0x12345678
** 0x81 0x81 0x81 0x81 0x01 becomes 0x10204081
**
** Variable length integers are used for rowids and to hold the number of
** bytes of key and data in a btree cell.
**
** The content of a cell looks like this:
**
** SIZE DESCRIPTION
** 4 Page number of the left child. Omitted if leaf flag is set.
** var Number of bytes of data. Omitted if the zerodata flag is set.
** var Number of bytes of key. Or the key itself if intkey flag is set.
** * Payload
** 4 First page of the overflow chain. Omitted if no overflow
**
** Overflow pages form a linked list. Each page except the last is completely
** filled with data (pagesize - 4 bytes). The last page can have as little
** as 1 byte of data.
**
** SIZE DESCRIPTION
** 4 Page number of next overflow page
** * Data
**
** Freelist pages come in two subtypes: trunk pages and leaf pages. The
** file header points to first in a linked list of trunk page. Each trunk
** page points to multiple leaf pages. The content of a leaf page is
** unspecified. A trunk page looks like this:
**
** SIZE DESCRIPTION
** 4 Page number of next trunk page
** 4 Number of leaf pointers on this page
** * zero or more pages numbers of leaves
*/
#include "sqliteInt.h"
#include "pager.h"
#include "btree.h"
#include "os.h"
#include <assert.h>
/* Round up a number to the next larger multiple of 8. This is used
** to force 8-byte alignment on 64-bit architectures.
*/
#define ROUND8(x) ((x+7)&~7)
/* The following value is the maximum cell size assuming a maximum page
** size give above.
*/
#define MX_CELL_SIZE(pBt) (pBt->pageSize-8)
/* The maximum number of cells on a single page of the database. This
** assumes a minimum cell size of 3 bytes. Such small cells will be
** exceedingly rare, but they are possible.
*/
#define MX_CELL(pBt) ((pBt->pageSize-8)/3)
/* Forward declarations */
typedef struct MemPage MemPage;
typedef struct BtLock BtLock;
/*
** This is a magic string that appears at the beginning of every
** SQLite database in order to identify the file as a real database.
**
** You can change this value at compile-time by specifying a
** -DSQLITE_FILE_HEADER="..." on the compiler command-line. The
** header must be exactly 16 bytes including the zero-terminator so
** the string itself should be 15 characters long. If you change
** the header, then your custom library will not be able to read
** databases generated by the standard tools and the standard tools
** will not be able to read databases created by your custom library.
*/
#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */
# define SQLITE_FILE_HEADER "SQLite format 3"
#endif
/*
** Page type flags. An ORed combination of these flags appear as the
** first byte of every BTree page.
*/
#define PTF_INTKEY 0x01
#define PTF_ZERODATA 0x02
#define PTF_LEAFDATA 0x04
#define PTF_LEAF 0x08
/*
** As each page of the file is loaded into memory, an instance of the following
** structure is appended and initialized to zero. This structure stores
** information about the page that is decoded from the raw file page.
**
** The pParent field points back to the parent page. This allows us to
** walk up the BTree from any leaf to the root. Care must be taken to
** unref() the parent page pointer when this page is no longer referenced.
** The pageDestructor() routine handles that chore.
*/
struct MemPage {
u8 isInit; /* True if previously initialized. MUST BE FIRST! */
u8 idxShift; /* True if Cell indices have changed */
u8 nOverflow; /* Number of overflow cell bodies in aCell[] */
u8 intKey; /* True if intkey flag is set */
u8 leaf; /* True if leaf flag is set */
u8 zeroData; /* True if table stores keys only */
u8 leafData; /* True if tables stores data on leaves only */
u8 hasData; /* True if this page stores data */
u8 hdrOffset; /* 100 for page 1. 0 otherwise */
u8 childPtrSize; /* 0 if leaf==1. 4 if leaf==0 */
u16 maxLocal; /* Copy of Btree.maxLocal or Btree.maxLeaf */
u16 minLocal; /* Copy of Btree.minLocal or Btree.minLeaf */
u16 cellOffset; /* Index in aData of first cell pointer */
u16 idxParent; /* Index in parent of this node */
u16 nFree; /* Number of free bytes on the page */
u16 nCell; /* Number of cells on this page, local and ovfl */
struct _OvflCell { /* Cells that will not fit on aData[] */
u8 *pCell; /* Pointers to the body of the overflow cell */
u16 idx; /* Insert this cell before idx-th non-overflow cell */
} aOvfl[5];
BtShared *pBt; /* Pointer back to BTree structure */
u8 *aData; /* Pointer back to the start of the page */
DbPage *pDbPage; /* Pager page handle */
Pgno pgno; /* Page number for this page */
MemPage *pParent; /* The parent of this page. NULL for root */
};
/*
** The in-memory image of a disk page has the auxiliary information appended
** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
** that extra information.
*/
#define EXTRA_SIZE sizeof(MemPage)
/* Btree handle */
struct Btree {
sqlite3 *pSqlite;
BtShared *pBt;
u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */
};
/*
** Btree.inTrans may take one of the following values.
**
** If the shared-data extension is enabled, there may be multiple users
** of the Btree structure. At most one of these may open a write transaction,
** but any number may have active read transactions. Variable Btree.pDb
** points to the handle that owns any current write-transaction.
*/
#define TRANS_NONE 0
#define TRANS_READ 1
#define TRANS_WRITE 2
/*
** Everything we need to know about an open database
*/
struct BtShared {
Pager *pPager; /* The page cache */
BtCursor *pCursor; /* A list of all open cursors */
MemPage *pPage1; /* First page of the database */
u8 inStmt; /* True if we are in a statement subtransaction */
u8 readOnly; /* True if the underlying file is readonly */
u8 maxEmbedFrac; /* Maximum payload as % of total page size */
u8 minEmbedFrac; /* Minimum payload as % of total page size */
u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
u8 pageSizeFixed; /* True if the page size can no longer be changed */
#ifndef SQLITE_OMIT_AUTOVACUUM
u8 autoVacuum; /* True if auto-vacuum is enabled */
u8 incrVacuum; /* True if incr-vacuum is enabled */
Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
#endif
u16 pageSize; /* Total number of bytes on a page */
u16 usableSize; /* Number of usable bytes on each page */
int maxLocal; /* Maximum local payload in non-LEAFDATA tables */
int minLocal; /* Minimum local payload in non-LEAFDATA tables */
int maxLeaf; /* Maximum local payload in a LEAFDATA table */
int minLeaf; /* Minimum local payload in a LEAFDATA table */
BusyHandler *pBusyHandler; /* Callback for when there is lock contention */
u8 inTransaction; /* Transaction state */
int nRef; /* Number of references to this structure */
int nTransaction; /* Number of open transactions (read + write) */
void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */
void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */
#ifndef SQLITE_OMIT_SHARED_CACHE
BtLock *pLock; /* List of locks held on this shared-btree struct */
BtShared *pNext; /* Next in ThreadData.pBtree linked list */
#endif
};
/*
** An instance of the following structure is used to hold information
** about a cell. The parseCellPtr() function fills in this structure
** based on information extract from the raw disk page.
*/
typedef struct CellInfo CellInfo;
struct CellInfo {
u8 *pCell; /* Pointer to the start of cell content */
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
u32 nData; /* Number of bytes of data */
u32 nPayload; /* Total amount of payload */
u16 nHeader; /* Size of the cell content header in bytes */
u16 nLocal; /* Amount of payload held locally */
u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
u16 nSize; /* Size of the cell content on the main b-tree page */
};
/*
** A cursor is a pointer to a particular entry in the BTree.
** The entry is identified by its MemPage and the index in
** MemPage.aCell[] of the entry.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */
int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */
void *pArg; /* First arg to xCompare() */
Pgno pgnoRoot; /* The root page of this tree */
MemPage *pPage; /* Page that contains the entry */
int idx; /* Index of the entry in pPage->aCell[] */
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */
#ifndef SQLITE_OMIT_INCRBLOB
u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */
Pgno *aOverflow; /* Cache of overflow page locations */
#endif
};
/*
** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
**
** CURSOR_INVALID:
** Cursor does not point to a valid entry. This can happen (for example)
** because the table is empty or because BtreeCursorFirst() has not been
** called.
**
** CURSOR_REQUIRESEEK:
** The table that this cursor was opened on still exists, but has been
** modified since the cursor was last used. The cursor position is saved
** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in
** this state, restoreOrClearCursorPosition() can be called to attempt to
** seek the cursor to the saved position.
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
#define CURSOR_REQUIRESEEK 2
/*
** The TRACE macro will print high-level status information about the
** btree operation when the global variable sqlite3_btree_trace is
** enabled.
*/
#if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace ){ printf X; fflush(stdout); }
#else
# define TRACE(X)
#endif
/*
** Routines to read and write variable-length integers. These used to
** be defined locally, but now we use the varint routines in the util.c
** file.
*/
#define getVarint sqlite3GetVarint
#define getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))
#define putVarint sqlite3PutVarint
/* The database page the PENDING_BYTE occupies. This page is never used.
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
** should possibly be consolidated (presumably in pager.h).
**
** If disk I/O is omitted (meaning that the database is stored purely
** in memory) then there is no pending byte.
*/
#ifdef SQLITE_OMIT_DISKIO
# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
#else
# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
#endif
/*
** A linked list of the following structures is stored at BtShared.pLock.
** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor
** is opened on the table with root page BtShared.iTable. Locks are removed
** from this list when a transaction is committed or rolled back, or when
** a btree handle is closed.
*/
struct BtLock {
Btree *pBtree; /* Btree handle holding this lock */
Pgno iTable; /* Root page of table */
u8 eLock; /* READ_LOCK or WRITE_LOCK */
BtLock *pNext; /* Next in BtShared.pLock list */
};
/* Candidate values for BtLock.eLock */
#define READ_LOCK 1
#define WRITE_LOCK 2
/*
** These macros define the location of the pointer-map entry for a
** database page. The first argument to each is the number of usable
** bytes on each page of the database (often 1024). The second is the
** page number to look up in the pointer map.
**
** PTRMAP_PAGENO returns the database page number of the pointer-map
** page that stores the required pointer. PTRMAP_PTROFFSET returns
** the offset of the requested map entry.
**
** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,
** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements
** this test.
*/
#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)
#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))
#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))
/*
** The pointer map is a lookup table that identifies the parent page for
** each child page in the database file. The parent page is the page that
** contains a pointer to the child. Every page in the database contains
** 0 or 1 parent pages. (In this context 'database page' refers
** to any page that is not part of the pointer map itself.) Each pointer map
** entry consists of a single byte 'type' and a 4 byte parent page number.
** The PTRMAP_XXX identifiers below are the valid types.
**
** The purpose of the pointer map is to facility moving pages from one
** position in the file to another as part of autovacuum. When a page
** is moved, the pointer in its parent must be updated to point to the
** new location. The pointer map is used to locate the parent page quickly.
**
** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not
** used in this case.
**
** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number
** is not used in this case.
**
** PTRMAP_OVERFLOW1: The database page is the first page in a list of
** overflow pages. The page number identifies the page that
** contains the cell with a pointer to this overflow page.
**
** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of
** overflow pages. The page-number identifies the previous
** page in the overflow page list.
**
** PTRMAP_BTREE: The database page is a non-root btree page. The page number
** identifies the parent page in the btree.
*/
#define PTRMAP_ROOTPAGE 1
#define PTRMAP_FREEPAGE 2
#define PTRMAP_OVERFLOW1 3
#define PTRMAP_OVERFLOW2 4
#define PTRMAP_BTREE 5
/* A bunch of assert() statements to check the transaction state variables
** of handle p (type Btree*) are internally consistent.
*/
#define btreeIntegrity(p) \
assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \
assert( p->pBt->nTransaction<=p->pBt->nRef ); \
assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \
assert( p->pBt->inTransaction>=p->inTrans );
/*
** The ISAUTOVACUUM macro is used within balance_nonroot() to determine
** if the database supports auto-vacuum or not. Because it is used
** within an expression that is an argument to another macro
** (sqliteMallocRaw), it is not possible to use conditional compilation.
** So, this macro is defined instead.
*/
#ifndef SQLITE_OMIT_AUTOVACUUM
#define ISAUTOVACUUM (pBt->autoVacuum)
#else
#define ISAUTOVACUUM 0
#endif
/*
** This structure is passed around through all the sanity checking routines
** in order to keep track of some global state information.
*/
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
BtShared *pBt; /* The tree being checked out */
Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */
int nPage; /* Number of pages in the database */
int *anRef; /* Number of times each page is referenced */
int mxErr; /* Stop accumulating errors when this reaches zero */
char *zErrMsg; /* An error message. NULL if no errors seen. */
int nErr; /* Number of messages written to zErrMsg so far */
};
/*
** Read or write a two- and four-byte big-endian integer values.
*/
#define get2byte sqlite3Get2byte
#define get4byte sqlite3Get4byte
#define put2byte sqlite3Put2byte
#define put4byte sqlite3Put4byte

839
src/malloc.c Normal file
View File

@@ -0,0 +1,839 @@
/*
** 2001 September 15
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** Memory allocation functions used throughout sqlite.
**
**
** $Id: malloc.c,v 1.1 2007/05/05 11:48:54 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <stdarg.h>
#include <ctype.h>
/*
** MALLOC WRAPPER ARCHITECTURE
**
** The sqlite code accesses dynamic memory allocation/deallocation by invoking
** the following six APIs (which may be implemented as macros).
**
** sqlite3Malloc()
** sqlite3MallocRaw()
** sqlite3Realloc()
** sqlite3ReallocOrFree()
** sqlite3Free()
** sqlite3AllocSize()
**
** The function sqlite3FreeX performs the same task as sqlite3Free and is
** guaranteed to be a real function. The same holds for sqlite3MallocX
**
** The above APIs are implemented in terms of the functions provided in the
** operating-system interface. The OS interface is never accessed directly
** by code outside of this file.
**
** sqlite3OsMalloc()
** sqlite3OsRealloc()
** sqlite3OsFree()
** sqlite3OsAllocationSize()
**
** Functions sqlite3MallocRaw() and sqlite3Realloc() may invoke
** sqlite3_release_memory() if a call to sqlite3OsMalloc() or
** sqlite3OsRealloc() fails (or if the soft-heap-limit for the thread is
** exceeded). Function sqlite3Malloc() usually invokes
** sqlite3MallocRaw().
**
** MALLOC TEST WRAPPER ARCHITECTURE
**
** The test wrapper provides extra test facilities to ensure the library
** does not leak memory and handles the failure of the underlying OS level
** allocation system correctly. It is only present if the library is
** compiled with the SQLITE_MEMDEBUG macro set.
**
** * Guardposts to detect overwrites.
** * Ability to cause a specific Malloc() or Realloc() to fail.
** * Audit outstanding memory allocations (i.e check for leaks).
*/
#define MAX(x,y) ((x)>(y)?(x):(y))
#if defined(SQLITE_ENABLE_MEMORY_MANAGEMENT) && !defined(SQLITE_OMIT_DISKIO)
/*
** Set the soft heap-size limit for the current thread. Passing a negative
** value indicates no limit.
*/
void sqlite3_soft_heap_limit(int n){
ThreadData *pTd = sqlite3ThreadData();
if( pTd ){
pTd->nSoftHeapLimit = n;
}
sqlite3ReleaseThreadData();
}
/*
** Release memory held by SQLite instances created by the current thread.
*/
int sqlite3_release_memory(int n){
return sqlite3PagerReleaseMemory(n);
}
#else
/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version
** of sqlite3_release_memory() to be used by other code in this file.
** This is done for no better reason than to reduce the number of
** pre-processor #ifndef statements.
*/
#define sqlite3_release_memory(x) 0 /* 0 == no memory freed */
#endif
#ifdef SQLITE_MEMDEBUG
/*--------------------------------------------------------------------------
** Begin code for memory allocation system test layer.
**
** Memory debugging is turned on by defining the SQLITE_MEMDEBUG macro.
**
** SQLITE_MEMDEBUG==1 -> Fence-posting only (thread safe)
** SQLITE_MEMDEBUG==2 -> Fence-posting + linked list of allocations (not ts)
** SQLITE_MEMDEBUG==3 -> Above + backtraces (not thread safe, req. glibc)
*/
/* Figure out whether or not to store backtrace() information for each malloc.
** The backtrace() function is only used if SQLITE_MEMDEBUG is set to 2 or
** greater and glibc is in use. If we don't want to use backtrace(), then just
** define it as an empty macro and set the amount of space reserved to 0.
*/
#if defined(__GLIBC__) && SQLITE_MEMDEBUG>2
extern int backtrace(void **, int);
#define TESTALLOC_STACKSIZE 128
#define TESTALLOC_STACKFRAMES ((TESTALLOC_STACKSIZE-8)/sizeof(void*))
#else
#define backtrace(x, y)
#define TESTALLOC_STACKSIZE 0
#define TESTALLOC_STACKFRAMES 0
#endif
/*
** Number of 32-bit guard words. This should probably be a multiple of
** 2 since on 64-bit machines we want the value returned by sqliteMalloc()
** to be 8-byte aligned.
*/
#ifndef TESTALLOC_NGUARD
# define TESTALLOC_NGUARD 2
#endif
/*
** Size reserved for storing file-name along with each malloc()ed blob.
*/
#define TESTALLOC_FILESIZE 64
/*
** Size reserved for storing the user string. Each time a Malloc() or Realloc()
** call succeeds, up to TESTALLOC_USERSIZE bytes of the string pointed to by
** sqlite3_malloc_id are stored along with the other test system metadata.
*/
#define TESTALLOC_USERSIZE 64
const char *sqlite3_malloc_id = 0;
/*
** Blocks used by the test layer have the following format:
**
** <sizeof(void *) pNext pointer>
** <sizeof(void *) pPrev pointer>
** <TESTALLOC_NGUARD 32-bit guard words>
** <The application level allocation>
** <TESTALLOC_NGUARD 32-bit guard words>
** <32-bit line number>
** <TESTALLOC_FILESIZE bytes containing null-terminated file name>
** <TESTALLOC_STACKSIZE bytes of backtrace() output>
*/
#define TESTALLOC_OFFSET_GUARD1(p) (sizeof(void *) * 2)
#define TESTALLOC_OFFSET_DATA(p) ( \
TESTALLOC_OFFSET_GUARD1(p) + sizeof(u32) * TESTALLOC_NGUARD \
)
#define TESTALLOC_OFFSET_GUARD2(p) ( \
TESTALLOC_OFFSET_DATA(p) + sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD \
)
#define TESTALLOC_OFFSET_LINENUMBER(p) ( \
TESTALLOC_OFFSET_GUARD2(p) + sizeof(u32) * TESTALLOC_NGUARD \
)
#define TESTALLOC_OFFSET_FILENAME(p) ( \
TESTALLOC_OFFSET_LINENUMBER(p) + sizeof(u32) \
)
#define TESTALLOC_OFFSET_USER(p) ( \
TESTALLOC_OFFSET_FILENAME(p) + TESTALLOC_FILESIZE \
)
#define TESTALLOC_OFFSET_STACK(p) ( \
TESTALLOC_OFFSET_USER(p) + TESTALLOC_USERSIZE + 8 - \
(TESTALLOC_OFFSET_USER(p) % 8) \
)
#define TESTALLOC_OVERHEAD ( \
sizeof(void *)*2 + /* pPrev and pNext pointers */ \
TESTALLOC_NGUARD*sizeof(u32)*2 + /* Guard words */ \
sizeof(u32) + TESTALLOC_FILESIZE + /* File and line number */ \
TESTALLOC_USERSIZE + /* User string */ \
TESTALLOC_STACKSIZE /* backtrace() stack */ \
)
/*
** For keeping track of the number of mallocs and frees. This
** is used to check for memory leaks. The iMallocFail and iMallocReset
** values are used to simulate malloc() failures during testing in
** order to verify that the library correctly handles an out-of-memory
** condition.
*/
int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */
int sqlite3_nFree; /* Number of sqliteFree() calls */
int sqlite3_memUsed; /* TODO Total memory obtained from malloc */
int sqlite3_memMax; /* TODO Mem usage high-water mark */
int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */
int sqlite3_iMallocReset = -1; /* When iMallocFail reaches 0, set to this */
void *sqlite3_pFirst = 0; /* Pointer to linked list of allocations */
int sqlite3_nMaxAlloc = 0; /* High water mark of ThreadData.nAlloc */
int sqlite3_mallocDisallowed = 0; /* assert() in sqlite3Malloc() if set */
int sqlite3_isFail = 0; /* True if all malloc calls should fail */
const char *sqlite3_zFile = 0; /* Filename to associate debug info with */
int sqlite3_iLine = 0; /* Line number for debug info */
/*
** Check for a simulated memory allocation failure. Return true if
** the failure should be simulated. Return false to proceed as normal.
*/
int sqlite3TestMallocFail(){
if( sqlite3_isFail ){
return 1;
}
if( sqlite3_iMallocFail>=0 ){
sqlite3_iMallocFail--;
if( sqlite3_iMallocFail==0 ){
sqlite3_iMallocFail = sqlite3_iMallocReset;
sqlite3_isFail = 1;
return 1;
}
}
return 0;
}
/*
** The argument is a pointer returned by sqlite3OsMalloc() or xRealloc().
** assert() that the first and last (TESTALLOC_NGUARD*4) bytes are set to the
** values set by the applyGuards() function.
*/
static void checkGuards(u32 *p)
{
int i;
char *zAlloc = (char *)p;
char *z;
/* First set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
assert(((u32 *)z)[i]==0xdead1122);
}
/* Second set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
u32 guard = 0;
memcpy(&guard, &z[i*sizeof(u32)], sizeof(u32));
assert(guard==0xdead3344);
}
}
/*
** The argument is a pointer returned by sqlite3OsMalloc() or Realloc(). The
** first and last (TESTALLOC_NGUARD*4) bytes are set to known values for use as
** guard-posts.
*/
static void applyGuards(u32 *p)
{
int i;
char *z;
char *zAlloc = (char *)p;
/* First set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD1(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
((u32 *)z)[i] = 0xdead1122;
}
/* Second set of guard words */
z = &zAlloc[TESTALLOC_OFFSET_GUARD2(p)];
for(i=0; i<TESTALLOC_NGUARD; i++){
static const int guard = 0xdead3344;
memcpy(&z[i*sizeof(u32)], &guard, sizeof(u32));
}
/* Line number */
z = &((char *)z)[TESTALLOC_NGUARD*sizeof(u32)]; /* Guard words */
z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
memcpy(z, &sqlite3_iLine, sizeof(u32));
/* File name */
z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
strncpy(z, sqlite3_zFile, TESTALLOC_FILESIZE);
z[TESTALLOC_FILESIZE - 1] = '\0';
/* User string */
z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
z[0] = 0;
if( sqlite3_malloc_id ){
strncpy(z, sqlite3_malloc_id, TESTALLOC_USERSIZE);
z[TESTALLOC_USERSIZE-1] = 0;
}
/* backtrace() stack */
z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
backtrace((void **)z, TESTALLOC_STACKFRAMES);
/* Sanity check to make sure checkGuards() is working */
checkGuards(p);
}
/*
** The argument is a malloc()ed pointer as returned by the test-wrapper.
** Return a pointer to the Os level allocation.
*/
static void *getOsPointer(void *p)
{
char *z = (char *)p;
return (void *)(&z[-1 * TESTALLOC_OFFSET_DATA(p)]);
}
#if SQLITE_MEMDEBUG>1
/*
** The argument points to an Os level allocation. Link it into the threads list
** of allocations.
*/
static void linkAlloc(void *p){
void **pp = (void **)p;
pp[0] = 0;
pp[1] = sqlite3_pFirst;
if( sqlite3_pFirst ){
((void **)sqlite3_pFirst)[0] = p;
}
sqlite3_pFirst = p;
}
/*
** The argument points to an Os level allocation. Unlinke it from the threads
** list of allocations.
*/
static void unlinkAlloc(void *p)
{
void **pp = (void **)p;
if( p==sqlite3_pFirst ){
assert(!pp[0]);
assert(!pp[1] || ((void **)(pp[1]))[0]==p);
sqlite3_pFirst = pp[1];
if( sqlite3_pFirst ){
((void **)sqlite3_pFirst)[0] = 0;
}
}else{
void **pprev = pp[0];
void **pnext = pp[1];
assert(pprev);
assert(pprev[1]==p);
pprev[1] = (void *)pnext;
if( pnext ){
assert(pnext[0]==p);
pnext[0] = (void *)pprev;
}
}
}
/*
** Pointer p is a pointer to an OS level allocation that has just been
** realloc()ed. Set the list pointers that point to this entry to it's new
** location.
*/
static void relinkAlloc(void *p)
{
void **pp = (void **)p;
if( pp[0] ){
((void **)(pp[0]))[1] = p;
}else{
sqlite3_pFirst = p;
}
if( pp[1] ){
((void **)(pp[1]))[0] = p;
}
}
#else
#define linkAlloc(x)
#define relinkAlloc(x)
#define unlinkAlloc(x)
#endif
/*
** This function sets the result of the Tcl interpreter passed as an argument
** to a list containing an entry for each currently outstanding call made to
** sqliteMalloc and friends by the current thread. Each list entry is itself a
** list, consisting of the following (in order):
**
** * The number of bytes allocated
** * The __FILE__ macro at the time of the sqliteMalloc() call.
** * The __LINE__ macro ...
** * The value of the sqlite3_malloc_id variable ...
** * The output of backtrace() (if available) ...
**
** Todo: We could have a version of this function that outputs to stdout,
** to debug memory leaks when Tcl is not available.
*/
#if defined(TCLSH) && defined(SQLITE_DEBUG) && SQLITE_MEMDEBUG>1
#include <tcl.h>
int sqlite3OutstandingMallocs(Tcl_Interp *interp){
void *p;
Tcl_Obj *pRes = Tcl_NewObj();
Tcl_IncrRefCount(pRes);
for(p=sqlite3_pFirst; p; p=((void **)p)[1]){
Tcl_Obj *pEntry = Tcl_NewObj();
Tcl_Obj *pStack = Tcl_NewObj();
char *z;
u32 iLine;
int nBytes = sqlite3OsAllocationSize(p) - TESTALLOC_OVERHEAD;
char *zAlloc = (char *)p;
int i;
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(nBytes));
z = &zAlloc[TESTALLOC_OFFSET_FILENAME(p)];
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
z = &zAlloc[TESTALLOC_OFFSET_LINENUMBER(p)];
memcpy(&iLine, z, sizeof(u32));
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewIntObj(iLine));
z = &zAlloc[TESTALLOC_OFFSET_USER(p)];
Tcl_ListObjAppendElement(0, pEntry, Tcl_NewStringObj(z, -1));
z = &zAlloc[TESTALLOC_OFFSET_STACK(p)];
for(i=0; i<TESTALLOC_STACKFRAMES; i++){
char zHex[128];
sqlite3_snprintf(sizeof(zHex), zHex, "%p", ((void **)z)[i]);
Tcl_ListObjAppendElement(0, pStack, Tcl_NewStringObj(zHex, -1));
}
Tcl_ListObjAppendElement(0, pEntry, pStack);
Tcl_ListObjAppendElement(0, pRes, pEntry);
}
Tcl_ResetResult(interp);
Tcl_SetObjResult(interp, pRes);
Tcl_DecrRefCount(pRes);
return TCL_OK;
}
#endif
/*
** This is the test layer's wrapper around sqlite3OsMalloc().
*/
static void * OSMALLOC(int n){
sqlite3OsEnterMutex();
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
sqlite3_nMaxAlloc =
MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
#endif
assert( !sqlite3_mallocDisallowed );
if( !sqlite3TestMallocFail() ){
u32 *p;
p = (u32 *)sqlite3OsMalloc(n + TESTALLOC_OVERHEAD);
assert(p);
sqlite3_nMalloc++;
applyGuards(p);
linkAlloc(p);
sqlite3OsLeaveMutex();
return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
}
sqlite3OsLeaveMutex();
return 0;
}
static int OSSIZEOF(void *p){
if( p ){
u32 *pOs = (u32 *)getOsPointer(p);
return sqlite3OsAllocationSize(pOs) - TESTALLOC_OVERHEAD;
}
return 0;
}
/*
** This is the test layer's wrapper around sqlite3OsFree(). The argument is a
** pointer to the space allocated for the application to use.
*/
static void OSFREE(void *pFree){
u32 *p; /* Pointer to the OS-layer allocation */
sqlite3OsEnterMutex();
p = (u32 *)getOsPointer(pFree);
checkGuards(p);
unlinkAlloc(p);
memset(pFree, 0x55, OSSIZEOF(pFree));
sqlite3OsFree(p);
sqlite3_nFree++;
sqlite3OsLeaveMutex();
}
/*
** This is the test layer's wrapper around sqlite3OsRealloc().
*/
static void * OSREALLOC(void *pRealloc, int n){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
sqlite3_nMaxAlloc =
MAX(sqlite3_nMaxAlloc, sqlite3ThreadDataReadOnly()->nAlloc);
#endif
assert( !sqlite3_mallocDisallowed );
if( !sqlite3TestMallocFail() ){
u32 *p = (u32 *)getOsPointer(pRealloc);
checkGuards(p);
p = sqlite3OsRealloc(p, n + TESTALLOC_OVERHEAD);
applyGuards(p);
relinkAlloc(p);
return (void *)(&p[TESTALLOC_NGUARD + 2*sizeof(void *)/sizeof(u32)]);
}
return 0;
}
static void OSMALLOC_FAILED(){
sqlite3_isFail = 0;
}
#else
/* Define macros to call the sqlite3OsXXX interface directly if
** the SQLITE_MEMDEBUG macro is not defined.
*/
#define OSMALLOC(x) sqlite3OsMalloc(x)
#define OSREALLOC(x,y) sqlite3OsRealloc(x,y)
#define OSFREE(x) sqlite3OsFree(x)
#define OSSIZEOF(x) sqlite3OsAllocationSize(x)
#define OSMALLOC_FAILED()
#endif /* SQLITE_MEMDEBUG */
/*
** End code for memory allocation system test layer.
**--------------------------------------------------------------------------*/
/*
** This routine is called when we are about to allocate n additional bytes
** of memory. If the new allocation will put is over the soft allocation
** limit, then invoke sqlite3_release_memory() to try to release some
** memory before continuing with the allocation.
**
** This routine also makes sure that the thread-specific-data (TSD) has
** be allocated. If it has not and can not be allocated, then return
** false. The updateMemoryUsedCount() routine below will deallocate
** the TSD if it ought to be.
**
** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
** a no-op
*/
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
static int enforceSoftLimit(int n){
ThreadData *pTsd = sqlite3ThreadData();
if( pTsd==0 ){
return 0;
}
assert( pTsd->nAlloc>=0 );
if( n>0 && pTsd->nSoftHeapLimit>0 ){
while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ){}
}
return 1;
}
#else
# define enforceSoftLimit(X) 1
#endif
/*
** Update the count of total outstanding memory that is held in
** thread-specific-data (TSD). If after this update the TSD is
** no longer being used, then deallocate it.
**
** If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, this routine is
** a no-op
*/
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
static void updateMemoryUsedCount(int n){
ThreadData *pTsd = sqlite3ThreadData();
if( pTsd ){
pTsd->nAlloc += n;
assert( pTsd->nAlloc>=0 );
if( pTsd->nAlloc==0 && pTsd->nSoftHeapLimit==0 ){
sqlite3ReleaseThreadData();
}
}
}
#else
#define updateMemoryUsedCount(x) /* no-op */
#endif
/*
** Allocate and return N bytes of uninitialised memory by calling
** sqlite3OsMalloc(). If the Malloc() call fails, attempt to free memory
** by calling sqlite3_release_memory().
*/
void *sqlite3MallocRaw(int n, int doMemManage){
void *p = 0;
if( n>0 && !sqlite3MallocFailed() && (!doMemManage || enforceSoftLimit(n)) ){
while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) ){}
if( !p ){
sqlite3FailedMalloc();
OSMALLOC_FAILED();
}else if( doMemManage ){
updateMemoryUsedCount(OSSIZEOF(p));
}
}
return p;
}
/*
** Resize the allocation at p to n bytes by calling sqlite3OsRealloc(). The
** pointer to the new allocation is returned. If the Realloc() call fails,
** attempt to free memory by calling sqlite3_release_memory().
*/
void *sqlite3Realloc(void *p, int n){
if( sqlite3MallocFailed() ){
return 0;
}
if( !p ){
return sqlite3Malloc(n, 1);
}else{
void *np = 0;
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int origSize = OSSIZEOF(p);
#endif
if( enforceSoftLimit(n - origSize) ){
while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) ){}
if( !np ){
sqlite3FailedMalloc();
OSMALLOC_FAILED();
}else{
updateMemoryUsedCount(OSSIZEOF(np) - origSize);
}
}
return np;
}
}
/*
** Free the memory pointed to by p. p must be either a NULL pointer or a
** value returned by a previous call to sqlite3Malloc() or sqlite3Realloc().
*/
void sqlite3FreeX(void *p){
if( p ){
updateMemoryUsedCount(0 - OSSIZEOF(p));
OSFREE(p);
}
}
/*
** A version of sqliteMalloc() that is always a function, not a macro.
** Currently, this is used only to alloc to allocate the parser engine.
*/
void *sqlite3MallocX(int n){
return sqliteMalloc(n);
}
/*
** sqlite3Malloc
** sqlite3ReallocOrFree
**
** These two are implemented as wrappers around sqlite3MallocRaw(),
** sqlite3Realloc() and sqlite3Free().
*/
void *sqlite3Malloc(int n, int doMemManage){
void *p = sqlite3MallocRaw(n, doMemManage);
if( p ){
memset(p, 0, n);
}
return p;
}
void *sqlite3ReallocOrFree(void *p, int n){
void *pNew;
pNew = sqlite3Realloc(p, n);
if( !pNew ){
sqlite3FreeX(p);
}
return pNew;
}
/*
** sqlite3ThreadSafeMalloc() and sqlite3ThreadSafeFree() are used in those
** rare scenarios where sqlite may allocate memory in one thread and free
** it in another. They are exactly the same as sqlite3Malloc() and
** sqlite3Free() except that:
**
** * The allocated memory is not included in any calculations with
** respect to the soft-heap-limit, and
**
** * sqlite3ThreadSafeMalloc() must be matched with ThreadSafeFree(),
** not sqlite3Free(). Calling sqlite3Free() on memory obtained from
** ThreadSafeMalloc() will cause an error somewhere down the line.
*/
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
void *sqlite3ThreadSafeMalloc(int n){
(void)ENTER_MALLOC;
return sqlite3Malloc(n, 0);
}
void sqlite3ThreadSafeFree(void *p){
(void)ENTER_MALLOC;
if( p ){
OSFREE(p);
}
}
#endif
/*
** Return the number of bytes allocated at location p. p must be either
** a NULL pointer (in which case 0 is returned) or a pointer returned by
** sqlite3Malloc(), sqlite3Realloc() or sqlite3ReallocOrFree().
**
** The number of bytes allocated does not include any overhead inserted by
** any malloc() wrapper functions that may be called. So the value returned
** is the number of bytes that were available to SQLite using pointer p,
** regardless of how much memory was actually allocated.
*/
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
int sqlite3AllocSize(void *p){
return OSSIZEOF(p);
}
#endif
/*
** Make a copy of a string in memory obtained from sqliteMalloc(). These
** functions call sqlite3MallocRaw() directly instead of sqliteMalloc(). This
** is because when memory debugging is turned on, these two functions are
** called via macros that record the current file and line number in the
** ThreadData structure.
*/
char *sqlite3StrDup(const char *z){
char *zNew;
int n;
if( z==0 ) return 0;
n = strlen(z)+1;
zNew = sqlite3MallocRaw(n, 1);
if( zNew ) memcpy(zNew, z, n);
return zNew;
}
char *sqlite3StrNDup(const char *z, int n){
char *zNew;
if( z==0 ) return 0;
zNew = sqlite3MallocRaw(n+1, 1);
if( zNew ){
memcpy(zNew, z, n);
zNew[n] = 0;
}
return zNew;
}
/*
** Create a string from the 2nd and subsequent arguments (up to the
** first NULL argument), store the string in memory obtained from
** sqliteMalloc() and make the pointer indicated by the 1st argument
** point to that string. The 1st argument must either be NULL or
** point to memory obtained from sqliteMalloc().
*/
void sqlite3SetString(char **pz, ...){
va_list ap;
int nByte;
const char *z;
char *zResult;
assert( pz!=0 );
nByte = 1;
va_start(ap, pz);
while( (z = va_arg(ap, const char*))!=0 ){
nByte += strlen(z);
}
va_end(ap);
sqliteFree(*pz);
*pz = zResult = sqliteMallocRaw( nByte );
if( zResult==0 ){
return;
}
*zResult = 0;
va_start(ap, pz);
while( (z = va_arg(ap, const char*))!=0 ){
int n = strlen(z);
memcpy(zResult, z, n);
zResult += n;
}
zResult[0] = 0;
va_end(ap);
}
/*
** This function must be called before exiting any API function (i.e.
** returning control to the user) that has called sqlite3Malloc or
** sqlite3Realloc.
**
** The returned value is normally a copy of the second argument to this
** function. However, if a malloc() failure has occured since the previous
** invocation SQLITE_NOMEM is returned instead.
**
** If the first argument, db, is not NULL and a malloc() error has occured,
** then the connection error-code (the value returned by sqlite3_errcode())
** is set to SQLITE_NOMEM.
*/
static int mallocHasFailed = 0;
int sqlite3ApiExit(sqlite3* db, int rc){
if( sqlite3MallocFailed() ){
mallocHasFailed = 0;
sqlite3OsLeaveMutex();
sqlite3Error(db, SQLITE_NOMEM, 0);
rc = SQLITE_NOMEM;
}
return rc & (db ? db->errMask : 0xff);
}
/*
** Return true is a malloc has failed in this thread since the last call
** to sqlite3ApiExit(), or false otherwise.
*/
int sqlite3MallocFailed(){
return (mallocHasFailed && sqlite3OsInMutex(1));
}
/*
** Set the "malloc has failed" condition to true for this thread.
*/
void sqlite3FailedMalloc(){
if( !sqlite3MallocFailed() ){
sqlite3OsEnterMutex();
assert( mallocHasFailed==0 );
mallocHasFailed = 1;
}
}
#ifdef SQLITE_MEMDEBUG
/*
** This function sets a flag in the thread-specific-data structure that will
** cause an assert to fail if sqliteMalloc() or sqliteRealloc() is called.
*/
void sqlite3MallocDisallow(){
assert( sqlite3_mallocDisallowed>=0 );
sqlite3_mallocDisallowed++;
}
/*
** This function clears the flag set in the thread-specific-data structure set
** by sqlite3MallocDisallow().
*/
void sqlite3MallocAllow(){
assert( sqlite3_mallocDisallowed>0 );
sqlite3_mallocDisallowed--;
}
#endif

View File

@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** another is writing.
** **
** @(#) $Id: pager.c,v 1.335 2007/05/04 13:15:56 drh Exp $ ** @(#) $Id: pager.c,v 1.336 2007/05/05 11:48:54 drh Exp $
*/ */
#ifndef SQLITE_OMIT_DISKIO #ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -458,7 +458,7 @@ static int read32bits(OsFile *fd, u32 *pRes){
unsigned char ac[4]; unsigned char ac[4];
int rc = sqlite3OsRead(fd, ac, sizeof(ac)); int rc = sqlite3OsRead(fd, ac, sizeof(ac));
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
*pRes = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; *pRes = sqlite3Get4byte(ac);
} }
return rc; return rc;
} }
@@ -466,12 +466,7 @@ static int read32bits(OsFile *fd, u32 *pRes){
/* /*
** Write a 32-bit integer into a string buffer in big-endian byte order. ** Write a 32-bit integer into a string buffer in big-endian byte order.
*/ */
static void put32bits(char *ac, u32 val){ #define put32bits(A,B) sqlite3Put4byte((u8*)A,B)
ac[0] = (val>>24) & 0xff;
ac[1] = (val>>16) & 0xff;
ac[2] = (val>>8) & 0xff;
ac[3] = val & 0xff;
}
/* /*
** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK ** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
@@ -490,7 +485,7 @@ static int write32bits(OsFile *fd, u32 val){
static u32 retrieve32bits(PgHdr *p, int offset){ static u32 retrieve32bits(PgHdr *p, int offset){
unsigned char *ac; unsigned char *ac;
ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset]; ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset];
return (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; return sqlite3Get4byte(ac);
} }

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.556 2007/05/04 18:30:41 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.557 2007/05/05 11:48:54 drh Exp $
*/ */
#ifndef _SQLITEINT_H_ #ifndef _SQLITEINT_H_
#define _SQLITEINT_H_ #define _SQLITEINT_H_
@@ -1915,6 +1915,11 @@ FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
int sqlite3Reprepare(Vdbe*); int sqlite3Reprepare(Vdbe*);
u32 sqlite3Get2byte(const u8*);
u32 sqlite3Get4byte(const u8*);
void sqlite3Put2byte(u8*, u32);
void sqlite3Put4byte(u8*, u32);
#ifdef SQLITE_SSE #ifdef SQLITE_SSE
#include "sseInt.h" #include "sseInt.h"
#endif #endif

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated ** is not included in the SQLite library. It is used for automated
** testing of the SQLite library. ** testing of the SQLite library.
** **
** $Id: test1.c,v 1.244 2007/05/04 19:03:03 danielk1977 Exp $ ** $Id: test1.c,v 1.245 2007/05/05 11:48:54 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "tcl.h" #include "tcl.h"
@@ -31,6 +31,43 @@ struct SqliteDb {
sqlite3 *db; sqlite3 *db;
}; };
/*
** Convert text generated by the "%p" conversion format back into
** a pointer.
*/
static int testHexToInt(int h){
if( h>='0' && h<='9' ){
return h - '0';
}else if( h>='a' && h<='f' ){
return h - 'a' + 10;
}else{
assert( h>='A' && h<='F' );
return h - 'A' + 10;
}
}
void *sqlite3TextToPtr(const char *z){
void *p;
u64 v;
u32 v2;
if( z[0]=='0' && z[1]=='x' ){
z += 2;
}
v = 0;
while( *z ){
v = (v<<4) + testHexToInt(*z);
z++;
}
if( sizeof(p)==sizeof(v) ){
memcpy(&p, &v, sizeof(p));
}else{
assert( sizeof(p)==sizeof(v2) );
v2 = (u32)v;
memcpy(&p, &v2, sizeof(p));
}
return p;
}
/* /*
** A TCL command that returns the address of the sqlite* pointer ** A TCL command that returns the address of the sqlite* pointer
** for an sqlite connection instance. Bad things happen if the ** for an sqlite connection instance. Bad things happen if the

File diff suppressed because it is too large Load Diff

View File

@@ -72,6 +72,7 @@ puts $out [subst \
# #
foreach hdr { foreach hdr {
btree.h btree.h
btreeInt.h
hash.h hash.h
keywordhash.h keywordhash.h
opcodes.h opcodes.h
@@ -152,6 +153,7 @@ foreach file {
date.c date.c
os.c os.c
malloc.c
printf.c printf.c
random.c random.c
utf.c utf.c