/ Changes On Branch sqlite3_blob_reset
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch sqlite3_blob_reset Excluding Merge-Ins

This is equivalent to a diff from 97ccf3e4de to 61bd2a885d

2017-02-04
17:33
Allow sqlite3session_apply() to apply changesets to tables that have been extended using ALTER TABLE ADD COLUMN. (check-in: b20ff81ff9 user: dan tags: trunk)
15:29
Merge recent trunk enhancements. (check-in: 6c3f09028f user: drh tags: apple-osx)
14:30
Merge the latest trunk changes, especially the RTREE enhancement to use sqlite3_blob objects. (Leaf check-in: 61bd2a885d user: drh tags: sqlite3_blob_reset)
14:24
In RTREE, use an sqlite3_blob object rather than an sqlite3_stmt object for reading content out of the %_node shadow table. (check-in: 97ccf3e4de user: drh tags: trunk)
13:12
Close sqlite3_blob objects on xSync rather than waiting until xCommit. (Closed-Leaf check-in: 95ee745fce user: drh tags: rtree-blob-agressive-release)
2017-02-03
20:54
Improved performance and stack usage when processing VALUES clauses with a very large number of rows. (check-in: 5706d4708a user: drh tags: trunk)
2017-02-02
23:57
Add the sqlite3_blob_reset() interface. Enhance the behavior of sqlite3_blob objects so that they can go active again after encountering an error by rerunning sqlite3_blob_reopen(). More work needed on the documentation. (check-in: 53b77838f0 user: drh tags: sqlite3_blob_reset)

Changes to src/sqlite.h.in.

6134
6135
6136
6137
6138
6139
6140
6141

6142
6143
6144




6145
6146
6147
6148
6149










6150
6151
6152
6153
6154
6155
6156
6157
6158
6159


6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
6173
6174
6175
6176
6177
6178
6179





6180
6181
6182
6183
6184
6185
6186
6134
6135
6136
6137
6138
6139
6140

6141
6142


6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169


6170
6171
6172
6173
6174
6175
6176
6177
6178
6179
6180
6181
6182
6183
6184
6185
6186
6187




6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199







-
+

-
-
+
+
+
+





+
+
+
+
+
+
+
+
+
+








-
-
+
+
















-
-
-
-
+
+
+
+
+







**
** When the virtual-table mechanism stabilizes, we will declare the
** interface fixed, support it indefinitely, and remove this comment.
*/

/*
** CAPI3REF: A Handle To An Open BLOB
** KEYWORDS: {BLOB handle} {BLOB handles}
** KEYWORDS: {BLOB handle} {BLOB handles} {sqlite3_blob object}
**
** An instance of this object represents an open BLOB on which
** [sqlite3_blob_open | incremental BLOB I/O] can be performed.
** An instance of this object represents a connection to a single
** column in a single row of a table that holds either a BLOB or string
** and on which [sqlite3_blob_open | incremental BLOB I/O] can be performed.
**
** ^Objects of this type are created by [sqlite3_blob_open()]
** and destroyed by [sqlite3_blob_close()].
** ^The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
** can be used to read or write small subsections of the BLOB.
** ^The [sqlite3_blob_bytes()] interface returns the size of the BLOB in bytes.
**
** An sqlite3_blob object can be in two states: ACTIVE and RESET.  When in
** the ACTIVE state, the object is pointing to a specific entry and is
** ready to do I/O.  When RESET, the sqlite3_blob object is in standby mode,
** is not associated with any particular row of its table, 
** and is not available for I/O.
**
** The sqlite3_blob object does not contain a mutex and so a single
** sqlite3_blob object may not be safely used by multiple threads
** concurrently.
*/
typedef struct sqlite3_blob sqlite3_blob;

