Merge lp:~gerdusvanzyl/storm/firebird into lp:storm

Proposed by Gerdus van Zyl
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
Reviewer Review Type Date Requested Status
Storm Developers Pending
Storm Developers Pending
Review via email: mp+28559@code.launchpad.net

Description of the change

Basic Firebird database support.

Passes all tests except "Connection.rollback() swallows disconnect errors" which I have so far been unable to fix.

example connection string env variable for tests: STORM_FIREBIRD_URI=firebird://sysdba:masterke@localhost:3050/stormtest.fdb

To post a comment you must log in.
Revision history for this message
Gustavo Niemeyer (niemeyer) 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://www.canonical.com/contributors

Revision history for this message
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://www.canonical.com/contributors
> --
> https://code.launchpad.net/~gerdusvanzyl/storm/firebird/+merge/28559
> 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_disconnection_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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'storm/databases/firebird.py'
--- storm/databases/firebird.py 1970-01-01 00:00:00 +0000
+++ storm/databases/firebird.py 2010-06-26 13:26:23 +0000
@@ -0,0 +1,229 @@
1#
2# Copyright (c) 2010 Canonical
3#
4# Initial Code by Gerdus van Zyl
5#
6# This file is part of Storm Object Relational Mapper.
7#
8#
9# Storm is free software; you can redistribute it and/or modify
10# it under the terms of the GNU Lesser General Public License as
11# published by the Free Software Foundation; either version 2.1 of
12# the License, or (at your option) any later version.
13#
14# Storm is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU Lesser General Public License for more details.
18#
19# You should have received a copy of the GNU Lesser General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21#
22#
23"""
24Tested only with: Kinterbase 3.3 and Firebird 2.1
25"""
26
27import os.path
28from datetime import timedelta
29from storm.databases import dummy
30
31from storm.expr import (compile, Select, compile_select, Undef,
32 Expr, Insert,COLUMN,Sequence)
33from storm.variables import (Variable,IntVariable)
34from storm.database import Database, Connection, Result
35
36from storm.exceptions import (
37 install_exceptions, DatabaseError, DatabaseModuleError, InterfaceError,
38 OperationalError, ProgrammingError, TimeoutError)
39
40try:
41 import kinterbasdb
42 install_exceptions(kinterbasdb)
43except ImportError:
44 kinterbasdb = dummy
45
46try:
47 kinterbasdb.init(type_conv=200)
48except kinterbasdb.ProgrammingError:
49 pass #Cannot initialize module more than once.
50
51compile = compile.create_child()
52
53@compile.when(int, long)
54def compile_int(compile, expr, state):
55 state.parameters.append(IntVariable(expr))
56 return "cast(? as integer)"
57
58@compile.when(Select)
59def compile_select_firebird(compile, select, state):
60 limit = select.limit
61 offset = select.offset
62 # Make sure limit is Undef'ed.
63 select.offset = select.limit = Undef
64
65 if select.default_tables is Undef:
66 select.default_tables = ["RDB$DATABASE"]
67
68 sql = compile_select(compile, select, state)
69
70 if limit is not Undef or offset is not Undef:
71 rowstart = 1
72 rowstop = None
73 if offset is not Undef:
74 rowstart = offset + 1
75 if limit is not Undef:
76 rowstop = rowstart + limit - 1
77 if rowstop < rowstart:
78 rowstop = rowstart
79
80 sql += " ROWS %i" % rowstart
81 if rowstop:
82 sql += " TO %i " % rowstop
83 #print sql
84
85 return sql
86
87@compile.when(Sequence)
88def compile_sequence_firebird(compile, sequence, state):
89 return "gen_id(%s, 1)" % sequence.name
90
91class Returning(Expr):
92 """Appends the "RETURNING <primary_columns>" suffix to an INSERT.
93
94 This is only supported in Firebird 2.0
95 """
96 def __init__(self, insert):
97 self.insert = insert
98
99@compile.when(Returning)
100def compile_returning(compile, expr, state):
101 state.push("context", COLUMN)
102 columns = compile(expr.insert.primary_columns, state)
103 state.pop()
104 state.push("precedence", 0)
105 insert = compile(expr.insert, state)
106 state.pop()
107 return "%s RETURNING %s" % (insert, columns)
108
109class FirebirdResult(Result):
110 @staticmethod
111 def from_database(row):
112 """Convert Firebird-specific datatypes to "normal" Python types.
113
114 If there are any C{array} instances in the row, convert them
115 to strings.
116 """
117 for value in row:
118 yield value
119
120 def get_insert_identity(self, primary_key, primary_variables):
121 """
122 Firebird does not support insert identity
123 - autoinc is implemented using custom triggers
124 so no clear way to support it in a generic way
125 """
126 raise NotImplementedError
127
128class FirebirdConnection(Connection):
129
130 result_factory = FirebirdResult
131 param_mark = "?"
132 compile = compile
133 server_version = None
134
135 def execute(self, statement, params=None, noresult=False):
136 """Execute a statement with the given parameters.
137
138 This extends the L{Connection.execute} method to add support
139 for automatic retrieval of inserted primary keys to link
140 in-memory objects with their specific rows.
141 """
142 if not self.server_version:
143 version = 0
144 version = self._raw_connection.db_info(kinterbasdb.isc_info_version)
145 version = str(version).split("Firebird")[1].strip()
146 version = float(version)
147 self.server_version = version
148
149 if (isinstance(statement, Insert) and
150 self.server_version >= 2 and
151 statement.primary_variables is not Undef and
152 statement.primary_columns is not Undef):
153
154 # Here we decorate the Insert statement with a Returning
155 # expression, so that we get back in the result the values
156 # for the primary key just inserted. This prevents a round
157 # trip to the database for obtaining these values.
158 result = Connection.execute(self, Returning(statement), params)
159 for variable, value in zip(statement.primary_variables,
160 result.get_one()):
161 result.set_variable(variable, value)
162 return result
163
164 return Connection.execute(self, statement, params, noresult)
165
166 def is_disconnection_error(self, exc):
167 """Check whether an exception represents a database disconnection.
168
169 """
170 if isinstance(exc, ProgrammingError) or isinstance(exc,OperationalError):
171 code,description = exc.args
172 if code == -902:
173 return True
174
175
176 return False
177
178 def to_database(self, params):
179 for param in params:
180 if isinstance(param, Variable):
181 param = param.get(to_db=True)
182 if isinstance(param, timedelta):
183 yield str(param)
184 else:
185 yield param
186
187class Firebird(Database):
188
189 connection_factory = FirebirdConnection
190 _converters = None
191
192 def __init__(self, uri):
193 if kinterbasdb is dummy:
194 raise DatabaseModuleError("'kinterbasdb' module not found")
195 self._connect_kwargs = {}
196 if uri.database is not None:
197 if os.path.isfile(uri.database):
198 uri.database = os.path.abspath(uri.database)
199 self._connect_kwargs["database"] = uri.database
200 if uri.host is not None:
201 self._connect_kwargs["host"] = uri.host
202 if uri.port is not None:
203 #firebird expects nonstandard port spec: http://www.firebirdfaq.org/faq259/
204 self._connect_kwargs["host"] = "%s/%s" % (uri.host,uri.port)
205 if uri.port is not None:
206 self._connect_kwargs["port"] = uri.port
207 if uri.username is not None:
208 self._connect_kwargs["user"] = uri.username
209 if uri.password is not None:
210 self._connect_kwargs["password"] = uri.password
211 for option in ["unix_socket"]:
212 if option in uri.options:
213 self._connect_kwargs[option] = uri.options.get(option)
214
215
216
217 def raw_connect(self):
218 customTPB = (
219 kinterbasdb.isc_tpb_write
220 + kinterbasdb.isc_tpb_concurrency
221 )
222
223 raw_connection = kinterbasdb.connect(**self._connect_kwargs)
224 raw_connection.default_tpb = customTPB
225
226 return raw_connection
227
228
229create_from_uri = Firebird
0230
=== modified file 'tests/databases/base.py'
--- tests/databases/base.py 2010-04-16 07:12:13 +0000
+++ tests/databases/base.py 2010-06-26 13:26:23 +0000
@@ -132,7 +132,7 @@
132 self.assertTrue(result.get_one())132 self.assertTrue(result.get_one())
133133
134 def test_execute_result(self):134 def test_execute_result(self):
135 result = self.connection.execute("SELECT 1")135 result = self.connection.execute("SELECT 1 FROM TEST")
136 self.assertTrue(isinstance(result, Result))136 self.assertTrue(isinstance(result, Result))
137 self.assertTrue(result.get_one())137 self.assertTrue(result.get_one())
138138
@@ -357,7 +357,7 @@
357 event.hook("register-transaction", register_transaction)357 event.hook("register-transaction", register_transaction)
358358
359 connection = self.database.connect(event)359 connection = self.database.connect(event)
360 connection.execute("SELECT 1")360 connection.execute("SELECT 1 FROM TEST")
361 self.assertEqual(len(calls), 1)361 self.assertEqual(len(calls), 1)
362 self.assertEqual(calls[0], marker)362 self.assertEqual(calls[0], marker)
363363
@@ -425,16 +425,16 @@
425425
426 def test_block_access(self):426 def test_block_access(self):
427 """Access to the connection is blocked by block_access()."""427 """Access to the connection is blocked by block_access()."""
428 self.connection.execute("SELECT 1")428 self.connection.execute("SELECT 1 FROM TEST")
429 self.connection.block_access()429 self.connection.block_access()
430 self.assertRaises(ConnectionBlockedError,430 self.assertRaises(ConnectionBlockedError,
431 self.connection.execute, "SELECT 1")431 self.connection.execute, "SELECT 1 FROM TEST")
432 self.assertRaises(ConnectionBlockedError, self.connection.commit)432 self.assertRaises(ConnectionBlockedError, self.connection.commit)
433 # Allow rolling back a blocked connection.433 # Allow rolling back a blocked connection.
434 self.connection.rollback()434 self.connection.rollback()
435 # Unblock the connection, allowing access again.435 # Unblock the connection, allowing access again.
436 self.connection.unblock_access()436 self.connection.unblock_access()
437 self.connection.execute("SELECT 1")437 self.connection.execute("SELECT 1 FROM TEST")
438438
439439
440class UnsupportedDatabaseTest(object):440class UnsupportedDatabaseTest(object):
@@ -556,20 +556,20 @@
556556
557 def test_proxy_works(self):557 def test_proxy_works(self):
558 """Ensure that we can talk to the database through the proxy."""558 """Ensure that we can talk to the database through the proxy."""
559 result = self.connection.execute("SELECT 1")559 result = self.connection.execute(Select(1))
560 self.assertEqual(result.get_one(), (1,))560 self.assertEqual(result.get_one(), (1,))
561561
562 def test_catch_disconnect_on_execute(self):562 def test_catch_disconnect_on_execute(self):
563 """Test that database disconnections get caught on execute()."""563 """Test that database disconnections get caught on execute()."""
564 result = self.connection.execute("SELECT 1")564 result = self.connection.execute(Select(1))
565 self.assertTrue(result.get_one())565 self.assertTrue(result.get_one())
566 self.proxy.restart()566 self.proxy.restart()
567 self.assertRaises(DisconnectionError,567 self.assertRaises(DisconnectionError,
568 self.connection.execute, "SELECT 1")568 self.connection.execute, Select(1))
569569
570 def test_catch_disconnect_on_commit(self):570 def test_catch_disconnect_on_commit(self):
571 """Test that database disconnections get caught on commit()."""571 """Test that database disconnections get caught on commit()."""
572 result = self.connection.execute("SELECT 1")572 result = self.connection.execute(Select(1))
573 self.assertTrue(result.get_one())573 self.assertTrue(result.get_one())
574 self.proxy.restart()574 self.proxy.restart()
575 self.assertRaises(DisconnectionError, self.connection.commit)575 self.assertRaises(DisconnectionError, self.connection.commit)
@@ -581,13 +581,13 @@
581 then it is possible that Storm won't see the disconnection.581 then it is possible that Storm won't see the disconnection.
582 It should be able to recover from this situation though.582 It should be able to recover from this situation though.
583 """583 """
584 result = self.connection.execute("SELECT 1")584 result = self.connection.execute(Select(1))
585 self.assertTrue(result.get_one())585 self.assertTrue(result.get_one())
586 self.proxy.restart()586 self.proxy.restart()
587 # Perform an action that should result in a disconnection.587 # Perform an action that should result in a disconnection.
588 try:588 try:
589 cursor = self.connection._raw_connection.cursor()589 cursor = self.connection._raw_connection.cursor()
590 cursor.execute("SELECT 1")590 cursor.execute("select 1 from test")
591 cursor.fetchone()591 cursor.fetchone()
592 except Error, exc:592 except Error, exc:
593 self.assertTrue(self.connection.is_disconnection_error(exc))593 self.assertTrue(self.connection.is_disconnection_error(exc))
@@ -614,59 +614,59 @@
614 then it is possible that Storm won't see the disconnection.614 then it is possible that Storm won't see the disconnection.
615 It should be able to recover from this situation though.615 It should be able to recover from this situation though.
616 """616 """
617 result = self.connection.execute("SELECT 1")617 result = self.connection.execute(Select(1))
618 self.assertTrue(result.get_one())618 self.assertTrue(result.get_one())
619 self.proxy.restart()619 self.proxy.restart()
620 # Perform an action that should result in a disconnection.620 # Perform an action that should result in a disconnection.
621 try:621 try:
622 cursor = self.connection._raw_connection.cursor()622 cursor = self.connection._raw_connection.cursor()
623 cursor.execute("SELECT 1")623 cursor.execute("SELECT 1 FROM TEST")
624 cursor.fetchone()624 cursor.fetchone()
625 except DatabaseError, exc:625 except DatabaseError, exc:
626 self.assertTrue(self.connection.is_disconnection_error(exc))626 self.assertTrue(self.connection.is_disconnection_error(exc))
627 else:627 else:
628 self.fail("Disconnection was not caught.")628 self.fail("Disconnection was not caught.")
629 self.assertRaises(DisconnectionError,629 self.assertRaises(DisconnectionError,
630 self.connection.execute, "SELECT 1")630 self.connection.execute, Select(1))
631631
632 def test_connection_stays_disconnected_in_transaction(self):632 def test_connection_stays_disconnected_in_transaction(self):
633 """Test that connection does not immediately reconnect."""633 """Test that connection does not immediately reconnect."""
634 result = self.connection.execute("SELECT 1")634 result = self.connection.execute(Select(1))
635 self.assertTrue(result.get_one())635 self.assertTrue(result.get_one())
636 self.proxy.restart()636 self.proxy.restart()
637 self.assertRaises(DisconnectionError,637 self.assertRaises(DisconnectionError,
638 self.connection.execute, "SELECT 1")638 self.connection.execute, Select(1))
639 self.assertRaises(DisconnectionError,639 self.assertRaises(DisconnectionError,
640 self.connection.execute, "SELECT 1")640 self.connection.execute, Select(1))
641641
642 def test_reconnect_after_rollback(self):642 def test_reconnect_after_rollback(self):
643 """Test that we reconnect after rolling back the connection."""643 """Test that we reconnect after rolling back the connection."""
644 result = self.connection.execute("SELECT 1")644 result = self.connection.execute(Select(1))
645 self.assertTrue(result.get_one())645 self.assertTrue(result.get_one())
646 self.proxy.restart()646 self.proxy.restart()
647 self.assertRaises(DisconnectionError,647 self.assertRaises(DisconnectionError,
648 self.connection.execute, "SELECT 1")648 self.connection.execute, Select(1))
649 self.connection.rollback()649 self.connection.rollback()
650 result = self.connection.execute("SELECT 1")650 result = self.connection.execute(Select(1))
651 self.assertTrue(result.get_one())651 self.assertTrue(result.get_one())
652652
653 def test_catch_disconnect_on_reconnect(self):653 def test_catch_disconnect_on_reconnect(self):
654 """Test that reconnection failures result in DisconnectionError."""654 """Test that reconnection failures result in DisconnectionError."""
655 result = self.connection.execute("SELECT 1")655 result = self.connection.execute(Select(1))
656 self.assertTrue(result.get_one())656 self.assertTrue(result.get_one())
657 self.proxy.stop()657 self.proxy.stop()
658 self.assertRaises(DisconnectionError,658 self.assertRaises(DisconnectionError,
659 self.connection.execute, "SELECT 1")659 self.connection.execute, Select(1))
660 # Rollback the connection, but because the proxy is still660 # Rollback the connection, but because the proxy is still
661 # down, we get a DisconnectionError again.661 # down, we get a DisconnectionError again.
662 self.connection.rollback()662 self.connection.rollback()
663 self.assertRaises(DisconnectionError,663 self.assertRaises(DisconnectionError,
664 self.connection.execute, "SELECT 1")664 self.connection.execute, Select(1))
665665
666 def test_close_connection_after_disconnect(self):666 def test_close_connection_after_disconnect(self):
667 result = self.connection.execute("SELECT 1")667 result = self.connection.execute(Select(1))
668 self.assertTrue(result.get_one())668 self.assertTrue(result.get_one())
669 self.proxy.stop()669 self.proxy.stop()
670 self.assertRaises(DisconnectionError,670 self.assertRaises(DisconnectionError,
671 self.connection.execute, "SELECT 1")671 self.connection.execute, Select(1))
672 self.connection.close()672 self.connection.close()
673673
=== added file 'tests/databases/firebird.py'
--- tests/databases/firebird.py 1970-01-01 00:00:00 +0000
+++ tests/databases/firebird.py 2010-06-26 13:26:23 +0000
@@ -0,0 +1,171 @@
1#
2# Copyright (c) 2010 Canonical
3#
4# Initial Code by Gerdus van Zyl
5#
6# This file is part of Storm Object Relational Mapper.
7#
8# Storm is free software; you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License as
10# published by the Free Software Foundation; either version 2.1 of
11# the License, or (at your option) any later version.
12#
13# Storm is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Lesser General Public License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21import os
22
23from storm.database import create_database
24from storm.database import *
25
26from tests.helper import TestHelper
27
28from tests.databases.base import (
29 DatabaseTest, UnsupportedDatabaseTest, DatabaseDisconnectionTest)
30
31from storm.variables import (
32 IntVariable, Variable )
33
34from storm.exceptions import (
35 DatabaseError, DatabaseModuleError,
36 DisconnectionError, Error, OperationalError, ConnectionBlockedError)
37
38from tests.expr import (
39 Select,Column,Insert, column1, column2, column3, elem1,
40 table1, TrackContext,Sequence)
41
42#import storm.tracer
43#import sys
44#storm.tracer.debug(True, stream=sys.stdout)
45
46class FirebirdTest(DatabaseTest, TestHelper):
47 supports_microseconds = False
48
49 def is_supported(self):
50 return bool(os.environ.get("STORM_FIREBIRD_URI"))
51
52 def create_database(self):
53 self.database = create_database(os.environ["STORM_FIREBIRD_URI"])
54
55 def create_tables(self):
56 self.connection.execute('CREATE TABLE NUMBER (one INTEGER, two INTEGER, three INTEGER)')
57 self.connection.execute('CREATE TABLE TEST (id INTEGER PRIMARY KEY, title VARCHAR(50) CHARACTER SET UTF8)')
58 self.connection.execute('CREATE TABLE DATETIME_TEST (id INT UNIQUE,dt TIMESTAMP, d DATE, t TIME, td BLOB SUB_TYPE TEXT)')
59
60 self.connection.execute('CREATE TABLE BIN_TEST (id INT UNIQUE,b BLOB)')
61
62 self.connection.execute('CREATE GENERATOR GEN_TEST_AUTOID')
63 self.connection.execute('SET GENERATOR GEN_TEST_AUTOID TO 0')
64
65 self.connection.execute("""CREATE TRIGGER TEST_PK_AUTO FOR TEST ACTIVE BEFORE INSERT POSITION 0 AS
66begin
67 if ( (new.ID is null) or (new.ID = 0) )
68 then new.ID = gen_id(GEN_TEST_AUTOID, 1);
69end""")
70
71 self.connection.execute("""CREATE TABLE insert_returning_test
72 (id0 INTEGER,
73 id1 INTEGER DEFAULT 123,
74 id2 INTEGER DEFAULT 456)""")
75
76 self.connection.commit()
77
78 def drop_tables(self):
79 try:
80 self.connection.execute("DROP TRIGGER TEST_PK_AUTO")
81 self.connection.execute("DROP GENERATOR GEN_TEST_AUTOID")
82 self.connection.commit()
83 except:
84 self.connection.rollback()
85
86 for table in ["number", "test", "datetime_test", "bin_test", "insert_returning_test"]:
87 try:
88 self.connection.execute("DROP TABLE " + table)
89 self.connection.commit()
90 except:
91 self.connection.rollback()
92
93 def test_get_insert_identity(self):
94 """test_get_insert_identity -Does not support insert identity"""
95 #http://www.firebirdfaq.org/faq243/
96 pass
97
98 def test_get_insert_identity_composed(self):
99 """test_get_insert_identity_composed - Does not support insert identity"""
100 #http://www.firebirdfaq.org/faq243/
101 pass
102
103 def test_execute_insert_returning(self):
104 if self.connection.server_version < 2:
105 return # Can't run this test with old PostgreSQL versions.
106
107 column0 = Column("id0", "insert_returning_test")
108 column1 = Column("id1", "insert_returning_test")
109 column2 = Column("id2", "insert_returning_test")
110 variable1 = IntVariable()
111 variable2 = IntVariable()
112 insert = Insert({column0: 999}, primary_columns=(column1, column2),
113 primary_variables=(variable1, variable2))
114 self.connection.execute(insert)
115
116 self.assertTrue(variable1.is_defined())
117 self.assertTrue(variable2.is_defined())
118
119 self.assertEquals(variable1.get(), 123)
120 self.assertEquals(variable2.get(), 456)
121
122 result = self.connection.execute("SELECT * FROM insert_returning_test")
123 self.assertEquals(result.get_one(), (999,123, 456))
124
125 def test_sequence(self):
126 expr1 = Select(Sequence("GEN_TEST_AUTOID"))
127 expr2 = "SELECT gen_id(GEN_TEST_AUTOID,0) FROM RDB$DATABASE"
128 value1 = self.connection.execute(expr1).get_one()[0]
129 value2 = self.connection.execute(expr2).get_one()[0]
130 value3 = self.connection.execute(expr1).get_one()[0]
131 self.assertEquals(value1, value2)
132 self.assertEquals(value3-value1, 1)
133
134 def test_limit_offset(self):
135 self.connection.execute("delete from test")
136 self.connection.commit()
137
138 for z in range(100,200+1):
139 sql = "INSERT INTO test (id,title) VALUES (%i,'%i')" % (z,z)
140 self.connection.execute(sql)
141 self.connection.commit()
142
143 select = Select(Column("id", "test"))
144 select.limit = 1
145 select.offset = 0
146 select.order_by = Column("id", "test")
147
148 result = self.connection.execute(select)
149 self.assertEquals(result.get_all(), [(100,),] )
150
151
152 select = Select(Column("id", "test"))
153 select.limit = 2
154 select.offset = 50
155 select.order_by = Column("id", "test")
156
157 result = self.connection.execute(select)
158 self.assertEquals(result.get_all(), [(150,),(151,)] )
159
160
161class FirebirdUnsupportedTest(UnsupportedDatabaseTest, TestHelper):
162
163 dbapi_module_names = ["kinterbasdb"]
164 db_module_name = "firebird"
165
166
167class FirebirdDisconnectionTest(DatabaseDisconnectionTest, TestHelper):
168
169 environment_variable = "STORM_FIREBIRD_URI"
170 host_environment_variable = "STORM_FIREBIRD_HOST_URI"
171 default_port = 3050
0172
=== modified file 'tests/databases/proxy.py'
--- tests/databases/proxy.py 2007-10-24 06:27:06 +0000
+++ tests/databases/proxy.py 2010-06-26 13:26:23 +0000
@@ -52,14 +52,14 @@
52 return52 return
5353
54 if self.request in rlist:54 if self.request in rlist:
55 chunk = os.read(self.request.fileno(), 1024)55 chunk = self.request.recv(1024)
56 dst.send(chunk)56 dst.send(chunk)
57 if chunk == "":57 if chunk == "":
58 readers.remove(self.request)58 readers.remove(self.request)
59 dst.shutdown(socket.SHUT_WR)59 dst.shutdown(socket.SHUT_WR)
6060
61 if dst in rlist:61 if dst in rlist:
62 chunk = os.read(dst.fileno(), 1024)62 chunk = dst.recv(1024)
63 self.request.send(chunk)63 self.request.send(chunk)
64 if chunk == "":64 if chunk == "":
65 readers.remove(dst)65 readers.remove(dst)

Subscribers

People subscribed via source and target branches

to status/vote changes: