wasCSharpSQLite – Blame information for rev

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 using System.Diagnostics;
2  
3 namespace Community.CsharpSqlite
4 {
5 using sqlite3_stmt = Sqlite3.Vdbe;
6  
7 public partial class Sqlite3
8 {
9 /*
10 ** 2007 May 1
11 **
12 ** The author disclaims copyright to this source code. In place of
13 ** a legal notice, here is a blessing:
14 **
15 ** May you do good and not evil.
16 ** May you find forgiveness for yourself and forgive others.
17 ** May you share freely, never taking more than you give.
18 **
19 *************************************************************************
20 **
21 ** This file contains code used to implement incremental BLOB I/O.
22 *************************************************************************
23 ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
24 ** C#-SQLite is an independent reimplementation of the SQLite software library
25 **
26 ** SQLITE_SOURCE_ID: 2011-06-23 19:49:22 4374b7e83ea0a3fbc3691f9c0c936272862f32f2
27 **
28 *************************************************************************
29 */
30 //#include "sqliteInt.h"
31 //#include "vdbeInt.h"
32  
33 #if !SQLITE_OMIT_INCRBLOB
34 /*
35 ** Valid sqlite3_blob* handles point to Incrblob structures.
36 */
37 typedef struct Incrblob Incrblob;
38 struct Incrblob {
39 int flags; /* Copy of "flags" passed to sqlite3_blob_open() */
40 int nByte; /* Size of open blob, in bytes */
41 int iOffset; /* Byte offset of blob in cursor data */
42 BtCursor *pCsr; /* Cursor pointing at blob row */
43 sqlite3_stmt *pStmt; /* Statement holding cursor open */
44 sqlite3 db; /* The associated database */
45 };
46  
47 /*
48 ** Open a blob handle.
49 */
50 int sqlite3_blob_open(
51 sqlite3* db, /* The database connection */
52 string zDb, /* The attached database containing the blob */
53 string zTable, /* The table containing the blob */
54 string zColumn, /* The column containing the blob */
55 sqlite_int64 iRow, /* The row containing the glob */
56 int flags, /* True -> read/write access, false -> read-only */
57 sqlite3_blob **ppBlob /* Handle for accessing the blob returned here */
58 ){
59 int nAttempt = 0;
60 int iCol; /* Index of zColumn in row-record */
61  
62 /* This VDBE program seeks a btree cursor to the identified
63 ** db/table/row entry. The reason for using a vdbe program instead
64 ** of writing code to use the b-tree layer directly is that the
65 ** vdbe program will take advantage of the various transaction,
66 ** locking and error handling infrastructure built into the vdbe.
67 **
68 ** After seeking the cursor, the vdbe executes an OP_ResultRow.
69 ** Code external to the Vdbe then "borrows" the b-tree cursor and
70 ** uses it to implement the blob_read(), blob_write() and
71 ** blob_bytes() functions.
72 **
73 ** The sqlite3_blob_close() function finalizes the vdbe program,
74 ** which closes the b-tree cursor and (possibly) commits the
75 ** transaction.
76 */
77 static const VdbeOpList openBlob[] = {
78 {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */
79 {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */
80 {OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */
81  
82 /* One of the following two instructions is replaced by an OP_Noop. */
83 {OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */
84 {OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */
85  
86 {OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */
87 {OP_NotExists, 0, 9, 1}, /* 6: Seek the cursor */
88 {OP_Column, 0, 0, 1}, /* 7 */
89 {OP_ResultRow, 1, 0, 0}, /* 8 */
90 {OP_Close, 0, 0, 0}, /* 9 */
91 {OP_Halt, 0, 0, 0}, /* 10 */
92 };
93  
94 Vdbe *v = 0;
95 int rc = SQLITE_OK;
96 string zErr = 0;
97 Table *pTab;
98 Parse *pParse;
99  
100 *ppBlob = 0;
101 sqlite3_mutex_enter(db->mutex);
102 pParse = sqlite3StackAllocRaw(db, sizeof(*pParse));
103 if( pParse==0 ){
104 rc = SQLITE_NOMEM;
105 goto blob_open_out;
106 }
107 do {
108 memset(pParse, 0, sizeof(Parse));
109 pParse->db = db;
110  
111 sqlite3BtreeEnterAll(db);
112 pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
113 if( pTab && IsVirtual(pTab) ){
114 pTab = 0;
115 sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
116 }
117 #if !SQLITE_OMIT_VIEW
118 if( pTab && pTab->pSelect ){
119 pTab = 0;
120 sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable);
121 }
122 #endif
123 if( null==pTab ){
124 if( pParse->zErrMsg ){
125 sqlite3DbFree(db, zErr);
126 zErr = pParse->zErrMsg;
127 pParse->zErrMsg = 0;
128 }
129 rc = SQLITE_ERROR;
130 sqlite3BtreeLeaveAll(db);
131 goto blob_open_out;
132 }
133  
134 /* Now search pTab for the exact column. */
135 for(iCol=0; iCol < pTab->nCol; iCol++) {
136 if( sqlite3StrICmp(pTab->aCol[iCol].zName, zColumn)==0 ){
137 break;
138 }
139 }
140 if( iCol==pTab->nCol ){
141 sqlite3DbFree(db, zErr);
142 zErr = sqlite3MPrintf(db, "no such column: \"%s\"", zColumn);
143 rc = SQLITE_ERROR;
144 sqlite3BtreeLeaveAll(db);
145 goto blob_open_out;
146 }
147  
148 /* If the value is being opened for writing, check that the
149 ** column is not indexed, and that it is not part of a foreign key.
150 ** It is against the rules to open a column to which either of these
151 ** descriptions applies for writing. */
152 if( flags ){
153 string zFault = 0;
154 Index *pIdx;
155 #if !SQLITE_OMIT_FOREIGN_KEY
156 if( db->flags&SQLITE_ForeignKeys ){
157 /* Check that the column is not part of an FK child key definition. It
158 ** is not necessary to check if it is part of a parent key, as parent
159 ** key columns must be indexed. The check below will pick up this
160 ** case. */
161 FKey *pFKey;
162 for(pFKey=pTab->pFKey; pFKey; pFKey=pFKey->pNextFrom){
163 int j;
164 for(j=0; j<pFKey->nCol; j++){
165 if( pFKey->aCol[j].iFrom==iCol ){
166 zFault = "foreign key";
167 }
168 }
169 }
170 }
171 #endif
172 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
173 int j;
174 for(j=0; j<pIdx->nColumn; j++){
175 if( pIdx->aiColumn[j]==iCol ){
176 zFault = "indexed";
177 }
178 }
179 }
180 if( zFault ){
181 sqlite3DbFree(db, zErr);
182 zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault);
183 rc = SQLITE_ERROR;
184 sqlite3BtreeLeaveAll(db);
185 goto blob_open_out;
186 }
187 }
188  
189 v = sqlite3VdbeCreate(db);
190 if( v ){
191 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
192 sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob);
193 flags = !!flags; /* flags = (flags ? 1 : 0); */
194  
195 /* Configure the OP_Transaction */
196 sqlite3VdbeChangeP1(v, 0, iDb);
197 sqlite3VdbeChangeP2(v, 0, flags);
198  
199 /* Configure the OP_VerifyCookie */
200 sqlite3VdbeChangeP1(v, 1, iDb);
201 sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie);
202 sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration);
203  
204 /* Make sure a mutex is held on the table to be accessed */
205 sqlite3VdbeUsesBtree(v, iDb);
206  
207 /* Configure the OP_TableLock instruction */
208 #if SQLITE_OMIT_SHARED_CACHE
209 sqlite3VdbeChangeToNoop(v, 2, 1);
210 #else
211 sqlite3VdbeChangeP1(v, 2, iDb);
212 sqlite3VdbeChangeP2(v, 2, pTab->tnum);
213 sqlite3VdbeChangeP3(v, 2, flags);
214 sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT);
215 #endif
216  
217 /* Remove either the OP_OpenWrite or OpenRead. Set the P2
218 ** parameter of the other to pTab->tnum. */
219 sqlite3VdbeChangeToNoop(v, 4 - flags, 1);
220 sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum);
221 sqlite3VdbeChangeP3(v, 3 + flags, iDb);
222  
223 /* Configure the number of columns. Configure the cursor to
224 ** think that the table has one more column than it really
225 ** does. An OP_Column to retrieve this imaginary column will
226 ** always return an SQL NULL. This is useful because it means
227 ** we can invoke OP_Column to fill in the vdbe cursors type
228 ** and offset cache without causing any IO.
229 */
230 sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32);
231 sqlite3VdbeChangeP2(v, 7, pTab->nCol);
232 if( null==db->mallocFailed ){
233 pParse->nVar = 1;
234 pParse->nMem = 1;
235 pParse->nTab = 1;
236 sqlite3VdbeMakeReady(v, pParse);
237 }
238 }
239  
240 sqlite3BtreeLeaveAll(db);
241 goto blob_open_out;
242 }
243  
244 sqlite3_bind_int64((sqlite3_stmt )v, 1, iRow);
245 rc = sqlite3_step((sqlite3_stmt )v);
246 if( rc!=SQLITE_ROW ){
247 nAttempt++;
248 rc = sqlite3_finalize((sqlite3_stmt )v);
249 sqlite3DbFree(db, zErr);
250 zErr = sqlite3MPrintf(db, sqlite3_errmsg(db));
251 v = 0;
252 }
253 } while( nAttempt<5 && rc==SQLITE_SCHEMA );
254  
255 if( rc==SQLITE_ROW ){
256 /* The row-record has been opened successfully. Check that the
257 ** column in question contains text or a blob. If it contains
258 ** text, it is up to the caller to get the encoding right.
259 */
260 Incrblob *pBlob;
261 u32 type = v->apCsr[0]->aType[iCol];
262  
263 if( type<12 ){
264 sqlite3DbFree(db, zErr);
265 zErr = sqlite3MPrintf(db, "cannot open value of type %s",
266 type==0?"null": type==7?"real": "integer"
267 );
268 rc = SQLITE_ERROR;
269 goto blob_open_out;
270 }
271 pBlob = (Incrblob )sqlite3DbMallocZero(db, sizeof(Incrblob));
272 if( db->mallocFailed ){
273 sqlite3DbFree(db, ref pBlob);
274 goto blob_open_out;
275 }
276 pBlob->flags = flags;
277 pBlob->pCsr = v->apCsr[0]->pCursor;
278 sqlite3BtreeEnterCursor(pBlob->pCsr);
279 sqlite3BtreeCacheOverflow(pBlob->pCsr);
280 sqlite3BtreeLeaveCursor(pBlob->pCsr);
281 pBlob->pStmt = (sqlite3_stmt )v;
282 pBlob->iOffset = v->apCsr[0]->aOffset[iCol];
283 pBlob->nByte = sqlite3VdbeSerialTypeLen(type);
284 pBlob->db = db;
285 *ppBlob = (sqlite3_blob )pBlob;
286 rc = SQLITE_OK;
287 }else if( rc==SQLITE_OK ){
288 sqlite3DbFree(db, zErr);
289 zErr = sqlite3MPrintf(db, "no such rowid: %lld", iRow);
290 rc = SQLITE_ERROR;
291 }
292  
293 blob_open_out:
294 if( v && (rc!=SQLITE_OK || db->mallocFailed) ){
295 sqlite3VdbeFinalize(v);
296 }
297 sqlite3Error(db, rc, zErr);
298 sqlite3DbFree(db, zErr);
299 sqlite3StackFree(db, pParse);
300 rc = sqlite3ApiExit(db, rc);
301 sqlite3_mutex_leave(db->mutex);
302 return rc;
303 }
304  
305 /*
306 ** Close a blob handle that was previously created using
307 ** sqlite3_blob_open().
308 */
309 int sqlite3_blob_close(sqlite3_blob *pBlob){
310 Incrblob *p = (Incrblob )pBlob;
311 int rc;
312 sqlite3 db;
313  
314 if( p ){
315 db = p->db;
316 sqlite3_mutex_enter(db->mutex);
317 rc = sqlite3_finalize(p->pStmt);
318 sqlite3DbFree(db, ref p);
319 sqlite3_mutex_leave(db->mutex);
320 }else{
321 rc = SQLITE_OK;
322 }
323 return rc;
324 }
325  
326 /*
327 ** Perform a read or write operation on a blob
328 */
329 static int blobReadWrite(
330 sqlite3_blob *pBlob,
331 void *z,
332 int n,
333 int iOffset,
334 int (*xCall)(BtCursor*, u32, u32, void)
335 ){
336 int rc;
337 Incrblob *p = (Incrblob )pBlob;
338 Vdbe *v;
339 sqlite3 db;
340  
341 if( p==0 ) return SQLITE_MISUSE_BKPT();
342 db = p->db;
343 sqlite3_mutex_enter(db->mutex);
344 v = (Vdbe)p->pStmt;
345  
346 if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){
347 /* Request is out of range. Return a transient error. */
348 rc = SQLITE_ERROR;
349 sqlite3Error(db, SQLITE_ERROR, 0);
350 } else if( v==0 ){
351 /* If there is no statement handle, then the blob-handle has
352 ** already been invalidated. Return SQLITE_ABORT in this case.
353 */
354 rc = SQLITE_ABORT;
355 }else{
356 /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
357 ** returned, clean-up the statement handle.
358 */
359 Debug.Assert( db == v->db );
360 sqlite3BtreeEnterCursor(p->pCsr);
361 rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
362 sqlite3BtreeLeaveCursor(p->pCsr);
363 if( rc==SQLITE_ABORT ){
364 sqlite3VdbeFinalize(v);
365 p->pStmt = null;
366 }else{
367 db->errCode = rc;
368 v->rc = rc;
369 }
370 }
371 rc = sqlite3ApiExit(db, rc);
372 sqlite3_mutex_leave(db->mutex);
373 return rc;
374 }
375  
376 /*
377 ** Read data from a blob handle.
378 */
379 int sqlite3_blob_read(sqlite3_blob *pBlob, object *z, int n, int iOffset){
380 return blobReadWrite(pBlob, z, n, iOffset, sqlite3BtreeData);
381 }
382  
383 /*
384 ** Write data to a blob handle.
385 */
386 int sqlite3_blob_write(sqlite3_blob *pBlob, string z, int n, int iOffset){
387 return blobReadWrite(pBlob, (void )z, n, iOffset, sqlite3BtreePutData);
388 }
389  
390 /*
391 ** Query a blob handle for the size of the data.
392 **
393 ** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
394 ** so no mutex is required for access.
395 */
396 int sqlite3_blob_bytes(sqlite3_blob *pBlob){
397 Incrblob *p = (Incrblob )pBlob;
398 return p ? p->nByte : 0;
399 }
400  
401 #endif // * #if !SQLITE_OMIT_INCRBLOB */
402 }
403 }