Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Test that virtual table methods xBestIndex, xOpen, xFilter, xNext, xColumn, xRowid, xUpdate, xSync and xBegin can all return error messages using the sqlite3_vtab.zErrMsg variable. (CVS 5519) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
007359b770f225877880b11f4c5d97bb |
User & Date: | danielk1977 2008-08-01 17:37:41.000 |
Context
2008-08-01
| ||
17:51 | Also test that setting sqlite3_vtab.zErrMsg works from within the xRename method. (CVS 5520) (check-in: 4f4a9ccae7 user: danielk1977 tags: trunk) | |
17:37 | Test that virtual table methods xBestIndex, xOpen, xFilter, xNext, xColumn, xRowid, xUpdate, xSync and xBegin can all return error messages using the sqlite3_vtab.zErrMsg variable. (CVS 5519) (check-in: 007359b770 user: danielk1977 tags: trunk) | |
16:31 | Test cases for sqlite3_db_config() and sqlite3_db_status(). (CVS 5518) (check-in: 6a6b94302a user: drh tags: trunk) | |
Changes
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.749 2008/08/01 17:37:41 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build |
︙ | ︙ | |||
2263 2264 2265 2266 2267 2268 2269 | # define sqlite3VtabClear(X) # define sqlite3VtabSync(X,Y) (Y) # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabTransferError(A,B,C) #else void sqlite3VtabClear(Table*); | | | 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 | # define sqlite3VtabClear(X) # define sqlite3VtabSync(X,Y) (Y) # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabTransferError(A,B,C) #else void sqlite3VtabClear(Table*); int sqlite3VtabSync(sqlite3 *db, char **); int sqlite3VtabRollback(sqlite3 *db); int sqlite3VtabCommit(sqlite3 *db); void sqlite3VtabTransferError(sqlite3 *db, int, sqlite3_vtab*); #endif void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabLock(sqlite3_vtab*); void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*); |
︙ | ︙ |
Changes to src/test8.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the virtual table interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test8.c,v 1.70 2008/08/01 17:37:41 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #ifndef SQLITE_OMIT_VIRTUALTABLE |
︙ | ︙ | |||
39 40 41 42 43 44 45 46 47 48 49 50 51 52 | ** This is used for automated testing of virtual table modules. ** ** The ::echo_module_sync_fail variable is set by test scripts and read ** by code in this file. If it is set to the name of a real table in the ** the database, then all xSync operations on echo virtual tables that ** use the named table as a backing store will fail. */ /* ** An echo virtual-table object. ** ** echo.vtab.aIndex is an array of booleans. The nth entry is true if ** the nth column of the real table is the left-most column of an index ** (implicit or otherwise). In other words, if SQLite can optimize | > > > > > > > > > > > > > > > > | 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 | ** This is used for automated testing of virtual table modules. ** ** The ::echo_module_sync_fail variable is set by test scripts and read ** by code in this file. If it is set to the name of a real table in the ** the database, then all xSync operations on echo virtual tables that ** use the named table as a backing store will fail. */ /* ** Errors can be provoked within the following echo virtual table methods: ** ** xBestIndex xOpen xFilter xNext ** xColumn xRowid xUpdate xSync ** xBegin ** ** This is done by setting the global tcl variable: ** ** echo_module_fail($method,$tbl) ** ** where $method is set to the name of the virtual table method to fail ** (i.e. "xBestIndex") and $tbl is the name of the table being echoed (not ** the name of the virtual table, the name of the underlying real table). */ /* ** An echo virtual-table object. ** ** echo.vtab.aIndex is an array of booleans. The nth entry is true if ** the nth column of the real table is the left-most column of an index ** (implicit or otherwise). In other words, if SQLite can optimize |
︙ | ︙ | |||
71 72 73 74 75 76 77 78 79 80 81 82 83 84 | }; /* An echo cursor object */ struct echo_cursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; }; /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine ** is a no-op. ** | > > > > > > > > > > > > | 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 | }; /* An echo cursor object */ struct echo_cursor { sqlite3_vtab_cursor base; sqlite3_stmt *pStmt; }; static int simulateVtabError(echo_vtab *p, const char *zMethod){ const char *zErr; char zVarname[128]; zVarname[127] = '\0'; snprintf(zVarname, 127, "echo_module_fail(%s,%s)", zMethod, p->zTableName); zErr = Tcl_GetVar(p->interp, zVarname, TCL_GLOBAL_ONLY); if( zErr ){ p->base.zErrMsg = sqlite3_mprintf("echo-vtab-error: %s", zErr); } return (zErr!=0); } /* ** Convert an SQL-style quoted string into a normal string by removing ** the quote characters. The conversion is done in-place. If the ** input does not begin with a quote character, then this routine ** is a no-op. ** |
︙ | ︙ | |||
520 521 522 523 524 525 526 527 528 529 530 531 532 533 | } /* ** Echo virtual table module xOpen method. */ static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ echo_cursor *pCur; pCur = sqlite3MallocZero(sizeof(echo_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; return (pCur ? SQLITE_OK : SQLITE_NOMEM); } /* ** Echo virtual table module xClose method. | > > > | 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 | } /* ** Echo virtual table module xOpen method. */ static int echoOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ echo_cursor *pCur; if( simulateVtabError((echo_vtab *)pVTab, "xOpen") ){ return SQLITE_ERROR; } pCur = sqlite3MallocZero(sizeof(echo_cursor)); *ppCursor = (sqlite3_vtab_cursor *)pCur; return (pCur ? SQLITE_OK : SQLITE_NOMEM); } /* ** Echo virtual table module xClose method. |
︙ | ︙ | |||
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 | /* ** Echo virtual table module xNext method. */ static int echoNext(sqlite3_vtab_cursor *cur){ int rc = SQLITE_OK; echo_cursor *pCur = (echo_cursor *)cur; if( pCur->pStmt ){ rc = sqlite3_step(pCur->pStmt); if( rc==SQLITE_ROW ){ rc = SQLITE_OK; }else{ rc = sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; } } return rc; } /* ** Echo virtual table module xColumn method. */ static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ int iCol = i + 1; sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt; if( !pStmt ){ sqlite3_result_null(ctx); }else{ assert( sqlite3_data_count(pStmt)>iCol ); sqlite3_result_value(ctx, sqlite3_column_value(pStmt, iCol)); } return SQLITE_OK; } /* ** Echo virtual table module xRowid method. */ static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt; *pRowid = sqlite3_column_int64(pStmt, 0); return SQLITE_OK; } /* ** Compute a simple hash of the null terminated string zString. ** | > > > > > > > > > > > > > > | 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 | /* ** Echo virtual table module xNext method. */ static int echoNext(sqlite3_vtab_cursor *cur){ int rc = SQLITE_OK; echo_cursor *pCur = (echo_cursor *)cur; if( simulateVtabError((echo_vtab *)(cur->pVtab), "xNext") ){ return SQLITE_ERROR; } if( pCur->pStmt ){ rc = sqlite3_step(pCur->pStmt); if( rc==SQLITE_ROW ){ rc = SQLITE_OK; }else{ rc = sqlite3_finalize(pCur->pStmt); pCur->pStmt = 0; } } return rc; } /* ** Echo virtual table module xColumn method. */ static int echoColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ int iCol = i + 1; sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt; if( simulateVtabError((echo_vtab *)(cur->pVtab), "xColumn") ){ return SQLITE_ERROR; } if( !pStmt ){ sqlite3_result_null(ctx); }else{ assert( sqlite3_data_count(pStmt)>iCol ); sqlite3_result_value(ctx, sqlite3_column_value(pStmt, iCol)); } return SQLITE_OK; } /* ** Echo virtual table module xRowid method. */ static int echoRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ sqlite3_stmt *pStmt = ((echo_cursor *)cur)->pStmt; if( simulateVtabError((echo_vtab *)(cur->pVtab), "xRowid") ){ return SQLITE_ERROR; } *pRowid = sqlite3_column_int64(pStmt, 0); return SQLITE_OK; } /* ** Compute a simple hash of the null terminated string zString. ** |
︙ | ︙ | |||
622 623 624 625 626 627 628 629 630 631 632 633 634 635 | ){ int rc; int i; echo_cursor *pCur = (echo_cursor *)pVtabCursor; echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab; sqlite3 *db = pVtab->db; /* Check that idxNum matches idxStr */ assert( idxNum==hashString(idxStr) ); /* Log arguments to the ::echo_module Tcl variable */ appendToEchoModule(pVtab->interp, "xFilter"); appendToEchoModule(pVtab->interp, idxStr); | > > > > | 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 | ){ int rc; int i; echo_cursor *pCur = (echo_cursor *)pVtabCursor; echo_vtab *pVtab = (echo_vtab *)pVtabCursor->pVtab; sqlite3 *db = pVtab->db; if( simulateVtabError(pVtab, "xFilter") ){ return SQLITE_ERROR; } /* Check that idxNum matches idxStr */ assert( idxNum==hashString(idxStr) ); /* Log arguments to the ::echo_module Tcl variable */ appendToEchoModule(pVtab->interp, "xFilter"); appendToEchoModule(pVtab->interp, idxStr); |
︙ | ︙ | |||
730 731 732 733 734 735 736 | Tcl_Interp *interp = pVtab->interp; int nRow; int useIdx = 0; int rc = SQLITE_OK; int useCost = 0; double cost; | < > > > > | 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 | Tcl_Interp *interp = pVtab->interp; int nRow; int useIdx = 0; int rc = SQLITE_OK; int useCost = 0; double cost; int isIgnoreUsable = 0; if( Tcl_GetVar(interp, "echo_module_ignore_usable", TCL_GLOBAL_ONLY) ){ isIgnoreUsable = 1; } if( simulateVtabError(pVtab, "xBestIndex") ){ return SQLITE_ERROR; } /* Determine the number of rows in the table and store this value in local ** variable nRow. The 'estimated-cost' of the scan will be the number of ** rows in the table for a linear scan, or the log (base 2) of the ** number of rows if the proposed scan uses an index. */ if( Tcl_GetVar(interp, "echo_module_cost", TCL_GLOBAL_ONLY) ){ |
︙ | ︙ | |||
887 888 889 890 891 892 893 894 895 896 897 898 899 900 | int i; /* Counter variable used by for loops */ assert( nData==pVtab->nCol+2 || nData==1 ); /* Ticket #3083 - make sure we always start a transaction prior to ** making any changes to a virtual table */ assert( pVtab->inTransaction ); /* If apData[0] is an integer and nData>1 then do an UPDATE */ if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ char *zSep = " SET"; z = sqlite3_mprintf("UPDATE %Q", pVtab->zTableName); if( !z ){ rc = SQLITE_NOMEM; | > > > > | 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 | int i; /* Counter variable used by for loops */ assert( nData==pVtab->nCol+2 || nData==1 ); /* Ticket #3083 - make sure we always start a transaction prior to ** making any changes to a virtual table */ assert( pVtab->inTransaction ); if( simulateVtabError(pVtab, "xUpdate") ){ return SQLITE_ERROR; } /* If apData[0] is an integer and nData>1 then do an UPDATE */ if( nData>1 && sqlite3_value_type(apData[0])==SQLITE_INTEGER ){ char *zSep = " SET"; z = sqlite3_mprintf("UPDATE %Q", pVtab->zTableName); if( !z ){ rc = SQLITE_NOMEM; |
︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; /* Ticket #3083 - do not start a transaction if we are already in ** a transaction */ assert( !pVtab->inTransaction ); rc = echoTransactionCall(tab, "xBegin"); if( rc==SQLITE_OK ){ /* Check if the $::echo_module_begin_fail variable is defined. If it is, ** and it is set to the name of the real table underlying this virtual ** echo module table, then cause this xSync operation to fail. | > > > > | 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 | echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; /* Ticket #3083 - do not start a transaction if we are already in ** a transaction */ assert( !pVtab->inTransaction ); if( simulateVtabError(pVtab, "xBegin") ){ return SQLITE_ERROR; } rc = echoTransactionCall(tab, "xBegin"); if( rc==SQLITE_OK ){ /* Check if the $::echo_module_begin_fail variable is defined. If it is, ** and it is set to the name of the real table underlying this virtual ** echo module table, then cause this xSync operation to fail. |
︙ | ︙ | |||
1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 | echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; /* Ticket #3083 - Only call xSync if we have previously started a ** transaction */ assert( pVtab->inTransaction ); rc = echoTransactionCall(tab, "xSync"); if( rc==SQLITE_OK ){ /* Check if the $::echo_module_sync_fail variable is defined. If it is, ** and it is set to the name of the real table underlying this virtual ** echo module table, then cause this xSync operation to fail. | > > > > | 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 | echo_vtab *pVtab = (echo_vtab *)tab; Tcl_Interp *interp = pVtab->interp; const char *zVal; /* Ticket #3083 - Only call xSync if we have previously started a ** transaction */ assert( pVtab->inTransaction ); if( simulateVtabError(pVtab, "xSync") ){ return SQLITE_ERROR; } rc = echoTransactionCall(tab, "xSync"); if( rc==SQLITE_OK ){ /* Check if the $::echo_module_sync_fail variable is defined. If it is, ** and it is set to the name of the real table underlying this virtual ** echo module table, then cause this xSync operation to fail. |
︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 | static int echoCommit(sqlite3_vtab *tab){ echo_vtab *pVtab = (echo_vtab*)tab; int rc; /* Ticket #3083 - Only call xCommit if we have previously started ** a transaction */ assert( pVtab->inTransaction ); sqlite3BeginBenignMalloc(); rc = echoTransactionCall(tab, "xCommit"); sqlite3EndBenignMalloc(); pVtab->inTransaction = 0; return rc; } | > > > > | 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 | static int echoCommit(sqlite3_vtab *tab){ echo_vtab *pVtab = (echo_vtab*)tab; int rc; /* Ticket #3083 - Only call xCommit if we have previously started ** a transaction */ assert( pVtab->inTransaction ); if( simulateVtabError(pVtab, "xCommit") ){ return SQLITE_ERROR; } sqlite3BeginBenignMalloc(); rc = echoTransactionCall(tab, "xCommit"); sqlite3EndBenignMalloc(); pVtab->inTransaction = 0; return rc; } |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.770 2008/08/01 17:37:41 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
4566 4567 4568 4569 4570 4571 4572 | break; } #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VBegin * * * P4 * ** | | | > > > > > | > > > > > | 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 | break; } #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VBegin * * * P4 * ** ** P4 may be a pointer to an sqlite3_vtab structure. If so, call the ** xBegin method for that table. ** ** Also, whether or not P4 is set, check that this is not being called from ** within a callback to a virtual table xSync() method. If it is, set the ** error code to SQLITE_LOCKED. */ case OP_VBegin: { sqlite3_vtab *pVtab = pOp->p4.pVtab; rc = sqlite3VtabBegin(db, pVtab); if( pVtab ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; } break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VCreate P1 * * P4 * ** |
︙ | ︙ | |||
4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 | storeTypeInfo(apArg[i], 0); } if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; p->inVtabMethod = 1; rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); p->inVtabMethod = 0; if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( res ){ pc = pOp->p2 - 1; | > > > | 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 | storeTypeInfo(apArg[i], 0); } if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; p->inVtabMethod = 1; rc = pModule->xFilter(pVtabCursor, iQuery, pOp->p4.z, nArg, apArg); p->inVtabMethod = 0; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( res ){ pc = pOp->p2 - 1; |
︙ | ︙ | |||
4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VRowid P1 P2 * * * ** ** Store into register P2 the rowid of ** the virtual-table that the P1 cursor is pointing to. */ case OP_VRowid: { /* out2-prerelease */ const sqlite3_module *pModule; sqlite_int64 iRow; Cursor *pCur = p->apCsr[pOp->p1]; assert( pCur->pVtabCursor ); if( pCur->nullRow ){ break; } | > | > > > > > | > > > > | 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 | #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VRowid P1 P2 * * * ** ** Store into register P2 the rowid of ** the virtual-table that the P1 cursor is pointing to. */ case OP_VRowid: { /* out2-prerelease */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; sqlite_int64 iRow; Cursor *pCur = p->apCsr[pOp->p1]; assert( pCur->pVtabCursor ); if( pCur->nullRow ){ break; } pVtab = pCur->pVtabCursor->pVtab; pModule = pVtab->pModule; assert( pModule->xRowid ); if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xRowid(pCur->pVtabCursor, &iRow); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; MemSetTypeFlag(pOut, MEM_Int); pOut->u.i = iRow; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VColumn P1 P2 P3 * * ** ** Store the value of the P2-th column of ** the row of the virtual-table that the ** P1 cursor is pointing to into register P3. */ case OP_VColumn: { sqlite3_vtab *pVtab; const sqlite3_module *pModule; Mem *pDest; sqlite3_context sContext; Cursor *pCur = p->apCsr[pOp->p1]; assert( pCur->pVtabCursor ); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pDest = &p->aMem[pOp->p3]; if( pCur->nullRow ){ sqlite3VdbeMemSetNull(pDest); break; } pVtab = pCur->pVtabCursor->pVtab; pModule = pVtab->pModule; assert( pModule->xColumn ); memset(&sContext, 0, sizeof(sContext)); /* The output cell may already have a buffer allocated. Move ** the current contents to sContext.s so in case the user-function ** can use the already allocated buffer instead of allocating a ** new one. */ sqlite3VdbeMemMove(&sContext.s, pDest); MemSetTypeFlag(&sContext.s, MEM_Null); if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; rc = pModule->xColumn(pCur->pVtabCursor, &sContext, pOp->p2); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; /* Copy the result of the function to the P3 register. We ** do this regardless of whether or not an error occured to ensure any ** dynamic allocation in sContext.s (a Mem struct) is released. */ sqlite3VdbeChangeEncoding(&sContext.s, encoding); REGISTER_TRACE(pOp->p3, pDest); |
︙ | ︙ | |||
4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 | /* Opcode: VNext P1 P2 * * * ** ** Advance virtual table P1 to the next row in its result set and ** jump to instruction P2. Or, if the virtual table has reached ** the end of its result set, then fall through to the next instruction. */ case OP_VNext: { /* jump */ const sqlite3_module *pModule; int res = 0; Cursor *pCur = p->apCsr[pOp->p1]; assert( pCur->pVtabCursor ); if( pCur->nullRow ){ break; } | > | > > > > | 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 | /* Opcode: VNext P1 P2 * * * ** ** Advance virtual table P1 to the next row in its result set and ** jump to instruction P2. Or, if the virtual table has reached ** the end of its result set, then fall through to the next instruction. */ case OP_VNext: { /* jump */ sqlite3_vtab *pVtab; const sqlite3_module *pModule; int res = 0; Cursor *pCur = p->apCsr[pOp->p1]; assert( pCur->pVtabCursor ); if( pCur->nullRow ){ break; } pVtab = pCur->pVtabCursor->pVtab; pModule = pVtab->pModule; assert( pModule->xNext ); /* Invoke the xNext() method of the module. There is no way for the ** underlying implementation to return an error if one occurs during ** xNext(). Instead, if an error occurs, true is returned (indicating that ** data is available) and the error code returned when xColumn or ** some other method is next invoked on the save virtual table cursor. */ if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse; p->inVtabMethod = 1; rc = pModule->xNext(pCur->pVtabCursor); p->inVtabMethod = 0; sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); } if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse; if( !res ){ /* If there is data, jump to P2 */ |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** ** $Id: vdbeaux.c,v 1.403 2008/08/01 17:37:41 danielk1977 Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | /* ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine ** takes care of the master journal trickery. */ | | | | 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 | /* ** A read or write transaction may or may not be active on database handle ** db. If a transaction is active, commit it. If there is a ** write-transaction spanning more than one database file, this routine ** takes care of the master journal trickery. */ static int vdbeCommit(sqlite3 *db, Vdbe *p){ int i; int nTrans = 0; /* Number of databases with an active write-transaction */ int rc = SQLITE_OK; int needXcommit = 0; /* Before doing anything else, call the xSync() callback for any ** virtual module tables written in this transaction. This has to ** be done before determining whether a master journal file is ** required, as an xSync() callback may add an attached database ** to the transaction. */ rc = sqlite3VtabSync(db, &p->zErrMsg); if( rc!=SQLITE_OK ){ return rc; } /* This loop determines (a) if the commit hook should be invoked and ** (b) how many database files have open write transactions, not ** including the temp database. (b) is important because if more than |
︙ | ︙ | |||
1588 1589 1590 1591 1592 1593 1594 | */ if( db->autoCommit && db->activeVdbeCnt==1 ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ /* The auto-commit flag is true, and the vdbe program was ** successful or hit an 'OR FAIL' constraint. This means a commit ** is required. */ | | | 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 | */ if( db->autoCommit && db->activeVdbeCnt==1 ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ /* The auto-commit flag is true, and the vdbe program was ** successful or hit an 'OR FAIL' constraint. This means a commit ** is required. */ int rc = vdbeCommit(db, p); if( rc==SQLITE_BUSY ){ sqlite3BtreeMutexArrayLeave(&p->aMutex); return SQLITE_BUSY; }else if( rc!=SQLITE_OK ){ p->rc = rc; sqlite3RollbackAll(db); }else{ |
︙ | ︙ |
Changes to src/vtab.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 June 10 ** ** 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. ** ************************************************************************* ** This file contains code used to help implement virtual tables. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2006 June 10 ** ** 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. ** ************************************************************************* ** This file contains code used to help implement virtual tables. ** ** $Id: vtab.c,v 1.73 2008/08/01 17:37:41 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" static int createModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ |
︙ | ︙ | |||
636 637 638 639 640 641 642 | sqlite3DbFree(db, db->aVTrans); db->nVTrans = 0; db->aVTrans = 0; } } /* | < | | | > > > | < > > > | 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 | sqlite3DbFree(db, db->aVTrans); db->nVTrans = 0; db->aVTrans = 0; } } /* ** Invoke the xSync method of all virtual tables in the sqlite3.aVTrans ** array. Return the error code for the first error that occurs, or ** SQLITE_OK if all xSync operations are successful. ** ** Set *pzErrmsg to point to a buffer that should be released using ** sqlite3DbFree() containing an error message, if one is available. */ int sqlite3VtabSync(sqlite3 *db, char **pzErrmsg){ int i; int rc = SQLITE_OK; int rcsafety; sqlite3_vtab **aVTrans = db->aVTrans; rc = sqlite3SafetyOff(db); db->aVTrans = 0; for(i=0; rc==SQLITE_OK && i<db->nVTrans && aVTrans[i]; i++){ sqlite3_vtab *pVtab = aVTrans[i]; int (*x)(sqlite3_vtab *); x = pVtab->pModule->xSync; if( x ){ rc = x(pVtab); sqlite3DbFree(db, *pzErrmsg); *pzErrmsg = pVtab->zErrMsg; pVtab->zErrMsg = 0; } } db->aVTrans = aVTrans; rcsafety = sqlite3SafetyOn(db); if( rc==SQLITE_OK ){ rc = rcsafety; |
︙ | ︙ | |||
723 724 725 726 727 728 729 | if( db->aVTrans[i]==pVtab ){ return SQLITE_OK; } } /* Invoke the xBegin method */ rc = pModule->xBegin(pVtab); | < | | < < | 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 | if( db->aVTrans[i]==pVtab ){ return SQLITE_OK; } } /* Invoke the xBegin method */ rc = pModule->xBegin(pVtab); if( rc==SQLITE_OK ){ rc = addToVTrans(db, pVtab); } } return rc; } /* ** The first parameter (pDef) is a function implementation. The ** second parameter (pExpr) is the first argument to this function. |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is responsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** ** $Id: where.c,v 1.319 2008/08/01 17:37:41 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #define BMS (sizeof(Bitmask)*8) |
︙ | ︙ | |||
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 | struct SrcList_item *pSrc, /* The FROM clause term to search */ Bitmask notReady, /* Mask of cursors that are not available */ ExprList *pOrderBy, /* The order by clause */ int orderByUsable, /* True if we can potential sort */ sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ ){ Table *pTab = pSrc->pTab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; int i, j; int nOrderBy; | > | 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 | struct SrcList_item *pSrc, /* The FROM clause term to search */ Bitmask notReady, /* Mask of cursors that are not available */ ExprList *pOrderBy, /* The order by clause */ int orderByUsable, /* True if we can potential sort */ sqlite3_index_info **ppIdxInfo /* Index information passed to xBestIndex */ ){ Table *pTab = pSrc->pTab; sqlite3_vtab *pVtab = pTab->pVtab; sqlite3_index_info *pIdxInfo; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; WhereTerm *pTerm; int i, j; int nOrderBy; |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | */ /* The module name must be defined. Also, by this point there must ** be a pointer to an sqlite3_vtab structure. Otherwise ** sqlite3ViewGetColumnNames() would have picked up the error. */ assert( pTab->azModuleArg && pTab->azModuleArg[0] ); | | | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 | */ /* The module name must be defined. Also, by this point there must ** be a pointer to an sqlite3_vtab structure. Otherwise ** sqlite3ViewGetColumnNames() would have picked up the error. */ assert( pTab->azModuleArg && pTab->azModuleArg[0] ); assert( pVtab ); #if 0 if( pTab->pVtab==0 ){ sqlite3ErrorMsg(pParse, "undefined module %s for table %s", pTab->azModuleArg[0], pTab->zName); return 0.0; } #endif |
︙ | ︙ | |||
1419 1420 1421 1422 1423 1424 1425 | if( pIdxInfo->nOrderBy && !orderByUsable ){ *(int*)&pIdxInfo->nOrderBy = 0; } (void)sqlite3SafetyOff(pParse->db); WHERETRACE(("xBestIndex for %s\n", pTab->zName)); TRACE_IDX_INPUTS(pIdxInfo); | | > > > > > > > > > > > > < < < < < < < < | 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 | if( pIdxInfo->nOrderBy && !orderByUsable ){ *(int*)&pIdxInfo->nOrderBy = 0; } (void)sqlite3SafetyOff(pParse->db); WHERETRACE(("xBestIndex for %s\n", pTab->zName)); TRACE_IDX_INPUTS(pIdxInfo); rc = pVtab->pModule->xBestIndex(pVtab, pIdxInfo); TRACE_IDX_OUTPUTS(pIdxInfo); (void)sqlite3SafetyOn(pParse->db); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ){ pParse->db->mallocFailed = 1; }else if( !pVtab->zErrMsg ){ sqlite3ErrorMsg(pParse, "%s", sqlite3ErrStr(rc)); }else{ sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg); } } sqlite3DbFree(pParse->db, pVtab->zErrMsg); pVtab->zErrMsg = 0; for(i=0; i<pIdxInfo->nConstraint; i++){ if( !pIdxInfo->aConstraint[i].usable && pUsage[i].argvIndex>0 ){ sqlite3ErrorMsg(pParse, "table %s: xBestIndex returned an invalid plan", pTab->zName); return 0.0; } } *(int*)&pIdxInfo->nOrderBy = nOrderBy; return pIdxInfo->estimatedCost; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ /* ** Find the best index for accessing a particular table. Return a pointer ** to the index, flags that describe how the index should be used, the |
︙ | ︙ |
Changes to test/vtab1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2006 June 10 # # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is creating and dropping virtual tables. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2006 June 10 # # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is creating and dropping virtual tables. # # $Id: vtab1.test,v 1.56 2008/08/01 17:37:41 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !vtab||!schema_pragmas { finish_test return |
︙ | ︙ | |||
48 49 50 51 52 53 54 55 56 57 58 59 60 61 | #---------------------------------------------------------------------- # Test cases vtab1.1.* # # We cannot create a virtual table if the module has not been registered. # do_test vtab1-1.1 { catchsql { CREATE VIRTUAL TABLE t1 USING echo; } } {1 {no such module: echo}} do_test vtab1-1.2 { execsql { SELECT name FROM sqlite_master ORDER BY 1 | > > > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | #---------------------------------------------------------------------- # Test cases vtab1.1.* # # We cannot create a virtual table if the module has not been registered. # do_test vtab1-1.1 { explain { CREATE VIRTUAL TABLE t1 USING echo; } catchsql { CREATE VIRTUAL TABLE t1 USING echo; } } {1 {no such module: echo}} do_test vtab1-1.2 { execsql { SELECT name FROM sqlite_master ORDER BY 1 |
︙ | ︙ | |||
1104 1105 1106 1107 1108 1109 1110 | } {45 {} {} {} 46 {} {} {}} do_test vtab1-15.4 { catchsql { INSERT INTO echo_t1(rowid) VALUES('new rowid'); } } {1 {datatype mismatch}} | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 | } {45 {} {} {} 46 {} {} {}} do_test vtab1-15.4 { catchsql { INSERT INTO echo_t1(rowid) VALUES('new rowid'); } } {1 {datatype mismatch}} # The following tests - vtab1-16.* - are designed to test that setting # sqlite3_vtab.zErrMsg variable can be used by the vtab interface to # return an error message to the user. # do_test vtab1-16.1 { execsql { CREATE TABLE t2(a PRIMARY KEY, b, c); INSERT INTO t2 VALUES(1, 2, 3); INSERT INTO t2 VALUES(4, 5, 6); CREATE VIRTUAL TABLE echo_t2 USING echo(t2); } } {} set tn 2 foreach method [list \ xBestIndex \ xOpen \ xFilter \ xNext \ xColumn \ xRowid \ ] { do_test vtab1-16.$tn { set echo_module_fail($method,t2) "the $method method has failed" catchsql { SELECT rowid, * FROM echo_t2 WHERE a >= 1 } } "1 {echo-vtab-error: the $method method has failed}" unset echo_module_fail($method,t2) incr tn } foreach method [list \ xUpdate \ xBegin \ xSync \ ] { do_test vtab1-16.$tn { set echo_module_fail($method,t2) "the $method method has failed" catchsql { INSERT INTO echo_t2 VALUES(7, 8, 9) } } "1 {echo-vtab-error: the $method method has failed}" unset echo_module_fail($method,t2) incr tn } unset -nocomplain echo_module_begin_fail finish_test |