xref: /illumos-gate/usr/src/lib/libsqlite/src/test2.c (revision 4a7ceb24cfcc0a97f96d86cfe5852ae445b50e57)
1 
2 #pragma ident	"%Z%%M%	%I%	%E% SMI"
3 
4 /*
5 ** 2001 September 15
6 **
7 ** The author disclaims copyright to this source code.  In place of
8 ** a legal notice, here is a blessing:
9 **
10 **    May you do good and not evil.
11 **    May you find forgiveness for yourself and forgive others.
12 **    May you share freely, never taking more than you give.
13 **
14 *************************************************************************
15 ** Code for testing the pager.c module in SQLite.  This code
16 ** is not included in the SQLite library.  It is used for automated
17 ** testing of the SQLite library.
18 **
19 ** $Id: test2.c,v 1.16 2004/02/10 01:54:28 drh Exp $
20 */
21 #include "os.h"
22 #include "sqliteInt.h"
23 #include "pager.h"
24 #include "tcl.h"
25 #include <stdlib.h>
26 #include <string.h>
27 
28 /*
29 ** Interpret an SQLite error number
30 */
31 static char *errorName(int rc){
32   char *zName;
33   switch( rc ){
34     case SQLITE_OK:         zName = "SQLITE_OK";          break;
35     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
36     case SQLITE_INTERNAL:   zName = "SQLITE_INTERNAL";    break;
37     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
38     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
39     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
40     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
41     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
42     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
43     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
44     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
45     case SQLITE_NOTFOUND:   zName = "SQLITE_NOTFOUND";    break;
46     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
47     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
48     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
49     case SQLITE_EMPTY:      zName = "SQLITE_EMPTY";       break;
50     case SQLITE_SCHEMA:     zName = "SQLITE_SCHEMA";      break;
51     case SQLITE_TOOBIG:     zName = "SQLITE_TOOBIG";      break;
52     case SQLITE_CONSTRAINT: zName = "SQLITE_CONSTRAINT";  break;
53     case SQLITE_MISMATCH:   zName = "SQLITE_MISMATCH";    break;
54     case SQLITE_MISUSE:     zName = "SQLITE_MISUSE";      break;
55     case SQLITE_NOLFS:      zName = "SQLITE_NOLFS";       break;
56     default:                zName = "SQLITE_Unknown";     break;
57   }
58   return zName;
59 }
60 
61 /*
62 ** Usage:   pager_open FILENAME N-PAGE
63 **
64 ** Open a new pager
65 */
66 static int pager_open(
67   void *NotUsed,
68   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
69   int argc,              /* Number of arguments */
70   const char **argv      /* Text of each argument */
71 ){
72   Pager *pPager;
73   int nPage;
74   int rc;
75   char zBuf[100];
76   if( argc!=3 ){
77     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
78        " FILENAME N-PAGE\"", 0);
79     return TCL_ERROR;
80   }
81   if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
82   rc = sqlitepager_open(&pPager, argv[1], nPage, 0, 1);
83   if( rc!=SQLITE_OK ){
84     Tcl_AppendResult(interp, errorName(rc), 0);
85     return TCL_ERROR;
86   }
87   sprintf(zBuf,"0x%x",(int)pPager);
88   Tcl_AppendResult(interp, zBuf, 0);
89   return TCL_OK;
90 }
91 
92 /*
93 ** Usage:   pager_close ID
94 **
95 ** Close the given pager.
96 */
97 static int pager_close(
98   void *NotUsed,
99   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
100   int argc,              /* Number of arguments */
101   const char **argv      /* Text of each argument */
102 ){
103   Pager *pPager;
104   int rc;
105   if( argc!=2 ){
106     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
107        " ID\"", 0);
108     return TCL_ERROR;
109   }
110   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
111   rc = sqlitepager_close(pPager);
112   if( rc!=SQLITE_OK ){
113     Tcl_AppendResult(interp, errorName(rc), 0);
114     return TCL_ERROR;
115   }
116   return TCL_OK;
117 }
118 
119 /*
120 ** Usage:   pager_rollback ID
121 **
122 ** Rollback changes
123 */
124 static int pager_rollback(
125   void *NotUsed,
126   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
127   int argc,              /* Number of arguments */
128   const char **argv      /* Text of each argument */
129 ){
130   Pager *pPager;
131   int rc;
132   if( argc!=2 ){
133     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
134        " ID\"", 0);
135     return TCL_ERROR;
136   }
137   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
138   rc = sqlitepager_rollback(pPager);
139   if( rc!=SQLITE_OK ){
140     Tcl_AppendResult(interp, errorName(rc), 0);
141     return TCL_ERROR;
142   }
143   return TCL_OK;
144 }
145 
146 /*
147 ** Usage:   pager_commit ID
148 **
149 ** Commit all changes
150 */
151 static int pager_commit(
152   void *NotUsed,
153   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
154   int argc,              /* Number of arguments */
155   const char **argv      /* Text of each argument */
156 ){
157   Pager *pPager;
158   int rc;
159   if( argc!=2 ){
160     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
161        " ID\"", 0);
162     return TCL_ERROR;
163   }
164   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
165   rc = sqlitepager_commit(pPager);
166   if( rc!=SQLITE_OK ){
167     Tcl_AppendResult(interp, errorName(rc), 0);
168     return TCL_ERROR;
169   }
170   return TCL_OK;
171 }
172 
173 /*
174 ** Usage:   pager_ckpt_begin ID
175 **
176 ** Start a new checkpoint.
177 */
178 static int pager_ckpt_begin(
179   void *NotUsed,
180   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
181   int argc,              /* Number of arguments */
182   const char **argv      /* Text of each argument */
183 ){
184   Pager *pPager;
185   int rc;
186   if( argc!=2 ){
187     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
188        " ID\"", 0);
189     return TCL_ERROR;
190   }
191   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
192   rc = sqlitepager_ckpt_begin(pPager);
193   if( rc!=SQLITE_OK ){
194     Tcl_AppendResult(interp, errorName(rc), 0);
195     return TCL_ERROR;
196   }
197   return TCL_OK;
198 }
199 
200 /*
201 ** Usage:   pager_ckpt_rollback ID
202 **
203 ** Rollback changes to a checkpoint
204 */
205 static int pager_ckpt_rollback(
206   void *NotUsed,
207   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
208   int argc,              /* Number of arguments */
209   const char **argv      /* Text of each argument */
210 ){
211   Pager *pPager;
212   int rc;
213   if( argc!=2 ){
214     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
215        " ID\"", 0);
216     return TCL_ERROR;
217   }
218   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
219   rc = sqlitepager_ckpt_rollback(pPager);
220   if( rc!=SQLITE_OK ){
221     Tcl_AppendResult(interp, errorName(rc), 0);
222     return TCL_ERROR;
223   }
224   return TCL_OK;
225 }
226 
227 /*
228 ** Usage:   pager_ckpt_commit ID
229 **
230 ** Commit changes to a checkpoint
231 */
232 static int pager_ckpt_commit(
233   void *NotUsed,
234   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
235   int argc,              /* Number of arguments */
236   const char **argv      /* Text of each argument */
237 ){
238   Pager *pPager;
239   int rc;
240   if( argc!=2 ){
241     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
242        " ID\"", 0);
243     return TCL_ERROR;
244   }
245   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
246   rc = sqlitepager_ckpt_commit(pPager);
247   if( rc!=SQLITE_OK ){
248     Tcl_AppendResult(interp, errorName(rc), 0);
249     return TCL_ERROR;
250   }
251   return TCL_OK;
252 }
253 
254 /*
255 ** Usage:   pager_stats ID
256 **
257 ** Return pager statistics.
258 */
259 static int pager_stats(
260   void *NotUsed,
261   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
262   int argc,              /* Number of arguments */
263   const char **argv      /* Text of each argument */
264 ){
265   Pager *pPager;
266   int i, *a;
267   if( argc!=2 ){
268     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
269        " ID\"", 0);
270     return TCL_ERROR;
271   }
272   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
273   a = sqlitepager_stats(pPager);
274   for(i=0; i<9; i++){
275     static char *zName[] = {
276       "ref", "page", "max", "size", "state", "err",
277       "hit", "miss", "ovfl",
278     };
279     char zBuf[100];
280     Tcl_AppendElement(interp, zName[i]);
281     sprintf(zBuf,"%d",a[i]);
282     Tcl_AppendElement(interp, zBuf);
283   }
284   return TCL_OK;
285 }
286 
287 /*
288 ** Usage:   pager_pagecount ID
289 **
290 ** Return the size of the database file.
291 */
292 static int pager_pagecount(
293   void *NotUsed,
294   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
295   int argc,              /* Number of arguments */
296   const char **argv      /* Text of each argument */
297 ){
298   Pager *pPager;
299   char zBuf[100];
300   if( argc!=2 ){
301     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
302        " ID\"", 0);
303     return TCL_ERROR;
304   }
305   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
306   sprintf(zBuf,"%d",sqlitepager_pagecount(pPager));
307   Tcl_AppendResult(interp, zBuf, 0);
308   return TCL_OK;
309 }
310 
311 /*
312 ** Usage:   page_get ID PGNO
313 **
314 ** Return a pointer to a page from the database.
315 */
316 static int page_get(
317   void *NotUsed,
318   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
319   int argc,              /* Number of arguments */
320   const char **argv      /* Text of each argument */
321 ){
322   Pager *pPager;
323   char zBuf[100];
324   void *pPage;
325   int pgno;
326   int rc;
327   if( argc!=3 ){
328     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
329        " ID PGNO\"", 0);
330     return TCL_ERROR;
331   }
332   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
333   if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
334   rc = sqlitepager_get(pPager, pgno, &pPage);
335   if( rc!=SQLITE_OK ){
336     Tcl_AppendResult(interp, errorName(rc), 0);
337     return TCL_ERROR;
338   }
339   sprintf(zBuf,"0x%x",(int)pPage);
340   Tcl_AppendResult(interp, zBuf, 0);
341   return TCL_OK;
342 }
343 
344 /*
345 ** Usage:   page_lookup ID PGNO
346 **
347 ** Return a pointer to a page if the page is already in cache.
348 ** If not in cache, return an empty string.
349 */
350 static int page_lookup(
351   void *NotUsed,
352   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
353   int argc,              /* Number of arguments */
354   const char **argv      /* Text of each argument */
355 ){
356   Pager *pPager;
357   char zBuf[100];
358   void *pPage;
359   int pgno;
360   if( argc!=3 ){
361     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
362        " ID PGNO\"", 0);
363     return TCL_ERROR;
364   }
365   if( Tcl_GetInt(interp, argv[1], (int*)&pPager) ) return TCL_ERROR;
366   if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
367   pPage = sqlitepager_lookup(pPager, pgno);
368   if( pPage ){
369     sprintf(zBuf,"0x%x",(int)pPage);
370     Tcl_AppendResult(interp, zBuf, 0);
371   }
372   return TCL_OK;
373 }
374 
375 /*
376 ** Usage:   page_unref PAGE
377 **
378 ** Drop a pointer to a page.
379 */
380 static int page_unref(
381   void *NotUsed,
382   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
383   int argc,              /* Number of arguments */
384   const char **argv      /* Text of each argument */
385 ){
386   void *pPage;
387   int rc;
388   if( argc!=2 ){
389     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
390        " PAGE\"", 0);
391     return TCL_ERROR;
392   }
393   if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR;
394   rc = sqlitepager_unref(pPage);
395   if( rc!=SQLITE_OK ){
396     Tcl_AppendResult(interp, errorName(rc), 0);
397     return TCL_ERROR;
398   }
399   return TCL_OK;
400 }
401 
402 /*
403 ** Usage:   page_read PAGE
404 **
405 ** Return the content of a page
406 */
407 static int page_read(
408   void *NotUsed,
409   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
410   int argc,              /* Number of arguments */
411   const char **argv      /* Text of each argument */
412 ){
413   char zBuf[100];
414   void *pPage;
415   if( argc!=2 ){
416     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
417        " PAGE\"", 0);
418     return TCL_ERROR;
419   }
420   if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR;
421   memcpy(zBuf, pPage, sizeof(zBuf));
422   Tcl_AppendResult(interp, zBuf, 0);
423   return TCL_OK;
424 }
425 
426 /*
427 ** Usage:   page_number PAGE
428 **
429 ** Return the page number for a page.
430 */
431 static int page_number(
432   void *NotUsed,
433   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
434   int argc,              /* Number of arguments */
435   const char **argv      /* Text of each argument */
436 ){
437   char zBuf[100];
438   void *pPage;
439   if( argc!=2 ){
440     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
441        " PAGE\"", 0);
442     return TCL_ERROR;
443   }
444   if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR;
445   sprintf(zBuf, "%d", sqlitepager_pagenumber(pPage));
446   Tcl_AppendResult(interp, zBuf, 0);
447   return TCL_OK;
448 }
449 
450 /*
451 ** Usage:   page_write PAGE DATA
452 **
453 ** Write something into a page.
454 */
455 static int page_write(
456   void *NotUsed,
457   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
458   int argc,              /* Number of arguments */
459   const char **argv      /* Text of each argument */
460 ){
461   void *pPage;
462   int rc;
463   if( argc!=3 ){
464     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
465        " PAGE DATA\"", 0);
466     return TCL_ERROR;
467   }
468   if( Tcl_GetInt(interp, argv[1], (int*)&pPage) ) return TCL_ERROR;
469   rc = sqlitepager_write(pPage);
470   if( rc!=SQLITE_OK ){
471     Tcl_AppendResult(interp, errorName(rc), 0);
472     return TCL_ERROR;
473   }
474   strncpy((char*)pPage, argv[2], SQLITE_USABLE_SIZE-1);
475   ((char*)pPage)[SQLITE_USABLE_SIZE-1] = 0;
476   return TCL_OK;
477 }
478 
479 /*
480 ** Usage:   fake_big_file  N  FILENAME
481 **
482 ** Write a few bytes at the N megabyte point of FILENAME.  This will
483 ** create a large file.  If the file was a valid SQLite database, then
484 ** the next time the database is opened, SQLite will begin allocating
485 ** new pages after N.  If N is 2096 or bigger, this will test the
486 ** ability of SQLite to write to large files.
487 */
488 static int fake_big_file(
489   void *NotUsed,
490   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
491   int argc,              /* Number of arguments */
492   const char **argv      /* Text of each argument */
493 ){
494   int rc;
495   int n;
496   off_t offset;
497   OsFile fd;
498   int readOnly = 0;
499   if( argc!=3 ){
500     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
501        " N-MEGABYTES FILE\"", 0);
502     return TCL_ERROR;
503   }
504   if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
505   rc = sqliteOsOpenReadWrite(argv[2], &fd, &readOnly);
506   if( rc ){
507     Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0);
508     return TCL_ERROR;
509   }
510   offset = n;
511   offset *= 1024*1024;
512   rc = sqliteOsSeek(&fd, offset);
513   if( rc ){
514     Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0);
515     return TCL_ERROR;
516   }
517   rc = sqliteOsWrite(&fd, "Hello, World!", 14);
518   sqliteOsClose(&fd);
519   if( rc ){
520     Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0);
521     return TCL_ERROR;
522   }
523   return TCL_OK;
524 }
525 
526 /*
527 ** Register commands with the TCL interpreter.
528 */
529 int Sqlitetest2_Init(Tcl_Interp *interp){
530   extern int sqlite_io_error_pending;
531   char zBuf[100];
532   static struct {
533     char *zName;
534     Tcl_CmdProc *xProc;
535   } aCmd[] = {
536     { "pager_open",              (Tcl_CmdProc*)pager_open          },
537     { "pager_close",             (Tcl_CmdProc*)pager_close         },
538     { "pager_commit",            (Tcl_CmdProc*)pager_commit        },
539     { "pager_rollback",          (Tcl_CmdProc*)pager_rollback      },
540     { "pager_ckpt_begin",        (Tcl_CmdProc*)pager_ckpt_begin    },
541     { "pager_ckpt_commit",       (Tcl_CmdProc*)pager_ckpt_commit   },
542     { "pager_ckpt_rollback",     (Tcl_CmdProc*)pager_ckpt_rollback },
543     { "pager_stats",             (Tcl_CmdProc*)pager_stats         },
544     { "pager_pagecount",         (Tcl_CmdProc*)pager_pagecount     },
545     { "page_get",                (Tcl_CmdProc*)page_get            },
546     { "page_lookup",             (Tcl_CmdProc*)page_lookup         },
547     { "page_unref",              (Tcl_CmdProc*)page_unref          },
548     { "page_read",               (Tcl_CmdProc*)page_read           },
549     { "page_write",              (Tcl_CmdProc*)page_write          },
550     { "page_number",             (Tcl_CmdProc*)page_number         },
551     { "fake_big_file",           (Tcl_CmdProc*)fake_big_file       },
552   };
553   int i;
554   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
555     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
556   }
557   Tcl_LinkVar(interp, "sqlite_io_error_pending",
558      (char*)&sqlite_io_error_pending, TCL_LINK_INT);
559 #ifdef SQLITE_TEST
560   Tcl_LinkVar(interp, "journal_format",
561      (char*)&journal_format, TCL_LINK_INT);
562 #endif
563   sprintf(zBuf, "%d", SQLITE_PAGE_SIZE);
564   Tcl_SetVar(interp, "SQLITE_PAGE_SIZE", zBuf, TCL_GLOBAL_ONLY);
565   sprintf(zBuf, "%d", SQLITE_PAGE_RESERVE);
566   Tcl_SetVar(interp, "SQLITE_PAGE_RESERVE", zBuf, TCL_GLOBAL_ONLY);
567   sprintf(zBuf, "%d", SQLITE_USABLE_SIZE);
568   Tcl_SetVar(interp, "SQLITE_USABLE_SIZE", zBuf, TCL_GLOBAL_ONLY);
569   return TCL_OK;
570 }
571