diff --git a/Makefile.in b/Makefile.in index 9e50779a4a..d36e86681b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -123,7 +123,7 @@ TCC += -DSQLITE_OMIT_LOAD_EXTENSION=1 LIBOBJ = alter.lo analyze.lo attach.lo auth.lo btree.lo build.lo \ callback.lo complete.lo date.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 \ select.lo table.lo tokenize.lo trigger.lo update.lo \ util.lo vacuum.lo \ @@ -152,6 +152,7 @@ SRC = \ $(TOP)/src/legacy.c \ $(TOP)/src/loadext.c \ $(TOP)/src/main.c \ + $(TOP)/src/mallo.c \ $(TOP)/src/os.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ @@ -204,6 +205,7 @@ TESTSRC = \ $(TOP)/src/date.c \ $(TOP)/src/func.c \ $(TOP)/src/insert.c \ + $(TOP)/src/malloc.c \ $(TOP)/src/os.c \ $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ @@ -238,6 +240,7 @@ TESTSRC = \ HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ + $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ opcodes.h \ $(TOP)/src/os.h \ @@ -366,6 +369,9 @@ loadext.lo: $(TOP)/src/loadext.c $(HDR) main.lo: $(TOP)/src/main.c $(HDR) $(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 $(LTCOMPILE) -c $(TOP)/src/pager.c diff --git a/main.mk b/main.mk index 44cb08296c..c8b72d44b7 100644 --- a/main.mk +++ b/main.mk @@ -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 \ callback.o complete.o date.o delete.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 \ select.o table.o tclsqlite.o tokenize.o trigger.o \ update.o util.o vacuum.o \ @@ -87,6 +87,7 @@ SRC = \ $(TOP)/src/legacy.c \ $(TOP)/src/loadext.c \ $(TOP)/src/main.c \ + $(TOP)/src/malloc.c \ $(TOP)/src/os.c \ $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ @@ -160,6 +161,7 @@ TESTSRC = \ $(TOP)/src/func.c \ $(TOP)/src/insert.c \ $(TOP)/src/main.c \ + $(TOP)/src/malloc.c \ $(TOP)/src/os.c \ $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ @@ -194,6 +196,7 @@ TESTSRC = \ HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ + $(TOP)/src/btreeInt.h \ $(TOP)/src/hash.h \ opcodes.h \ $(TOP)/src/os.h \ @@ -319,6 +322,9 @@ loadext.o: $(TOP)/src/loadext.c $(HDR) main.o: $(TOP)/src/main.c $(HDR) $(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 $(TCCX) -c $(TOP)/src/pager.c diff --git a/manifest b/manifest index 72004120bf..89882f2344 100644 --- a/manifest +++ b/manifest @@ -1,6 +1,6 @@ -C Add\sdocumentation\son\sthe\sincremental\svacuum\sfeature.\s(CVS\s3924) -D 2007-05-04T19:16:30 -F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 +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-05T11:48:53 +F Makefile.in 80d63bf2c61619ae0e29795948ec19e79f91acc3 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F VERSION 6de5e9812c227f00155cb59af3535017aef3e258 @@ -44,7 +44,7 @@ F ext/fts2/fts2_tokenizer1.c 5c979fe8815f95396beb22b627571da895a025af F ext/fts2/mkfts2amal.tcl 2a9ec76b0760fe7f3669dca5bc0d60728bc1c977 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh 56abb507100ed2d4261f6dd1653dec3cf4066387 -F main.mk 2bc462dba2a8332a8a831f5ddd718b4ad7aac6c8 +F main.mk b9fd506a8ff3abd83b01dff9abdb98948a207f26 F mkdll.sh ed62756baf44babf562a7843588790c02fee2106 F mkopcodec.awk bd46ad001c98dfbab07b1713cb8e692fa0e5415d F mkopcodeh.awk cde995d269aa06c94adbf6455bea0acedb913fa5 @@ -59,8 +59,9 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3 F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651 F src/attach.c f088f8155541ff75542239ec40cf05f3d81390ba F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f -F src/btree.c 1bd7820b84e93ecd7b4364faeb58565c76cf3cad +F src/btree.c 7311696faf137cb37421c8e1d0e22e2d3a15de51 F src/btree.h a9cd72b05a14f6be22e057daf954ae548d2bcbe4 +F src/btreeInt.h 2de5f19abb59fcc5e87474fe59ef8110cfa0d343 F src/build.c 0dd6f0d0a5d304be91374f4c7228a3e9b00ff7f1 F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675 @@ -75,6 +76,7 @@ F src/insert.c e595ca26805dfb3a9ebaabc28e7947c479f3b14d F src/legacy.c 388c71ad7fbcd898ba1bcbfc98a3ac954bfa5d01 F src/loadext.c afe4f4755dc49c36ef505748bbdddecb9f1d02a2 F src/main.c e6eb036c3580ba9116fedfe4a8b58ed63d5abb37 +F src/malloc.c b89e31258a85158d15795bf87ae3ba007e56329b F src/md5.c c5fdfa5c2593eaee2e32a5ce6c6927c986eaf217 F src/os.c 4650e98aadd27abfe1698ff58edf6893c58d4881 F src/os.h 9240adf088fd55732f8926f9017601ba3430ead8 @@ -87,7 +89,7 @@ F src/os_unix.c cb1fb044b84870c7b1b8b2902e9d7be779f8b7ce F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_win.c 5e9e3d2aeed4d6f1b6ae81e866919f4f43b4a23d F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b -F src/pager.c f01e0e577b7b54c3cdba24a30ecc585a805f23fa +F src/pager.c 9c9a9df78636f4b9c8e18f90e93337a1231aaef7 F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c F src/parse.y a5bdc301e970ceb3826b56a84898b8966d5353f8 F src/pragma.c 3f16c1274bc25afb630b61a3630ea19a2fd0b5dc @@ -99,10 +101,10 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c d07ae326b3815d80f71c69b3c7584382e47f6447 F src/sqlite.h.in a666300976897eced975b448f722a722b362c6b1 F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890 -F src/sqliteInt.h 93ac1a9f1c8facfd861cf548845d2abc36039670 +F src/sqliteInt.h 3ffe2f9c801575e315451e7d2831c4a90a165aa8 F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d F src/tclsqlite.c f3414b2d6bc37e6760b49c9abd3504ff69f4441b -F src/test1.c ed62a5f1e319bb85232b98b97a438011b96da5a8 +F src/test1.c 9fb5a4300897c01add79ff8691114e54e5a83ff0 F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88 F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86 F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25 @@ -123,7 +125,7 @@ F src/tokenize.c 7d611fc942ca0b12514eea2e1fbb148a65af23f2 F src/trigger.c 420192efe3e6f03addf7897c60c3c8bf913d3493 F src/update.c 3359041db390a8f856d67272f299600e2104f350 F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528 -F src/util.c 9f9fec5dc7ffab8ff982508d03af37269a59ff91 +F src/util.c 5eff5cec4ae43490ca3fb97f10a25aac1a5f9b55 F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef F src/vdbe.c 725a808e9bdc317aba963f33054db2dbebdfeecd F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 @@ -409,7 +411,7 @@ F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8 F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf F tool/mkkeywordhash.c fe15d1cbc61c2b0375634b6d8c1ef24520799ea0 F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x -F tool/mksqlite3c.tcl fa0429d32cb0756b23def531ec863bc0e216f375 +F tool/mksqlite3c.tcl 3664556f06f7e4acd81552195ea2a9f16b887dcc F tool/mksqlite3internalh.tcl a85bb0c812db1a060e6e6dfab4e4c817f53d194b F tool/omittest.tcl e6b3d6a1285f9813bc1dea53bb522b4b72774710 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -475,7 +477,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P a0f8adc692839d0645daf0630533a87b0543f6e8 -R 2ab54f3f4a04566149d9fc08dd42a530 +P b3e2cdaed3638f033437b5561705cb253449c392 +R f966d62a9229ee8e5f7295776797e7fa U drh -Z d993c75ec553297a4f21ca68fdcc08cc +Z 93ccb6a5bb856df574c55be8b837f833 diff --git a/manifest.uuid b/manifest.uuid index a333d69bac..a1884dc319 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b3e2cdaed3638f033437b5561705cb253449c392 \ No newline at end of file +16041116aaaa2d52a289aa02a24bef579ba60896 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9b99fa2107..025fbf35dd 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,431 +9,27 @@ ** 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. -** 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 +** See the header comment on "btreeInt.h" for additional information. +** Including a description of file format and an overview of operation. */ -#include "sqliteInt.h" -#include "pager.h" -#include "btree.h" -#include "os.h" -#include - -/* 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; +#include "btreeInt.h" /* -** 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. +** The header string that appears at the beginning of every +** SQLite database. */ -#ifndef SQLITE_FILE_HEADER /* 123456789 123456 */ -# define SQLITE_FILE_HEADER "SQLite format 3" -#endif 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 -** 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. +** Set this global variable to 1 to enable tracing using the TRACE +** macro. */ #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 */ -#else -# define TRACE(X) #endif /* @@ -441,66 +37,6 @@ int sqlite3_btree_trace=0; /* True to enable tracing */ */ 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 /* @@ -785,24 +321,10 @@ static int restoreOrClearCursorPositionX(BtCursor *pCur){ #ifndef SQLITE_OMIT_AUTOVACUUM /* -** 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. +** Given a page number of a regular database page, return the page +** number for the pointer-map page that contains the entry for the +** input page number. */ -#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){ int nPagesPerMapPage = (pBt->usableSize/5)+1; int iPtrMap = (pgno-2)/nPagesPerMapPage; @@ -813,43 +335,6 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){ 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. ** @@ -1090,15 +575,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){ #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->nTransactionpBt->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 ** 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 */ -/* -** 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 ** 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; } -/* -** 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 /* ** Append a message to the error message string. diff --git a/src/btreeInt.h b/src/btreeInt.h new file mode 100644 index 0000000000..90c8a872ea --- /dev/null +++ b/src/btreeInt.h @@ -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 + +/* 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->nTransactionpBt->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 diff --git a/src/malloc.c b/src/malloc.c new file mode 100644 index 0000000000..524f5ea605 --- /dev/null +++ b/src/malloc.c @@ -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 +#include + +/* +** 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: +** +** +** +** +** +** +** <32-bit line number> +** +** +*/ + +#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; i1 +/* +** 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 +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; inAlloc); +#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 diff --git a/src/pager.c b/src/pager.c index e9c0f408f4..1226e28de1 100644 --- a/src/pager.c +++ b/src/pager.c @@ -18,7 +18,7 @@ ** file simultaneously, or one process from reading the database while ** 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 #include "sqliteInt.h" @@ -458,7 +458,7 @@ static int read32bits(OsFile *fd, u32 *pRes){ unsigned char ac[4]; int rc = sqlite3OsRead(fd, ac, sizeof(ac)); if( rc==SQLITE_OK ){ - *pRes = (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; + *pRes = sqlite3Get4byte(ac); } 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. */ -static void put32bits(char *ac, u32 val){ - ac[0] = (val>>24) & 0xff; - ac[1] = (val>>16) & 0xff; - ac[2] = (val>>8) & 0xff; - ac[3] = val & 0xff; -} +#define put32bits(A,B) sqlite3Put4byte((u8*)A,B) /* ** 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){ unsigned char *ac; ac = &((unsigned char*)PGHDR_TO_DATA(p))[offset]; - return (ac[0]<<24) | (ac[1]<<16) | (ac[2]<<8) | ac[3]; + return sqlite3Get4byte(ac); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index dc2cdd12e4..c5917c643b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** 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_ #define _SQLITEINT_H_ @@ -1915,6 +1915,11 @@ FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*); void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**); int sqlite3Reprepare(Vdbe*); +u32 sqlite3Get2byte(const u8*); +u32 sqlite3Get4byte(const u8*); +void sqlite3Put2byte(u8*, u32); +void sqlite3Put4byte(u8*, u32); + #ifdef SQLITE_SSE #include "sseInt.h" #endif diff --git a/src/test1.c b/src/test1.c index 0f3b5411b5..bb303ee9df 100644 --- a/src/test1.c +++ b/src/test1.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** 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 "tcl.h" @@ -31,6 +31,43 @@ struct SqliteDb { 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 ** for an sqlite connection instance. Bad things happen if the diff --git a/src/util.c b/src/util.c index 1908329080..cc73dc3a7a 100644 --- a/src/util.c +++ b/src/util.c @@ -14,767 +14,13 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.200 2007/05/04 13:15:56 drh Exp $ +** $Id: util.c,v 1.201 2007/05/05 11:48:54 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include #include -/* -** 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: -** -** -** -** -** -** -** <32-bit line number> -** -** -*/ - -#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; i1 -/* -** 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 -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; inAlloc); -#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); -} /* ** Set the most recent error code and error string for the sqlite @@ -1132,58 +378,6 @@ int sqlite3FitsIn64Bits(const char *zNum){ } -/* -** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY. -** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN -** when this routine is called. -** -** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN -** value indicates that the database connection passed into the API is -** open and is not being used by another thread. By changing the value -** to SQLITE_MAGIC_BUSY we indicate that the connection is in use. -** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN -** when the API exits. -** -** This routine is a attempt to detect if two threads use the -** same sqlite* pointer at the same time. There is a race -** condition so it is possible that the error is not detected. -** But usually the problem will be seen. The result will be an -** error which can be used to debug the application that is -** using SQLite incorrectly. -** -** Ticket #202: If db->magic is not a valid open value, take care not -** to modify the db structure at all. It could be that db is a stale -** pointer. In other words, it could be that there has been a prior -** call to sqlite3_close(db) and db has been deallocated. And we do -** not want to write into deallocated memory. -*/ -int sqlite3SafetyOn(sqlite3 *db){ - if( db->magic==SQLITE_MAGIC_OPEN ){ - db->magic = SQLITE_MAGIC_BUSY; - return 0; - }else if( db->magic==SQLITE_MAGIC_BUSY ){ - db->magic = SQLITE_MAGIC_ERROR; - db->u1.isInterrupted = 1; - } - return 1; -} - -/* -** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. -** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY -** when this routine is called. -*/ -int sqlite3SafetyOff(sqlite3 *db){ - if( db->magic==SQLITE_MAGIC_BUSY ){ - db->magic = SQLITE_MAGIC_OPEN; - return 0; - }else { - db->magic = SQLITE_MAGIC_ERROR; - db->u1.isInterrupted = 1; - return 1; - } -} - /* ** Check to make sure we have a valid db pointer. This test is not ** foolproof but it does provide some measure of protection against @@ -1338,6 +532,29 @@ int sqlite3VarintLen(u64 v){ return i; } + +/* +** Read or write a two- and four-byte big-endian integer values. +*/ +u32 sqlite3Get2byte(const u8 *p){ + return (p[0]<<8) | p[1]; +} +u32 sqlite3Get4byte(const u8 *p){ + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; +} +void sqlite3Put2byte(unsigned char *p, u32 v){ + p[0] = v>>8; + p[1] = v; +} +void sqlite3Put4byte(unsigned char *p, u32 v){ + p[0] = v>>24; + p[1] = v>>16; + p[2] = v>>8; + p[3] = v; +} + + + #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) \ || defined(SQLITE_TEST) /* @@ -1378,33 +595,58 @@ void *sqlite3HexToBlob(const char *z){ } #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ -#if defined(SQLITE_TEST) + /* -** Convert text generated by the "%p" conversion format back into -** a pointer. +** Change the sqlite.magic from SQLITE_MAGIC_OPEN to SQLITE_MAGIC_BUSY. +** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN +** when this routine is called. +** +** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN +** value indicates that the database connection passed into the API is +** open and is not being used by another thread. By changing the value +** to SQLITE_MAGIC_BUSY we indicate that the connection is in use. +** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN +** when the API exits. +** +** This routine is a attempt to detect if two threads use the +** same sqlite* pointer at the same time. There is a race +** condition so it is possible that the error is not detected. +** But usually the problem will be seen. The result will be an +** error which can be used to debug the application that is +** using SQLite incorrectly. +** +** Ticket #202: If db->magic is not a valid open value, take care not +** to modify the db structure at all. It could be that db is a stale +** pointer. In other words, it could be that there has been a prior +** call to sqlite3_close(db) and db has been deallocated. And we do +** not want to write into deallocated memory. */ -void *sqlite3TextToPtr(const char *z){ - void *p; - u64 v; - u32 v2; - if( z[0]=='0' && z[1]=='x' ){ - z += 2; +int sqlite3SafetyOn(sqlite3 *db){ + if( db->magic==SQLITE_MAGIC_OPEN ){ + db->magic = SQLITE_MAGIC_BUSY; + return 0; + }else if( db->magic==SQLITE_MAGIC_BUSY ){ + db->magic = SQLITE_MAGIC_ERROR; + db->u1.isInterrupted = 1; + } + return 1; +} + +/* +** Change the magic from SQLITE_MAGIC_BUSY to SQLITE_MAGIC_OPEN. +** Return an error (non-zero) if the magic was not SQLITE_MAGIC_BUSY +** when this routine is called. +*/ +int sqlite3SafetyOff(sqlite3 *db){ + if( db->magic==SQLITE_MAGIC_BUSY ){ + db->magic = SQLITE_MAGIC_OPEN; + return 0; + }else { + db->magic = SQLITE_MAGIC_ERROR; + db->u1.isInterrupted = 1; + return 1; } - v = 0; - while( *z ){ - v = (v<<4) + hexToInt(*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; } -#endif /* ** Return a pointer to the ThreadData associated with the calling thread. @@ -1436,66 +678,3 @@ const ThreadData *sqlite3ThreadDataReadOnly(){ void sqlite3ReleaseThreadData(){ sqlite3OsThreadSpecificData(-1); } - -/* -** 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 diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index a984920933..ec9e7a1a3f 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -72,6 +72,7 @@ puts $out [subst \ # foreach hdr { btree.h + btreeInt.h hash.h keywordhash.h opcodes.h @@ -152,6 +153,7 @@ foreach file { date.c os.c + malloc.c printf.c random.c utf.c