/ Check-in [5a1eac24]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Add new test file e_blobclose.test, containing tests for sqlite3_blob_close().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 5a1eac2419b1462e6f21595a3fff26d9cc49d203
User & Date: dan 2014-11-11 12:20:35
Context
2014-11-11
14:59
Permit read operations to continue after a ROLLBACK as long as the schema does not change. check-in: b5df5ac0 user: drh tags: trunk
12:20
Add new test file e_blobclose.test, containing tests for sqlite3_blob_close(). check-in: 5a1eac24 user: dan tags: trunk
2014-11-10
19:16
New test cases for deleting content out from under a SELECT statement. check-in: 8289c3e9 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/sqlite.h.in.

5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
** ^This function sets the database handle error code and message.
*/
SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);

/*
** CAPI3REF: Close A BLOB Handle
**
** ^Closes an open [BLOB handle].
**
** ^Closing a BLOB shall cause the current transaction to commit
** if there are no other BLOBs, no pending prepared statements, and the
** database connection is in [autocommit mode].
** ^If any writes were made to the BLOB, they might be held in cache
** until the close operation if they will fit.
**
** ^(Closing the BLOB often forces the changes
** out to disk and so if any I/O errors occur, they will likely occur
** at the time when the BLOB is closed.  Any errors that occur during
** closing are reported as a non-zero return value.)^
**
** ^(The BLOB is closed unconditionally.  Even if this routine returns
** an error code, the BLOB is still closed.)^
**
** ^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.
*/
int sqlite3_blob_close(sqlite3_blob *);

/*
** CAPI3REF: Return The Size Of An Open BLOB
**
** ^Returns the size in bytes of the BLOB accessible via the 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<
<







5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772


5773
5774
5775
5776
5777
5778
5779
** ^This function sets the database handle error code and message.
*/
SQLITE_EXPERIMENTAL int sqlite3_blob_reopen(sqlite3_blob *, sqlite3_int64);

/*
** CAPI3REF: Close A BLOB Handle
**
** ^This function closes an open [BLOB handle]. ^(The BLOB handle is closed
** unconditionally.  Even if this routine returns an error code, the 
** handle 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
** 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 
** 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 
** sqlite3_errcode() and sqlite3_errmsg() functions are set before returning.


*/
int sqlite3_blob_close(sqlite3_blob *);

/*
** CAPI3REF: Return The Size Of An Open BLOB
**
** ^Returns the size in bytes of the BLOB accessible via the 

Added test/e_blobclose.test.























































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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
69
70
71
72
73
74
75
76
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# 2014 October 30
#
# 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.
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix e_blobclose

set dots [string repeat . 40]
do_execsql_test 1.0 {
  CREATE TABLE x1(a INTEGER PRIMARY KEY, b DOTS);
  INSERT INTO x1 VALUES(-1, $dots);
  INSERT INTO x1 VALUES(-10, $dots);
  INSERT INTO x1 VALUES(-100, $dots);
  INSERT INTO x1 VALUES(-1000, $dots);
  INSERT INTO x1 VALUES(-10000, $dots);
}

# EVIDENCE-OF: R-03145-46390 This function closes an open BLOB handle.
#
#   It's not clear how to test that a blob handle really is closed.
#   Attempting to use a closed blob handle will likely crash the process.
#   Assume here that if the SHARED lock on the db file is released,
#   the blob handle has been closed.
#
do_execsql_test 1.1 { PRAGMA lock_status } {main unlocked temp closed}
sqlite3_blob_open db main x1 b -1 0 B
do_execsql_test 1.2 { PRAGMA lock_status } {main shared temp closed}
sqlite3_blob_close $B
do_execsql_test 1.3 { PRAGMA lock_status } {main unlocked temp closed}


# EVIDENCE-OF: R-34027-00617 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 blob handles or active write
# statements, the current transaction is committed.
#
#   2.1.*: Transaction is not committed if there are other open 
#          read-write blob handles.
#
#   2.2.*: Transaction is not committed if not in auto-commit mode.
#
#   2.3.*: Active write statements.
#
do_test 2.1.1 {
  sqlite3_blob_open db main x1 b -100 1 B1
  sqlite3_blob_open db main x1 b -1000 1 B2
  sqlite3_blob_open db main x1 b -10000 1 B3
  sqlite3_blob_open db main x1 b -10000 0 B4      ;# B4 is read-only!
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.1.2 {
  sqlite3_blob_close $B1 
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.1.3 {
  sqlite3_blob_close $B2 
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.1.4 {
  sqlite3_blob_close $B3 
  execsql { PRAGMA lock_status }
} {main shared temp closed}
do_test 2.1.5 {
  sqlite3_blob_close $B4 
  execsql { PRAGMA lock_status }
} {main unlocked temp closed}

do_test 2.2.1 {
  sqlite3_blob_open db main x1 b -100 1 B1
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.2.2 {
  execsql { BEGIN }
  sqlite3_blob_close $B1 
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.2.3 {
  execsql { COMMIT }
  execsql { PRAGMA lock_status }
} {main unlocked temp closed}

proc val {} { 
  sqlite3_blob_close $::B 
  db eval { PRAGMA lock_status }
}
db func val val
do_test 2.3.1 {
  sqlite3_blob_open db main x1 b -100 1 B
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.3.2 {
  execsql { INSERT INTO x1 VALUES(15, val()) }
  execsql { PRAGMA lock_status }
} {main unlocked temp closed}
do_test 2.3.3 {
  execsql { SELECT * FROM x1 WHERE a = 15 }
} {15 {main reserved temp closed}}

# A reader does not inhibit commit.
do_test 2.3.4 {
  sqlite3_blob_open db main x1 b -100 1 B
  execsql { PRAGMA lock_status }
} {main reserved temp closed}
do_test 2.3.5 {
  execsql { SELECT a, val() FROM x1 LIMIT 1 }
} {-10000 {main shared temp closed}}


do_test 3.1 {
  sqlite3_blob_open db main x1 b -10 1 B
  execsql {
    INSERT INTO x1 VALUES(1, 'abc');
    SELECT * FROM x1 WHERE a=1;
  }
} {1 abc}
do_test 3.2 {
  sqlite3_blob_write $B 0 "abcdefghij" 10
  execsql { SELECT * FROM x1 WHERE a=-10 }
} {-10 abcdefghij..............................}

do_test 3.3 {
  sqlite3 db2 test.db
  execsql { BEGIN ; SELECT * FROM x1 } db2
  sqlite3_blob_close $B 
} {SQLITE_BUSY}

# EVIDENCE-OF: R-41959-38737 Otherwise, if this function is passed a
# valid open blob handle, the values returned by the sqlite3_errcode()
# and sqlite3_errmsg() functions are set before returning.
#
do_test 3.4 {
  list [sqlite3_errcode db] [sqlite3_errmsg db]
} {SQLITE_BUSY {database is locked}}

# EVIDENCE-OF: R-37801-37633 The BLOB handle is closed unconditionally.
# Even if this routine returns an error code, the handle is still
# closed.
#
#   Test that the lock has been released. Assume this means the handle
#   is closed, even though blob_close() returned SQLITE_BUSY.
#
do_execsql_test 3.4 { PRAGMA lock_status } {main unlocked temp closed}

# EVIDENCE-OF: R-35111-05628 If an error occurs while committing the
# transaction, an error code is returned and the transaction rolled
# back.
#
#   Row 1 is removed (it was inserted this transaction) and row -10
#   is restored to its original state. Transaction has been rolled back.
#
do_execsql_test 3.5 {
  SELECT * FROM x1 WHERE a IN (1, -10);
} {-10 ........................................}

# EVIDENCE-OF: R-25894-51060 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.
#
do_test 4.0 { sqlite3_blob_close 0 } {}

finish_test