/*
** CAPI3REF: Open A BLOB For Incremental I/O
** METHOD: sqlite3
** CONSTRUCTOR: sqlite3_blob
**
** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located
** in row iRow, column zColumn, table zTable in database zDb;
** ^(This interfaces creates an sqlite3_blob object pointing to the string
** or BLOB located in row iRow, column zColumn, table zTable in database zDb;
** in other words, the same BLOB that would be selected by:
**
** <pre>
**     SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow;
** </pre>)^
**
** ^(Parameter zDb is not the filename that contains the database, but 
** rather the symbolic name of the database. For attached databases, this is
** the name that appears after the AS keyword in the [ATTACH] statement.
** For the main database file, the database name is "main". For TEMP
** tables, the database name is "temp".)^
**
** ^If the flags parameter is non-zero, then the BLOB is opened for read
** and write access. ^If the flags parameter is zero, the BLOB is opened for
** read-only access.
**
** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored
** in *ppBlob. Otherwise an [error code] is returned and, unless the error
** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided
** the API is not misused, it is always safe to call [sqlite3_blob_close()] 
** ^(On success, [SQLITE_OK] is returned and the new [sqlite3_blob object]
** is stored in *ppBlob. Otherwise an [error code] is returned and
** *ppBlob is set to NULL.)^ ^Because *ppBlob is always set to either a
** valid sqlite3_blob object or NULL
** it is always safe to call [sqlite3_blob_close()] 
** on *ppBlob after this function it returns.
**
** This function fails with SQLITE_ERROR if any of the following are true:
** <ul>
**   <li> ^(Database zDb does not exist)^, 
**   <li> ^(Table zTable does not exist within database zDb)^, 
**   <li> ^(Table zTable is a WITHOUT ROWID table)^, 
6204
6205
6206
6207
6208
6209
6210
6211


6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223


6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234


6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247

6248
6249
6250

6251
6252
6253
6254

6255
6256
6257
6258
6259
6260
6261
6262


6263
6264

6265
6266
6267
6268
6269
6270
6271
6272

6273
6274
6275


6276
6277

6278
6279
6280




6281
6282
6283
6284
6285
6286



6287
6288
6289

6290
6291
6292
6293
6294










6295

6296
6297
6298
6299


6300
6301

6302
6303

6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316



6317
6318
6319
6320
6321
6322
6323
6324



6325
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342
6343
6344
6345




6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366




6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6217
6218
6219
6220
6221
6222
6223

6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236

6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248

6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262

6263
6264
6265

6266
6267
6268
6269

6270
6271
6272
6273
6274
6275
6276


6277
6278


6279
6280
6281
6282
6283
6284
6285
6286

6287
6288
6289

6290
6291
6292

6293
6294


6295
6296
6297
6298
6299
6300
6301
6302


6303
6304
6305
6306
6307

6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323

6324
6325
6326


6327
6328
6329

6330
6331

6332
6333
6334
6335
6336
6337
6338
6339
6340
6341
6342



6343
6344
6345
6346
6347
6348
6349
6350
6351
6352

6353
6354
6355
6356
6357
6358
6359
6360





6361
6362
6363
6364
6365
6366
6367
6368



6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391


6392
6393
6394
6395









6396
6397
6398
6399
6400
6401
6402







-
+
+











-
+
+










-
+
+












-
+


-
+



-
+






-
-
+
+
-
-
+







-
+


-
+
+

-
+

-
-
+
+
+
+




-
-
+
+
+


-
+





+
+
+
+
+
+
+
+
+
+
-
+


-
-
+
+

-
+

-
+










-
-
-
+
+
+







-
+
+
+





-
-
-
-
-








-
-
-
+
+
+
+



















-
-
+
+
+
+
-
-
-
-
-
-
-
-
-







** [sqlite3_blob_write()].  The [BLOB handle] can be moved to a
** different row of the same table using the [sqlite3_blob_reopen()]
** interface.  However, the column, table, or database of a [BLOB handle]
** cannot be changed after the [BLOB handle] is opened.
**
** ^(If the row that a BLOB handle points to is modified by an
** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects
** then the BLOB handle is marked as "expired".
** then the BLOB handle is marked as "expired" and cannot be used
** successfully with first being [sqlite3_blob_reopen|reopened].
** This is true if any column of the row is changed, even a column
** other than the one the BLOB handle is open on.)^
** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for
** an expired BLOB handle fail with a return code of [SQLITE_ABORT].
** ^(Changes written into a BLOB prior to the BLOB expiring are not
** rolled back by the expiration of the BLOB.  Such changes will eventually
** commit if the transaction continues to completion.)^
**
** ^Use the [sqlite3_blob_bytes()] interface to determine the size of
** the opened blob.  ^The size of a blob may not be changed by this
** interface.  Use the [UPDATE] SQL command to change the size of a
** blob.
** blob.  The [sqlite3_blob_bytes()] interface returns an arbitrary
** number when used on an expired sqlite3_blob object.
**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
** and the built-in [zeroblob] SQL function may be used to create a 
** zero-filled blob to read or write using the incremental-blob interface.
**
** To avoid a resource leak, every open [BLOB handle] should eventually
** be released by a call to [sqlite3_blob_close()].
**
** See also: [sqlite3_blob_close()],
** [sqlite3_blob_reopen()], [sqlite3_blob_read()],
** [sqlite3_blob_bytes()], [sqlite3_blob_write()].
** [sqlite3_blob_bytes()], [sqlite3_blob_write()],
** [sqlite3_blob_reset()].
*/
int sqlite3_blob_open(
  sqlite3*,
  const char *zDb,
  const char *zTable,
  const char *zColumn,
  sqlite3_int64 iRow,
  int flags,
  sqlite3_blob **ppBlob
);

/*
** CAPI3REF: Move a BLOB Handle to a New Row
** CAPI3REF: Move an sqlite3_blob object to a New Row
** METHOD: sqlite3_blob
**
** ^This function is used to move an existing [BLOB handle] so that it points
** ^This function updates an existing [sqlite3_blob object] so that it points
** to a different row of the same database table. ^The new row is identified
** by the rowid value passed as the second argument. Only the row can be
** changed. ^The database, table and column on which the blob handle is open
** remain the same. Moving an existing [BLOB handle] to a new row is
** remain the same. Moving an existing [sqlite3_blob object] to a new row is
** faster than closing the existing handle and opening a new one.
**
** ^(The new row must meet the same criteria as for [sqlite3_blob_open()] -
** it must exist and there must be either a blob or text value stored in
** the nominated column.)^ ^If the new row is not present in the table, or if
** it does not contain a blob or text value, or if another error occurs, an
** SQLite error code is returned and the blob handle is considered aborted.
** ^All subsequent calls to [sqlite3_blob_read()], [sqlite3_blob_write()] or
** SQLite error code is returned and the [sqlite3_blob object] is changed
** to the RESET state.
** [sqlite3_blob_reopen()] on an aborted blob handle immediately return
** SQLITE_ABORT. ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
** ^Calling [sqlite3_blob_bytes()] on an aborted blob handle
** always returns zero.
**
** ^This function sets the database handle error code and message.
*/
int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);

/*
** CAPI3REF: Close A BLOB Handle
** CAPI3REF: Close an sqlite3_blob object
** DESTRUCTOR: sqlite3_blob
**
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
** ^This function is the destructor for an [sqlite3_blob object]. 
** ^(The [sqlite3_blob object] is closed
** unconditionally.  Even if this routine returns an error code, the 
** handle is still closed.)^
** object is still closed.)^
**
** ^If the blob handle being closed was opened for read-write access, and if
** the database is in auto-commit mode and there are no other open read-write
** ^If the sqlite3_blob object being closed was opened for read-write access,
** and is in the ACTIVE state,
** and if the database is in auto-commit mode and there are no other open 
** read-write
** blob handles or active write statements, the current transaction is
** committed. ^If an error occurs while committing the transaction, an error
** code is returned and the transaction rolled back.
**
** Calling this function with an argument that is not a NULL pointer or an
** open blob handle results in undefined behaviour. ^Calling this routine 
** Calling this function with an argument that is not a NULL pointer or a
** valid sqlite3_blob object pointer results in undefined behaviour. 
** ^Calling this routine 
** with a null pointer (such as would be returned by a failed call to 
** [sqlite3_blob_open()]) is a harmless no-op. ^Otherwise, if this function
** is passed a valid open blob handle, the values returned by the 
** is passed a valid sqlite3_blob objecct pointer, the values returned by the 
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.
*/
int sqlite3_blob_close(sqlite3_blob *);

/*
** CAPI3REF: Reset an sqlite3_blob object
** METHOD: sqlite3_blob
**
** ^This function changes an [sqlite3_blob object] to the RESET state.
** ^If the [sqlite3_blob object] was already in the RESET state, then this
** routine is a harmless no-op.
*/
int sqlite3_blob_reset(sqlite3_blob *);

/*
** CAPI3REF: Return The Size Of An Open BLOB
** CAPI3REF: Return The Size Of A BLOB
** METHOD: sqlite3_blob
**
** ^Returns the size in bytes of the BLOB accessible via the 
** successfully opened [BLOB handle] in its only argument.  ^The
** ^Returns the size in bytes of the BLOB or string accessible via the 
** ACTIVE [sqlite3_blob object] in its only argument.  ^The
** incremental blob I/O routines can only read or overwriting existing
** blob content; they cannot change the size of a blob.
** content; they cannot change the size of a blob or string.
**
** This routine only works on a [BLOB handle] which has been created
** This routine only works on an [sqlite3_blob object] that has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()].  Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
*/
int sqlite3_blob_bytes(sqlite3_blob *);

