/[eiffelstudio]/trunk/Src/framework/sqlite3/sqlite_statement_iteration_cursor.e
ViewVC logotype

Annotation of /trunk/Src/framework/sqlite3/sqlite_statement_iteration_cursor.e

Parent Directory Parent Directory | Revision Log Revision Log


Revision 85923 - (hide annotations)
Fri Mar 18 15:53:01 2011 UTC (8 years, 10 months ago) by jfiat
File size: 8277 byte(s)
Fixed void-safety issue with sqlite3 library
1 paulb 82641 note
2     description: "[
3 jfiat 85923 Cursor to iterate over SQLITE_STATEMENT execution result
4 paulb 82641 ]"
5     legal: "See notice at end of class."
6     status: "See notice at end of class."
7     date: "$Date$"
8     revision: "$Revision$"
9    
10     class
11     SQLITE_STATEMENT_ITERATION_CURSOR
12    
13     inherit
14     ITERATION_CURSOR [SQLITE_RESULT_ROW]
15     rename
16 jfiat 83322 make as iteration_make,
17     cursor_index as index
18 paulb 82641 redefine
19 manus 83307 start, forth, after
20 paulb 82641 end
21    
22     SQLITE_SHARED_API
23     export
24     {NONE} all
25     end
26    
27     SQLITE_INTERNALS
28     export
29     {NONE} all
30     end
31    
32     SQLITE_DATABASE_EXTERNALS
33     export
34     {NONE} all
35     end
36    
37     SQLITE_STATEMENT_EXTERNALS
38     export
39     {NONE} all
40     end
41    
42     SQLITE_BIND_ARG_MARSHALLER
43     export
44     {NONE} all
45     end
46    
47     create
48     make,
49     make_with_bindings
50    
51 jfiat 85923 feature {NONE} -- Initalization
52 paulb 82641
53     make (a_statement: SQLITE_STATEMENT)
54 jfiat 85923 -- Initialize the cursor for `a_statement'.
55 paulb 82641 require
56     a_statement_attached: attached a_statement
57     a_statement_is_accessible: a_statement.is_accessible
58     a_statement_is_connected: a_statement.is_connected
59     do
60     statement := a_statement
61 jfiat 85923 --| Create a dummy attached `target' to satisfy void-safety
62     --| This dummy value will be overwritten by `iteration_make'
63     target := dummy_target
64 paulb 82641 iteration_make (Current)
65     last_result := {SQLITE_RESULT_CODE}.ok
66     ensure
67     statement_statement: statement = a_statement
68     last_result_is_ok: last_result = {SQLITE_RESULT_CODE}.ok
69     end
70    
71     make_with_bindings (a_statement: SQLITE_STATEMENT; a_bindings: ARRAY [SQLITE_BIND_ARG [ANY]])
72 jfiat 85923 -- Initialize the cursor for `a_statement' using `a_binding'.
73 paulb 82641 require
74     a_statement_attached: attached a_statement
75     a_statement_is_accessible: a_statement.is_accessible
76     a_statement_is_connected: a_statement.is_connected
77     a_bindings_attached: attached a_bindings
78     not_a_bindings_is_empty: not a_bindings.is_empty
79     do
80     make (a_statement)
81     bindings := a_bindings
82     ensure
83     statement_statement: statement = a_statement
84     bindings_set: bindings = a_bindings
85     last_result_is_ok: last_result = {SQLITE_RESULT_CODE}.ok
86     end
87    
88     feature -- Access
89    
90     statement: SQLITE_STATEMENT
91     -- SQLite statement being iterated over.
92    
93     bindings: detachable ARRAY [SQLITE_BIND_ARG [ANY]]
94     -- Binding arguments to execute the statement with.
95    
96     item: SQLITE_RESULT_ROW
97     -- <Precursor>
98     local
99     l_result: like internal_item
100     do
101     l_result := internal_item
102     check l_result_attached: attached l_result end
103     Result := l_result
104     end
105    
106     feature {NONE} -- Access
107    
108     last_result: INTEGER
109     -- Last result code set by `start'/`forth'.
110    
111     feature -- Status report
112    
113 manus 83307 after: BOOLEAN
114 paulb 82641 -- <Precursor>
115     do
116     Result := not sqlite_success (last_result) or else last_result = {SQLITE_RESULT_CODE}.done
117     --has_started and then not attached internal_item
118     end
119    
120     feature {NONE} -- Status report
121    
122     has_started: BOOLEAN
123     -- Indicates if the cursor has been started yet.
124    
125     feature -- Cursor movement
126    
127     start
128     -- <Precursor>
129     local
130     l_api: like sqlite_api
131     l_stmt: POINTER
132     l_result: INTEGER
133     i_upper, i: INTEGER
134     l_arg_variable: IMMUTABLE_STRING_8
135     l_arg_id: C_STRING
136     l_arg_index: INTEGER
137     do
138 jfiat 83322 Precursor
139 paulb 82641 -- Reset the iternal item
140     internal_item := Void
141    
142     l_api := sqlite_api
143     l_stmt := statement.internal_stmt
144    
145     -- Reset statement, for reuse.
146     l_result := sqlite3_reset (l_api, l_stmt)
147     check success: sqlite_success (l_result) end
148    
149     -- Perform bindings
150     if attached bindings as l_bindings then
151     -- `sqlite3_reset' does not reset the bindings! We have to do it as a second stage.
152     -- In a future release, when we might allow bindings to be set arbitrarily we might
153     -- not want to reset them. There is a performance gain for clients, because there is
154     -- not object marshalling required for arguments that do not change. Currently we have
155     -- to pass all arguments again when executing, and they are rebound (involving copy
156     -- operations etc.)
157     l_result := sqlite3_clear_bindings (l_api, l_stmt)
158     check success: sqlite_success (l_result) end
159    
160     from
161     i := l_bindings.lower
162     i_upper := l_bindings.upper
163     until
164     i > i_upper
165     loop
166     if attached l_bindings[i] as l_arg then
167     l_arg_variable := l_arg.variable
168     create l_arg_id.make (l_arg_variable)
169     l_arg_index := sqlite3_bind_parameter_index (l_api, l_stmt, l_arg_id.item)
170     if l_arg_index = 0 and then l_arg_variable[1] = '?' then
171     l_arg_variable := l_arg_variable.substring (2, l_arg_variable.count)
172     if l_arg_variable.is_integer_32 then
173     l_arg_index := l_arg_variable.to_integer_32
174     else
175     -- Contracts in SQLITE_BIND_ARG should make this impossible.
176     check should_never_happen: False end
177     end
178     end
179    
180     if l_arg_index > 0 then
181     l_arg.bind_to_statement (statement, l_arg_index)
182     else
183     -- Silently ignore unknown variables.
184     end
185     end
186     i := i + 1
187     end
188     end
189    
190     last_result := l_result
191    
192     -- Reset index, because `forth' will increase it.
193     index := 0
194    
195     -- Raise an exception, if there was an exception case.
196     sqlite_raise_on_failure (l_result)
197    
198     if not after then
199     -- Notify the statement that execution has begun.
200     statement.on_before_execute
201    
202     -- Go to first element.
203     forth
204     else
205     index := 1
206     end
207     end
208    
209     forth
210     -- <Precursor>
211     local
212     l_api: like sqlite_api
213     l_stmt: POINTER
214     l_db: detachable SQLITE_DATABASE
215     l_exception: detachable SQLITE_EXCEPTION
216     l_result: INTEGER
217     l_done: BOOLEAN
218     l_locked: BOOLEAN
219     do
220 jfiat 83322 Precursor
221 paulb 82641
222     l_api := sqlite_api
223     l_stmt := statement.internal_stmt
224     l_db := statement.database
225    
226     -- Note the locking sequencing, to ensure access to the error messages
227     -- are not affected by other threads.
228     l_db.lock -- (+1) 1
229     l_locked := True
230    
231     l_result := sqlite3_step (l_api, l_stmt)
232     l_done := l_result = {SQLITE_RESULT_CODE}.done
233     if sqlite_success (l_result) then
234     create internal_item.make (statement)
235     else
236     internal_item := Void
237     l_exception := l_db.last_exception
238     end
239    
240     -- Unlock before any callback because it may need access to the DB using another thread.
241     l_locked := False
242     l_db.unlock -- (-1) 0
243    
244     -- Set last result
245     last_result := l_result
246    
247     if after then
248     -- Notify the statement that execution has completed.
249     statement.on_after_executed
250     end
251    
252     -- Raise an exception, if there was an exception case.
253     if attached l_exception then
254     l_exception.raise
255     else
256     sqlite_raise_on_failure (l_result)
257     end
258     rescue
259     if l_locked and attached l_db then
260     l_locked := False
261     l_db.unlock
262     end
263     end
264    
265     feature {NONE} -- Implementation: Internal cache
266    
267     internal_item: detachable like item
268     -- Cached version of `item'.
269     -- Note: Do not use directly!
270    
271 jfiat 85923 feature {NONE} -- Implementation: void-safety helper
272    
273     dummy_target: ITERABLE [SQLITE_RESULT_ROW]
274     -- Dummy object used to initialize `target' with attached value
275     once
276     create {SPECIAL [SQLITE_RESULT_ROW]} Result .make_empty (0)
277     end
278    
279 paulb 82641 ;note
280 jfiat 85923 copyright: "Copyright (c) 1984-2011, Eiffel Software"
281 paulb 82641 license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)"
282     licensing_options: "http://www.eiffel.com/licensing"
283     copying: "[
284     This file is part of Eiffel Software's Eiffel Development Environment.
285    
286     Eiffel Software's Eiffel Development Environment is free
287     software; you can redistribute it and/or modify it under
288     the terms of the GNU General Public License as published
289     by the Free Software Foundation, version 2 of the License
290     (available at the URL listed under "license" above).
291    
292     Eiffel Software's Eiffel Development Environment is
293     distributed in the hope that it will be useful, but
294     WITHOUT ANY WARRANTY; without even the implied warranty
295     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
296     See the GNU General Public License for more details.
297    
298     You should have received a copy of the GNU General Public
299     License along with Eiffel Software's Eiffel Development
300     Environment; if not, write to the Free Software Foundation,
301     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
302     ]"
303     source: "[
304     Eiffel Software
305     5949 Hollister Ave., Goleta, CA 93117 USA
306     Telephone 805-685-1006, Fax 805-685-6869
307     Website http://www.eiffel.com
308     Customer support http://support.eiffel.com
309     ]"
310    
311     end

Properties

Name Value
svn:eol-style native
svn:keywords Author Date ID Revision

  ViewVC Help
Powered by ViewVC 1.1.23