Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the sqlite3_result_error_code() application interface. Use it in the ATTACH function so that a failed attach returns a proper error code. Ticket #2914. (CVS 4775) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
c24616204307936d03d39d2ef0fe6856 |
User & Date: | drh 2008-02-06 14:11:35.000 |
Context
2008-02-06
| ||
14:14 | Bump the version number to 3.5.6. (CVS 4776) (check-in: 3444efabfc user: drh tags: trunk) | |
14:11 | Add the sqlite3_result_error_code() application interface. Use it in the ATTACH function so that a failed attach returns a proper error code. Ticket #2914. (CVS 4775) (check-in: c246162043 user: drh tags: trunk) | |
2008-02-02
| ||
20:47 | Delete unused "pager3_refinfo_enable" flag and its associated debugging macros. Ticket #2923. (CVS 4774) (check-in: fccb217d91 user: drh tags: trunk) | |
Changes
Changes to src/attach.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** ** $Id: attach.c,v 1.71 2008/02/06 14:11:35 drh Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_ATTACH /* ** Resolve an expression that was part of an ATTACH or DETACH statement. This ** is slightly different from resolving a normal SQL expression, because simple |
︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 228 229 230 231 | if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3_free(zErrDyn); }else{ zErr[sizeof(zErr)-1] = 0; sqlite3_result_error(context, zErr, -1); } } /* ** An SQL user-function registered to do the work of an DETACH statement. The ** three arguments to the function come directly from a detach statement: ** ** DETACH DATABASE x | > | 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3_free(zErrDyn); }else{ zErr[sizeof(zErr)-1] = 0; sqlite3_result_error(context, zErr, -1); } if( rc ) sqlite3_result_error_code(context, rc); } /* ** An SQL user-function registered to do the work of an DETACH statement. The ** three arguments to the function come directly from a detach statement: ** ** DETACH DATABASE x |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** ** @(#) $Id: sqlite.h.in,v 1.284 2008/02/06 14:11:35 drh Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 | ** {F16415} If the third parameter to sqlite3_result_error() or ** sqlite3_result_error16() is non-negative then SQLite takes that many ** bytes (not characters) from the 2nd parameter as the error message. ** {F16417} The sqlite3_result_error() and sqlite3_result_error16() ** routines make a copy private copy of the error message text before ** they return. {END} Hence, the calling function can deallocate or ** modify the text after they return without harm. ** ** {F16421} The sqlite3_result_toobig() interface causes SQLite ** to throw an error indicating that a string or BLOB is to long ** to represent. {F16422} The sqlite3_result_nomem() interface ** causes SQLite to throw an exception indicating that the a ** memory allocation failed. ** | > > > | 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 | ** {F16415} If the third parameter to sqlite3_result_error() or ** sqlite3_result_error16() is non-negative then SQLite takes that many ** bytes (not characters) from the 2nd parameter as the error message. ** {F16417} The sqlite3_result_error() and sqlite3_result_error16() ** routines make a copy private copy of the error message text before ** they return. {END} Hence, the calling function can deallocate or ** modify the text after they return without harm. ** The sqlite3_result_error_code() function changes the error code ** returned by SQLite as a result of an error in a function. By default, ** the error code is SQLITE_ERROR. ** ** {F16421} The sqlite3_result_toobig() interface causes SQLite ** to throw an error indicating that a string or BLOB is to long ** to represent. {F16422} The sqlite3_result_nomem() interface ** causes SQLite to throw an exception indicating that the a ** memory allocation failed. ** |
︙ | ︙ | |||
3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 | */ void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_error_toobig(sqlite3_context*); void sqlite3_result_error_nomem(sqlite3_context*); void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); | > | 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 | */ void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_double(sqlite3_context*, double); void sqlite3_result_error(sqlite3_context*, const char*, int); void sqlite3_result_error16(sqlite3_context*, const void*, int); void sqlite3_result_error_toobig(sqlite3_context*); void sqlite3_result_error_nomem(sqlite3_context*); void sqlite3_result_error_code(sqlite3_context*, int); void sqlite3_result_int(sqlite3_context*, int); void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); void sqlite3_result_null(sqlite3_context*); void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); |
︙ | ︙ |
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.708 2008/02/06 14:11:35 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 | pOp->p4.pVdbeFunc = ctx.pVdbeFunc; pOp->p4type = P4_VDBEFUNC; } /* If the function returned an error, throw an exception */ if( ctx.isError ){ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); | | | 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 | pOp->p4.pVdbeFunc = ctx.pVdbeFunc; pOp->p4type = P4_VDBEFUNC; } /* If the function returned an error, throw an exception */ if( ctx.isError ){ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); rc = ctx.isError; } /* Copy the result of the function into register P3 */ sqlite3VdbeChangeEncoding(&ctx.s, encoding); assert( pOp->p3>0 && pOp->p3<=p->nMem ); pOut = &p->aMem[pOp->p3]; sqlite3VdbeMemMove(pOut, &ctx.s); |
︙ | ︙ | |||
4214 4215 4216 4217 4218 4219 4220 | assert( pOp[-1].p4type==P4_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); ctx.pColl = pOp[-1].p4.pColl; } (ctx.pFunc->xStep)(&ctx, n, apVal); if( ctx.isError ){ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); | | | 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 | assert( pOp[-1].p4type==P4_COLLSEQ ); assert( pOp[-1].opcode==OP_CollSeq ); ctx.pColl = pOp[-1].p4.pColl; } (ctx.pFunc->xStep)(&ctx, n, apVal); if( ctx.isError ){ sqlite3SetString(&p->zErrMsg, sqlite3_value_text(&ctx.s), (char*)0); rc = ctx.isError; } sqlite3VdbeMemRelease(&ctx.s); break; } /* Opcode: AggFinal P1 P2 * P4 * ** |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
205 206 207 208 209 210 211 | ** (Mem) which are only defined there. */ struct sqlite3_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ | | | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | ** (Mem) which are only defined there. */ struct sqlite3_context { FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */ VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */ Mem s; /* The return value is stored here */ Mem *pMem; /* Memory cell used to store aggregate context */ int isError; /* Error code returned by the function. */ CollSeq *pColl; /* Collating sequence */ }; /* ** A Set structure is used for quick testing to see if a value ** is part of a small set. Sets are used to implement code like ** this: |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
159 160 161 162 163 164 165 | } void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetDouble(&pCtx->s, rVal); } void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); | | | | 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | } void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetDouble(&pCtx->s, rVal); } void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF8, SQLITE_TRANSIENT); } #ifndef SQLITE_OMIT_UTF16 void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); pCtx->isError = SQLITE_ERROR; sqlite3VdbeMemSetStr(&pCtx->s, z, n, SQLITE_UTF16NATIVE, SQLITE_TRANSIENT); } #endif void sqlite3_result_int(sqlite3_context *pCtx, int iVal){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetInt64(&pCtx->s, (i64)iVal); } |
︙ | ︙ | |||
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemCopy(&pCtx->s, pValue); } void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetZeroBlob(&pCtx->s, n); } /* Force an SQLITE_TOOBIG error. */ void sqlite3_result_error_toobig(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetZeroBlob(&pCtx->s, SQLITE_MAX_LENGTH+1); } /* An SQLITE_NOMEM error. */ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetNull(&pCtx->s); | > > > | | 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 | assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemCopy(&pCtx->s, pValue); } void sqlite3_result_zeroblob(sqlite3_context *pCtx, int n){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetZeroBlob(&pCtx->s, n); } void sqlite3_result_error_code(sqlite3_context *pCtx, int errCode){ pCtx->isError = errCode; } /* Force an SQLITE_TOOBIG error. */ void sqlite3_result_error_toobig(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetZeroBlob(&pCtx->s, SQLITE_MAX_LENGTH+1); } /* An SQLITE_NOMEM error. */ void sqlite3_result_error_nomem(sqlite3_context *pCtx){ assert( sqlite3_mutex_held(pCtx->s.db->mutex) ); sqlite3VdbeMemSetNull(&pCtx->s); pCtx->isError = SQLITE_NOMEM; pCtx->s.db->mallocFailed = 1; } /* ** Execute the statement pStmt, either until a row of data is ready, the ** statement is completely executed or an error occurs. ** |
︙ | ︙ |
Changes to test/attach.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # # $Id: attach.test,v 1.48 2008/02/06 14:11:35 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !attach { finish_test |
︙ | ︙ | |||
114 115 116 117 118 119 120 121 122 123 124 125 126 127 | } {0 main 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9} } ;# ifcapable schema_pragmas do_test attach-1.12 { catchsql { ATTACH 'test.db' as db2; } } {1 {database db2 is already in use}} do_test attach-1.13 { catchsql { ATTACH 'test.db' as db5; } } {1 {database db5 is already in use}} do_test attach-1.14 { catchsql { | > > > | 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | } {0 main 2 db2 3 db3 4 db4 5 db5 6 db6 7 db7 8 db8 9 db9} } ;# ifcapable schema_pragmas do_test attach-1.12 { catchsql { ATTACH 'test.db' as db2; } } {1 {database db2 is already in use}} do_test attach-1.12.2 { db errorcode } {1} do_test attach-1.13 { catchsql { ATTACH 'test.db' as db5; } } {1 {database db5 is already in use}} do_test attach-1.14 { catchsql { |
︙ | ︙ | |||
152 153 154 155 156 157 158 159 160 161 162 163 164 165 | } } {0 {}} do_test attach-1.19 { catchsql { ATTACH 'test.db' as db12; } } {1 {too many attached databases - max 10}} do_test attach-1.20.1 { execsql { DETACH db5; } } {} ifcapable schema_pragmas { do_test attach-1.20.2 { | > > > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | } } {0 {}} do_test attach-1.19 { catchsql { ATTACH 'test.db' as db12; } } {1 {too many attached databases - max 10}} do_test attach-1.19.1 { db errorcode } {1} do_test attach-1.20.1 { execsql { DETACH db5; } } {} ifcapable schema_pragmas { do_test attach-1.20.2 { |
︙ | ︙ | |||
176 177 178 179 180 181 182 183 184 185 186 187 188 189 | } } {0 {}} do_test attach-1.22 { catchsql { ATTACH 'test.db' as db13; } } {1 {too many attached databases - max 10}} do_test attach-1.23 { catchsql { DETACH "db14"; } } {1 {no such database: db14}} do_test attach-1.24 { catchsql { | > > > | 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 | } } {0 {}} do_test attach-1.22 { catchsql { ATTACH 'test.db' as db13; } } {1 {too many attached databases - max 10}} do_test attach-1.22.1 { db errorcode } {1} do_test attach-1.23 { catchsql { DETACH "db14"; } } {1 {no such database: db14}} do_test attach-1.24 { catchsql { |
︙ | ︙ | |||
720 721 722 723 724 725 726 727 728 729 730 731 732 733 | file delete -force cannot-read exit 1 } catchsql { ATTACH DATABASE 'cannot-read' AS noread; } } {1 {unable to open database: cannot-read}} file delete -force cannot-read } # Check the error message if we try to access a database that has # not been attached. do_test attach-6.3 { catchsql { | > > > | 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | file delete -force cannot-read exit 1 } catchsql { ATTACH DATABASE 'cannot-read' AS noread; } } {1 {unable to open database: cannot-read}} do_test attach-6.2.2 { db errorcode } {14} file delete -force cannot-read } # Check the error message if we try to access a database that has # not been attached. do_test attach-6.3 { catchsql { |
︙ | ︙ | |||
748 749 750 751 752 753 754 755 | catchsql { DETACH RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL ) } } {1 {invalid name: "RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL )"}} } finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 | catchsql { DETACH RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL ) } } {1 {invalid name: "RAISE ( IGNORE ) IN ( SELECT "AAAAAA" . * ORDER BY REGISTER LIMIT "AAAAAA" . "AAAAAA" OFFSET RAISE ( IGNORE ) NOT NULL )"}} } # Create a malformed file (a file that is not a valid database) # and try to attach it # do_test attach-8.1 { set fd [open test2.db w] puts $fd "This file is not a valid SQLite database" close $fd catchsql { ATTACH 'test2.db' AS t2; } } {1 {file is encrypted or is not a database}} do_test attach-8.2 { db errorcode } {26} file delete -force test2.db do_test attach-8.3 { sqlite3 db2 test2.db db2 eval {CREATE TABLE t1(x); BEGIN EXCLUSIVE} catchsql { ATTACH 'test2.db' AS t2; } } {1 {database is locked}} do_test attach-8.4 { db errorcode } {5} db2 close file delete -force test2.db finish_test |