/*
** CAPI3REF: Read Data From A BLOB Incrementally
** METHOD: sqlite3_blob
**
** ^(This function is used to read data from an open [BLOB handle] into a
** caller-supplied buffer. N bytes of data are copied into buffer Z
** from the open BLOB, starting at offset iOffset.)^
** ^(This function is used to read data from string or BLOB that an
** [sqlite3_blob object] is pointing to into a caller-supplied buffer. 
** N bytes of data are copied into buffer Z starting at offset iOffset.)^
**
** ^If offset iOffset is less than N bytes from the end of the BLOB,
** [SQLITE_ERROR] is returned and no data is read.  ^If N or iOffset is
** less than zero, [SQLITE_ERROR] is returned and no data is read.
** ^The size of the blob (and hence the maximum value of N+iOffset)
** can be determined using the [sqlite3_blob_bytes()] interface.
**
** ^An attempt to read from an expired [BLOB handle] fails with an
** ^An attempt to read from an [sqlite3_blob object] that is in the RESET
** state, or from a database row that has changed since the most recent
** call to [sqlite3_blob_open()] or [sqlite3_blob_reopen()] fails with an
** error code of [SQLITE_ABORT].
**
** ^(On success, sqlite3_blob_read() returns SQLITE_OK.
** Otherwise, an [error code] or an [extended error code] is returned.)^
**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()].  Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
**
** See also: [sqlite3_blob_write()].
*/
int sqlite3_blob_read(sqlite3_blob *, void *Z, int N, int iOffset);

/*
** CAPI3REF: Write Data Into A BLOB Incrementally
** METHOD: sqlite3_blob
**
** ^(This function is used to write data into an open [BLOB handle] from a
** caller-supplied buffer. N bytes of data are copied from the buffer Z
** into the open BLOB, starting at offset iOffset.)^
** ^(This function is used to write data from a caller-supplied buffer
** into a BLOB or string pointed to by an [sqlite3_blob object].
** N bytes of data are copied from the buffer Z
** into the BLOB or string, starting at offset iOffset.)^
**
** ^(On success, sqlite3_blob_write() returns SQLITE_OK.
** Otherwise, an  [error code] or an [extended error code] is returned.)^
** ^Unless SQLITE_MISUSE is returned, this function sets the 
** [database connection] error code and message accessible via 
** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. 
**
** ^If the [BLOB handle] passed as the first argument was not opened for
** writing (the flags parameter to [sqlite3_blob_open()] was zero),
** this function returns [SQLITE_READONLY].
**
** This function may only modify the contents of the BLOB; it is
** not possible to increase the size of a BLOB using this API.
** ^If offset iOffset is less than N bytes from the end of the BLOB,
** [SQLITE_ERROR] is returned and no data is written. The size of the 
** BLOB (and hence the maximum value of N+iOffset) can be determined 
** using the [sqlite3_blob_bytes()] interface. ^If N or iOffset are less 
** than zero [SQLITE_ERROR] is returned and no data is written.
**
** ^An attempt to write to an expired [BLOB handle] fails with an
** error code of [SQLITE_ABORT].  ^Writes to the BLOB that occurred
** ^An attempt to write into an [sqlite3_blob object] that is in the RESET
** state, or into a database row that has changed since the most recent
** call to [sqlite3_blob_open()] or [sqlite3_blob_reopen()] fails with an
** error code of [SQLITE_ABORT].
** before the [BLOB handle] expired are not rolled back by the
** expiration of the handle, though of course those changes might
** have been overwritten by the statement that expired the BLOB handle
** or by other independent statements.
**
** This routine only works on a [BLOB handle] which has been created
** by a prior successful call to [sqlite3_blob_open()] and which has not
** been closed by [sqlite3_blob_close()].  Passing any other pointer in
** to this routine results in undefined and probably undesirable behavior.
**
** See also: [sqlite3_blob_read()].
*/
int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);

