Merge lp:~chromakode/drizzle-interface/dbapi into lp:drizzle-interface

Proposed by Max Goodhart
Status: Merged
Merged at revision: not available
Proposed branch: lp:~chromakode/drizzle-interface/dbapi
Merge into: lp:drizzle-interface
Diff against target: 390 lines (+120/-46)
12 files modified
interface/globals.i (+1/-1)
interface/libdrizzle/column.i (+14/-14)
interface/libdrizzle/connection.i (+6/-6)
interface/libdrizzle/drizzle.i (+1/-1)
interface/libdrizzle/result.i (+2/-2)
interface/python/drizzle_exception.i (+1/-1)
interface/python/libdrizzle.i (+1/-1)
interface/python/row_buffered.i (+34/-9)
interface/python/unicode.i (+35/-0)
python/drizzle/db.py (+12/-2)
python/drizzle/errors.py (+9/-5)
python/tests/dbapi20.py (+4/-4)
To merge this branch: bzr merge lp:~chromakode/drizzle-interface/dbapi
Reviewer Review Type Date Requested Status
Max Goodhart Needs Resubmitting
Drizzle Developers Pending
Review via email: mp+21816@code.launchpad.net

Description of the change

Added typemaps and conversion code to output Python unicode objects wherever applicable. I'd like feedback on the "unicode" typedef+typemap approach. I didn't want to place a blanket "char *" typemap in case something truly needed to output bytes, but it doesn't seem like there's such an instance in the current SWIG code.

To post a comment you must log in.
172. By Max Goodhart

Add exception classes to the Connection object, and tweak the extension hierarchy to place coded libdrizzle InterfaceErrors in their own subclass.

173. By Max Goodhart

