Merge lp:~gerdusvanzyl/storm/firebird into lp:storm
- firebird
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~gerdusvanzyl/storm/firebird |
Merge into: | lp:storm |
Diff against target: |
587 lines (+427/-27) 4 files modified
storm/databases/firebird.py (+229/-0) tests/databases/base.py (+25/-25) tests/databases/firebird.py (+171/-0) tests/databases/proxy.py (+2/-2) |
To merge this branch: | bzr merge lp:~gerdusvanzyl/storm/firebird |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Storm Developers | Pending | ||
Storm Developers | Pending | ||
Review via email: mp+28559@code.launchpad.net |
Commit message
Description of the change
Basic Firebird database support.
Passes all tests except "Connection.
example connection string env variable for tests: STORM_FIREBIRD_
Gerdus van Zyl (gerdusvanzyl) wrote : | # |
No problem, I have just sent the email as per the instructions.
On Tue, Aug 10, 2010 at 7:23 PM, Gustavo Niemeyer <email address hidden> wrote:
> Hi Gerdus,
>
> Thanks for pushing this forward into a request!
>
> Sorry if this has been asked already, but if not, can you please sign the contributor agreement at:
>
> http://
> --
> https:/
> You are the owner of lp:~gerdusvanzyl/storm/firebird.
>
--
Gerdus van Zyl
Unmerged revisions
- 368. By Gerdus van Zyl
-
merge from trunk
- 367. By Gerdus van Zyl
-
cleanup unused comments
- 366. By Gerdus van Zyl
-
fixed proxy to work on windows
replaced os.read(self.request. fileno( ) .. with self.request.recv - 365. By Gerdus van Zyl
-
-
- 364. By Gerdus van Zyl
-
disconnect cleanup, push to vpc
- 363. By Gerdus van Zyl
-
is_disconnectio
n_error - 362. By Gerdus van Zyl
-
test cases for returning and select limit
- 361. By Gerdus van Zyl
-
start of disconnect test, fix base database test to not use "select 1"
- 360. By Gerdus van Zyl
-
cleanup and override non implementable tests
- 359. By Gerdus van Zyl
-
code to pass test test_execute_
expression and test_execute_ expression_ empty_params
Preview Diff
1 | === added file 'storm/databases/firebird.py' |
2 | --- storm/databases/firebird.py 1970-01-01 00:00:00 +0000 |
3 | +++ storm/databases/firebird.py 2010-06-26 13:26:23 +0000 |
4 | @@ -0,0 +1,229 @@ |
5 | +# |
6 | +# Copyright (c) 2010 Canonical |
7 | +# |
8 | +# Initial Code by Gerdus van Zyl |
9 | +# |
10 | +# This file is part of Storm Object Relational Mapper. |
11 | +# |
12 | +# |
13 | +# Storm is free software; you can redistribute it and/or modify |
14 | +# it under the terms of the GNU Lesser General Public License as |
15 | +# published by the Free Software Foundation; either version 2.1 of |
16 | +# the License, or (at your option) any later version. |
17 | +# |
18 | +# Storm is distributed in the hope that it will be useful, |
19 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | +# GNU Lesser General Public License for more details. |
22 | +# |
23 | +# You should have received a copy of the GNU Lesser General Public License |
24 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | +# |
26 | +# |
27 | +""" |
28 | +Tested only with: Kinterbase 3.3 and Firebird 2.1 |
29 | +""" |
30 | + |
31 | +import os.path |
32 | +from datetime import timedelta |
33 | +from storm.databases import dummy |
34 | + |
35 | +from storm.expr import (compile, Select, compile_select, Undef, |
36 | + Expr, Insert,COLUMN,Sequence) |
37 | +from storm.variables import (Variable,IntVariable) |
38 | +from storm.database import Database, Connection, Result |
39 | + |
40 | +from storm.exceptions import ( |
41 | + install_exceptions, DatabaseError, DatabaseModuleError, InterfaceError, |
42 | + OperationalError, ProgrammingError, TimeoutError) |
43 | + |
44 | +try: |
45 | + import kinterbasdb |
46 | + install_exceptions(kinterbasdb) |
47 | +except ImportError: |
48 | + kinterbasdb = dummy |
49 | + |
50 | +try: |
51 | + kinterbasdb.init(type_conv=200) |
52 | +except kinterbasdb.ProgrammingError: |
53 | + pass #Cannot initialize module more than once. |
54 | + |
55 | +compile = compile.create_child() |
56 | + |
57 | +@compile.when(int, long) |
58 | +def compile_int(compile, expr, state): |
59 | + state.parameters.append(IntVariable(expr)) |
60 | + return "cast(? as integer)" |
61 | + |
62 | +@compile.when(Select) |
63 | +def compile_select_firebird(compile, select, state): |
64 | + limit = select.limit |
65 | + offset = select.offset |
66 | + # Make sure limit is Undef'ed. |
67 | + select.offset = select.limit = Undef |
68 | + |
69 | + if select.default_tables is Undef: |
70 | + select.default_tables = ["RDB$DATABASE"] |
71 | + |
72 | + sql = compile_select(compile, select, state) |
73 | + |
74 | + if limit is not Undef or offset is not Undef: |
75 | + rowstart = 1 |
76 | + rowstop = None |
77 | + if offset is not Undef: |
78 | + rowstart = offset + 1 |
79 | + if limit is not Undef: |
80 | + rowstop = rowstart + limit - 1 |
81 | + if rowstop < rowstart: |
82 | + rowstop = rowstart |
83 | + |
84 | + sql += " ROWS %i" % rowstart |
85 | + if rowstop: |
86 | + sql += " TO %i " % rowstop |
87 | + #print sql |
88 | + |
89 | + return sql |
90 | + |
91 | +@compile.when(Sequence) |
92 | +def compile_sequence_firebird(compile, sequence, state): |
93 | + return "gen_id(%s, 1)" % sequence.name |
94 | + |
95 | +class Returning(Expr): |
96 | + """Appends the "RETURNING <primary_columns>" suffix to an INSERT. |
97 | + |
98 | + This is only supported in Firebird 2.0 |
99 | + """ |
100 | + def __init__(self, insert): |
101 | + self.insert = insert |
102 | + |
103 | +@compile.when(Returning) |
104 | +def compile_returning(compile, expr, state): |
105 | + state.push("context", COLUMN) |
106 | + columns = compile(expr.insert.primary_columns, state) |
107 | + state.pop() |
108 | + state.push("precedence", 0) |
109 | + insert = compile(expr.insert, state) |
110 | + state.pop() |
111 | + return "%s RETURNING %s" % (insert, columns) |
112 | + |
113 | +class FirebirdResult(Result): |
114 | + @staticmethod |
115 | + def from_database(row): |
116 | + """Convert Firebird-specific datatypes to "normal" Python types. |
117 | + |
118 | + If there are any C{array} instances in the row, convert them |
119 | + to strings. |
120 | + """ |
121 | + for value in row: |
122 | + yield value |
123 | + |
124 | + def get_insert_identity(self, primary_key, primary_variables): |
125 | + """ |
126 | + Firebird does not support insert identity |
127 | + - autoinc is implemented using custom triggers |
128 | + so no clear way to support it in a generic way |
129 | + """ |
130 | + raise NotImplementedError |
131 | + |
132 | +class FirebirdConnection(Connection): |
133 | + |
134 | + result_factory = FirebirdResult |
135 | + param_mark = "?" |
136 | + compile = compile |
137 | + server_version = None |
138 | + |
139 | + def execute(self, statement, params=None, noresult=False): |
140 | + """Execute a statement with the given parameters. |
141 | + |
142 | + This extends the L{Connection.execute} method to add support |
143 | + for automatic retrieval of inserted primary keys to link |
144 | + in-memory objects with their specific rows. |
145 | + """ |
146 | + if not self.server_version: |
147 | + version = 0 |
148 | + version = self._raw_connection.db_info(kinterbasdb.isc_info_version) |
149 | + version = str(version).split("Firebird")[1].strip() |
150 | + version = float(version) |
151 | + self.server_version = version |
152 | + |
153 | + if (isinstance(statement, Insert) and |
154 | + self.server_version >= 2 and |
155 | + statement.primary_variables is not Undef and |
156 | + statement.primary_columns is not Undef): |
157 | + |
158 | + # Here we decorate the Insert statement with a Returning |
159 | + # expression, so that we get back in the result the values |
160 | + # for the primary key just inserted. This prevents a round |
161 | + # trip to the database for obtaining these values. |
162 | + result = Connection.execute(self, Returning(statement), params) |
163 | + for variable, value in zip(statement.primary_variables, |
164 | + result.get_one()): |
165 | + result.set_variable(variable, value) |
166 | + return result |
167 | + |
168 | + return Connection.execute(self, statement, params, noresult) |
169 | + |
170 | + def is_disconnection_error(self, exc): |
171 | + """Check whether an exception represents a database disconnection. |
172 | + |
173 | + """ |
174 | + if isinstance(exc, ProgrammingError) or isinstance(exc,OperationalError): |
175 | + code,description = exc.args |
176 | + if code == -902: |
177 | + return True |
178 | + |
179 | + |
180 | + return False |
181 | + |
182 | + def to_database(self, params): |
183 | + for param in params: |
184 | + if isinstance(param, Variable): |
185 | + param = param.get(to_db=True) |
186 | + if isinstance(param, timedelta): |
187 | + yield str(param) |
188 | + else: |
189 | + yield param |
190 | + |
191 | +class Firebird(Database): |
192 | + |
193 | + connection_factory = FirebirdConnection |
194 | + _converters = None |
195 | + |
196 | + def __init__(self, uri): |
197 | + if kinterbasdb is dummy: |
198 | + raise DatabaseModuleError("'kinterbasdb' module not found") |
199 | + self._connect_kwargs = {} |
200 | + if uri.database is not None: |
201 | + if os.path.isfile(uri.database): |
202 | + uri.database = os.path.abspath(uri.database) |
203 | + self._connect_kwargs["database"] = uri.database |
204 | + if uri.host is not None: |
205 | + self._connect_kwargs["host"] = uri.host |
206 | + if uri.port is not None: |
207 | + #firebird expects nonstandard port spec: http://www.firebirdfaq.org/faq259/ |
208 | + self._connect_kwargs["host"] = "%s/%s" % (uri.host,uri.port) |
209 | + if uri.port is not None: |
210 | + self._connect_kwargs["port"] = uri.port |
211 | + if uri.username is not None: |
212 | + self._connect_kwargs["user"] = uri.username |
213 | + if uri.password is not None: |
214 | + self._connect_kwargs["password"] = uri.password |
215 | + for option in ["unix_socket"]: |
216 | + if option in uri.options: |
217 | + self._connect_kwargs[option] = uri.options.get(option) |
218 | + |
219 | + |
220 | + |
221 | + def raw_connect(self): |
222 | + customTPB = ( |
223 | + kinterbasdb.isc_tpb_write |
224 | + + kinterbasdb.isc_tpb_concurrency |
225 | + ) |
226 | + |
227 | + raw_connection = kinterbasdb.connect(**self._connect_kwargs) |
228 | + raw_connection.default_tpb = customTPB |
229 | + |
230 | + return raw_connection |
231 | + |
232 | + |
233 | +create_from_uri = Firebird |
234 | |
235 | === modified file 'tests/databases/base.py' |
236 | --- tests/databases/base.py 2010-04-16 07:12:13 +0000 |
237 | +++ tests/databases/base.py 2010-06-26 13:26:23 +0000 |
238 | @@ -132,7 +132,7 @@ |
239 | self.assertTrue(result.get_one()) |
240 | |
241 | def test_execute_result(self): |
242 | - result = self.connection.execute("SELECT 1") |
243 | + result = self.connection.execute("SELECT 1 FROM TEST") |
244 | self.assertTrue(isinstance(result, Result)) |
245 | self.assertTrue(result.get_one()) |
246 | |
247 | @@ -357,7 +357,7 @@ |
248 | event.hook("register-transaction", register_transaction) |
249 | |
250 | connection = self.database.connect(event) |
251 | - connection.execute("SELECT 1") |
252 | + connection.execute("SELECT 1 FROM TEST") |
253 | self.assertEqual(len(calls), 1) |
254 | self.assertEqual(calls[0], marker) |
255 | |
256 | @@ -425,16 +425,16 @@ |
257 | |
258 | def test_block_access(self): |
259 | """Access to the connection is blocked by block_access().""" |
260 | - self.connection.execute("SELECT 1") |
261 | + self.connection.execute("SELECT 1 FROM TEST") |
262 | self.connection.block_access() |
263 | self.assertRaises(ConnectionBlockedError, |
264 | - self.connection.execute, "SELECT 1") |
265 | + self.connection.execute, "SELECT 1 FROM TEST") |
266 | self.assertRaises(ConnectionBlockedError, self.connection.commit) |
267 | # Allow rolling back a blocked connection. |
268 | self.connection.rollback() |
269 | # Unblock the connection, allowing access again. |
270 | self.connection.unblock_access() |
271 | - self.connection.execute("SELECT 1") |
272 | + self.connection.execute("SELECT 1 FROM TEST") |
273 | |
274 | |
275 | class UnsupportedDatabaseTest(object): |
276 | @@ -556,20 +556,20 @@ |
277 | |
278 | def test_proxy_works(self): |
279 | """Ensure that we can talk to the database through the proxy.""" |
280 | - result = self.connection.execute("SELECT 1") |
281 | + result = self.connection.execute(Select(1)) |
282 | self.assertEqual(result.get_one(), (1,)) |
283 | |
284 | def test_catch_disconnect_on_execute(self): |
285 | """Test that database disconnections get caught on execute().""" |
286 | - result = self.connection.execute("SELECT 1") |
287 | + result = self.connection.execute(Select(1)) |
288 | self.assertTrue(result.get_one()) |
289 | self.proxy.restart() |
290 | self.assertRaises(DisconnectionError, |
291 | - self.connection.execute, "SELECT 1") |
292 | + self.connection.execute, Select(1)) |
293 | |
294 | def test_catch_disconnect_on_commit(self): |
295 | """Test that database disconnections get caught on commit().""" |
296 | - result = self.connection.execute("SELECT 1") |
297 | + result = self.connection.execute(Select(1)) |
298 | self.assertTrue(result.get_one()) |
299 | self.proxy.restart() |
300 | self.assertRaises(DisconnectionError, self.connection.commit) |
301 | @@ -581,13 +581,13 @@ |
302 | then it is possible that Storm won't see the disconnection. |
303 | It should be able to recover from this situation though. |
304 | """ |
305 | - result = self.connection.execute("SELECT 1") |
306 | + result = self.connection.execute(Select(1)) |
307 | self.assertTrue(result.get_one()) |
308 | self.proxy.restart() |
309 | # Perform an action that should result in a disconnection. |
310 | try: |
311 | cursor = self.connection._raw_connection.cursor() |
312 | - cursor.execute("SELECT 1") |
313 | + cursor.execute("select 1 from test") |
314 | cursor.fetchone() |
315 | except Error, exc: |
316 | self.assertTrue(self.connection.is_disconnection_error(exc)) |
317 | @@ -614,59 +614,59 @@ |
318 | then it is possible that Storm won't see the disconnection. |
319 | It should be able to recover from this situation though. |
320 | """ |
321 | - result = self.connection.execute("SELECT 1") |
322 | + result = self.connection.execute(Select(1)) |
323 | self.assertTrue(result.get_one()) |
324 | self.proxy.restart() |
325 | # Perform an action that should result in a disconnection. |
326 | try: |
327 | cursor = self.connection._raw_connection.cursor() |
328 | - cursor.execute("SELECT 1") |
329 | + cursor.execute("SELECT 1 FROM TEST") |
330 | cursor.fetchone() |
331 | except DatabaseError, exc: |
332 | self.assertTrue(self.connection.is_disconnection_error(exc)) |
333 | else: |
334 | self.fail("Disconnection was not caught.") |
335 | self.assertRaises(DisconnectionError, |
336 | - self.connection.execute, "SELECT 1") |
337 | + self.connection.execute, Select(1)) |
338 | |
339 | def test_connection_stays_disconnected_in_transaction(self): |
340 | """Test that connection does not immediately reconnect.""" |
341 | - result = self.connection.execute("SELECT 1") |
342 | + result = self.connection.execute(Select(1)) |
343 | self.assertTrue(result.get_one()) |
344 | self.proxy.restart() |
345 | self.assertRaises(DisconnectionError, |
346 | - self.connection.execute, "SELECT 1") |
347 | + self.connection.execute, Select(1)) |
348 | self.assertRaises(DisconnectionError, |
349 | - self.connection.execute, "SELECT 1") |
350 | + self.connection.execute, Select(1)) |
351 | |
352 | def test_reconnect_after_rollback(self): |
353 | """Test that we reconnect after rolling back the connection.""" |
354 | - result = self.connection.execute("SELECT 1") |
355 | + result = self.connection.execute(Select(1)) |
356 | self.assertTrue(result.get_one()) |
357 | self.proxy.restart() |
358 | self.assertRaises(DisconnectionError, |
359 | - self.connection.execute, "SELECT 1") |
360 | + self.connection.execute, Select(1)) |
361 | self.connection.rollback() |
362 | - result = self.connection.execute("SELECT 1") |
363 | + result = self.connection.execute(Select(1)) |
364 | self.assertTrue(result.get_one()) |
365 | |
366 | def test_catch_disconnect_on_reconnect(self): |
367 | """Test that reconnection failures result in DisconnectionError.""" |
368 | - result = self.connection.execute("SELECT 1") |
369 | + result = self.connection.execute(Select(1)) |
370 | self.assertTrue(result.get_one()) |
371 | self.proxy.stop() |
372 | self.assertRaises(DisconnectionError, |
373 | - self.connection.execute, "SELECT 1") |
374 | + self.connection.execute, Select(1)) |
375 | # Rollback the connection, but because the proxy is still |
376 | # down, we get a DisconnectionError again. |
377 | self.connection.rollback() |
378 | self.assertRaises(DisconnectionError, |
379 | - self.connection.execute, "SELECT 1") |
380 | + self.connection.execute, Select(1)) |
381 | |
382 | def test_close_connection_after_disconnect(self): |
383 | - result = self.connection.execute("SELECT 1") |
384 | + result = self.connection.execute(Select(1)) |
385 | self.assertTrue(result.get_one()) |
386 | self.proxy.stop() |
387 | self.assertRaises(DisconnectionError, |
388 | - self.connection.execute, "SELECT 1") |
389 | + self.connection.execute, Select(1)) |
390 | self.connection.close() |
391 | |
392 | === added file 'tests/databases/firebird.py' |
393 | --- tests/databases/firebird.py 1970-01-01 00:00:00 +0000 |
394 | +++ tests/databases/firebird.py 2010-06-26 13:26:23 +0000 |
395 | @@ -0,0 +1,171 @@ |
396 | +# |
397 | +# Copyright (c) 2010 Canonical |
398 | +# |
399 | +# Initial Code by Gerdus van Zyl |
400 | +# |
401 | +# This file is part of Storm Object Relational Mapper. |
402 | +# |
403 | +# Storm is free software; you can redistribute it and/or modify |
404 | +# it under the terms of the GNU Lesser General Public License as |
405 | +# published by the Free Software Foundation; either version 2.1 of |
406 | +# the License, or (at your option) any later version. |
407 | +# |
408 | +# Storm is distributed in the hope that it will be useful, |
409 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
410 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
411 | +# GNU Lesser General Public License for more details. |
412 | +# |
413 | +# You should have received a copy of the GNU Lesser General Public License |
414 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
415 | +# |
416 | +import os |
417 | + |
418 | +from storm.database import create_database |
419 | +from storm.database import * |
420 | + |
421 | +from tests.helper import TestHelper |
422 | + |
423 | +from tests.databases.base import ( |
424 | + DatabaseTest, UnsupportedDatabaseTest, DatabaseDisconnectionTest) |
425 | + |
426 | +from storm.variables import ( |
427 | + IntVariable, Variable ) |
428 | + |
429 | +from storm.exceptions import ( |
430 | + DatabaseError, DatabaseModuleError, |
431 | + DisconnectionError, Error, OperationalError, ConnectionBlockedError) |
432 | + |
433 | +from tests.expr import ( |
434 | + Select,Column,Insert, column1, column2, column3, elem1, |
435 | + table1, TrackContext,Sequence) |
436 | + |
437 | +#import storm.tracer |
438 | +#import sys |
439 | +#storm.tracer.debug(True, stream=sys.stdout) |
440 | + |
441 | +class FirebirdTest(DatabaseTest, TestHelper): |
442 | + supports_microseconds = False |
443 | + |
444 | + def is_supported(self): |
445 | + return bool(os.environ.get("STORM_FIREBIRD_URI")) |
446 | + |
447 | + def create_database(self): |
448 | + self.database = create_database(os.environ["STORM_FIREBIRD_URI"]) |
449 | + |
450 | + def create_tables(self): |
451 | + self.connection.execute('CREATE TABLE NUMBER (one INTEGER, two INTEGER, three INTEGER)') |
452 | + self.connection.execute('CREATE TABLE TEST (id INTEGER PRIMARY KEY, title VARCHAR(50) CHARACTER SET UTF8)') |
453 | + self.connection.execute('CREATE TABLE DATETIME_TEST (id INT UNIQUE,dt TIMESTAMP, d DATE, t TIME, td BLOB SUB_TYPE TEXT)') |
454 | + |
455 | + self.connection.execute('CREATE TABLE BIN_TEST (id INT UNIQUE,b BLOB)') |
456 | + |
457 | + self.connection.execute('CREATE GENERATOR GEN_TEST_AUTOID') |
458 | + self.connection.execute('SET GENERATOR GEN_TEST_AUTOID TO 0') |
459 | + |
460 | + self.connection.execute("""CREATE TRIGGER TEST_PK_AUTO FOR TEST ACTIVE BEFORE INSERT POSITION 0 AS |
461 | +begin |
462 | + if ( (new.ID is null) or (new.ID = 0) ) |
463 | + then new.ID = gen_id(GEN_TEST_AUTOID, 1); |
464 | +end""") |
465 | + |
466 | + self.connection.execute("""CREATE TABLE insert_returning_test |
467 | + (id0 INTEGER, |
468 | + id1 INTEGER DEFAULT 123, |
469 | + id2 INTEGER DEFAULT 456)""") |
470 | + |
471 | + self.connection.commit() |
472 | + |
473 | + def drop_tables(self): |
474 | + try: |
475 | + self.connection.execute("DROP TRIGGER TEST_PK_AUTO") |
476 | + self.connection.execute("DROP GENERATOR GEN_TEST_AUTOID") |
477 | + self.connection.commit() |
478 | + except: |
479 | + self.connection.rollback() |
480 | + |
481 | + for table in ["number", "test", "datetime_test", "bin_test", "insert_returning_test"]: |
482 | + try: |
483 | + self.connection.execute("DROP TABLE " + table) |
484 | + self.connection.commit() |
485 | + except: |
486 | + self.connection.rollback() |
487 | + |
488 | + def test_get_insert_identity(self): |
489 | + """test_get_insert_identity -Does not support insert identity""" |
490 | + #http://www.firebirdfaq.org/faq243/ |
491 | + pass |
492 | + |
493 | + def test_get_insert_identity_composed(self): |
494 | + """test_get_insert_identity_composed - Does not support insert identity""" |
495 | + #http://www.firebirdfaq.org/faq243/ |
496 | + pass |
497 | + |
498 | + def test_execute_insert_returning(self): |
499 | + if self.connection.server_version < 2: |
500 | + return # Can't run this test with old PostgreSQL versions. |
501 | + |
502 | + column0 = Column("id0", "insert_returning_test") |
503 | + column1 = Column("id1", "insert_returning_test") |
504 | + column2 = Column("id2", "insert_returning_test") |
505 | + variable1 = IntVariable() |
506 | + variable2 = IntVariable() |
507 | + insert = Insert({column0: 999}, primary_columns=(column1, column2), |
508 | + primary_variables=(variable1, variable2)) |
509 | + self.connection.execute(insert) |
510 | + |
511 | + self.assertTrue(variable1.is_defined()) |
512 | + self.assertTrue(variable2.is_defined()) |
513 | + |
514 | + self.assertEquals(variable1.get(), 123) |
515 | + self.assertEquals(variable2.get(), 456) |
516 | + |
517 | + result = self.connection.execute("SELECT * FROM insert_returning_test") |
518 | + self.assertEquals(result.get_one(), (999,123, 456)) |
519 | + |
520 | + def test_sequence(self): |
521 | + expr1 = Select(Sequence("GEN_TEST_AUTOID")) |
522 | + expr2 = "SELECT gen_id(GEN_TEST_AUTOID,0) FROM RDB$DATABASE" |
523 | + value1 = self.connection.execute(expr1).get_one()[0] |
524 | + value2 = self.connection.execute(expr2).get_one()[0] |
525 | + value3 = self.connection.execute(expr1).get_one()[0] |
526 | + self.assertEquals(value1, value2) |
527 | + self.assertEquals(value3-value1, 1) |
528 | + |
529 | + def test_limit_offset(self): |
530 | + self.connection.execute("delete from test") |
531 | + self.connection.commit() |
532 | + |
533 | + for z in range(100,200+1): |
534 | + sql = "INSERT INTO test (id,title) VALUES (%i,'%i')" % (z,z) |
535 | + self.connection.execute(sql) |
536 | + self.connection.commit() |
537 | + |
538 | + select = Select(Column("id", "test")) |
539 | + select.limit = 1 |
540 | + select.offset = 0 |
541 | + select.order_by = Column("id", "test") |
542 | + |
543 | + result = self.connection.execute(select) |
544 | + self.assertEquals(result.get_all(), [(100,),] ) |
545 | + |
546 | + |
547 | + select = Select(Column("id", "test")) |
548 | + select.limit = 2 |
549 | + select.offset = 50 |
550 | + select.order_by = Column("id", "test") |
551 | + |
552 | + result = self.connection.execute(select) |
553 | + self.assertEquals(result.get_all(), [(150,),(151,)] ) |
554 | + |
555 | + |
556 | +class FirebirdUnsupportedTest(UnsupportedDatabaseTest, TestHelper): |
557 | + |
558 | + dbapi_module_names = ["kinterbasdb"] |
559 | + db_module_name = "firebird" |
560 | + |
561 | + |
562 | +class FirebirdDisconnectionTest(DatabaseDisconnectionTest, TestHelper): |
563 | + |
564 | + environment_variable = "STORM_FIREBIRD_URI" |
565 | + host_environment_variable = "STORM_FIREBIRD_HOST_URI" |
566 | + default_port = 3050 |
567 | |
568 | === modified file 'tests/databases/proxy.py' |
569 | --- tests/databases/proxy.py 2007-10-24 06:27:06 +0000 |
570 | +++ tests/databases/proxy.py 2010-06-26 13:26:23 +0000 |
571 | @@ -52,14 +52,14 @@ |
572 | return |
573 | |
574 | if self.request in rlist: |
575 | - chunk = os.read(self.request.fileno(), 1024) |
576 | + chunk = self.request.recv(1024) |
577 | dst.send(chunk) |
578 | if chunk == "": |
579 | readers.remove(self.request) |
580 | dst.shutdown(socket.SHUT_WR) |
581 | |
582 | if dst in rlist: |
583 | - chunk = os.read(dst.fileno(), 1024) |
584 | + chunk = dst.recv(1024) |
585 | self.request.send(chunk) |
586 | if chunk == "": |
587 | readers.remove(dst) |
Hi Gerdus,
Thanks for pushing this forward into a request!
Sorry if this has been asked already, but if not, can you please sign the contributor agreement at:
http:// www.canonical. com/contributor s