/*
** CAPI3REF: Virtual File System Objects

Changes to src/vdbeblob.c.

19
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34

35
36
37
38
39
40
41







-
+








-







#ifndef SQLITE_OMIT_INCRBLOB

/*
** Valid sqlite3_blob* handles point to Incrblob structures.
*/
typedef struct Incrblob Incrblob;
struct Incrblob {
  int nByte;              /* Size of open blob, in bytes */
  int nByte;              /* Size of open blob if ACTIVE. -1 if RESET */
  int iOffset;            /* Byte offset of blob in cursor data */
  u16 iCol;               /* Table column this handle is open on */
  BtCursor *pCsr;         /* Cursor pointing at blob row */
  sqlite3_stmt *pStmt;    /* Statement holding cursor open */
  sqlite3 *db;            /* The associated database */
  char *zDb;              /* Database name */
  Table *pTab;            /* Table object */
};


/*
** This function is used by both blob_open() and blob_reopen(). It seeks
** the b-tree cursor associated with blob handle p to point to row iRow.
** If successful, SQLITE_OK is returned and subsequent calls to
** sqlite3_blob_read() or sqlite3_blob_write() access the specified row.
**
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
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







-
-
+
+










-
-
-
+
+
+







    testcase( pC->nHdrParsed==p->iCol );
    testcase( pC->nHdrParsed==p->iCol+1 );
    if( type<12 ){
      zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
          type==0?"null": type==7?"real": "integer"
      );
      rc = SQLITE_ERROR;
      sqlite3_finalize(p->pStmt);
      p->pStmt = 0;
      sqlite3_reset(p->pStmt);
      p->nByte = -1;
    }else{
      p->iOffset = pC->aType[p->iCol + pC->nField];
      p->nByte = sqlite3VdbeSerialTypeLen(type);
      p->pCsr =  pC->uc.pCursor;
      sqlite3BtreeIncrblobCursor(p->pCsr);
    }
  }

  if( rc==SQLITE_ROW ){
    rc = SQLITE_OK;
  }else if( p->pStmt ){
    rc = sqlite3_finalize(p->pStmt);
    p->pStmt = 0;
  }else if( p->nByte>=0 ){
    rc = sqlite3_reset(p->pStmt);
    p->nByte = -1;
    if( rc==SQLITE_OK ){
      zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow);
      rc = SQLITE_ERROR;
    }else{
      zErr = sqlite3MPrintf(p->db, "%s", sqlite3_errmsg(p->db));
    }
  }
153
154
155
156
157
158
159

160
161
162
163
164
165
166
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166







+







  if( !pParse ) goto blob_open_out;

  do {
    memset(pParse, 0, sizeof(Parse));
    pParse->db = db;
    sqlite3DbFree(db, zErr);
    zErr = 0;
    sqlite3_finalize(pBlob->pStmt);

    sqlite3BtreeEnterAll(db);
    pTab = sqlite3LocateTable(pParse, 0, zTable, zDb);
    if( pTab && IsVirtual(pTab) ){
      pTab = 0;
      sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable);
    }
320
321
322
323
324
325
326

327
328
329
330
331
332
333
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334







+







        pParse->nTab = 1;
        sqlite3VdbeMakeReady(v, pParse);
      }
    }
   
    pBlob->iCol = iCol;
    pBlob->db = db;
    pBlob->nByte = 0;
    sqlite3BtreeLeaveAll(db);
    if( db->mallocFailed ){
      goto blob_open_out;
    }
    rc = blobSeekToRow(pBlob, iRow, &zErr);
  } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA );

355
356
357
358
359
360
361
362

363
364
365
366
367
368
369
356
357
358
359
360
361
362

363
364
365
366
367
368
369
370







-
+







  Incrblob *p = (Incrblob *)pBlob;
  int rc;
  sqlite3 *db;

  if( p ){
    db = p->db;
    sqlite3_mutex_enter(db->mutex);
    rc = sqlite3_finalize(p->pStmt);
    rc = sqlite3VdbeFinalize((Vdbe*)p->pStmt);
    sqlite3DbFree(db, p);
    sqlite3_mutex_leave(db->mutex);
  }else{
    rc = SQLITE_OK;
  }
  return rc;
}
380
381
382
383
384
385
386




387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398





399
400
401
402
403
404
405







+
+
+
+







-
-
-
-
-







){
  int rc;
  Incrblob *p = (Incrblob *)pBlob;
  Vdbe *v;
  sqlite3 *db;

  if( p==0 ) return SQLITE_MISUSE_BKPT;
  if( p->nByte<0 ){
    /* The blob handle is in the RESET state.  Always return SQLITE_ABORT. */
    return SQLITE_ABORT;
  }
  db = p->db;
  sqlite3_mutex_enter(db->mutex);
  v = (Vdbe*)p->pStmt;

  if( n<0 || iOffset<0 || ((sqlite3_int64)iOffset+n)>p->nByte ){
    /* Request is out of range. Return a transient error. */
    rc = SQLITE_ERROR;
  }else if( v==0 ){
    /* If there is no statement handle, then the blob-handle has
    ** already been invalidated. Return SQLITE_ABORT in this case.
    */
    rc = SQLITE_ABORT;
  }else{
    /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is
    ** returned, clean-up the statement handle.
    */
    assert( db == v->db );
    sqlite3BtreeEnterCursor(p->pCsr);

425
426
427
428
429
430
431
432
433


434
435
436
437
438
439
440
425
426
427
428
429
430
431


432
433
434
435
436
437
438
439
440







-
-
+
+







      );
    }