Fix the rowcount test in the DBAPI test suite to accept a value of 0 for DDL statements (see bug #543885).

174. By Max Goodhart

Return None when in place of NULL values.

Revision history for this message
Max Goodhart (chromakode) wrote :

Alright, that fixes up the last of the failed unit tests that don't depend on threadsafety or paramstyle. Should be ready to merge and in sync with the upcoming Boots release.

review: Needs Resubmitting
175. By Max Goodhart

Add missing unicode.i -- oops!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'interface/globals.i'
2--- interface/globals.i 2010-01-23 20:48:37 +0000
3+++ interface/globals.i 2010-03-22 07:03:28 +0000
4@@ -71,7 +71,7 @@
5 drizzle_result_st *result;
6 } row_buffer;
7
8-
9+typedef const char* unicode;
10 %}
11
12 %ignore drizzle_state_fn;
13
14=== modified file 'interface/libdrizzle/column.i'
15--- interface/libdrizzle/column.i 2009-10-27 08:45:31 +0000
16+++ interface/libdrizzle/column.i 2010-03-22 07:03:28 +0000
17@@ -45,29 +45,29 @@
18 return drizzle_column_drizzle_result($self);
19 }
20
21- const char *catalog()
22- {
23- return drizzle_column_catalog($self);
24- }
25-
26- const char *db()
27- {
28- return drizzle_column_catalog($self);
29- }
30-
31- const char *table()
32+ unicode catalog()
33+ {
34+ return drizzle_column_catalog($self);
35+ }
36+
37+ unicode db()
38+ {
39+ return drizzle_column_catalog($self);
40+ }
41+
42+ unicode table()
43 {
44 return drizzle_column_table($self);
45 }
46- const char *orig_table()
47+ unicode orig_table()
48 {
49 return drizzle_column_orig_table($self);
50 }
51- const char *name()
52+ unicode name()
53 {
54 return drizzle_column_name(self);
55 }
56- const char *orig_name()
57+ unicode orig_name()
58 {
59 return drizzle_column_orig_name(self);
60 }
61
62=== modified file 'interface/libdrizzle/connection.i'
63--- interface/libdrizzle/connection.i 2010-02-28 07:06:22 +0000
64+++ interface/libdrizzle/connection.i 2010-03-22 07:03:28 +0000
65@@ -34,7 +34,7 @@
66 %extend Connection {
67
68 /* Set options for a connection. */
69- const char *host()
70+ unicode host()
71 {
72 return drizzle_con_host($self);
73 }
74@@ -49,7 +49,7 @@
75 drizzle_con_set_tcp($self, host, port);
76 }
77
78- const char *uds()
79+ unicode uds()
80 {
81 return drizzle_con_uds($self);
82 }
83@@ -59,12 +59,12 @@
84 drizzle_con_set_uds($self, uds);
85 }
86
87- const char *user()
88+ unicode user()
89 {
90 return drizzle_con_user($self);
91 }
92
93- const char *password()
94+ unicode password()
95 {
96 return drizzle_con_password($self);
97 }
98@@ -74,7 +74,7 @@
99 drizzle_con_set_auth($self, user, password);
100 }
101
102- const char *db()
103+ unicode db()
104 {
105 return drizzle_con_db($self);
106 }
107@@ -122,7 +122,7 @@
108 return drizzle_con_protocol_version($self);
109 }
110
111- const char *server_version()
112+ unicode server_version()
113 {
114 return drizzle_con_server_version($self);
115 }
116
117=== modified file 'interface/libdrizzle/drizzle.i'
118--- interface/libdrizzle/drizzle.i 2010-01-26 07:43:15 +0000
119+++ interface/libdrizzle/drizzle.i 2010-03-22 07:03:28 +0000
120@@ -55,7 +55,7 @@
121 }
122
123 /* Return an error string for last library error encountered. */
124- const char *error()
125+ unicode error()
126 {
127 return drizzle_error($self);
128 }
129
130=== modified file 'interface/libdrizzle/result.i'
131--- interface/libdrizzle/result.i 2010-02-28 07:06:22 +0000
132+++ interface/libdrizzle/result.i 2010-03-22 07:03:28 +0000
133@@ -241,12 +241,12 @@
134 return drizzle_result_eof($self);
135 }
136
137- const char *info()
138+ unicode info()
139 {
140 return drizzle_result_info($self);
141 }
142
143- const char *error()
144+ unicode error()
145 {
146 return drizzle_result_error($self);
147 }
148
149=== modified file 'interface/python/drizzle_exception.i'
150--- interface/python/drizzle_exception.i 2010-02-28 07:06:22 +0000
151+++ interface/python/drizzle_exception.i 2010-03-22 07:03:28 +0000
152@@ -73,7 +73,7 @@
153 exception = GET_pyexcept("CouldNotConnectError");
154 break;
155 default:
156- exception = GET_pyexcept("InterfaceError");
157+ exception = GET_pyexcept("LibDrizzleError");
158 break;
159 }
160 break;
161
162=== modified file 'interface/python/libdrizzle.i'
163--- interface/python/libdrizzle.i 2010-01-23 22:46:05 +0000
164+++ interface/python/libdrizzle.i 2010-03-22 07:03:28 +0000
165@@ -34,7 +34,6 @@
166 %include "typemaps.i"
167
168
169-
170 %include "interface/globals.i"
171
172 %include "interface/python/drizzle_exception.i"
173@@ -43,6 +42,7 @@
174 %include "interface/python/drizzle_row_t.i"
175 %include "interface/python/value_return.i"
176 %include "interface/python/row_buffered.i"
177+%include "interface/python/unicode.i"
178
179 %include "interface/libdrizzle/drizzle.i"
180 %include "interface/libdrizzle/connection.i"
181
182=== modified file 'interface/python/row_buffered.i'
183--- interface/python/row_buffered.i 2010-01-23 20:48:37 +0000
184+++ interface/python/row_buffered.i 2010-03-22 07:03:28 +0000
185@@ -30,24 +30,49 @@
186 */
187
188 %{
189- PyObject *row_buffer_to_tuple(row_buffer *buffer) {
190+ PyObject *convert_field(drizzle_field_t field, size_t size, drizzle_column_st *column)
191+ {
192+ if (size == 0)
193+ {
194+ Py_RETURN_NONE;
195+ }
196+ else
197+ {
198+ switch (drizzle_column_type(column))
199+ {
200+ case DRIZZLE_COLUMN_TYPE_TINY_BLOB:
201+ case DRIZZLE_COLUMN_TYPE_MEDIUM_BLOB:
202+ case DRIZZLE_COLUMN_TYPE_LONG_BLOB:
203+ case DRIZZLE_COLUMN_TYPE_BLOB:
204+ case DRIZZLE_COLUMN_TYPE_VAR_STRING:
205+ case DRIZZLE_COLUMN_TYPE_STRING:
206+ if ((drizzle_column_flags(column) & DRIZZLE_COLUMN_FLAGS_BINARY) == 1)
207+ break;
208+ case DRIZZLE_COLUMN_TYPE_VARCHAR:
209+ /* Textual fields should be in unicode */
210+ return PyUnicode_DecodeUTF8(field, size, NULL);
211+ default:
212+ return SWIG_FromCharPtrAndSize(field, size);
213+ }
214+ }
215+ }
216+
217+ PyObject *row_buffer_to_tuple(row_buffer *buffer)
218+ {
219 if (buffer->row == NULL)
220 {
221 return Py_None;
222 }
223
224 PyObject *row_tuple= PyTuple_New((Py_ssize_t)(buffer->field_count));
225-
226+ size_t *field_sizes= drizzle_row_field_sizes(buffer->result);
227 uint16_t field;
228- size_t *field_sizes= drizzle_row_field_sizes(buffer->result);
229-
230- PyObject *field_buffer= NULL;
231-
232 for (field= 0; field < buffer->field_count; field++)
233 {
234- /* Create a Python string copy of the field and add it to the tuple */
235- field_buffer= SWIG_FromCharPtrAndSize(buffer->row[field], field_sizes[field]);
236- PyTuple_SetItem(row_tuple, field, field_buffer);
237+ /* Create a Python copy of the field and add it to the tuple */
238+ drizzle_column_st *field_column= drizzle_column_index(buffer->result, field);
239+ PyObject *field_obj= convert_field(buffer->row[field], field_sizes[field], field_column);
240+ PyTuple_SetItem(row_tuple, field, field_obj);
241 }
242
243 return row_tuple;
244
245=== added file 'interface/python/unicode.i'
246--- interface/python/unicode.i 1970-01-01 00:00:00 +0000
247+++ interface/python/unicode.i 2010-03-22 07:03:28 +0000
248@@ -0,0 +1,35 @@
249+/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
250+ * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
251+ *
252+ * drizzle-interface: Interface Wrappers for Drizzle
253+ * Copyright (c) 2009 Sun Microsystems
254+ * All rights reserved.
255+ *
256+ * Redistribution and use in source and binary forms, with or without
257+ * modification, are permitted provided that the following conditions are met:
258+ *
259+ * 1. Redistributions of source code must retain the above copyright
260+ * notice, this list of conditions and the following disclaimer.
261+ * 2. Redistributions in binary form must reproduce the above copyright
262+ * notice, this list of conditions and the following disclaimer in the
263+ * documentation and/or other materials provided with the distribution.
264+ * 3. The name of the author may not be used to endorse or promote products
265+ * derived from this software without specific prior written permission.
266+ *
267+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
268+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
269+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
270+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
271+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
272+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
273+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
274+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
275+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
276+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
277+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278+ */
279+
280+%typemap(out) unicode
281+%{
282+ return PyUnicode_DecodeUTF8($1, strlen($1), NULL);
283+%}
284\ No newline at end of file
285
286=== modified file 'python/drizzle/db.py'
287--- python/drizzle/db.py 2010-03-21 19:05:56 +0000
288+++ python/drizzle/db.py 2010-03-22 07:03:28 +0000
289@@ -32,7 +32,6 @@
290 from drizzle.errors import *
291 from drizzle.column_types import *
292
293-
294 libdrizzle = _libdrizzle.Drizzle()
295
296 apilevel = "2.0"
297@@ -67,7 +66,7 @@
298 precision, scale, null_ok))
299 return description
300
301-class Connection(object):
302+class Connection(object):
303 def __init__(self, host=None, username=None, password=None, database=None, port=None):
304 self.host = host
305 self.port = port
306@@ -141,6 +140,17 @@
307 self._check_connected()
308 return self._drizzle_connection.protocol_version()
309
310+# DB-API Extension: exception classes as members of Connection object
311+Connection.Warning = Warning
312+Connection.Error = Error
313+Connection.InterfaceError = InterfaceError
314+Connection.DatabaseError = DatabaseError
315+Connection.OperationalError = OperationalError
316+Connection.IntegrityError = IntegrityError
317+Connection.InternalError = InternalError
318+Connection.ProgrammingError = ProgrammingError
319+Connection.NotSupportedError = NotSupportedError
320+
321 class Cursor(object):
322 def __init__(self, connection, convert=True):
323 self._connection = connection
324
325=== modified file 'python/drizzle/errors.py'
326--- python/drizzle/errors.py 2010-03-21 19:05:56 +0000
327+++ python/drizzle/errors.py 2010-03-22 07:03:28 +0000
328@@ -48,7 +48,7 @@
329 """Exception raised for important warnings."""
330 pass
331
332-class InterfaceError(CodedError):
333+class InterfaceError(Error):
334 """Exception raised for errors that are related to the database interface
335 rather than the database itself.
336
337@@ -92,19 +92,23 @@
338 """
339 pass
340
341+class LibDrizzleError(InterfaceError, CodedError):
342+ """Exception raised for coded errors raised by libdrizzle."""
343+ pass
344+
345 # Drizzle Return Code Exceptions
346-class AddressError(InterfaceError):
347+class AddressError(LibDrizzleError):
348 """Exception raised when a hostname or IP is invalid or cannot be resolved."""
349 pass
350
351-class AuthFailedError(InterfaceError):
352+class AuthFailedError(LibDrizzleError):
353 """Exception raised when authentication with the server failed."""
354 pass
355
356-class LostConnectionError(InterfaceError):
357+class LostConnectionError(LibDrizzleError):
358 """Exception raised when the connection to a database is lost."""
359 pass
360
361-class CouldNotConnectError(InterfaceError):
362+class CouldNotConnectError(LibDrizzleError):
363 """Exception raised when a connection could not be established."""
364 pass
365
366=== modified file 'python/tests/dbapi20.py'
367--- python/tests/dbapi20.py 2010-01-21 04:19:33 +0000
368+++ python/tests/dbapi20.py 2010-03-22 07:03:28 +0000
369@@ -320,8 +320,8 @@
370 try:
371 cur = con.cursor()
372 self.executeDDL1(cur)
373- self.assertEqual(cur.rowcount,-1,
374- 'cursor.rowcount should be -1 after executing no-result '
375+ self.failUnless(cur.rowcount in (0,-1),
376+ 'cursor.rowcount should be 0 or -1 after executing no-result '
377 'statements'
378 )
379 cur.execute("insert into %sbooze values ('Victoria Bitter')" % (
380@@ -337,8 +337,8 @@
381 'set to -1 after executing a select statement'
382 )
383 self.executeDDL2(cur)
384- self.assertEqual(cur.rowcount,-1,
385- 'cursor.rowcount not being reset to -1 after executing '
386+ self.failUnless(cur.rowcount in (0,-1),
387+ 'cursor.rowcount not being reset to 0 or -1 after executing '
388 'no-result statements'
389 )
390 finally:

Subscribers

People subscribed via source and target branches