Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Added the "memory:" driver (CVS 158) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
54d60c68dc83410e911b828a68077254 |
User & Date: | drh 2000-10-19 14:10:08.000 |
Context
2000-10-19
| ||
14:10 | Added the "memory:" driver (CVS 1707) (check-in: e9236833d9 user: drh tags: trunk) | |
14:10 | Added the "memory:" driver (CVS 158) (check-in: 54d60c68dc user: drh tags: trunk) | |
02:00 | Version 1.0.13 (CVS 490) (check-in: b9c84fa579 user: drh tags: trunk) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
43 44 45 46 47 48 49 | # The library that programs using readline() must link against. # LIBREADLINE = @TARGET_READLINE_LIBS@ # Object files for the SQLite library. # | | > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | # The library that programs using readline() must link against. # LIBREADLINE = @TARGET_READLINE_LIBS@ # Object files for the SQLite library. # LIBOBJ = build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \ main.o parse.o printf.o select.o table.o tokenize.o update.o \ util.o vdbe.o where.o tclsqlite.o # All of the source code files. # SRC = \ $(TOP)/src/build.c \ $(TOP)/src/dbbe.c \ $(TOP)/src/dbbegdbm.c \ $(TOP)/src/dbbemem.c \ $(TOP)/src/dbbe.h \ $(TOP)/src/dbbemem.c \ $(TOP)/src/delete.c \ $(TOP)/src/expr.c \ $(TOP)/src/insert.c \ $(TOP)/src/main.c \ $(TOP)/src/parse.y \ |
︙ | ︙ | |||
118 119 120 121 122 123 124 125 126 127 128 129 130 131 | dbbe.o: $(TOP)/src/dbbe.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbe.c dbbegdbm.o: $(TOP)/src/dbbegdbm.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbegdbm.c main.o: $(TOP)/src/main.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/main.c parse.o: parse.c $(HDR) $(TCC) $(GDBM_FLAGS) -c parse.c parse.h: parse.c | > > > | 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | dbbe.o: $(TOP)/src/dbbe.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbe.c dbbegdbm.o: $(TOP)/src/dbbegdbm.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbegdbm.c dbbemem.o: $(TOP)/src/dbbemem.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/dbbemem.c main.o: $(TOP)/src/main.c $(HDR) $(TCC) $(GDBM_FLAGS) -c $(TOP)/src/main.c parse.o: parse.c $(HDR) $(TCC) $(GDBM_FLAGS) -c parse.c parse.h: parse.c |
︙ | ︙ |
Changes to VERSION.
|
| | | 1 | 1.0.14 |
Changes to src/dbbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** sqlite and the code that does the actually reading and writing ** of information to the disk. ** ** This file uses GDBM as the database backend. It should be ** relatively simple to convert to a different database such ** as NDBM, SDBM, or BerkeleyDB. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** sqlite and the code that does the actually reading and writing ** of information to the disk. ** ** This file uses GDBM as the database backend. It should be ** relatively simple to convert to a different database such ** as NDBM, SDBM, or BerkeleyDB. ** ** $Id: dbbe.c,v 1.21 2000/10/19 14:10:09 drh Exp $ */ #include "sqliteInt.h" /* ** This routine opens a new database. It looks at the first ** few characters of the database name to try to determine what ** kind of database to open. If the first characters are "gdbm:", |
︙ | ︙ | |||
52 53 54 55 56 57 58 | int createFlag, /* True to create database if it doesn't exist */ char **pzErrMsg /* Write error messages (if any) here */ ){ extern Dbbe *sqliteGdbmOpen(const char*,int,int,char**); if( strncmp(zName, "gdbm:", 5)==0 ){ return sqliteGdbmOpen(&zName[5], writeFlag, createFlag, pzErrMsg); } | < < | 52 53 54 55 56 57 58 59 60 61 62 63 64 | int createFlag, /* True to create database if it doesn't exist */ char **pzErrMsg /* Write error messages (if any) here */ ){ extern Dbbe *sqliteGdbmOpen(const char*,int,int,char**); if( strncmp(zName, "gdbm:", 5)==0 ){ return sqliteGdbmOpen(&zName[5], writeFlag, createFlag, pzErrMsg); } if( strncmp(zName, "memory:", 7)==0 ){ extern Dbbe *sqliteMemOpen(const char*,int,int,char**); return sqliteMemOpen(&zName[7], writeFlag, createFlag, pzErrMsg); } return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg); } |
Changes to src/dbbemem.c.
1 | /* | | | 1 2 3 4 5 6 7 8 9 | /* ** Copyright (c) 2000 D. Richard Hipp ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public ** License as published by the Free Software Foundation; either ** version 2 of the License, or (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, |
︙ | ︙ | |||
22 23 24 25 26 27 28 | ** ************************************************************************* ** This file contains code to implement the database backend (DBBE) ** for sqlite. The database backend is the interface between ** sqlite and the code that does the actually reading and writing ** of information to the disk. ** | | < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < < < < < < < < | < < < < < < < | | | < < < < < < < < | < < < < < < | | | | | | < < | 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 | ** ************************************************************************* ** This file contains code to implement the database backend (DBBE) ** for sqlite. The database backend is the interface between ** sqlite and the code that does the actually reading and writing ** of information to the disk. ** ** This file uses an in-memory hash talbe as the database backend. ** ** $Id: dbbemem.c,v 1.2 2000/10/19 14:10:09 drh Exp $ */ #include "sqliteInt.h" #include <sys/stat.h> #include <unistd.h> #include <ctype.h> #include <time.h> typedef struct Array Array; typedef struct ArrayElem ArrayElem; typedef struct Datum Datum; /* A complete associative array is an instance of the following structure. ** The internals of this structure are intended to be opaque -- client ** code should not attempt to access or modify the fields of this structure ** directly. Change this structure only by using the routines below. ** However, many of the "procedures" and "functions" for modifying and ** accessing this structure are really macros, so we can't really make ** this structure opaque. */ struct Array { int count; /* Number of entries in the array */ ArrayElem *first; /* The first element of the array */ int htsize; /* Number of buckets in the hash table */ struct _Array_ht { /* the hash table */ int count; /* Number of entries with this hash */ ArrayElem *chain; /* Pointer to first entry with this hash */ } *ht; }; /* ** An instance of the following structure stores a single key or ** data element. */ struct Datum { int n; void *p; }; /* Each element in the associative array is an instance of the following ** structure. All elements are stored on a single doubly-linked list. ** ** Again, this structure is intended to be opaque, but it can't really ** be opaque because it is used by macros. */ struct ArrayElem { ArrayElem *next, *prev; /* Next and previous elements in the array */ Datum key, data; /* Key and data for this element */ }; /* Some routines are so simple that they can be implemented as macros ** These are given first. */ /* Return the number of entries in the array */ #define ArrayCount(X) ((X)->count) /* Return a pointer to the first element of the array */ #define ArrayFirst(X) ((X)->first) /* Return a pointer to the next (or previous) element of the array */ #define ArrayNext(X) ((X)->next) #define ArrayPrev(X) ((X)->prev) /* Return TRUE if the element given is the last element in the array */ #define ArrayIsLast(X) ((X)->next==0) #define ArrayIsFirst(X) ((X)->prev==0) /* Return the data or key for an element of the array */ #define ArrayData(X) ((X)->data.p) #define ArrayDataSize(X) ((X)->data.n) #define ArrayKey(X) ((X)->key.p) #define ArrayKeySize(X) ((X)->key.n) /* Turn bulk memory into an associative array object by initializing the ** fields of the Array structure. */ static void ArrayInit(Array *new){ new->first = 0; new->count = 0; new->htsize = 0; new->ht = 0; } /* Remove all entries from an associative array. Reclaim all memory. ** This is the opposite of ArrayInit(). */ static void ArrayClear(Array *array){ ArrayElem *elem; /* For looping over all elements of the array */ elem = array->first; array->first = 0; array->count = 0; if( array->ht ) sqliteFree(array->ht); array->ht = 0; array->htsize = 0; while( elem ){ ArrayElem *next_elem = elem->next; sqliteFree(elem); elem = next_elem; } } /* ** Generate a hash from an N-byte key */ static int ArrayHash(Datum d){ int h = 0; while( d.n-- > 0 ){ h = (h<<9) ^ (h<<3) ^ h ^ *(((char*)d.p)++); } if( h<0 ) h = -h; return h; } /* Resize the hash table for a Array array */ static void ArrayRehash(Array *array, int new_size){ struct _Array_ht *new_ht; /* The new hash table */ ArrayElem *elem, *next_elem; /* For looping over existing elements */ int i; /* Loop counter */ ArrayElem *x; /* Element being copied to new hash table */ new_ht = sqliteMalloc( new_size*sizeof(struct _Array_ht) ); if( array->ht ) sqliteFree(array->ht); array->ht = new_ht; array->htsize = new_size; for(i=new_size-1; i>=0; i--){ new_ht[i].count = 0; new_ht[i].chain = 0; } for(elem=array->first, array->first=0; elem; elem = next_elem){ int h = ArrayHash(elem->key) & (new_size-1); next_elem = elem->next; x = new_ht[h].chain; if( x ){ elem->next = x; elem->prev = x->prev; if( x->prev ) x->prev->next = elem; else array->first = elem; x->prev = elem; }else{ elem->next = array->first; if( array->first ) array->first->prev = elem; elem->prev = 0; array->first = elem; } new_ht[h].chain = elem; new_ht[h].count++; } } /* This function (for internal use only) locates an element in an ** array that matches the given key. The hash for this key has ** already been computed and is passed as the 3rd parameter. */ static ArrayElem *ArrayFindElementGivenHash( const Array *array, /* The array to be searched */ const Datum key, /* The key we are searching for */ int h /* The hash for this key. */ ){ ArrayElem *elem; /* Used to loop thru the element list */ int count; /* Number of elements left to test */ if( array->count ){ elem = array->ht[h].chain; count = array->ht[h].count; while( count-- && elem ){ if( elem->key.n==key.n && memcmp(elem->key.p,key.p,key.n)==0 ){ return elem; } elem = elem->next; } } return 0; } /* Attempt to locate an element of the associative array with a key ** that matches "key". Return the ArrayElement if found and NULL if ** if no match. */ static ArrayElem *ArrayFindElement(const Array *array, Datum key){ int h; /* A hash on key */ if( array->count==0 ) return 0; h = ArrayHash(key); return ArrayFindElementGivenHash(array, key, h & (array->htsize-1)); } /* Remove a single entry from the array given a pointer to that ** element and a hash on the element's key. */ static void ArrayRemoveElementGivenHash( Array *array, /* The array containing "elem" */ ArrayElem* elem, /* The element to be removed from the array */ int h /* Hash value for the element */ ){ if( elem->prev ){ elem->prev->next = elem->next; }else{ array->first = elem->next; } if( elem->next ){ elem->next->prev = elem->prev; } if( array->ht[h].chain==elem ){ array->ht[h].chain = elem->next; } array->ht[h].count--; if( array->ht[h].count<=0 ){ array->ht[h].chain = 0; } sqliteFree( elem ); array->count--; } /* Attempt to locate an element of the associative array with a key ** that matches "key". Return the data for this element if it is ** found, or NULL if no match is found. */ static Datum ArrayFind(const Array *array, Datum key){ int h; /* A hash on key */ ArrayElem *elem; /* The element that matches key */ static Datum nil = {0, 0}; if( array->count==0 ) return nil; h = ArrayHash(key); elem = ArrayFindElementGivenHash(array, key, h & (array->htsize-1)); return elem ? elem->data : nil; } /* Insert an element into the array. The key will be "key" and ** the data will be "data". ** ** If no array element exists with a matching key, then a new ** array element is created. The key is copied into the new element. ** But only a pointer to the data is stored. NULL is returned. ** ** If another element already exists with the same key, then the ** new data replaces the old data and the old data is returned. ** The key is not copied in this instance. ** ** If the "data" parameter to this function is NULL, then the ** element corresponding to "key" is removed from the array. */ static Datum ArrayInsert(Array *array, Datum key, Datum data){ int hraw; /* Raw hash value of the key */ int h; /* the hash of the key modulo hash table size */ ArrayElem *elem; /* Used to loop thru the element list */ ArrayElem *new_elem; /* New element added to the array */ Datum rv; /* Return value */ static Datum nil = {0, 0}; hraw = ArrayHash(key); h = hraw & (array->htsize-1); elem = ArrayFindElementGivenHash(array,key,h); if( elem ){ Datum old_data = elem->data; if( data.p==0 ){ ArrayRemoveElementGivenHash(array,elem,h); }else{ elem->data = data; } return old_data; } if( data.p==0 ) return nil; new_elem = (ArrayElem*)sqliteMalloc( sizeof(ArrayElem) + key.n ); if( new_elem==0 ) return nil; new_elem->key.n = key.n; new_elem->key.p = (void*)&new_elem[1]; memcpy(new_elem->key.p, key.p, key.n); array->count++; if( array->htsize==0 ) ArrayRehash(array,4); if( array->count > array->htsize ){ ArrayRehash(array,array->htsize*2); } h = hraw & (array->htsize-1); elem = array->ht[h].chain; if( elem ){ new_elem->next = elem; new_elem->prev = elem->prev; if( elem->prev ){ elem->prev->next = new_elem; } else { array->first = new_elem; } elem->prev = new_elem; }else{ new_elem->next = array->first; new_elem->prev = 0; if( array->first ){ array->first->prev = new_elem; } array->first = new_elem; } array->ht[h].count++; array->ht[h].chain = new_elem; new_elem->data = data; rv.p = 0; rv.n = 0; return rv; } /* ** Information about each open database table is an instance of this ** structure. There will only be one such structure for each ** table. If the VDBE opens the same table twice (as will happen ** for a self-join, for example) then two DbbeCursor structures are ** created but there is only a single MTable structure. */ typedef struct MTable MTable; struct MTable { char *zName; /* Name of the table */ int delOnClose; /* Delete when closing */ Array data; /* The data in this stable */ }; /* ** The following structure holds the current state of the RC4 algorithm. ** We use RC4 as a random number generator. Each call to RC4 gives ** a random 8-bit number. ** ** Nothing in this file or anywhere else in SQLite does any kind of ** encryption. The RC4 algorithm is being used as a PRNG (pseudo-random ** number generator) not as an encryption device. */ struct rc4 { int i, j; int s[256]; }; /* ** The following structure contains all information used by GDBM ** database driver. This is a subclass of the Dbbe structure. */ typedef struct Dbbex Dbbex; struct Dbbex { Dbbe dbbe; /* The base class */ Array tables; /* All tables of the database */ int nTemp; /* Number of temporary files created */ FILE **apTemp; /* Space to hold temporary file pointers */ char **azTemp; /* Names of the temporary files */ struct rc4 rc4; /* The random number generator */ }; /* ** An cursor into a database file is an instance of the following structure. ** There can only be a single MTable structure for each disk file, but ** there can be multiple DbbeCursor structures. Each DbbeCursor represents ** a cursor pointing to a particular part of the open MTable. The ** MTable.nRef field hold a count of the number of DbbeCursor structures ** associated with the same disk file. */ struct DbbeCursor { Dbbex *pBe; /* The database of which this record is a part */ MTable *pTble; /* The database file for this table */ ArrayElem *elem; /* Most recently accessed record */ int needRewind; /* Next key should be the first */ }; /* ** Initialize the RC4 PRNG. "seed" is a pointer to some random ** data used to initialize the PRNG. */ static void rc4init(struct rc4 *p, char *seed, int seedlen){ |
︙ | ︙ | |||
142 143 144 145 146 147 148 | p->s[p->i] = p->s[p->j]; p->s[p->j] = t; t = p->s[p->i] + p->s[p->j]; return t & 0xff; } /* | < < < | < < < < < < < < < < < | < < < < | < < < < < < | < < | | | < < < | | | < > | < < < | > | > | | | > | 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | p->s[p->i] = p->s[p->j]; p->s[p->j] = t; t = p->s[p->i] + p->s[p->j]; return t & 0xff; } /* ** Forward declaration */ static void sqliteMemCloseCursor(DbbeCursor *pCursr); /* ** Erase all the memory of an MTable */ static void deleteMTable(MTable *p){ ArrayElem *i; for(i=ArrayFirst(&p->data); i; i=ArrayNext(i)){ void *data = ArrayData(i); sqliteFree(data); } ArrayClear(&p->data); sqliteFree(p); } /* ** Completely shutdown the given database. Close all files. Free all memory. */ static void sqliteMemClose(Dbbe *pDbbe){ Dbbex *pBe = (Dbbex*)pDbbe; MTable *pTble, *pNext; int i; ArrayElem *j, *k; for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){ pTble = ArrayData(j); deleteMTable(pTble); } ArrayClear(&pBe->tables); for(i=0; i<pBe->nTemp; i++){ if( pBe->apTemp[i]!=0 ){ unlink(pBe->azTemp[i]); fclose(pBe->apTemp[i]); sqliteFree(pBe->azTemp[i]); pBe->apTemp[i] = 0; pBe->azTemp[i] = 0; |
︙ | ︙ | |||
239 240 241 242 243 244 245 | int c = rc4byte(pRc4) % (sizeof(zRandomChars) - 1); zBuf[j++] = zRandomChars[c]; } zBuf[j] = 0; } /* | > | > > > | | | < < < > | < | < | < < < < > | < < < | | 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 | int c = rc4byte(pRc4) % (sizeof(zRandomChars) - 1); zBuf[j++] = zRandomChars[c]; } zBuf[j] = 0; } /* ** Translate the name of an SQL table (or index) into its ** canonical name. ** ** Space to hold the canonical name is obtained from ** sqliteMalloc() and must be freed by the calling function. */ static char *sqliteNameOfTable(const char *zTable){ char *zNew = 0; int i, c; sqliteSetString(&zNew, zTable, 0); if( zNew==0 ) return 0; for(i=0; (c = zNew[i])!=0; i++){ if( isupper(c) ){ zNew[i] = tolower(c); } } return zNew; } /* ** Open a new table cursor. Write a pointer to the corresponding ** DbbeCursor structure into *ppCursr. Return an integer success ** code: ** |
︙ | ︙ | |||
288 289 290 291 292 293 294 | ** (This can happen if a SELECT callback tries to ** do an UPDATE or DELETE.) ** ** If zTable is 0 or "", then a temporary database file is created and ** a cursor to that temporary file is opened. The temporary file ** will be deleted from the disk when it is closed. */ | | | < > | > > | > | > | | | | | | | | | | > > | < > > < < < < | < < < < < < < | < | < < < < < < | < | < < < < < | < < < < < < < < < < < < < < < < < < < < | | > > | > > | > > > | > > > > > | > | > > > > > > > > > > > > > > > > > | > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | | | | | < | | | > | | | | | | > | | | | | | | < | | | > > | < | | > > | | | | | | < < < < < | < | < < < < < < < | < | | < < | < > | > < > > | | | < | | > | < | < > | < | < | < < < < > | | < < | | < | > | < < > | < | | > | | | | | | | | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 | ** (This can happen if a SELECT callback tries to ** do an UPDATE or DELETE.) ** ** If zTable is 0 or "", then a temporary database file is created and ** a cursor to that temporary file is opened. The temporary file ** will be deleted from the disk when it is closed. */ static int sqliteMemOpenCursor( Dbbe *pDbbe, /* The database the table belongs to */ const char *zTable, /* The SQL name of the file to be opened */ int writeable, /* True to open for writing */ DbbeCursor **ppCursr /* Write the resulting table pointer here */ ){ DbbeCursor *pCursr; /* The new table cursor */ char *zName; /* Canonical table name */ MTable *pTble; /* The underlying data file for this table */ int rc = SQLITE_OK; /* Return value */ int rw_mask; /* Permissions mask for opening a table */ int mode; /* Mode for opening a table */ Dbbex *pBe = (Dbbex*)pDbbe; *ppCursr = 0; pCursr = sqliteMalloc( sizeof(*pCursr) ); if( pCursr==0 ) return SQLITE_NOMEM; if( zTable ){ Datum key; zName = sqliteNameOfTable(zTable); key.p = zName; key.n = strlen(zName); pTble = ArrayFind(&pBe->tables, key).p; }else{ zName = 0; pTble = 0; } if( pTble==0 ){ pTble = sqliteMalloc( sizeof(*pTble) ); if( pTble==0 ){ sqliteFree(zName); return SQLITE_NOMEM; } if( zName ){ Datum ins_key, ins_data; pTble->zName = zName; pTble->delOnClose = 0; ins_data.p = pTble; ins_data.n = sizeof( *pTble ); ins_key.p = zName; ins_key.n = strlen(zName); ArrayInsert(&pBe->tables, ins_key, ins_data); }else{ pTble->zName = 0; pTble->delOnClose = 1; } ArrayInit(&pTble->data); }else{ sqliteFree(zName); } pCursr->pBe = pBe; pCursr->pTble = pTble; pCursr->needRewind = 1; *ppCursr = pCursr; return rc; } /* ** Drop a table from the database. The file on the disk that corresponds ** to this table is deleted. */ static void sqliteMemDropTable(Dbbe *pDbbe, const char *zTable){ char *zName; /* Name of the table file */ Datum key, data; MTable *pTble; ArrayElem *i; Dbbex *pBe = (Dbbex*)pDbbe; zName = sqliteNameOfTable(zTable); key.p = zName; key.n = strlen(zName); pTble = ArrayFind(&pBe->tables, key).p; if( pTble ){ data.p = 0; data.n = 0; ArrayInsert(&pBe->tables, key, data); deleteMTable(pTble); } sqliteFree(zName); } /* ** Close a cursor previously opened by sqliteMemOpenCursor(). ** ** There can be multiple cursors pointing to the same open file. ** The underlying file is not closed until all cursors have been ** closed. This routine decrements the MTable.nref field of the ** underlying file and closes the file when nref reaches 0. */ static void sqliteMemCloseCursor(DbbeCursor *pCursr){ MTable *pTble; Dbbex *pBe; if( pCursr==0 ) return; pTble = pCursr->pTble; pBe = pCursr->pBe; if( pTble->delOnClose ){ deleteMTable(pTble); } sqliteFree(pCursr); } /* ** Reorganize a table to reduce search times and disk usage. */ static int sqliteMemReorganizeTable(Dbbe *pBe, const char *zTable){ /* Do nothing */ return SQLITE_OK; } /* ** Fetch a single record from an open cursor. Return 1 on success ** and 0 on failure. */ static int sqliteMemFetch(DbbeCursor *pCursr, int nKey, char *pKey){ Datum key; key.n = nKey; key.p = pKey; pCursr->elem = ArrayFindElement(&pCursr->pTble->data, key); return pCursr->elem!=0; } /* ** Return 1 if the given key is already in the table. Return 0 ** if it is not. */ static int sqliteMemTest(DbbeCursor *pCursr, int nKey, char *pKey){ return sqliteMemFetch(pCursr, nKey, pKey); } /* ** Copy bytes from the current key or data into a buffer supplied by ** the calling function. Return the number of bytes copied. */ static int sqliteMemCopyKey(DbbeCursor *pCursr, int offset, int size, char *zBuf){ int n; if( pCursr->elem==0 ) return 0; if( offset>=ArrayKeySize(pCursr->elem) ) return 0; if( offset+size>ArrayKeySize(pCursr->elem) ){ n = ArrayKeySize(pCursr->elem) - offset; }else{ n = size; } memcpy(zBuf, &((char*)ArrayKey(pCursr->elem))[offset], n); return n; } static int sqliteMemCopyData(DbbeCursor *pCursr, int offset, int size, char *zBuf){ int n; if( pCursr->elem==0 ) return 0; if( offset>=ArrayDataSize(pCursr->elem) ) return 0; if( offset+size>ArrayDataSize(pCursr->elem) ){ n = ArrayDataSize(pCursr->elem) - offset; }else{ n = size; } memcpy(zBuf, &((char*)ArrayData(pCursr->elem))[offset], n); return n; } /* ** Return a pointer to bytes from the key or data. The data returned ** is ephemeral. */ static char *sqliteMemReadKey(DbbeCursor *pCursr, int offset){ if( pCursr->elem==0 || offset<0 || offset>=ArrayKeySize(pCursr->elem) ){ return ""; } return &((char*)ArrayKey(pCursr->elem))[offset]; } static char *sqliteMemReadData(DbbeCursor *pCursr, int offset){ if( pCursr->elem==0 || offset<0 || offset>=ArrayDataSize(pCursr->elem) ){ return ""; } return &((char*)ArrayData(pCursr->elem))[offset]; } /* ** Return the total number of bytes in either data or key. */ static int sqliteMemKeyLength(DbbeCursor *pCursr){ return pCursr->elem ? ArrayKeySize(pCursr->elem) : 0; } static int sqliteMemDataLength(DbbeCursor *pCursr){ return pCursr->elem ? ArrayDataSize(pCursr->elem) : 0; } /* ** Make is so that the next call to sqliteNextKey() finds the first ** key of the table. */ static int sqliteMemRewind(DbbeCursor *pCursr){ pCursr->needRewind = 1; return SQLITE_OK; } /* ** Read the next key from the table. Return 1 on success. Return ** 0 if there are no more keys. */ static int sqliteMemNextKey(DbbeCursor *pCursr){ if( pCursr->needRewind || pCursr->elem==0 ){ pCursr->elem = ArrayFirst(&pCursr->pTble->data); pCursr->needRewind = 0; }else{ pCursr->elem = ArrayNext(pCursr->elem); } return pCursr->elem!=0; } /* ** Get a new integer key. */ static int sqliteMemNew(DbbeCursor *pCursr){ int iKey; Datum key; int go = 1; int i; struct rc4 *pRc4; pRc4 = &pCursr->pBe->rc4; while( go ){ iKey = 0; for(i=0; i<4; i++){ iKey = (iKey<<8) + rc4byte(pRc4); } if( iKey==0 ) continue; key.p = (char*)&iKey; key.n = 4; go = ArrayFindElement(&pCursr->pTble->data, key)!=0; } return iKey; } /* ** Write an entry into the table. Overwrite any prior entry with the ** same key. */ static int sqliteMemPut(DbbeCursor *pCursr, int nKey,char *pKey, int nData, char *pData){ Datum data, key; data.n = nData; data.p = sqliteMalloc( data.n ); memcpy(data.p, pData, data.n); key.n = nKey; key.p = pKey; data = ArrayInsert(&pCursr->pTble->data, key, data); if( data.p ){ sqliteFree(data.p); } return SQLITE_OK; } /* ** Remove an entry from a table, if the entry exists. */ static int sqliteMemDelete(DbbeCursor *pCursr, int nKey, char *pKey){ Datum key, data; key.n = nKey; key.p = pKey; data.p = 0; data.n = 0; data = ArrayInsert(&pCursr->pTble->data, key, data); if( data.p ){ sqliteFree(data.p); } return SQLITE_OK; } /* ** Open a temporary file. The file should be deleted when closed. ** ** Note that we can't use the old Unix trick of opening the file ** and then immediately unlinking the file. That works great ** under Unix, but fails when we try to port to Windows. */ static int sqliteMemOpenTempFile(Dbbe *pDbbe, FILE **ppTble){ char *zName; /* Full name of the temporary file */ char zBuf[50]; /* Base name of the temporary file */ int i; /* Loop counter */ int limit; /* Prevent an infinite loop */ int rc = SQLITE_OK; /* Value returned by this function */ Dbbex *pBe = (Dbbex*)pDbbe; for(i=0; i<pBe->nTemp; i++){ if( pBe->apTemp[i]==0 ) break; } if( i>=pBe->nTemp ){ pBe->nTemp++; pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) ); pBe->azTemp = sqliteRealloc(pBe->azTemp, pBe->nTemp*sizeof(char*) ); } if( pBe->apTemp==0 ){ *ppTble = 0; return SQLITE_NOMEM; } limit = 4; zName = 0; do{ randomName(&pBe->rc4, zBuf, "/tmp/_temp_file_"); sqliteFree(zName); zName = 0; sqliteSetString(&zName, zBuf, 0); }while( access(zName,0)==0 && limit-- >= 0 ); *ppTble = pBe->apTemp[i] = fopen(zName, "w+"); if( pBe->apTemp[i]==0 ){ rc = SQLITE_ERROR; sqliteFree(zName); pBe->azTemp[i] = 0; }else{ pBe->azTemp[i] = zName; } return rc; } /* ** Close a temporary file opened using sqliteMemOpenTempFile() */ static void sqliteMemCloseTempFile(Dbbe *pDbbe, FILE *f){ int i; Dbbex *pBe = (Dbbex*)pDbbe; for(i=0; i<pBe->nTemp; i++){ if( pBe->apTemp[i]==f ){ unlink(pBe->azTemp[i]); sqliteFree(pBe->azTemp[i]); pBe->apTemp[i] = 0; pBe->azTemp[i] = 0; break; } } fclose(f); } /* ** This routine opens a new database. For the GDBM driver ** implemented here, the database name is the name of the directory ** containing all the files of the database. ** ** If successful, a pointer to the Dbbe structure is returned. ** If there are errors, an appropriate error message is left ** in *pzErrMsg and NULL is returned. */ Dbbe *sqliteMemOpen( const char *zName, /* The name of the database */ int writeFlag, /* True if we will be writing to the database */ int createFlag, /* True to create database if it doesn't exist */ char **pzErrMsg /* Write error messages (if any) here */ ){ Dbbex *pNew; long now; pNew = sqliteMalloc( sizeof(*pNew) ); if( pNew==0 ){ sqliteSetString(pzErrMsg, "out of memory", 0); return 0; } ArrayInit(&pNew->tables); pNew->dbbe.Close = sqliteMemClose; pNew->dbbe.OpenCursor = sqliteMemOpenCursor; pNew->dbbe.DropTable = sqliteMemDropTable; pNew->dbbe.ReorganizeTable = sqliteMemReorganizeTable; pNew->dbbe.CloseCursor = sqliteMemCloseCursor; pNew->dbbe.Fetch = sqliteMemFetch; pNew->dbbe.Test = sqliteMemTest; pNew->dbbe.CopyKey = sqliteMemCopyKey; pNew->dbbe.CopyData = sqliteMemCopyData; pNew->dbbe.ReadKey = sqliteMemReadKey; pNew->dbbe.ReadData = sqliteMemReadData; pNew->dbbe.KeyLength = sqliteMemKeyLength; pNew->dbbe.DataLength = sqliteMemDataLength; pNew->dbbe.NextKey = sqliteMemNextKey; pNew->dbbe.Rewind = sqliteMemRewind; pNew->dbbe.New = sqliteMemNew; pNew->dbbe.Put = sqliteMemPut; pNew->dbbe.Delete = sqliteMemDelete; pNew->dbbe.OpenTempFile = sqliteMemOpenTempFile; pNew->dbbe.CloseTempFile = sqliteMemCloseTempFile; time(&now); rc4init(&pNew->rc4, (char*)&now, sizeof(now)); return &pNew->dbbe; } |
Changes to test/all.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # Author contact information: # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file runs all tests. # | | > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | # Author contact information: # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file runs all tests. # # $Id: all.test,v 1.3 2000/10/19 14:10:09 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl rename finish_test really_finish_test proc finish_test {} {} if {[file exists ./sqlite_test_count]} { set COUNT [exec cat ./sqlite_test_count] } else { set COUNT 1 } for {set Counter 0} {$Counter<$COUNT} {incr Counter} { set dbprefix memory: foreach testfile [lsort -dictionary [glob $testdir/*.test]] { if {[file tail $testfile]=="all.test"} continue source $testfile } set dbprefix gdbm: foreach testfile [lsort -dictionary [glob $testdir/*.test]] { if {[file tail $testfile]=="all.test"} continue source $testfile } } really_finish_test |
Changes to test/index.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # | | > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE INDEX statement. # # $Id: index.test,v 1.8 2000/10/19 14:10:09 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic index and verify it is added to sqlite_master # do_test index-1.1 { execsql {CREATE TABLE test1(f1 int, f2 int, f3 int)} execsql {CREATE INDEX index1 ON test1(f1)} execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1} do_test index-1.1b { execsql {SELECT name, sql, tbl_name, type FROM sqlite_master WHERE name='index1'} } {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} skipif memory: do_test index-1.1c { db close sqlite db testdb execsql {SELECT name, sql, tbl_name, type FROM sqlite_master WHERE name='index1'} } {index1 {CREATE INDEX index1 ON test1(f1)} test1 index} skipif memory: do_test index-1.1d { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } {index1 test1} # Verify that the index dies with the table |
︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 | # Add a single entry to the table. Verify that files are created # for every index. # set r {} for {set i 1} {$i<100} {incr i} { lappend r testdb/index$i.tbl } do_test index-3.2 { execsql {INSERT INTO test1 VALUES(1,2,3,4,5)} lsort -dictionary [glob testdb/index*.tbl] } $r # Verify that all the indices go away when we drop the table. # | > | 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # Add a single entry to the table. Verify that files are created # for every index. # set r {} for {set i 1} {$i<100} {incr i} { lappend r testdb/index$i.tbl } skipif memory: do_test index-3.2 { execsql {INSERT INTO test1 VALUES(1,2,3,4,5)} lsort -dictionary [glob testdb/index*.tbl] } $r # Verify that all the indices go away when we drop the table. # |
︙ | ︙ | |||
219 220 221 222 223 224 225 226 227 228 229 230 231 232 | # Create a primary key # do_test index-7.1 { execsql {CREATE TABLE test1(f1 int, f2 int primary key)} for {set i 1} {$i<20} {incr i} { execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" } lsort -dictionary [glob testdb/test1*.tbl] } {testdb/test1.tbl testdb/test1__primary_key.tbl} do_test index-7.2 { execsql {SELECT f1 FROM test1 WHERE f2=65536} } {16} do_test index-7.3 { set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}] | > > > > | 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | # Create a primary key # do_test index-7.1 { execsql {CREATE TABLE test1(f1 int, f2 int primary key)} for {set i 1} {$i<20} {incr i} { execsql "INSERT INTO test1 VALUES($i,[expr {int(pow(2,$i))}])" } execsql {SELECT count(*) FROM test1} } {19} skipif memory: do_test index-7.1b { lsort -dictionary [glob testdb/test1*.tbl] } {testdb/test1.tbl testdb/test1__primary_key.tbl} do_test index-7.2 { execsql {SELECT f1 FROM test1 WHERE f2=65536} } {16} do_test index-7.3 { set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}] |
︙ | ︙ |
Changes to test/lock.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is database locks. # | | > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is database locks. # # $Id: lock.test,v 1.4 2000/10/19 14:10:09 drh Exp $ if {$dbprefix=="gdbm:"} { set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a largish table # |
︙ | ︙ | |||
95 96 97 98 99 100 101 | } {xyz} catch {exec ps -uax | grep $::lock_pid} catch {exec kill -HUP $::lock_pid} catch {exec kill -9 $::lock_pid} finish_test | > > | 97 98 99 100 101 102 103 104 105 | } {xyz} catch {exec ps -uax | grep $::lock_pid} catch {exec kill -HUP $::lock_pid} catch {exec kill -9 $::lock_pid} finish_test } |
Changes to test/select2.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SELECT statement. # # $Id: select2.test,v 1.9 2000/10/19 14:10:09 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table with some data # execsql {CREATE TABLE tbl1(f1 int, f2 int)} |
︙ | ︙ | |||
100 101 102 103 104 105 106 107 108 | do_test select2-3.2b { execsql {SELECT f1 FROM tbl2 WHERE 1000=f2} } {500} do_test select2-3.2c { execsql {SELECT f1 FROM tbl2 WHERE f2=1000} } {500} do_test select2-3.2d { set t1 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}} 1] 0] set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2=1000}} 1] 0] | > > > > > > > | > > > | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | do_test select2-3.2b { execsql {SELECT f1 FROM tbl2 WHERE 1000=f2} } {500} do_test select2-3.2c { execsql {SELECT f1 FROM tbl2 WHERE f2=1000} } {500} do_test select2-3.2d { execsql {SELECT fcnt() FROM tbl2 WHERE 1000=f2} } {2} do_test select2-3.2e { execsql {SELECT fcnt() FROM tbl2 WHERE f2=1000} } {2} testif gdbm: do_test select2-3.2f { set t1 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE 1000=f2}} 1] 0] set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2=1000}} 1] 0] expr {$t1*0.7<$t2 && $t2*0.7<$t1} } {1} # Make sure queries run faster with an index than without # do_test select2-3.3 { set t1 [lindex [time {execsql {SELECT f1 from tbl2 WHERE f2==2000}} 1] 0] execsql {DROP INDEX idx1} set t2 [lindex [time {execsql {SELECT f1 FROM tbl2 WHERE f2==2000}} 1] 0] expr {$t1*10 < $t2} } {1} do_test select2-3.4 { expr {[execsql {SELECT fcnt() FROM tbl2 WHERE f2==2000}]>10} } {1} finish_test |
Changes to test/table.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the CREATE TABLE statement. # # $Id: table.test,v 1.7 2000/10/19 14:10:09 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a basic table and verify it is added to sqlite_master # do_test table-1.1 { |
︙ | ︙ | |||
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | two text )}} # Verify that both table files exists in the database directory # do_test table-1.2 { execsql {INSERT INTO test1 VALUES('hi', 'y''all')} lsort [glob -nocomplain testdb/*.tbl] } {testdb/sqlite_master.tbl testdb/test1.tbl} # Verify the other fields of the sqlite_master file. # do_test table-1.3 { execsql {SELECT name, tbl_name, type FROM sqlite_master WHERE type!='meta'} } {test1 test1 table} # Close and reopen the database. Verify that everything is # still the same. # do_test table-1.4 { db close sqlite db testdb execsql {SELECT name, tbl_name, type from sqlite_master WHERE type!='meta'} } {test1 test1 table} # Drop the database and make sure it disappears. # do_test table-1.5 { execsql {DROP TABLE test1} execsql {SELECT * FROM sqlite_master WHERE type!='meta'} } {} # Verify that the file associated with the database is gone. # do_test table-1.5 { lsort [glob -nocomplain testdb/*.tbl] } {testdb/sqlite_master.tbl} # Close and reopen the database. Verify that the table is # still gone. # do_test table-1.6 { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {} # Repeat the above steps, but this time quote the table name. | > > > > > > | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | two text )}} # Verify that both table files exists in the database directory # do_test table-1.2 { execsql {INSERT INTO test1 VALUES('hi', 'y''all')} } {} testif gdbm: do_test table-1.2b { lsort [glob -nocomplain testdb/*.tbl] } {testdb/sqlite_master.tbl testdb/test1.tbl} # Verify the other fields of the sqlite_master file. # do_test table-1.3 { execsql {SELECT name, tbl_name, type FROM sqlite_master WHERE type!='meta'} } {test1 test1 table} # Close and reopen the database. Verify that everything is # still the same. # skipif memory: do_test table-1.4 { db close sqlite db testdb execsql {SELECT name, tbl_name, type from sqlite_master WHERE type!='meta'} } {test1 test1 table} # Drop the database and make sure it disappears. # do_test table-1.5 { execsql {DROP TABLE test1} execsql {SELECT * FROM sqlite_master WHERE type!='meta'} } {} # Verify that the file associated with the database is gone. # testif gdbm: do_test table-1.5 { lsort [glob -nocomplain testdb/*.tbl] } {testdb/sqlite_master.tbl} # Close and reopen the database. Verify that the table is # still gone. # skipif memory: do_test table-1.6 { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {} # Repeat the above steps, but this time quote the table name. |
︙ | ︙ | |||
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | set v [catch {execsql {CREATE TABLE test2(two text)}} msg] lappend v $msg } {1 {table test2 already exists}} do_test table-2.1b { set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} do_test table-2.1c { db close sqlite db testdb set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} do_test table-2.1d { execsql {DROP TABLE test2; SELECT name FROM sqlite_master WHERE type!='meta'} } {} # Verify that we cannot make a table with the same name as an index # do_test table-2.2a { execsql {CREATE TABLE test2(one text); CREATE INDEX test3 ON test2(one)} set v [catch {execsql {CREATE TABLE test3(two text)}} msg] lappend v $msg } {1 {there is already an index named test3}} do_test table-2.2b { db close sqlite db testdb set v [catch {execsql {CREATE TABLE test3(two text)}} msg] lappend v $msg } {1 {there is already an index named test3}} do_test table-2.2c { | > > | 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | set v [catch {execsql {CREATE TABLE test2(two text)}} msg] lappend v $msg } {1 {table test2 already exists}} do_test table-2.1b { set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} skipif memory: do_test table-2.1c { db close sqlite db testdb set v [catch {execsql {CREATE TABLE sqlite_master(two text)}} msg] lappend v $msg } {1 {table sqlite_master already exists}} do_test table-2.1d { execsql {DROP TABLE test2; SELECT name FROM sqlite_master WHERE type!='meta'} } {} # Verify that we cannot make a table with the same name as an index # do_test table-2.2a { execsql {CREATE TABLE test2(one text); CREATE INDEX test3 ON test2(one)} set v [catch {execsql {CREATE TABLE test3(two text)}} msg] lappend v $msg } {1 {there is already an index named test3}} skipif memory: do_test table-2.2b { db close sqlite db testdb set v [catch {execsql {CREATE TABLE test3(two text)}} msg] lappend v $msg } {1 {there is already an index named test3}} do_test table-2.2c { |
︙ | ︙ | |||
194 195 196 197 198 199 200 201 202 203 204 205 206 207 | set v [catch {execsql {CREATE TABLE biG(xyz foo)}} msg] lappend v $msg } {1 {table biG already exists}} do_test table-3.4 { set v [catch {execsql {CREATE TABLE bIg(xyz foo)}} msg] lappend v $msg } {1 {table bIg already exists}} do_test table-3.5 { db close sqlite db testdb set v [catch {execsql {CREATE TABLE Big(xyz foo)}} msg] lappend v $msg } {1 {table Big already exists}} do_test table-3.6 { | > | 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | set v [catch {execsql {CREATE TABLE biG(xyz foo)}} msg] lappend v $msg } {1 {table biG already exists}} do_test table-3.4 { set v [catch {execsql {CREATE TABLE bIg(xyz foo)}} msg] lappend v $msg } {1 {table bIg already exists}} skipif memory: do_test table-3.5 { db close sqlite db testdb set v [catch {execsql {CREATE TABLE Big(xyz foo)}} msg] lappend v $msg } {1 {table Big already exists}} do_test table-3.6 { |
︙ | ︙ | |||
222 223 224 225 226 227 228 229 230 231 232 233 234 235 | append sql "field$k text," } append sql "last_field text)" execsql $sql } execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r do_test table-4.1b { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r # Drop the even number tables | > | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | append sql "field$k text," } append sql "last_field text)" execsql $sql } execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r skipif memory: do_test table-4.1b { db close sqlite db testdb execsql {SELECT name FROM sqlite_master WHERE type!='meta' ORDER BY name} } $r # Drop the even number tables |
︙ | ︙ | |||
283 284 285 286 287 288 289 290 291 292 293 294 295 296 | execsql {CREATE TABLE test1(f1 int)} execsql {EXPLAIN DROP TABLE test1} execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {test1} # Create a table with a goofy name # do_test table-6.1 { execsql {CREATE TABLE 'Spaces In This Name!'(x int)} execsql {INSERT INTO 'spaces in this name!' VALUES(1)} set list [glob -nocomplain testdb/spaces*.tbl] } {testdb/spaces+in+this+name+.tbl} finish_test | > | 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 | execsql {CREATE TABLE test1(f1 int)} execsql {EXPLAIN DROP TABLE test1} execsql {SELECT name FROM sqlite_master WHERE type!='meta'} } {test1} # Create a table with a goofy name # testif gdbm: do_test table-6.1 { execsql {CREATE TABLE 'Spaces In This Name!'(x int)} execsql {INSERT INTO 'spaces in this name!' VALUES(1)} set list [glob -nocomplain testdb/spaces*.tbl] } {testdb/spaces+in+this+name+.tbl} finish_test |
Changes to test/tester.tcl.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # | | > > > > > > > > > | | > > > > > | > | > > > > | | > > > > > > > > > > > > > > > > > > > > > > > | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # # $Id: tester.tcl,v 1.7 2000/10/19 14:10:09 drh Exp $ # Create a test database # if {![info exists dbprefix]} { if {[info exists env(SQLITE_PREFIX)]} { set dbprefix $env(SQLITE_PREFIX): } else { set dbprefix "gdbm:" } } switch $dbprefix { gdbm: { file delete -force testdb file mkdir testdb } memory: { # do nothing } } sqlite db ${dbprefix}testdb # Abort early if this script has been run before. # if {[info exists nTest]} return # Set the test counters to zero # set nErr 0 set nTest 0 set skip_test 0 # Invoke the do_test procedure to run a single test # proc do_test {name cmd expected} { global argv nErr nTest skip_test if {$skip_test} { set skip_test 0 return } if {[llength $argv]==0} { set go 1 } else { set go 0 foreach pattern $argv { if {[string match $pattern $name]} { set go 1 break } } } if {!$go} return incr nTest puts -nonewline $::dbprefix$name... flush stdout if {[catch {uplevel #0 "$cmd;\n"} result]} { puts "\nError: $result" incr nErr } elseif {[string compare $result $expected]} { puts "\nExpected: \[$expected\]\n Got: \[$result\]" incr nErr } else { puts " Ok" } } # Skip a test based on the dbprefix # proc skipif {args} { foreach a $args { if {$::dbprefix==$a} { set ::skip_test 1 return } } } # Run the next test only if the dbprefix is among the listed arguments # proc testif {args} { foreach a $args { if {$::dbprefix==$a} { set ::skip_test 0 return } } set ::skip_test 1 } # Run this routine last # proc finish_test {} { global nTest nErr catch {db close} puts "$nErr errors out of $nTest tests" |
︙ | ︙ |
Changes to test/vacuum.test.
︙ | ︙ | |||
19 20 21 22 23 24 25 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # | | | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | # drh@hwaci.com # http://www.hwaci.com/drh/ # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # # $Id: vacuum.test,v 1.2 2000/10/19 14:10:10 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to vacuum a non-existant table. # do_test vacuum-1.1 { |
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | execsql {CREATE INDEX index1 ON test1(a)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(2)} execsql {INSERT INTO test1 VALUES(3)} execsql {INSERT INTO test2 VALUES(4)} do_test vacuum-1.3 { set b1 [file mtime testdb/test1.tbl] set b2 [file mtime testdb/test2.tbl] set b3 [file mtime testdb/index1.tbl] after 1000 execsql {VACUUM test1} set a1 [file mtime testdb/test1.tbl] set a2 [file mtime testdb/test2.tbl] set a3 [file mtime testdb/index1.tbl] expr {$a1>$b1 && $a2==$b2 && $a3==$b3} } {1} do_test vacuum-1.4 { set b1 [file mtime testdb/test1.tbl] set b2 [file mtime testdb/test2.tbl] set b3 [file mtime testdb/index1.tbl] after 1000 execsql {VACUUM} set a1 [file mtime testdb/test1.tbl] | > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | execsql {CREATE INDEX index1 ON test1(a)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(1)} execsql {INSERT INTO test1 VALUES(2)} execsql {INSERT INTO test1 VALUES(3)} execsql {INSERT INTO test2 VALUES(4)} testif gdbm: do_test vacuum-1.3 { set b1 [file mtime testdb/test1.tbl] set b2 [file mtime testdb/test2.tbl] set b3 [file mtime testdb/index1.tbl] after 1000 execsql {VACUUM test1} set a1 [file mtime testdb/test1.tbl] set a2 [file mtime testdb/test2.tbl] set a3 [file mtime testdb/index1.tbl] expr {$a1>$b1 && $a2==$b2 && $a3==$b3} } {1} testif gdbm: do_test vacuum-1.4 { set b1 [file mtime testdb/test1.tbl] set b2 [file mtime testdb/test2.tbl] set b3 [file mtime testdb/index1.tbl] after 1000 execsql {VACUUM} set a1 [file mtime testdb/test1.tbl] |
︙ | ︙ |
Changes to www/changes.tcl.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2000 Oct 18 (1.0.13)} { <li>Break out the GDBM driver into a separate file in anticipation to added new drivers.</li> <li>Allow the name of a database to be prefixed by the driver type. For now, the only driver type is "gdbm:".<li> } | > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2000 Oct 19 (1.0.14)} { <li>Added a "memory:" backend driver that stores its database in an in-memory hash table.</li> } chng {2000 Oct 18 (1.0.13)} { <li>Break out the GDBM driver into a separate file in anticipation to added new drivers.</li> <li>Allow the name of a database to be prefixed by the driver type. For now, the only driver type is "gdbm:".<li> } |
︙ | ︙ |