#endif

    rc = xCall(p->pCsr, iOffset+p->iOffset, n, z);
    sqlite3BtreeLeaveCursor(p->pCsr);
    if( rc==SQLITE_ABORT ){
      sqlite3VdbeFinalize(v);
      p->pStmt = 0;
      sqlite3_reset(p->pStmt);
      p->nByte = -1;
    }else{
      v->rc = rc;
    }
  }
  sqlite3Error(db, rc);
  rc = sqlite3ApiExit(db, rc);
  sqlite3_mutex_leave(db->mutex);
454
455
456
457
458
459
460
461
462










463
464
465
466

467
468














469
470
471
472
473
474
475
476
477
478
479
480
481
482

483
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
454
455
456
457
458
459
460


461
462
463
464
465
466
467
468
469
470
471
472
473

474
475
476
477
478
479
480
481
482
483
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


515
516
517

518
519
520
521
522
523







-
-
+
+
+
+
+
+
+
+
+
+



-
+


+
+
+
+
+
+
+
+
+
+
+
+
+
+














+





-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-



-
+





int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
  return blobReadWrite(pBlob, (void *)z, n, iOffset, sqlite3BtreePutData);
}

/*
** Query a blob handle for the size of the data.
**
** The Incrblob.nByte field is fixed for the lifetime of the Incrblob
** so no mutex is required for access.
** The Incrblob.nByte field is fixed for as long as the sqlite3_blob
** object is pointing to the same row, so no mutex is required for access.
**
** When the sqlite3_blob interface was first designed in 2007, we specified
** that sqlite3_blob_bytes() returned 0 when in the RESET state.  It would
** have been better to return -1 in order to distinguish a RESET blob handle
** from an ACTIVE blob handle pointing to a zero-length string or blob.
** But, sadly, we cannot change that now without breaking compatibility.
** So 0 is returned for RESET blob handles and for ACTIVE blob handles
** pointing to zero-length blobs.
*/
int sqlite3_blob_bytes(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  return (p && p->pStmt) ? p->nByte : 0;
  return (p && p->pStmt && p->nByte>0) ? p->nByte : 0;
}

/*
** Move the sqlite3_blob object to the RESET state.  This releases
** any locks and gets the object out of the way of commits and
** rollbacks.
*/
int sqlite3_blob_reset(sqlite3_blob *pBlob){
  Incrblob *p = (Incrblob *)pBlob;
  if( p->nByte>=0 ){
    sqlite3_reset(p->pStmt);
    p->nByte = -1;
  }
  return SQLITE_OK;
}  

/*
** Move an existing blob handle to point to a different row of the same
** database table.
**
** If an error occurs, or if the specified row does not exist or does not
** contain a blob or text value, then an error code is returned and the
** database handle error code and message set. If this happens, then all 
** subsequent calls to sqlite3_blob_xxx() functions (except blob_close()) 
** immediately return SQLITE_ABORT.
*/
int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
  int rc;
  Incrblob *p = (Incrblob *)pBlob;
  sqlite3 *db;
  char *zErr;

  if( p==0 ) return SQLITE_MISUSE_BKPT;
  db = p->db;
  sqlite3_mutex_enter(db->mutex);

  if( p->pStmt==0 ){
    /* If there is no statement handle, then the blob-handle has
    ** already been invalidated. Return SQLITE_ABORT in this case.
    */
    rc = SQLITE_ABORT;
  }else{
    char *zErr;
    rc = blobSeekToRow(p, iRow, &zErr);
    if( rc!=SQLITE_OK ){
      sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
      sqlite3DbFree(db, zErr);
  rc = blobSeekToRow(p, iRow, &zErr);
  if( rc!=SQLITE_OK ){
    sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
    sqlite3DbFree(db, zErr);
    }
    assert( rc!=SQLITE_SCHEMA );
  }

  rc = sqlite3ApiExit(db, rc);
  assert( rc==SQLITE_OK || p->pStmt==0 );
  assert( rc==SQLITE_OK || p->nByte<0 );
  sqlite3_mutex_leave(db->mutex);
  return rc;
}

#endif /* #ifndef SQLITE_OMIT_INCRBLOB */

Changes to test/e_blobwrite.test.

137
138
139
140
141
142
143
144
145


146
147
148
149
150
151
152
137
138
139
140
141
142
143


144
145
146
147
148
149
150
151
152







-
-
+
+







} {}
blob_write_error_test 2.3.1 $B 5 $blob 5 \
    SQLITE_ABORT {callback requested query abort}
do_test 2.3.2 {
  execsql { SELECT 1, 2, 3 }
  sqlite3_errcode db
} {SQLITE_OK}
blob_write_error_test 2.3.3 $B 5 $blob 5 \
    SQLITE_ABORT {callback requested query abort}
#blob_write_error_test 2.3.3 $B 5 $blob 5 \
#    SQLITE_OK {not an error}
sqlite3_blob_close $B

# EVIDENCE-OF: R-08382-59936 Writes to the BLOB that occurred before the
# BLOB handle expired are not rolled back by the expiration of the
# handle, though of course those changes might have been overwritten by
# the statement that expired the BLOB handle or by other independent
# statements.

Changes to test/incrblob3.test.

58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
58
59
60
61
62
63
64

65
66
67
68
69
70
71
72







-
+







  list [catch {sqlite3_blob_reopen $::blob 3} msg] $msg
} {1 SQLITE_ERROR}
do_test incrblob3-2.1.2 {
  list [sqlite3_errcode db] [sqlite3_errmsg db]
} {SQLITE_ERROR {no such rowid: 3}}
do_test incrblob3-2.1.3 {
  list [catch {sqlite3_blob_reopen $::blob 1} msg] $msg
} {1 SQLITE_ABORT}
} {0 {}}
do_test incrblob3-2.1.4 { close $::blob } {}

do_execsql_test incrblob3-2.2.1 {
  INSERT INTO blobs VALUES(3, 42);
  INSERT INTO blobs VALUES(4, 54.4);
  INSERT INTO blobs VALUES(5, NULL);
}
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
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







-
+


-
+


-
+


+
+
+
-
+

-
+







  } {1 SQLITE_ERROR}
  do_test incrblob3-2.2.$tn.2 {
    list [sqlite3_errcode db] [sqlite3_errmsg db]
  } "SQLITE_ERROR {cannot open value of type $type}"

  do_test incrblob3-2.2.$tn.3 {
    list [catch {sqlite3_blob_reopen $::blob 1} msg] $msg
  } {1 SQLITE_ABORT}
  } {0 {}}
  do_test incrblob3-2.2.$tn.4 {
    list [catch {sqlite3_blob_read $::blob 0 10} msg] $msg
  } {1 SQLITE_ABORT}
  } {0 {hello worl}}
  do_test incrblob3-2.2.$tn.5 {
    list [catch {sqlite3_blob_write $::blob 0 "abcd"} msg] $msg
  } {1 SQLITE_ABORT}
  } {0 {}}
  do_test incrblob3-2.2.$tn.6 {
    sqlite3_blob_bytes $::blob
  } {100}
  do_test incrblob3-2.2.$tn.7 {
    list [catch {sqlite3_blob_write $::blob 0 "hello"} msg] $msg
  } {0}
  } {0 {}}

  do_test incrblob3-2.2.$tn.7 { close $::blob } {}
  do_test incrblob3-2.2.$tn.8 { close $::blob } {}
}

# Test that passing NULL to sqlite3_blob_XXX() APIs returns SQLITE_MISUSE.
#
#   incrblob3-3.1: sqlite3_blob_reopen()
#   incrblob3-3.2: sqlite3_blob_read()
#   incrblob3-3.3: sqlite3_blob_write()