1 #ident "@(#) $Id: MyPgSQL.py,v 1.2 2004/11/24 10:31:07 hmichelon Exp $"
2 # vi:set sw=4 ts=8 showmode ai:
3 #--(H+)-----------------------------------------------------------------+
6 # Description: This file implements a Python DB-API 2.0 interface to |
8 #=======================================================================|
9 # Copyright 2000 by Billy G. Allie. |
10 # All rights reserved. |
12 # Permission to use, copy, modify, and distribute this software and its |
13 # documentation for any purpose and without fee is hereby granted, pro- |
14 # vided that the above copyright notice appear in all copies and that |
15 # both that copyright notice and this permission notice appear in sup- |
16 # porting documentation, and that the copyright owner's name not be |
17 # used in advertising or publicity pertaining to distribution of the |
18 # software without specific, written prior permission. |
20 # THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
21 # INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN |
22 # NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
23 # CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS |
24 # OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE |
25 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE |
26 # USE OR PERFORMANCE OF THIS SOFTWARE. |
27 #=======================================================================|
30 # Date Ini Description |
31 # --------- --- ------------------------------------------------------- |
32 # 05JUL2003 bga - Fixed a problem with PgNumeric where an exception can |
33 # be thrown if the stated scale and precision of the |
34 # returned in the first result row does not match later |
36 # 26JUN2003 bga - Applied patch from Laurent Pinchart to allow _quote |
37 # to correctly process objects that are sub-classed |
38 # from String and Long types. |
39 # 05JUN2003 bga - Change the name of the quoting function back to |
40 # _quote. Variables named like __*__ should be restrict |
42 # 02JUN2003 bga - PgTypes is now hashable. repr() of a PgType will now |
43 # return the repr() of the underlying OID. |
44 # - Connection.binary() will now fail if autocommit is |
46 # - Connection.binary() will no longer commit the trans- |
47 # action after creating the large object. The applica- |
48 # tion developer is now responsible for commiting (or |
49 # for rolling back) the transaction [Bug #747525]. |
50 # - Added PG_TIMETZ to the mix [Patch #708013]. |
51 # - Pg_Money will now accept a string as a parameter. |
52 # - PostgreSQL int2, int, int4 will now be cast into |
53 # Python ints. Int8 will be cast into a Python long. |
54 # Float4, float8, and money types will be cast into |
56 # 07MAR2003 bga - Correct problem with the PgNumeric.__radd__ method. |
58 # - Correct problem with conversion of negitive integers |
59 # (with a given scale and precision) to PgNumerics. |
61 # - Work around a problem where the precision and scale |
62 # of a query result can be different from the first re- |
63 # sult in the result set. |
65 # 12JAN2003 bga - Change the code so that the display length in the |
66 # cursor.description attribute is always None instead |
68 # - Fixed another problem with interval <-> DateTimeDelta |
70 # 23DEC2002 bga - Corrected a problem that caused the close of a portal |
71 # (ie. PostgreSQL cursor) to fail. |
72 # 13DEC2002 bga - Corrected a problem with interval <-> DateTimeDelta |
73 # casting. [Bug #653044] |
74 # 06DEC2002 bga - Corrected problem found by Adam Buraczewski in the |
75 # __setupTransaction function. |
76 # - Allow both 'e' and 'E' to signify an exponet in the |
77 # PgNumeric constructor. |
78 # 04DEC2002 bga - Correct some problems that were missed in yesterday's |
79 # fixes (Thanks, Adam, for the help with the problems) |
80 # 03DEC2002 bga - Fixed various problems with the constructor and the |
81 # formatting routine. These correct the problems re- |
82 # ported by Adam Buraczewski. |
83 # 01DEC2002 bga - Fixed problems with new __setupTransaction function: |
84 # 1. Made it a method of Connection, not Cursor. |
85 # 2. inTransaction was only set if TransactionLevel was |
87 # - Fixed instances where method name was incorrect: |
88 # Connection__gcCursor -> _Connection__gcCursor |
89 # Connection__closeCursor -> _Connection__closeCursor |
90 # - Cleaned up code where there was unneeded references |
91 # to conn in Connection class. |
92 # 01DEC2002 gh - Handle the new '__quote__' method for arrays, too. |
93 # - Still handle '_quote' methods for backwards compati- |
94 # bility. This will will avoid complaints by users |
95 # who have code depending on this. Like me. |
96 # 28NOV2002 bga - Fixed changed PG_TIMESTAMP oid, added PG_TIMESTAMPTZ |
97 # and PG_REFCURSOR oids. [Bug #845360] |
98 # - Reference cursors are now type-casted into cursor ob- |
100 # 27NOV2002 bga - Completed the emulation of a String object for the |
101 # PgBytea and PgOther classes. This corrects several |
102 # problems with PgBytea concerning comparisons, using |
103 # PgBytea types as keys in dictionaries, etc. |
104 # 10NOV2002 bga - Added the __hash__ function to the PgNumeric class. |
105 # Cleaned up the code in PgNumeric class and made some |
106 # small improvments to it. |
107 # 02NOV2002 bga - Added the PgArray class. This is a wrapper around a |
108 # Python list and is used for all PostgreSQL arrays. |
109 # This change was made so that lists and tuples no |
110 # longer have a special meaning in the Cursor.execute() |
112 # - Changed the quoting methods defined in the various |
113 # classes defining PostgreSQL support types to __quote__|
114 # 27OCT2002 gh - Merged the Unicode patch. Closes #484468. |
115 # - Convert ROWID to PgInt8 instead of PgInt4 (the origi- |
116 # nal behaviour led to overflow errors.) |
117 # - Always set the displaysize field of |
118 # cursor.description to -1. PostgreSQL 7.3 doesn't |
119 # provide this information any more and it's pretty |
120 # useless nowadays that we've mostly left line printers |
122 # 26OCT2002 bga - Column access by name (attribute and dictionary) now |
123 # supports mixed-case column name. Be aware that if |
124 # you define mixed-case column names in the database, |
125 # you have to use the mixed-case name to access the co- |
126 # lumn or it will not be found. For column names that |
127 # were not defined with mixed-case in the database, the |
128 # column access by name is case insensitive. |
129 # 02OCT2002 gh - Only support mxDateTime 2.x and give useful error |
130 # message if import fails. |
131 # - Cosmetic changes: use cmp builtin where appropriate. |
132 # - Fixed typo where PgTypes.__str__ was spelled |
133 # incorrectly. Compare to None using "is" operator. |
134 # - Take into account that libpq.PgInt8Type might not be |
136 # - Add support for the INTERVAL type. |
137 # 08SEP2002 gh Fixed various problems with the PgResultSet: |
138 # - Column (attribute and dictionary) access is now case- |
140 # - Added __contains__ method. |
141 # - Added default value parameter to get method. |
142 # - Made setattr actually work. |
143 # 11AUG2002 bga Fixed various problems with the PgNumeric type: |
144 # - Added code to allow a float as an argument to the |
145 # PgNumeric constructor. |
146 # - You can now change the precision/scale of a PgNumeric |
147 # by: a = PgNumeric(pgnumeric, new prec, new scale). |
148 # This can be used to 'cast' a PgNumeric to the proper |
149 # precision and scale before storing it in a field. |
150 # - The arithmatic routines (__add__, __radd__, etc) now |
151 # ensure that the arguments are properly coerced to the |
153 # - Added support for the augmented arithmatic operations |
155 # - The math routines would lose precision becuase the |
156 # precision/scale were set to be the same as the first |
157 # operand. This is no longer the case all precision is |
158 # retained for the +, -, and * operations. |
159 # 03AUG2002 gh - Fixed problem that occurs when a query on an OID |
160 # field doesn't return any rows. [Bug #589370]. |
161 # 29JUL2002 gh - Applied patch #569203 and also added __pos__ and |
162 # __abs__ special methods to PgNumeric. |
163 # 15MAY2002 gh - Got rid of redundant building and storing of the |
164 # mapping of column names to column positions in the |
165 # PgResultSet class. Now, rows of the same query are |
166 # instances of a dynamically created class, which has |
167 # this mapping as a class attribute instead of an at- |
168 # tribute of the instance. This saves a lot of space, |
169 # and also slightly increases performance of cursor |
171 # 21APR2002 gh - Improved the array parsing, so that it now passes all |
172 # the new mean testcases. Added support for parsing |
173 # multidimensional arrays. Eventually, the array par- |
174 # sing code should go as a support function into libpq. |
175 # - Replaced all typechecks with "is" operators instead |
176 # of equals. Mark McEahern had a problem with using |
177 # pyPgSQL in combination with a FixedPoint class where |
178 # the reason was that the FixedPoint class was not com- |
179 # parable to None. The consensus on python-list was |
180 # that None and all types are singletons, so they |
181 # should be checked using "is", which is also faster, |
182 # because it only checks for object identity. |
183 # --------- bga Remove prior comments to reduce the size of the flower |
184 # box. See revision 1.22 for earlier comments. |
185 #--(H-)-----------------------------------------------------------------+
187 PgSQL - A PyDB-SIG 2.0 compliant module for PostgreSQL.
189 Copyright 2000 by Billy G. Allie <Bill.Allie@mug.org>
190 See package documentation for further information on copyright.
192 Inline documentation is sparse.
193 See the Python DB-SIG 2.0 specification for usage information.
197 PgSQL.connect(connect_string) -> connection
198 connect_string = 'host:port:database:user:password:options:tty'
199 All parts are optional. You may also pass the information in as
200 keyword arguments with the following keywords: 'host', 'port',
201 'database', 'user', 'password', 'options', and 'tty'. The port
202 may also be passed in as part of the host keyword parameter,
203 ie. host='localhost:5432'. Other optional parameters are
204 client_encoding and unicode_results. If unicode_results is true,
205 all strings from the backend are returned as Unicode strings.
207 client_encoding accepts the same parameters as the encode method
208 of Unicode strings. If you also want to set a policy for encoding
209 errors, set client_encoding to a tuple, like ("koi8-r", "replace")
211 Note that you still must make sure that the PostgreSQL client is
212 using the same encoding as set with the client_encoding parameter.
213 This is typically done by issuing a "SET CLIENT_ENCODING TO ..."
214 SQL statement immediately after creating the connection.
216 connection.cursor() -> cursor
217 Create a new cursor object. A connection can support multiple
218 cursors at the same time.
221 Closes the connection now (instead of when __del__ is called).
222 The connection will be unusable from this point forward.
223 NOTE: Any uncommited transactions will be rolled back and any
224 open cursors for this connection will be closed.
227 Commit any pending transactions for this connection.
229 NOTE: This will reset any open cursors for this connection to their
230 inital state. Any PostgreSQL portals in use by cursors will
231 be closed and any remaining query results will be discarded.
233 connection.rollback()
234 Rollback any pending transactions for this connection.
236 NOTE: This will reset any open cursors for this connection to their
237 inital state. Any PostgreSQL portals in use by cursors will
238 be closed and any remaining query results will be discarded.
240 connection.binary(string) -> PgLargeObject
241 Create a new PostgreSQL large object. If string is present, it is
242 written to the new large object. The returned large object will
243 not be opened (i.e. it will be closed).
245 connection.un_link(OID|PgLargeObject)
246 Un-links (removes) the PgLargeObject from the database.
248 NOTE: This is a PostgreSQL extension to the Connection object.
249 It is not safe to un-link PgLargeObjects while in a trans-
250 action (in versions prior to 7.1) since this action can not
251 be rollbacked completely. Therefore, an attempt to un-link
252 while in a transaction (in versions prior to 7.1) will raise
256 This instance of the PgVersion class contains information about
257 the version of the PostgreSQL backend to which the connection
258 object is connected to.
260 NOTE: This is a PgSQL extension to the Connection object.
262 cursor.execute(query[, param1[, param2, ..., paramN])
263 Execute a query, binding the parameters if they are passed. The
264 binding syntax is the same as the '%' operator except that only %s
265 [or %(name)s] should be used and the %s [or %(name)s] should not be
266 quoted. Any necessary quoting will be performed by the execute
269 cursor.execute(query[, sequence])
270 Execute a query, binding the contents of the sequence as parameters.
271 The binding syntax is the same as the '%' operator except that only
272 %s should be used and the %s should not be quoted. Any necessary
273 quoting will be performed by the execute method.
275 cursor.execute(query[, dictionary])
276 Execute a query, binding the contents of the dictionary as para-
277 meters. The binding syntax is the same as the '%' operator except
278 that only %s [or %(name)s] should be used and the %s [or %(name)s]
279 should not be quoted. Any necessary quoting will be performed by
282 NOTE: In order to use a PostgreSQL portal (i.e. DECLARE ... CURSOR
283 FOR ...), the word SELECT must be the first word in the query,
284 and can only be be proceeded by spaces and tabs. If this is not
285 the case, a cursor will be simulated by reading the entire result
286 set into memory and handing out the results as needed.
288 NOTE: PostgreSQL cursors are read-only. SELECT ... FOR UPDATE queries
289 will not use PostgreSQL cursors, but will simulate a cursor by
290 reading the entire result set into memory and handing out the
293 NOTE: Setting the variable, PgSQL.noPostgresCursor, to 1 will cause
294 PgSQL to NOT use PostgreSQL cursor (DECLARE ... CURSOR FOR ...),
295 even if all the conditions for doing so are met. PgSQL will
296 simulate a cursor by reading the entire result set into memory
297 and handing out the results as needed.
299 cursor.executemany(query, sequence_of_params)
300 Execute a query many times, once for each params in the sequence.
302 NOTE: The restriction on the use of PostgreSQL cursors described in
303 the cursor.execute() note also applies to cursor.executemany().
304 The params in the sequence of params can be a list, tuple or
307 cursor.fetchone() -> PgResultSet
308 Fetch the next row of the query result set as a single PgResultSet
309 containing the column data. Returns None when no more rows are
310 available. A PgResultSet is a sequence that can be indexed by
311 a column name in addition to an integer.
313 cursor.fetchmany([size]) -> [PgResultSet, ...]
314 Fetch the next set of rows from the query result, returning a
315 sequence of PgResultSets. An empty sequence is returned when
316 no more rows are available.
318 The number of rows returned is determined by the size parameter.
319 If the size parameter is ommited, the value of cursor.arraysize
320 is used. If size is given, cursor.arraysize is set to that value.
322 cursor.fetchall() -> [PgResultSet, ...]
323 Fetch all (remaining) rows from the query result, returning a
324 sequence of PgResultSets. An empty sequence is returned when
325 no more rows are available.
327 cursor.description -> [(column info), ... ]
328 Returns a sequence of 8-item tuples. Each tuple describes one
329 column of the result: (name, type code, display size, internal
330 size, precision, scale, null_ok, isArray).
332 NOTE: null_ok is not implemented.
333 isArray is a PostgreSQL specific extension.
336 The number of rows the last execute produced (for DQL statements)
337 or affected (for DML statement).
340 The object ID of the inserted record, if the last SQL command
341 was an INSERT, otherwise it returns 0 (aka. InvalidOid)
343 NOTE: oidValue is a PostgreSQL specific extension.
346 Closes the cursor now (instead of when __del__ is called). The
347 cursor will be unusable from this point forward.
350 Moves the cursor back to the beginning of the query result.
351 This is a PgSQL extension to the PyDB 2.0 API.
353 PgResultSet.description() -> [(column info), ... ]
354 Returns a sequence of 8-item tuples. Each tuple describes one
355 column of the result: (name, type code, display size, internal
356 size, precision, scale, null_ok. isArray).
358 NOTE: null_ok is not implemented.
359 isArray is a PostgreSQL specific extension.
361 PgResultSet.<column name> -> value
362 Column names are attributes to the PgResultSet.
364 Note: Setting the variable, PgSQL.fetchReturnsList = 1 will cause
365 the fetch*() methods to return a list instead of a PgResultSet.
368 This string object contains the version number of PgSQL.
372 from sys
import getrefcount
, getdefaultencoding
386 from mx
import DateTime
389 """You need to install mxDateTime
390 (http://www.egenix.com/files/python/eGenix-mx-Extensions.html)"""
391 from pyPgSQL
.libpq
import *
393 version
= '$Revision: 1.2 $'
397 paramstyle
= 'pyformat'
399 # Setting this variable to 1 will cause the fetch*() methods to return
400 # a list instead of a PgResultSet
404 # Setting this variable to 1 will prevent the use of a PostgreSQL Cursor
405 # (via the "DECLARE ... CURSOR FOR ..." syntax). A cursor will be simulated
406 # by reading all of the query result into memory and doling out the results
411 re_DQL
= re
.compile('^[\s]*SELECT[\s]', re
.I
)
412 re_DRT
= re
.compile('[\s]*DROP[\s]+TABLE[\s]', re
.I
)
413 re_DRI
= re
.compile('[\s]*DROP[\s]+INDEX[\s]', re
.I
)
414 re_4UP
= re
.compile('[\s]FOR[\s]+UPDATE', re
.I
)
416 replace
= string
.replace
418 #-----------------------------------------------------------------------+
419 # Make the required Date/Time constructor visable in the PgSQL module. |
420 #-----------------------------------------------------------------------+
424 Timestamp
= DateTime
.Timestamp
425 DateFromTicks
= DateTime
.DateFromTicks
426 TimeFromTicks
= DateTime
.TimeFromTicks
427 TimestampFromTicks
= DateTime
.TimestampFromTicks
429 #-----------------------------------------------+
430 # The DateTimeDelta type for PgInterval support |
431 #-----------------------------------------------+
433 DateTimeDelta
= DateTime
.DateTimeDelta
435 #-------------------------------+
436 # Also the DateTime types |
437 #-------------------------------+
439 DateTimeType
= DateTime
.DateTimeType
440 DateTimeDeltaType
= DateTime
.DateTimeDeltaType
441 DateTimeDelta
= DateTime
.DateTimeDelta
443 #-----------------------------------------------------------------------+
444 # Name: DBAPITypeObject |
446 # Description: The DBAPITypeObject class allows implementing the re- |
447 # quired DP-API 2.0 type objects even if their are multi- |
448 # ple database types for the DP-API 2.0 types. |
450 # Note: This object is taken from the Python DP-API 2.0 imple- |
452 #-----------------------------------------------------------------------+
454 class DBAPITypeObject
:
455 def __init__(self
, name
, *values
):
462 def __cmp__(self
, other
):
463 if other
in self
.values
:
465 elif other
< self
.values
:
469 # Define the object types required by the DB-API 2.0 specification.
471 BINARY
= DBAPITypeObject('BINARY', PG_OID
, PG_BLOB
, PG_BYTEA
)
473 DATETIME
= DBAPITypeObject('DATETIME', PG_DATE
, PG_TIME
, PG_TIMETZ
,
474 PG_TIMESTAMP
, PG_TIMESTAMPTZ
,
475 PG_ABSTIME
, PG_RELTIME
,
476 PG_INTERVAL
, PG_TINTERVAL
)
478 NUMBER
= DBAPITypeObject('NUMBER', PG_INT8
, PG_INT2
, PG_INT4
, PG_FLOAT4
,
479 PG_FLOAT8
, PG_MONEY
, PG_NUMERIC
)
481 ROWID
= DBAPITypeObject('ROWID', PG_OID
, PG_ROWID
, PG_CID
, PG_TID
, PG_XID
)
483 STRING
= DBAPITypeObject('STRING', PG_CHAR
, PG_BPCHAR
, PG_TEXT
, PG_VARCHAR
,
486 # BOOLEAN is the PostgreSQL boolean type.
488 BOOLEAN
= DBAPITypeObject('BOOLEAN', PG_BOOL
)
490 # OTHER is for PostgreSQL types that don't fit in the standard Objects.
492 OTHER
= DBAPITypeObject('OTHER', PG_POINT
, PG_LSEG
, PG_PATH
, PG_BOX
,
493 PG_POLYGON
, PG_LINE
, PG_CIDR
, PG_CIRCLE
,
494 PG_INET
, PG_MACADDR
, PG_ACLITEM
,
497 #-----------------------------------------------------------------------+
500 # Description: PgTypes is an object wrapper for the type OID's used by |
501 # PostgreSQL. It is used to display a meaningful text |
502 # description of the type while still allowing it to be |
503 # compared as a numeric value. |
504 #-----------------------------------------------------------------------+
507 def __init__(self
, value
):
510 def __coerce__(self
, other
):
511 if type(other
) in [IntType
, LongType
, FloatType
]:
512 return (self
.value
, int(other
))
515 def __cmp__(self
, other
):
516 return cmp(self
.value
, other
)
519 return repr(self
.value
)
522 return PQftypeName(self
.value
)
525 return int(self
.value
)
528 return long(self
.value
)
531 return float(self
.value
)
533 def __complex__(self
):
534 return complex(self
.value
)
536 #-----------------------------------------------------------------------+
539 # Description: TypeCache is an object that defines methods to: |
540 # 1. Cast PostgreSQL result strings into the appropiate |
541 # Python type or object [typecast()]. |
542 # 2. Retrieve addition information about a type from the |
543 # PostgreSQL system catalogs [getTypeInfo()]. This |
544 # type information is maintained in a local cache so |
545 # that subsequent request for the same information do |
546 # not require a database query to fulfill it. |
547 #-----------------------------------------------------------------------+
550 """Type cache -- used to cache postgreSQL data type information."""
552 def __init__(self
, conn
):
556 self
.__conn
= weakref
.proxy(conn
, self
.__callback
)
557 self
.__type
_cache
= {}
560 def __callback(self
, o
):
563 def interval2DateTimeDelta(self
, s
):
564 """Parses PostgreSQL INTERVALs.
565 The expected format is [[[-]YY years] [-]DD days] [-]HH:MM:SS.ss"""
566 parser
= DateTime
.Parser
.DateTimeDeltaFromString
571 result
= DateTimeDelta(0)
573 # Convert any years using 365.2425 days per year, which is PostgreSQL's
574 # assumption about the number of days in a year.
576 if ydh
[1].lower().startswith('year'):
577 result
+= parser('%s days' % ((int(ydh
[0]) * 365.2425),))
580 # Converts any days and adds it to the years (as an interval)
582 if ydh
[1].lower().startswith('day'):
583 result
+= parser('%s days' % (ydh
[0],))
586 # Adds in the hours, minutes, seconds (as an interval)
588 result
+= parser(ydh
[0])
592 def parseArray(self
, s
):
593 """Parse a PostgreSQL array strings representation.
594 This parses a PostgreSQL array and return a list of the array
597 class LeaveLoopException(Exception): pass
599 # Get rid of the escaping in the array string
600 def convertEscapes(s
):
601 # If we're called with a list in a multi-dimensional
602 # array, simply return the list. We only convert the
603 # elements of the multi-dimensional array.
604 if type(s
) is ListType
:
619 if char
in string
.digits
:
620 octdigits
.append(char
)
623 curchar
= chr(int(octdigits
[0]) * 64) + \
624 chr(int(octdigits
[1]) * 8) + \
625 chr(int(octdigits
[2]))
626 schars
.append(curchar
)
632 return "".join(schars
)
635 s
= s
[1:-1] # drop '{' and '}' at start/end
637 # If the array is empty, return immediately
645 # A quoted element, find the end-quote, which is the next
646 # quote char that is not escaped.
647 end_quote_pos
= pos
+ 1
650 if s
[end_quote_pos
] == '\\':
652 elif s
[end_quote_pos
] == '"':
659 lst
.append(convertEscapes(s
[pos
+ 1:end_quote_pos
]))
661 # Skip quote char and next comma
662 pos
= end_quote_pos
+ 2
664 # If end-of-string. leave loop.
668 # This array element is not quoted, so it ends either at
669 # the next comma that isn't escaped, or at the end of the
670 # string, or, if it contains a subarray, at the position
671 # of the corresponding curly brace.
673 next_comma_pos
= pos
+ 1
676 if next_comma_pos
>= len(s
):
677 # This is the last array element.
678 lst
.append(convertEscapes(s
[pos
:]))
679 raise LeaveLoopException
681 if s
[next_comma_pos
] == '\\':
683 elif s
[next_comma_pos
] == ',':
691 curelem
= s
[pos
:next_comma_pos
]
692 if curelem
.startswith("{"):
693 lst
.append(self
.parseArray(curelem
[1:-1]))
695 lst
.append(convertEscapes(curelem
))
696 pos
= next_comma_pos
+ 1
700 # The current character is '{', which means we've
702 # We find the end of the sub-array, then feed this
703 # string into parseArray again.
706 closing_brace_pos
= pos
+ 1
709 if s
[closing_brace_pos
] == '\\':
711 elif s
[closing_brace_pos
] == '{':
712 if (not escape
) and (not in_quotes
):
715 elif s
[closing_brace_pos
] == '}':
716 if (not escape
) and (not in_quotes
):
721 elif s
[closing_brace_pos
] == '"':
723 in_quotes
= not in_quotes
727 closing_brace_pos
+= 1
729 curelem
= s
[pos
:closing_brace_pos
+ 1]
730 lst
.append(self
.parseArray(curelem
))
731 pos
= closing_brace_pos
+ 1
737 except LeaveLoopException
:
740 #lst = map(convertEscapes, lst)
743 def typecast(self
, colinfo
, value
):
745 typecast(rowinfo, value)
746 Convert certain postgreSQL data types into the appropiate python
752 _fn
, _ft
, _ds
, _is
, _p
, _s
, _nu
, _ia
= colinfo
757 # Convert string representation of the array into PgArray object.
758 _list
= self
.parseArray(value
)
759 return self
.handleArray(colinfo
, _list
)
762 if type(value
) is PgInt2Type
:
766 elif _ftv
== PG_INT4
:
767 if type(value
) is IntType
:
771 elif _ftv
== PG_INT8
or _ftv
== ROWID
:
772 if type(PgInt8
) is ClassType
:
773 if isinstance(value
, PgInt8
):
776 if type(value
) is PgInt8Type
:
779 elif _ftv
== PG_NUMERIC
:
780 if isinstance(value
, PgNumeric
):
784 return PgNumeric(value
, _p
, _s
)
785 except OverflowError:
786 # If we reached this point, then the precision and scale
787 # of the current field does not match the precision and
788 # scale of the first record in the result set (there are
789 # a few reasons why this can happen). Let PgNumeric
790 # figure out a precision and scale from the value.
791 return PgNumeric(value
)
792 elif _ftv
== PG_MONEY
:
793 if isinstance(value
, PgMoney
):
796 return PgMoney(value
).value
797 elif _ftv
== DATETIME
:
798 if type(value
) in [DateTimeType
, DateTimeDeltaType
]:
801 if _ftv
== PG_INTERVAL
:
802 return value
#self.interval2DateTimeDelta(value)
804 return value
#DateTime.ISO.ParseAny(value)
806 if isinstance(value
, PgBytea
) or type(value
) is PgLargeObjectType
:
808 elif type(value
) is IntType
:
809 return PgLargeObject(self
.conn
, value
)
811 return PgBytea(value
)
812 elif _ftv
== PG_REFCURSOR
:
813 return self
.__conn
.cursor(value
, isRefCursor
=PG_True
)
815 if isinstance(value
, PgOther
):
819 elif self
.__conn
.unicode_results \
820 and _ftv
in (PG_CHAR
, PG_BPCHAR
, PG_TEXT
, PG_VARCHAR
, PG_NAME
):
821 return unicode(value
, *self
.__conn
.client_encoding
)
822 # Other typecasting is not needed. It will be once support for
823 # the other built-in types (ie. box, line, inet, cidr, etc) are added.
827 def handleArray(self
, colinfo
, lst
):
828 # If the list is empty, just return the empty list.
833 _fn
, _ft
, _ds
, _is
, _p
, _s
, _nu
, _ia
= colinfo
837 for _i
in range(len(lst
)):
838 if isinstance(lst
[_i
], PgArray
):
839 lst
[_i
] = self
.handleArray(colinfo
, lst
[_i
])
840 elif _ftv
== PG_INT4
or _ftv
== ROWID
:
841 lst
[_i
] = int(lst
[_i
])
842 elif _ftv
== PG_INT8
:
843 lst
[_i
] = PgInt8(lst
[_i
])
844 elif _ftv
== PG_NUMERIC
:
846 lst
[_i
] = PgNumeric(lst
[_i
], _p
, _s
)
847 except OverflowError:
848 # If we reached this point, then the precision and scale
849 # of the current field does not match the precision and
850 # scale of the first record in the result set (there are
851 # a few reasons why this can happen). Let PgNumeric
852 # figure out a precision and scale from the value.
853 lst
[_i
] = PgNumeric(lst
[_i
])
854 elif _ftv
== PG_INT2
:
855 lst
[_i
] = PgInt2(lst
[_i
])
856 elif _ftv
== DATETIME
:
857 lst
[_i
] = DateTime
.ISO
.ParseAny(lst
[_i
])
858 elif _ftv
== PG_MONEY
:
859 if lst
[_i
][0] == '(':
860 lst
[_i
] = PgMoney(-float(replace(lst
[_i
][2:-1], ',', '')))
861 elif lst
[_i
][0] == '-':
862 lst
[_i
] = PgMoney(-float(replace(lst
[_i
][2:], ',', '')))
864 lst
[_i
] = PgMoney(float(replace(lst
[_i
][1:], ',', '')))
867 # There is no need to un-escape lst[_i], it's already been
868 # done when the PostgreSQL array was converted to a list
870 lst
[_i
] = PgBytea(lst
[_i
])
872 lst
[_i
] = PgLargeObject(self
.conn
, int(lst
[_i
]))
876 def getTypeInfo(self
, pgtype
):
878 return self
.__type
_cache
[pgtype
.value
]
880 _nl
= len(self
.__conn
.notices
)
881 _res
= self
.__conn
.conn
.query("SELECT typname, -1 , typelem "
883 "WHERE oid = %s" % pgtype
.value
)
885 if len(self
.__conn
.notices
) != _nl
:
886 raise Warning, self
.__conn
.notices
.pop()
888 _n
= _res
.getvalue(0, 0)
889 _p
= _res
.getvalue(0, 1)
890 _b
= _res
.getvalue(0, 2)
897 self
.__type
_cache
[pgtype
.value
] = (_n
, _p
, _i
, PgTypes(_b
))
899 return self
.__type
_cache
[pgtype
.value
]
901 #-----------------------------------------------------------------------+
904 # Description: A Python wrapper class for the PostgreSQL types that do |
905 # not (yet) have an implementation in python. The number |
906 # of types in this category will shrink as more wrappers |
909 # Note: A Python String is used to store the PostgreSQL type in |
911 #-----------------------------------------------------------------------+
914 def __init__(self
, value
):
915 if type(value
) is not StringType
:
916 raise TypeError, "argument must be a string."
920 if hasattr(value
, '__methods__'):
921 for i
in self
.value
.__methods
__:
922 exec 'self.%s = self.value.%s' % (i
, i
)
924 # This definition of __coerce__ will cause Python to always call the
925 # (existing) arithmatic operators for this class. We can the perform the
926 # appropiate operation on the base type, letting it decide what to do.
927 def __coerce__(self
, other
):
930 def __getitem__(self
, index
):
931 if type(index
) is SliceType
:
932 if index
.step
is None:
933 return PgOther(self
.value
[index
.start
:index
.stop
])
935 return PgOther(self
.value
[index
.start
:index
.stop
:index
.step
])
937 return self
.value
[index
];
939 def __setitem__(self
, index
, item
):
940 raise TypeError, "object doesn't support slice assignment"
942 def __delitem__(self
, index
):
943 raise TypeError, "object doesn't support slice deletion"
945 def __contains__(self
, item
):
946 return (item
in self
.value
)
948 if sys
.version_info
< (2, 0):
949 # They won't be defined if version is at least 2.0 final
950 def __getslice__(self
, i
, j
):
951 return PgOther(self
.value
[max(0, i
):max(0, j
)])
953 def __setslice__(self
, i
, j
, seq
):
954 raise TypeError, "object doesn't support slice assignment"
956 def __delslice__(self
, i
, j
):
957 raise TypeError, "object doesn't support slice deletion"
959 # NOTE: A string is being concatenated to a PgOther, so the result type
961 def __add__(self
, other
):
962 return PgOther((self
.value
+ other
))
964 # NOTE: A PgOther is being concatenated to a string, so the result type
966 def __radd__(self
, other
):
967 return (other
+ self
.value
)
969 def __mul__(self
, other
):
970 return PgOther((self
.value
* other
))
972 def __rmul__(self
, other
):
973 return PgOther((self
.value
* other
))
976 return repr(self
.value
)
979 return str(self
.value
)
982 return hash(self
.value
)
984 def __cmp__(self
, other
):
985 return cmp(self
.value
, other
)
987 def __rcmp__(self
, other
):
988 return cmp(other
, self
.value
)
990 def __lt__(self
, other
):
991 return self
.value
< other
993 def __le__(self
, other
):
994 return self
.value
<= other
996 def __eq__(self
, other
):
997 return self
.value
== other
999 def __ne__(self
, other
):
1000 return self
.value
!= other
1002 def __gt__(self
, other
):
1003 return self
.value
> other
1005 def __ge__(self
, other
):
1006 return self
.value
>= other
1008 # NOTE: A PgOther object will use the PgQuoteString() function in libpq.
1009 def _quote(self
, forArray
=0):
1011 return PgQuoteString(self
.value
, forArray
)
1014 #-----------------------------------------------------------------------+
1017 # Description: A Python wrapper class for PostgreSQL arrays. |
1018 # It is used so that the list type can be used as an arg- |
1019 # ument to Connection.execute() without being treated as |
1020 # a PostgreSQL array. |
1021 #-----------------------------------------------------------------------+
1024 def __init__(self
, value
=None):
1029 if type(value
) is not ListType
and not isinstance(value
, PgArray
):
1030 raise TypeError, "argument must be a list or a PgArray."
1032 # We have to insure that nested mutable sequences (list and PgArray)
1034 for i
in range(len(value
)):
1035 if type(value
[i
]) is ListType
or isinstance(value
[i
], PgArray
):
1036 value
[i
] = PgArray(value
[i
][:])
1040 # Define the methods used
1041 def append(self
, item
):
1042 if type(item
) is ListType
:
1043 item
= PgArray(item
)
1044 self
.value
.append(item
)
1046 def count(self
, item
):
1047 return self
.value
.count(item
)
1049 def extend(self
, item
):
1050 if type(item
) is ListType
:
1051 item
= PgArray(item
)
1052 self
.value
.extend(item
)
1054 def index(self
, item
):
1055 return self
.value
.index(item
)
1057 def insert(self
, key
, item
):
1058 if type(item
) is ListType
:
1059 item
= PgArray(item
)
1060 self
.value
.insert(key
, item
)
1062 def pop(self
, key
=-1):
1063 return self
.value
.pop(key
)
1065 def remove(self
, item
):
1066 self
.value
.remove(item
)
1069 self
.value
.reverse()
1071 def sort(self
, compfunc
=None):
1072 if compfunc
is None:
1075 self
.value
.sort(compfunc
)
1077 def __cmp__(self
, other
):
1078 if not isinstance(other
, PgArray
):
1079 return cmp(id(self
), id(other
))
1081 # PgArray objects are considered equal if:
1082 # 1. The lengh of the PgArray objects are equal and
1083 # 2. Each item[k] in the PgArray objects are equal.
1085 res
= cmp(len(self
), len(other
))
1089 for i
in range(len(self
.value
)):
1090 res
= cmp(self
.value
[i
], other
.value
[i
])
1097 return len(self
.value
)
1099 def __getitem__(self
, index
):
1100 if type(index
) is SliceType
:
1101 if index
.step
is None:
1102 return PgArray(self
.value
[index
.start
:index
.stop
])
1104 return PgArray(self
.value
[index
.start
:index
.stop
:index
.step
])
1106 return self
.value
[index
];
1108 def __setitem__(self
, index
, item
):
1109 if type(item
) is ListType
:
1110 item
= PgArray(item
)
1112 if type(index
) is SliceType
:
1113 if index
.step
is None:
1114 self
.value
[index
.start
:index
.stop
] = item
1116 self
.value
[index
.start
:index
.stop
:index
.step
] = item
1118 self
.value
[index
] = item
1120 def __delitem__(self
, index
):
1121 if type(index
) is SliceType
:
1122 if index
.step
is None:
1123 del self
.value
[index
.start
:index
.stop
]
1125 del self
.value
[index
.start
:index
.stop
:index
.step
]
1127 del self
.value
[index
];
1129 def __contains__(self
, item
):
1130 return (item
in self
.value
)
1132 if sys
.version_info
< (2, 0):
1133 # They won't be defined if version is at least 2.0 final
1134 def __getslice__(self
, i
, j
):
1135 return PgArray(self
.value
[max(0, i
):max(0, j
)])
1137 def __setslice__(self
, i
, j
, seq
):
1138 if type(seq
) is ListType
:
1140 self
.value
[max(0, i
):max(0, j
)] = seq
.value
1142 def __delslice__(self
, i
, j
):
1143 del self
.value
[max(0, i
):max(0, j
)]
1145 def __add__(self
, other
):
1146 return PgArray((self
.value
+ other
))
1148 def __radd__(self
, other
):
1149 return PgArray(other
+ self
.value
)
1151 def __iadd__(self
, other
):
1152 value
= value
+ other
1155 def __mul__(self
, other
):
1156 return PgArray((self
.value
* other
))
1158 def __rmul__(self
, other
):
1159 return PgArray((self
.value
* other
))
1161 def __imul__(self
, other
):
1162 value
= value
* other
1166 return repr(self
.value
)
1169 return str(self
.value
)
1171 # NOTE: A PgArray object will use the _handleArray() function to quote
1173 def _quote(self
, forArray
=0):
1175 return _handleArray(self
.value
)
1178 #-----------------------------------------------------------------------+
1181 # Description: A Python wrapper class for the PostgreSQL BYTEA type. |
1183 # Note: A Python String is used to store the PostgreSQL type in |
1185 #-----------------------------------------------------------------------+
1188 def __init__(self
, value
):
1189 if type(value
) is not StringType
:
1190 raise TypeError, "argument must be a string."
1194 if hasattr(value
, '__methods__'):
1195 for i
in self
.value
.__methods
__:
1196 exec 'self.%s = self.value.%s' % (i
, i
)
1198 # This definition of __coerce__ will cause Python to always call the
1199 # (existing) arithmatic operators for this class. We can the perform the
1200 # appropiate operation on the base type, letting it decide what to do.
1201 def __coerce__(self
, other
):
1202 return (self
, other
)
1204 def __getitem__(self
, index
):
1205 if type(index
) is SliceType
:
1206 if index
.step
is None:
1207 return PgBytea(self
.value
[index
.start
:index
.stop
])
1209 return PgBytea(self
.value
[index
.start
:index
.stop
:index
.step
])
1211 return self
.value
[index
];
1213 def __setitem__(self
, index
, item
):
1214 raise TypeError, "object doesn't support slice assignment"
1216 def __delitem__(self
, index
):
1217 raise TypeError, "object doesn't support slice deletion"
1219 def __contains__(self
, item
):
1220 return (item
in self
.value
)
1222 if sys
.version_info
< (2, 0):
1223 # They won't be defined if version is at least 2.0 final
1224 def __getslice__(self
, i
, j
):
1225 return PgBytea(self
.value
[max(0, i
):max(0, j
)])
1227 def __setslice__(self
, i
, j
, seq
):
1228 raise TypeError, "object doesn't support slice assignment"
1230 def __delslice__(self
, i
, j
):
1231 raise TypeError, "object doesn't support slice deletion"
1233 def __add__(self
, other
):
1234 return PgBytea((self
.value
+ other
))
1236 def __radd__(self
, other
):
1237 return PgBytea(other
+ self
.value
)
1239 def __mul__(self
, other
):
1240 return PgBytea((self
.value
* other
))
1242 def __rmul__(self
, other
):
1243 return PgBytea((self
.value
* other
))
1246 return repr(self
.value
)
1249 return str(self
.value
)
1252 return hash(self
.value
)
1254 def __cmp__(self
, other
):
1255 return cmp(self
.value
, other
)
1257 def __rcmp__(self
, other
):
1258 return cmp(other
, self
.value
)
1260 def __lt__(self
, other
):
1261 return self
.value
< other
1263 def __le__(self
, other
):
1264 return self
.value
<= other
1266 def __eq__(self
, other
):
1267 return self
.value
== other
1269 def __ne__(self
, other
):
1270 return self
.value
!= other
1272 def __gt__(self
, other
):
1273 return self
.value
> other
1275 def __ge__(self
, other
):
1276 return self
.value
>= other
1278 # NOTE: A PgBytea object will use the PgQuoteBytea() function in libpq
1279 def _quote(self
, forArray
=0):
1281 return PgQuoteBytea(self
.value
, forArray
)
1284 #-----------------------------------------------------------------------+
1287 # Description: A Python wrapper class for the PostgreSQL numeric type. |
1288 # It implements addition, subtraction, mulitplcation, and |
1289 # division of scaled, fixed precision numbers. |
1291 # Note: The PgNumeric class uses a Python Long type to store |
1292 # the PostgreSQL numeric type. |
1293 #-----------------------------------------------------------------------+
1296 def __init__(self
, value
, prec
=None, scale
=None):
1297 if type(value
) in [IntType
, LongType
] or value
is None:
1298 if prec
is None or scale
is None:
1300 "you must supply precision and scale when value is a " \
1301 "integer, long, or None"
1305 self
.__v
= long(value
)
1306 # Check to see if the value is too large for the given
1308 _v
= str(abs(value
))
1312 raise OverflowError, "value too large for PgNumeric"
1316 elif type(value
) in (FloatType
, StringType
):
1317 # Get the value to convert as a string.
1318 # The expected input is in the form of [+|-][d]*[.[d]*][e[d]+]
1320 # First get the value as a (trimmed) string
1321 if type(value
) is FloatType
:
1325 if len(_v
) == 0 or len(_v
) > 1:
1327 "invalid literal for PgNumeric: %s" % value
1330 # Save the sign character (if any) and remove from the string
1332 if _v
[0] in ('-', '+'):
1336 # Split the remaining string into int part, frac part and exponet
1340 # Ensure that _e and _v contains a sane value
1353 # Check the validity of the input
1354 if len(_ip
) == 0 and len(_fp
) == 0:
1356 "invalid literal for PgNumeric: %s" % value
1363 "invalid literal for PgNumeric: %s" % value
1368 raise OverflowError, "value too large for PgNumeric"
1371 raise OverflowError, "value too small for PgNumeric"
1373 # Create the string that will become the base (long) object
1379 _v
= _v
+ ("0" * (_exp
- _sc
))
1387 self
.__v
= long(_sign
+ _v
)
1390 "invalid literal for PgNumeric: %s" % value
1397 # Now adjust for the inputted scale (if any)
1401 _adj
= scale
- self
.__s
1403 self
.__v
= self
.__v
* (10L ** (scale
- self
.__s
))
1405 self
.__v
= self
._round
(self
.__v
, -_adj
)
1407 self
.__p
= self
.__p
+ _adj
1410 # Apply the inputted precision (if any)
1415 raise ValueError, "precision too large for PgNumeric"
1416 elif self
.__p
> prec
:
1417 raise OverflowError, "value too large for PgNumeric"
1420 elif isinstance(value
, PgNumeric
):
1421 # This is used to "cast" a PgNumeric to the specified precision
1422 # and scale. It can also make a copy of a PgNumeric.
1423 self
.__v
= value
.__v
1426 _ds
= scale
- value
.__s
1428 self
.__s
= value
.__s
1433 self
.__p
= value
.__p
1434 # Now we adjust the value to reflect the new scaling factor.
1437 self
.__v
= self
.__v
* 10
1439 self
.__v
= self
.__v
* (10L ** _ds
)
1441 self
.__v
= self
._round
(self
.__v
, -_ds
)
1442 if self
.__v
> (10L ** self
.__p
):
1443 raise OverflowError, "result exceeds precision of %d" % self
.__p
1445 raise TypeError, "value can not be converted to a PgNumeric."
1447 if self
.__s
> self
.__p
:
1449 "scale of %d exceeds precision of %d" % (self
.__s
, self
.__p
)
1451 # The value (10L ** self.__s) is used a lot. Save it as a constant
1452 # to save a (small) bit of time.
1454 self
.__sf
= 10L ** self
.__s
1456 def __fmtNumeric(self
, value
=None):
1462 # Check for a negative value and adjust if necessary
1470 # Check to see if the string representation of the python long has
1471 # a trailing 'L', if so, remove it. Python 1.5 has the trailing 'L',
1472 # Python 1.6 does not.
1476 # Check to see if the numeric is less than one and fix string if so.
1477 if len(_v
) <= self
.__s
:
1478 _v
= ("0" * (self
.__s
- len(_v
) + 1)) + _v
1481 _s
= "%s%s.%s" % (_sign
, _v
[:-(self
.__s
)], _v
[-(self
.__s
):])
1483 _s
= "%s%s" % (_sign
, _v
)
1487 return "<PgNumeric instance - precision: %d scale: %d value: %s>" % \
1488 (self
.__p
, self
.__s
, self
.__fmtNumeric
())
1491 return self
.__fmtNumeric
()
1496 def getPrecision(self
):
1499 def __coerce__(self
, other
):
1500 if isinstance(other
, PgNumeric
):
1502 elif type(other
) in [IntType
, LongType
]:
1505 _s
= _s
[:-1] # Work around v1.5/1.6 differences
1506 return (self
, PgNumeric(_s
))
1507 elif type(other
) == FloatType
:
1508 return (self
, PgNumeric(other
))
1511 def _round(self
, value
, drop
):
1513 return ((value
+ 5L) / 10L)
1515 return (((value
/ (10L ** (drop
- 1))) + 5L) / 10L)
1519 def __add__(self
, other
):
1520 _c
= self
.__coerce
__(other
)
1524 if self
.__s
< other
.__s
:
1525 _s
= self
.__v
* (other
.__sf
/ self
.__sf
)
1527 elif self
.__s
> other
.__s
:
1529 _o
= other
.__v
* (self
.__sf
/ other
.__sf
)
1534 mp
= max(self
.__p
- self
.__s
, other
.__p
- other
.__s
)
1535 ms
= max(self
.__s
, other
.__s
)
1537 # Check to see if the addition caused an increase in the precision
1538 # due to a carry. If so, compensate for it.
1539 if (v
/ (10L ** (mp
+ ms
))) > 0:
1542 return PgNumeric((_s
+ _o
), (mp
+ ms
), ms
)
1544 def __radd__(self
, other
):
1545 return self
.__add
__(other
)
1547 def __iadd__(self
, other
):
1548 _r
= self
.__add
__(other
)
1557 def __sub__(self
, other
):
1558 _c
= self
.__coerce
__(other
)
1562 if self
.__s
< other
.__s
:
1563 _s
= self
.__v
* (other
.__sf
/ self
.__sf
)
1565 elif self
.__s
> other
.__s
:
1567 _o
= other
.__v
* (self
.__sf
/ other
.__sf
)
1572 mp
= max(self
.__p
- self
.__s
, other
.__p
- other
.__s
)
1573 ms
= max(self
.__s
, other
.__s
)
1574 return PgNumeric((_s
- _o
), (mp
+ ms
), ms
)
1576 def __rsub__(self
, other
):
1577 return other
.__sub
__(self
)
1579 def __isub__(self
, other
):
1580 _r
= self
.__sub
__(other
)
1589 def __mul__(self
, other
):
1590 _c
= self
.__coerce
__(other
)
1594 _p
= self
.__v
* other
.__v
1595 return PgNumeric(_p
, self
.__p
+ other
.__p
, self
.__s
+ other
.__s
)
1597 def __rmul__(self
, other
):
1598 return self
.__mul
__(self
, other
)
1600 def __imul__(self
, other
):
1601 _r
= self
.__mul
__(other
)
1610 def __div__(self
, other
):
1611 _c
= self
.__coerce
__(other
)
1615 _n
= self
.__v
* other
.__sf
* self
.__sf
1617 _q
= self
._round
((_n
/ _d
), self
.__s
)
1618 return PgNumeric(_q
, self
.__p
, self
.__s
)
1620 def __rdiv__(self
, other
):
1621 return other
.__div
__(self
)
1623 def __idiv__(self
, other
):
1624 _r
= self
.__div
__(other
)
1633 def __cmp__(self
, other
):
1636 _c
= self
.__coerce
__(other
)
1640 if self
.__s
< other
.__s
:
1641 _s
= self
.__v
* (other
.__sf
/ self
.__sf
)
1643 elif self
.__s
> other
.__s
:
1645 _o
= other
.__v
* (self
.__sf
/ other
.__sf
)
1652 return PgNumeric(-self
.__v
, self
.__p
, self
.__s
)
1654 def __nonzero__(self
):
1655 return self
.__v
not in (None, 0)
1658 return PgNumeric(self
.__v
, self
.__p
, self
.__s
)
1662 return PgNumeric(self
.__v
, self
.__p
, self
.__s
)
1664 return PgNumeric(-self
.__v
, self
.__p
, self
.__s
)
1666 def _quote(self
, forArray
=0):
1669 return '"%s"' % self
.__fmtNumeric
()
1671 return "'%s'" % self
.__fmtNumeric
()
1675 return int(self
.__v
/ self
.__sf
)
1678 return self
.__v
/ self
.__sf
1680 def __float__(self
):
1683 return (float(v
/ s
) + (float(v
% s
) / float(s
)))
1685 def __complex__(self
):
1686 return complex(self
.__float
__())
1690 return hash(self
.__v
)
1691 v
= self
.__v
/ self
.__sf
1692 if (v
* self
.__sf
) == self
.__v
:
1694 return hash(float(self
))
1696 #-----------------------------------------------------------------------+
1699 # Description: A Python wrapper class for the PostgreSQL Money type. |
1700 # It's primary purpose it to check for overflow during |
1701 # calulations and to provide formatted output. |
1703 # Note: The PgMoney class uses a Python Floating point number |
1704 # represent a PostgreSQL money type. |
1705 #-----------------------------------------------------------------------+
1708 def __init__(self
, value
):
1713 if type(value
) is StringType
:
1715 self
.value
= PgMoney(-float(replace(value
[2:-1], ',', '')))
1716 elif value
[0] == '-':
1717 self
.value
= PgMoney(-float(replace(value
[2:], ',', '')))
1719 self
.value
= PgMoney(float(replace(value
[1:], ',', '')))
1721 self
.value
= float(value
)
1723 if self
.value
< -21474836.48 or self
.value
> 21474836.47:
1724 raise OverflowError, 'money initialization'
1727 def __checkresult(self
, value
, op
):
1728 if value
< -21474836.48 or value
> 21474836.47:
1729 raise OverflowError, 'money %s' % op
1730 return PgMoney(value
)
1732 def __coerce__(self
, other
):
1735 res
= coerce(self
.value
, other
)
1742 return hash(self
.value
)
1744 def __cmp__(self
, other
):
1745 return cmp(self
.value
, other
)
1747 def __add__(self
, other
):
1748 return self
.__checkresult
(self
.value
+ other
, "addition")
1750 def __sub__(self
, other
):
1751 return self
.__checkresult
(self
.value
- other
, "subtraction")
1753 def __mul__(self
, other
):
1754 return self
.__checkresult
(self
.value
* other
, "mulitplication")
1756 def __div__(self
, other
):
1757 return self
.__checkresult
(self
.value
/ other
, "division")
1759 def __divmod__(self
, other
):
1760 _a
, _b
= divmod(self
.value
, other
)
1761 return (self
.__checkresult
(_a
, "divmod"), _b
)
1763 def __pow__(self
, other
, modulus
=None):
1764 return self
.__checkresult
(pow(self
.value
, other
, modulus
), "pow")
1766 def __radd__(self
, other
):
1767 return self
.__checkresult
(other
+ self
.value
, "addition")
1769 def __rsub__(self
, other
):
1770 return self
.__checkresult
(other
- self
.value
, "subtraction")
1772 def __rmul__(self
, other
):
1773 return self
.__checkresult
(other
* self
.value
, "multiplication")
1775 def __rdiv__(self
, other
):
1776 return self
.__checkresult
(other
/ self
.value
, "division")
1778 def __rdivmod__(self
, other
):
1779 _a
, _b
= divmod(other
, self
.value
)
1780 return (self
.__checkresult
(_a
, "divmod"), _b
)
1782 def __rpow__(self
, other
, modulus
=None):
1783 return self
.__checkresult
(pow(other
, self
.value
, modulus
), "pow")
1786 return self
.__checkresult
(self
.value
* -1, "negation")
1792 return self
.__checkresult
(abs(self
.value
), "abs")
1794 def __complex__(self
):
1795 return complex(self
.value
)
1798 return int(self
.value
)
1801 return long(self
.value
)
1803 def __float__(self
):
1804 return self
.value
# PgMoney is already a float :-)
1807 return '%.2f' % self
.value
1810 _s
= '%.2f' % abs(self
.value
)
1811 _i
= string
.rfind(_s
, '.')
1813 for _j
in range(_c
):
1815 _s
= '%s,%s' % (_s
[:_i
], _s
[_i
:])
1816 if self
.value
< 0.0:
1821 def _quote(self
, forArray
=0):
1824 return '"%s"' % str(self
.value
)
1826 return "'%s'" % str(self
.value
)
1829 #-----------------------------------------------------------------------+
1832 # Description: A Python wrapper class for the PostgreSQL int8 type. |
1833 # It's primary purpose it to check for overflow during |
1836 # Note: The PgInt8 class uses a Python Long Integer to hold |
1837 # the PostgreSQL int8 type. |
1839 # Note: This class will only be defined if the C implementation |
1840 # of the PgInt8 object was not imported with/from libpq. |
1841 #-----------------------------------------------------------------------+
1843 if dir().count('PgInt8') == 0: # Only define this class is PgInt8 wasn't
1844 # brought in via libpq.
1846 def __init__(self
, value
):
1851 self
.value
= long(value
)
1852 if self
.value
< -9223372036854775808L or \
1853 self
.value
> 9223372936854775807L:
1854 raise OverflowError, 'int8 initialization'
1856 def __checkresult(self
, value
, op
):
1857 if value
< -9223372036854775808L or value
> 9223372936854775807L:
1858 raise OverflowError, 'int8 %s' % op
1859 return PgInt8(value
)
1861 def __coerce__(self
, other
):
1864 res
= coerce(self
.value
, other
)
1871 return hash(self
.value
)
1873 def __cmp__(self
, other
):
1874 return cmp(self
.value
, other
)
1876 def __nonzero__(self
):
1877 return self
.value
!= 0
1879 def __add__(self
, other
):
1880 return self
.__checkresult
(self
.value
+ other
, "addition")
1882 def __sub__(self
, other
):
1883 return self
.__checkresult
(self
.value
- other
, "subtraction")
1885 def __mul__(self
, other
):
1886 return self
.__checkresult
(self
.value
* other
, "mulitplication")
1888 def __div__(self
, other
):
1889 return self
.__checkresult
(self
.value
/ other
, "division")
1891 def __divmod__(self
, other
):
1892 _a
, _b
= divmod(self
.value
, other
)
1893 return (self
.__checkresult
(_a
, "divmod"), _b
)
1895 def __pow__(self
, other
, modulus
=None):
1896 return self
.__checkresult
(pow(self
.value
, other
, modulus
), "pow")
1898 def __lshift__(self
, other
):
1899 return self
.__checkresult
(self
.value
<< other
, 'lshift')
1901 def __rshift__(self
, other
):
1902 return self
.__checkresult
(self
.value
>> other
, 'rshift')
1904 def __and__(self
, other
):
1905 return self
.__checkresult
(self
.value
& other
, 'and')
1907 def __xor__(self
, other
):
1908 return self
.__checkresult
(self
.value ^ other
, 'xor')
1910 def __or__(self
, other
):
1911 return self
.__checkresult
(self
.value | other
, 'or')
1913 def __radd__(self
, other
):
1914 return self
.__checkresult
(other
+ self
.value
, "addition")
1916 def __rsub__(self
, other
):
1917 return self
.__checkresult
(other
- self
.value
, "subtraction")
1919 def __rmul__(self
, other
):
1920 return self
.__checkresult
(other
* self
.value
, "mulitplication")
1922 def __rdiv__(self
, other
):
1923 return self
.__checkresult
(other
/ self
.value
, "division")
1925 def __rdivmod__(self
, other
):
1926 _a
, _b
= divmod(other
, self
.value
)
1927 return (self
.__checkresult
(_a
, "divmod"),
1928 self
.__checkresult
(_b
, "divmod"))
1930 def __rpow__(self
, other
, modulus
=None):
1931 return self
.__checkresult
(pow(other
, self
.value
, modulus
), "pow")
1933 def __rlshift__(self
, other
):
1934 return self
.__checkresult
(other
<< self
.value
, 'lshift')
1936 def __rrshift__(self
, other
):
1937 return self
.__checkresult
(other
>> self
.value
, 'rshift')
1939 def __rand__(self
, other
):
1940 return self
.__checkresult
(other
& self
.value
, 'and')
1942 def __rxor__(self
, other
):
1943 return self
.__checkresult
(other ^ self
.value
, 'xor')
1945 def __ror__(self
, other
):
1946 return self
.__checkresult
(other | self
.value
, 'or')
1949 return self
.__checkresult
(neg(self
.value
), 'neg')
1952 return self
.__checkresult
(pos(self
.value
), 'pos')
1955 return self
.__checkresult
(abs(self
.value
), 'abs')
1957 def __complex__(self
):
1958 return complex(self
)
1961 return int(self
.value
)
1964 return self
.value
# PgInt8 is already a Long.
1966 def __float__(self
):
1967 return float(self
.value
)
1969 def __complex__(self
):
1970 return complex(self
.value
)
1973 return hex(self
.value
)
1976 return oct(self
.value
)
1979 return repr(self
.value
)
1982 return str(self
.value
)
1984 def _quote(self
, forArray
=0):
1985 if self
.value
is not None:
1995 #-----------------------------------------------------------------------+
1996 # Name: PgResultSet |
1998 # Description: This class defines the DB-API query result set for a |
1999 # single row. It emulates a sequence with the added |
2000 # feature of being able to reference an attribute by |
2001 # column name in addition to a zero-based numeric index. |
2003 # This class isn't used directly, instead it's used as a |
2004 # base class for the actual result set class created with |
2005 # make_PgResultSetClass. |
2007 #-----------------------------------------------------------------------+
2011 # It may not be obvious what self.__class__ does:
2012 # Apart from the __init__ method, all methods are called on instances of a
2013 # class dynamically created make_PgResultSetClass, which means that when
2014 # you call a method, self.__class__ is *not* PgResultSet, but a subclass of
2015 # it created with make_PgResultSetClass (using the new module). The
2016 # subclass will have a class attribute called _xlatkey, which is a mapping
2017 # of column names to column positions.
2019 def __init__(self
, value
):
2020 self
.__dict
__['baseObj'] = value
2022 def __getattr__(self
, key
):
2023 # When retrieving column data by name as an attribute, we must be
2024 # aware that a column name can be defiend with mixed-case within the
2025 # database. Because of this we must first check for an exact match
2026 # with the given key. If that fails, then we match with the key that
2027 # has been changed to lower case. Note: we are relying on the fact
2028 # that PostgreSQL sends column names that are not defined with mixed-
2029 # case to the client as lower-case names.
2031 if self
._xlatkey
.has_key(key
):
2032 return self
.baseObj
[self
._xlatkey
[key
]]
2033 if self
._xlatkey
.has_key(keyl
):
2034 return self
.baseObj
[self
._xlatkey
[keyl
]]
2035 raise AttributeError, key
2037 # We define a __setattr__ routine that will only allow the attributes that
2038 # are the column names to be updated. All other attributes are read-only.
2039 def __setattr__(self
, key
, value
):
2040 if key
in ('baseObj', '_xlatkey', '_desc_'):
2041 raise AttributeError, "%s is read-only." % key
2043 # Try an exact match first, then the case-insensitive match.
2044 # See comment in __getattr__ for details.
2046 if self
._xlatkey
.has_key(key
):
2047 self
.__dict
__['baseObj'][self
._xlatkey
[key
]] = value
2048 elif self
._xlatkey
.has_key(keyl
):
2049 self
.__dict
__['baseObj'][self
._xlatkey
[keyl
]] = value
2051 raise AttributeError, key
2054 return len(self
.baseObj
)
2056 def __getitem__(self
, key
):
2057 if isinstance(key
, StringType
):
2058 # Try an exact match first, then the case-insensitive match.
2059 # See comment in __getattr__ for details.
2061 key
= self
._xlatkey
[key
]
2063 key
= self
._xlatkey
[key
.lower()]
2064 return self
.baseObj
[key
]
2066 def __setitem__(self
, key
, value
):
2067 if isinstance(key
, StringType
):
2068 # Try an exact match first, then the case-insensitive match.
2069 # See comment in __getattr__ for details.
2071 key
= self
._xlatkey
[key
]
2073 key
= self
._xlatkey
[key
.lower()]
2074 self
.baseObj
[key
] = value
2076 def __contains__(self
, key
):
2077 return self
.has_key(key
)
2079 def __getslice__(self
, i
, j
):
2080 klass
= make_PgResultSetClass(self
._desc
_[i
:j
])
2081 obj
= klass(self
.baseObj
[i
:j
])
2085 return repr(self
.baseObj
)
2088 return str(self
.baseObj
)
2090 def __cmp__(self
, other
):
2091 return cmp(self
.baseObj
, other
)
2093 def description(self
):
2098 for _i
in self
._desc
_:
2103 return self
.baseObj
[:]
2107 for i
in range(len(self
.baseObj
)):
2108 _items
.append((self
._desc
_[i
][0], self
.baseObj
[i
]))
2111 def has_key(self
, key
):
2112 # Try an exact match first, then the case-insensitive match.
2113 # See comment in __getattr__ for details.
2114 if not self
._xlatkey
.has_key(key
):
2116 return self
._xlatkey
.has_key(key
)
2118 def get(self
, key
, defaultval
=None):
2120 if isinstance(key
, StringType
):
2121 # Try an exact match first, then the case-insensitive match.
2122 # See comment in __getattr__ for details.
2124 key
= self
._xlatkey
[key
]
2126 key
= self
._xlatkey
[key
.lower()]
2131 def make_PgResultSetClass(description
, mapname
=None):
2132 """Dynamically create a new subclass of PgResultSet."""
2133 klass
= new
.classobj("PgResultSetConcreteClass", (PgResultSet
,), {})
2134 klass
.__dict
__['_desc_'] = description
2136 klass
.__dict
__['_xlatkey'] = {}
2138 for _i
in range(len(description
)):
2139 klass
.__dict
__['_xlatkey'][description
[_i
][0]] = _i
2141 for k
, v
in mapname
.items():
2142 klass
.__dict
__['_xlatkey'][k
] = v
2146 #-----------------------------------------------------------------------+
2147 # Define the PgSQL function calls: |
2149 # connect() -- connect to a PostgreSQL database. |
2150 # _handleArray() -- Transform a PgArray class into a string rep- |
2151 # resenting a PostgreSQL array. |
2152 # _quote() -- Transform a Python object representing a |
2153 # PostgreSQL type into a appropiately quoted |
2154 # string that can be sent to the database in a |
2155 # UPDATE/INSERT statement. _quote() calls the |
2156 # _handleArray() function to quote arrays. |
2157 # _quoteall() -- transforms all elements of a list or diction- |
2158 # ary using _quote. |
2159 # dateTimeDelta2Interval() -- converts a DateTimeDelta type into |
2160 # a string PostgreSQL accepts as a interval. |
2161 #-----------------------------------------------------------------------+
2163 def connect(dsn
=None, user
=None, password
=None, host
=None, database
=None,
2164 port
=None, options
=None, tty
=None, client_encoding
=None,
2165 unicode_results
=None):
2167 connection = PgSQL.connect(dsn[, user, password, host, database, port,
2168 options, tty] [, client_encoding]
2169 [, unicode_results])
2170 Opens a connection to a PostgreSQL database."""
2174 # Try getting values from the DSN first.
2177 params
= string
.split(dsn
, ":")
2178 if params
[0] != '': _d
["host"] = params
[0]
2179 if params
[1] != '': _d
["port"] = params
[1]
2180 if params
[2] != '': _d
["dbname"] = params
[2]
2181 if params
[3] != '': _d
["user"] = params
[3]
2182 if params
[4] != '': _d
["password"] = params
[4]
2183 if params
[5] != '': _d
["options"] = params
[5]
2184 if params
[6] != '': _d
["tty"] = params
[6]
2188 # Override from the keyword arguments, if needed.
2189 if (user
is not None): _d
["user"] = user
2190 if (password
is not None): _d
["password"] = password
2191 if (host
is not None):
2194 params
= string
.split(host
, ":")
2195 _d
["host"] = params
[0]
2196 _d
["port"] = params
[1]
2199 if (database
is not None): _d
["dbname"] = database
2200 if (port
is not None): _d
["port"] = port
2201 if (options
is not None): _d
["options"] = options
2202 if (tty
is not None): _d
["tty"] = tty
2204 # Build up the connection info string passed to PQconnectdb
2205 # via the constructor to Connection.
2209 connInfo
= "%s%s=%s " % (connInfo
, i
, _d
[i
])
2211 return Connection(connInfo
, client_encoding
, unicode_results
)
2213 def _handleArray(value
):
2215 _handleArray(list) -> string
2216 This function handle the transformation of a Python list into a string that
2217 can be used to update a PostgreSQL array attribute."""
2219 #Check for, and handle an empty list.
2227 elif isinstance(_i
, PgArray
):
2228 _j
= _j
+ _handleArray(_i
)[1:-1] + ','
2229 elif hasattr(_i
, '_quote'):
2230 _j
= '%s%s,' % (_j
, _i
._quote
(1))
2231 elif type(_i
) is DateTimeType
:
2232 _j
= '%s"%s",' % (_j
, _i
)
2233 elif type(_i
) is DateTime
.DateTimeDeltaType
:
2234 _j
= '%s"%s",' % (_j
, dateTimeDelta2Interval(_i
))
2235 elif type(_i
) is PgInt2Type
or isinstance(_i
, PgInt8Type
):
2236 _j
= '%s%s,' % (_j
, str(_i
))
2238 _j
= '%s%s,' % (_j
, PgQuoteString(str(_i
), 1))
2240 return _j
[:-1] + "}'"
2244 _quote(value) -> string
2245 This function transforms the Python value into a string suitable to send
2246 to the PostgreSQL database in a insert or update statement. This function
2247 is automatically applied to all parameter sent vis an execute() call.
2248 Because of this an update/insert statement string in an execute() call
2249 should only use '%s' [or '%(name)s'] for variable subsitution without any
2254 elif hasattr(value
, '_quote'):
2255 return value
._quote
()
2256 elif type(value
) is DateTimeType
:
2257 return "'%s'" % value
2258 elif type(value
) is DateTimeDeltaType
:
2259 return "'%s'" % dateTimeDelta2Interval(value
)
2260 elif isinstance(value
, StringType
):
2261 return PgQuoteString(value
)
2262 elif isinstance(value
, LongType
):
2267 def _quoteall(vdict
):
2269 _quoteall(vdict)->dict
2270 Quotes all elements in a list or dictionary to make them suitable for
2273 if type(vdict
) is DictType
or isinstance(vdict
, PgResultSet
):
2275 for k
, v
in vdict
.items():
2277 elif type(vdict
) in (StringType
, UnicodeType
):
2278 # Note: a string is a SequenceType, but is treated as a single
2279 # entity, not a sequence of characters.
2280 t
= (_quote(vdict
), )
2281 elif type(vdict
) in [ListType
, TupleType
]:
2282 t
= tuple(map(_quote
, vdict
))
2285 "argument to _quoteall must be a sequence or dictionary!"
2289 def dateTimeDelta2Interval(interval
):
2291 DateTimeDelta2Interval - Converts a DateTimeDelta to an interval string\n
2292 The input format is [+-]DD:HH:MM:SS.ss\n
2293 The output format is DD days HH:MM:SS.ss [ago]\n
2296 if type(interval
) is DateTimeDeltaType
:
2306 return '%s:%s:%s %s' % (s
[0], s
[1], s
[2], ago
)
2308 return '%s days %s:%s:%s %s' % (s
[0], s
[1], s
[2], s
[3], ago
)
2310 raise TypeException
, "DateTimeDelta2Interval requires a DataTimeDelta."
2312 #-----------------------------------------------------------------------+
2313 # Name: Connection |
2315 # Description: Connection defines the Python DB-API 2.0 connection |
2316 # object. See the DB-API 2.0 specifiaction for details. |
2317 #-----------------------------------------------------------------------+
2320 """Python DB-API 2.0 Connection Object."""
2322 def __init__(self
, connInfo
, client_encoding
=None, unicode_results
=None):
2324 self
.__dict
__["conn"] = PQconnectdb(connInfo
)
2325 except Exception, m
:
2326 # The connection to the datadata failed.
2327 # Clean up the Connection object that was created.
2328 # Note: _isOpen must be defined for __del__ to work.
2329 self
.__dict
__["_isOpen"] = None
2331 raise DatabaseError
, m
2333 self
.__dict
__["autocommit"] = 0
2334 self
.__dict
__["TransactionLevel"] = ""
2335 self
.__dict
__["notices"] = self
.conn
.notices
2336 self
.__dict
__["inTransaction"] = 0
2337 self
.__dict
__["version"] = self
.conn
.version
2338 self
.__dict
__["_isOpen"] = 1
2339 self
.__dict
__["_cache"] = TypeCache(self
)
2341 self
.__dict
__["cursors"] = []
2343 self
.__dict
__["cursors"] = weakref
.WeakValueDictionary()
2345 self
.unicode_results
= unicode_results
2346 if type(client_encoding
) in (TupleType
, ListType
):
2347 self
.client_encoding
= client_encoding
2349 self
.client_encoding
= (client_encoding
or getdefaultencoding(),)
2353 self
.close() # Ensure that the connection is closed.
2355 def __setattr__(self
, name
, value
):
2356 if name
== "autocommit":
2358 raise InterfaceError
, \
2359 "Can't delete the autocommit attribute."
2360 # Don't allow autocommit to change if there are any opened cursor
2361 # associated with this connection.
2362 if self
.__anyLeft
():
2364 # If the are cursors left, but weak references are not
2365 # available, garbage collect any cursors that are only
2366 # referenced in self.cursors.
2370 if len(self
.cursors
) > 0:
2371 raise AttributeError, \
2372 "Can't change autocommit when a cursor is active."
2374 raise AttributeError, \
2375 "Can't change autocommit when a cursor is active."
2377 # It's possible that the connection can still have an open
2378 # transaction, even though there are no active cursors.
2380 if self
.inTransaction
:
2384 self
.__dict
__[name
] = 1
2386 self
.__dict
__[name
] = 0
2387 elif name
== "TransactionLevel":
2389 raise InterfaceError
, \
2390 "Can't delete the TransactinLevel attribute."
2391 # Don't allow TransactionLevel to change if there are any opened
2392 # cursors associated with this connection.
2393 if self
.__anyLeft
():
2395 # If the are cursors left, but weak references are not
2396 # available, garbage collect any cursors that are only
2397 # referenced in self.cursors.
2401 if len(self
.cursors
) > 0:
2402 raise AttributeError, \
2403 "Can't change TransactionLevel when a cursor is active."
2405 raise AttributeError, \
2406 "Can't change TransactionLevel when a cursor is active."
2408 # It's possible that the connection can still have an open
2409 # transaction, even though there are no active cursors.
2411 if self
.inTransaction
:
2414 if type(value
) is not StringType
:
2415 raise ValueError, "TransactionLevel must be a string."
2417 if value
.upper() in [ "", "READ COMMITTED", "SERIALIZABLE" ]:
2418 self
.__dict
__[name
] = value
.upper()
2421 'TransactionLevel must be: "", "READ COMMITTED", or "SERIALIZABLE"'
2422 elif name
in ('unicode_results', 'client_encoding'):
2423 self
.__dict
__[name
] = value
2424 elif self
.__dict
__.has_key(name
):
2425 raise AttributeError, "%s is read-only." % name
2427 raise AttributeError, name
2429 def __closeCursors(self
, flag
=0):
2431 __closeCursors() - closes all cursors associated with this connection"""
2432 if self
.__anyLeft
():
2434 curs
= self
.cursors
[:]
2436 curs
= map(lambda x
: x(), self
.cursors
.data
.values())
2444 return self
.inTransaction
2446 def __anyLeft(self
):
2448 return len(self
.cursors
) > 0
2450 return len(self
.cursors
.data
.keys()) > 0
2452 def __gcCursors(self
):
2453 # This routine, which will be called only if weak references are not
2454 # available, will check the reference counts of the cursors in the
2455 # connection.cursors list and close any that are only referenced
2456 # from that list. This will clean up deleted cursors.
2458 for i
in self
.cursors
[:]:
2459 # Check the reference count. It will be 4 if it only exists in
2460 # self.cursors. The magic number for is derived from the fact
2461 # that there will be 1 reference count for each of the follwoing:
2462 # self.cursors, self.cursors[:], i, and as the argument to
2465 if getrefcount(i
) < 5:
2468 def __setupTransaction(self
):
2470 __setupTransaction()
2471 Internal routine that will set up a transaction for this connection.\n"""
2472 self
.conn
.query("BEGIN WORK")
2473 if self
.TransactionLevel
!= "":
2474 _nl
= len(self
.notices
)
2475 self
.conn
.query('SET TRANSACTION ISOLATION LEVEL %s' %
2476 self
.TransactionLevel
)
2477 if len(self
.notices
) != _nl
:
2478 raise Warning, self
.notices
.pop()
2479 self
.__dict
__["inTransaction"] = 1
2485 Close the connection now (rather than whenever __del__ is called).
2486 Any active cursors for this connection will be closed and the connection
2487 will be unusable from this point forward.\n"""
2489 if not self
._isOpen
:
2490 raise InterfaceError
, "Connection is already closed."
2492 if self
.__closeCursors
(1):
2494 _nl
= len(self
.conn
.notices
)
2495 self
.conn
.query("ROLLBACK WORK")
2496 if len(self
.notices
) != _nl
:
2497 raise Warning, self
.notices
.pop()
2501 self
.__dict
__["_cache"] = None
2502 self
.__dict
__["_isOpen"] = 0
2503 self
.__dict
__["autocommit"] = None
2504 self
.__dict
__["conn"] = None
2505 self
.__dict
__["cursors"] = None
2506 self
.__dict
__["inTransaction"] = 0
2507 self
.__dict
__["TransactionLevel"] = None
2508 self
.__dict
__["version"] = None
2509 self
.__dict
__["notices"] = None
2514 Commit any pending transactions to the database.\n"""
2516 if not self
._isOpen
:
2517 raise InterfaceError
, "Commit failed - Connection is not open."
2520 raise InterfaceError
, "Commit failed - autocommit is on."
2522 if self
.__closeCursors
():
2523 self
.__dict
__["inTransaction"] = 0
2524 _nl
= len(self
.conn
.notices
)
2525 res
= self
.conn
.query("COMMIT WORK")
2526 if len(self
.notices
) != _nl
:
2527 raise Warning, self
.notices
.pop()
2528 if res
.resultStatus
!= COMMAND_OK
:
2529 raise InternalError
, "Commit failed - reason unknown."
2534 Rollback to the start of any pending transactions.\n"""
2536 if not self
._isOpen
:
2537 raise InterfaceError
, "Rollback failed - Connection is not open."
2540 raise InterfaceError
, "Rollback failed - autocommit is on."
2542 if self
.__closeCursors
():
2543 self
.__dict
__["inTransaction"] = 0
2544 _nl
= len(self
.conn
.notices
)
2545 res
= self
.conn
.query("ROLLBACK WORK")
2546 if len(self
.notices
) != _nl
:
2547 raise Warning, self
.notices
.pop()
2548 if res
.resultStatus
!= COMMAND_OK
:
2549 raise InternalError
, \
2550 "Rollback failed - %s" % res
.resultErrorMessage
2552 def cursor(self
, name
=None, isRefCursor
=PG_False
):
2555 Returns a new 'Cursor Object' (optionally named 'name')."""
2557 if not self
._isOpen
:
2558 raise InterfaceError
, \
2559 "Create cursor failed - Connection is not open."
2561 return Cursor(self
, name
, isRefCursor
)
2563 def binary(self
, string
=None):
2566 Returns a new 'Large Object'. If sting is present, it is used to
2567 initialize the large object."""
2569 if not self
._isOpen
:
2570 raise InterfaceError
, \
2571 "Creation of large object failed - Connection is not open."
2574 raise InterfaceError
, \
2575 "Creation of large object failed - autocommit is on."
2577 _nl
= len(self
.notices
)
2579 # Ensure that we are in a transaction for working with large objects
2580 if not self
.inTransaction
:
2581 self
.__setupTransaction
()
2584 _lo
= self
.conn
.lo_creat(INV_READ | INV_WRITE
)
2586 if len(self
.notices
) != _nl
:
2587 raise Warning, self
.notices
.pop()
2594 if len(self
.notices
) != _nl
:
2595 if self
.inTransaction
:
2596 self
.conn
.query("ROLLBACK WORK")
2597 raise Warning, self
.conn
.notices
.pop()
2601 def unlink(self
, lobj
):
2603 unlink(OID|PgLargeObject)
2604 Remove a large object from the database inversion file syste."""
2606 if not self
._isOpen
:
2607 raise InterfaceError
, \
2608 "Unlink of large object failed - Connection is not open."
2610 if not self
.version
.post70
and self
.inTransaction
:
2611 raise NotSupportedError
, \
2612 "unlink of a PostgreSQL Large Object in a transaction"
2614 if type(lobj
) is IntType
:
2616 elif type(lobj
) is PgLargeObjectType
:
2619 _nl
= len(self
.conn
.notices
)
2620 res
= self
.conn
.lo_unlink(oid
)
2621 if len(self
.notices
) != _nl
:
2622 raise Warning, self
.notices
.pop()
2626 #-----------------------------------------------------------------------+
2629 # Description: Cursor defines the Python DB-API 2.0 cursor object. |
2630 # See the DB-API 2.0 specification for details. |
2631 #-----------------------------------------------------------------------+
2634 """Python DB-API 2.0 Cursor Object."""
2636 def __init__(self
, conn
, name
, isRefCursor
=PG_False
):
2637 if not isinstance(conn
, Connection
):
2638 raise TypeError, "Cursor requires a connection."
2640 # Generate a unique name for the cursor is one is not given.
2643 raise TypeError, "Reference cursor requires a name."
2644 name
= "PgSQL_%08X" % id(self
)
2645 elif type(name
) is not StringType
:
2646 raise TypeError, "Cursor name must be a string."
2648 # Define the public variables for this cursor.
2649 self
.__dict
__["arraysize"] = 1
2651 # Define the private variables for this cursor.
2653 self
.__dict
__["conn"] = conn
2655 self
.__dict
__["conn"] = weakref
.proxy(conn
)
2656 self
.__dict
__["name"] = name
2658 # This needs to be defined here sot that the initial call to __reset()
2660 self
.__dict
__["closed"] = None
2663 # _varhdrsz is the length (in bytes) of the header for variable
2664 # sized postgreSQL data types.
2666 self
.__dict
__["_varhdrsz"] = 4
2668 # Add ourselves to the list of cursors for our owning connection.
2670 self
.conn
.cursors
.append(self
)
2671 if len(self
.conn
.cursors
) > 1:
2672 # We have additional cursors, garbage collect them.
2673 self
.conn
._Connection
__gcCursors
()
2675 self
.conn
.cursors
[id(self
)] = self
2677 if not self
.conn
.autocommit
:
2678 # Only the first created cursor begins the transaction.
2679 if not self
.conn
.inTransaction
:
2680 self
.conn
._Connection
__setupTransaction
()
2681 self
.__dict
__["PgResultSetClass"] = None
2684 # Ok -- we've created a cursor, we will pre-fetch the first row in
2685 # order to make the description array. Note: the first call to
2686 # fetchXXX will return the pre-fetched record.
2687 self
.__dict
__["closed"] = 0
2688 self
.res
= self
.conn
.conn
.query('FETCH 1 FROM "%s"' % self
.name
)
2689 self
._rows
_ = self
.res
.ntuples
2694 # Ensure that the cursor is closed when it is deleted. This takes
2695 # care of some actions that needs to be completed when a cursor is
2696 # deleted, such as disassociating the cursor from the connection
2697 # and closing an open transaction if this is the last cursor for
2704 if (self
.closed
== 0) and self
.conn
.inTransaction
:
2706 self
.conn
.conn
.query('CLOSE "%s"' % self
.name
)
2712 self
.__dict
__["res"] = None
2713 # closed is a trinary variable:
2714 # == None => Cursor has not been opened.
2715 # == 0 => Cursor is open.
2716 # == 1 => Curosr is closed.
2717 self
.__dict
__["closed"] = None
2718 self
.__dict
__["description"] = None
2719 self
.__dict
__["oidValue"] = None
2720 self
.__dict
__["_mapname"] = None
2721 self
.__dict
__["_rows_"] = 0
2722 self
.__dict
__["_idx_"] = 1
2723 self
.__dict
__["rowcount"] = -1
2725 def __setattr__(self
, name
, value
):
2727 raise InterfaceError
, "Operation failed - the cursor is closed."
2729 if name
in ["rowcount", "oidValue", "description"]:
2730 raise AttributeError, "%s is read-only." % name
2731 elif self
.__dict
__.has_key(name
):
2732 self
.__dict
__[name
] = value
2734 raise AttributeError, name
2736 def __unicodeConvert(self
, obj
):
2737 if type(obj
) is StringType
:
2739 elif type(obj
) is UnicodeType
:
2740 return obj
.encode(*self
.conn
.client_encoding
)
2741 elif type(obj
) in (ListType
, TupleType
):
2744 if type(item
) is UnicodeType
:
2745 converted_obj
.append(item
.encode(*self
.conn
.client_encoding
))
2747 converted_obj
.append(item
)
2748 return converted_obj
2749 elif type(obj
) is DictType
:
2751 for k
, v
in obj
.items():
2752 if type(v
) is UnicodeType
:
2753 converted_obj
[k
] = v
.encode(*self
.conn
.client_encoding
)
2755 converted_obj
[k
] = v
2756 return converted_obj
2757 elif isinstance(obj
, PgResultSet
):
2758 obj
= copy
.copy(obj
)
2759 for k
, v
in obj
.items():
2760 if type(v
) is UnicodeType
:
2761 obj
[k
] = v
.encode(*self
.conn
.client_encoding
)
2766 def __fetchOneRow(self
):
2767 if self
._idx
_ >= self
._rows
_:
2768 self
.__dict
__['rowcount'] = 0
2773 _c
= self
.conn
._cache
2774 for _i
in range(self
.res
.nfields
):
2775 _j
.append(_c
.typecast(self
.description
[_i
],
2776 _r
.getvalue(self
._idx
_, _i
)))
2778 self
._idx
_ = self
._idx
_ + 1
2780 self
.__dict
__['rowcount'] = 1
2782 if fetchReturnsList
:
2783 # Return a list (This is the minimum required by DB-API 2.0
2787 return self
.PgResultSetClass(_j
)
2789 def __fetchManyRows(self
, count
, iList
=[]):
2793 _j
= self
.__fetchOneRow
()
2799 for _i
in range(count
):
2800 _j
= self
.__fetchOneRow
()
2806 self
.__dict
__['rowcount'] = len(_many
)
2810 def __makedesc__(self
):
2811 # Since __makedesc__ will only be called after a successful query or
2812 # fetch, self.res will contain the information needed to build the
2813 # description attribute even if no rows were returned. So, we always
2814 # build up the description.
2815 self
.__dict
__['description'] = []
2818 _cache
= self
.conn
._cache
2819 for _i
in range(_res
.nfields
):
2822 _j
.append(_res
.fname(_i
))
2824 _typ
= PgTypes(_res
.ftype(_i
))
2825 _mod
= _res
.fmod(_i
)
2826 _tn
, _pl
, _ia
, _bt
= _cache
.getTypeInfo(_typ
)
2828 _s
, _pl
, _s
, _s
= _cache
.getTypeInfo(_bt
)
2830 _bt
= PgTypes(PG_BLOB
)
2832 elif _typ
.value
== PG_OID
:
2834 _p
= _res
.getvalue(0, _i
)
2835 except (ValueError, TypeError), m
:
2836 # We can only guess here ...
2837 _typ
= PgTypes(PG_BLOB
)
2839 if type(_p
) in [PgLargeObjectType
, NoneType
]:
2840 _typ
= PgTypes(PG_BLOB
)
2842 _typ
= PgTypes(PG_ROWID
)
2846 # Calculate Display size, Internal size, Precision and Scale.
2847 # Note: Precision and Scale only have meaning for PG_NUMERIC
2849 if _typ
.value
== PG_NUMERIC
:
2851 # We have a numeric with no scale/precision.
2852 # Get them from by converting the string to a PgNumeric
2853 # and pulling them form the PgNumeric object. If that
2854 # fails default to a precision of 30 with a scale of 6.
2856 nv
= PgNumeric(_res
.getvalue(0, _i
))
2857 _p
= nv
.getPrecision()
2859 except (ValueError, TypeError), m
:
2863 # We hava a valid scale/precision value. Use them.
2864 _s
= _mod
- self
._varhdrsz
2865 _p
= (_s
>> 16) & 0xffff
2867 _j
.append(None) # Display size (always None since PG7.3)
2868 _j
.append(_p
) # Internal (storage) size
2869 _j
.append(_p
) # Precision
2870 _j
.append(_s
) # Scale
2873 _pl
= _res
.fsize(_i
)
2875 _pl
= _mod
- self
._varhdrsz
2876 _j
.append(None) # Display size (always None since PG7.3)
2880 _j
.append(_s
) # Internal (storage) size
2881 if _typ
.value
== PG_MONEY
:
2882 _j
.append(9) # Presicion and Scale (from
2883 _j
.append(2) # the PostgreSQL doco.)
2885 _j
.append(None) # Preision
2886 _j
.append(None) # Scale
2888 _j
.append(None) # nullOK is not implemented (yet)
2889 _j
.append(_ia
) # Array indicator (PostgreSQL specific)
2891 self
.__dict
__["description"].append(_j
)
2893 # Add the fieldname:fieldindex to the _mapname dictionary
2894 self
._mapname
[_j
[0]] = _i
2896 # Create a subclass of PgResultSet. Note that we pass a copy of the
2897 # description to this class.
2898 self
.PgResultSetClass
= make_PgResultSetClass(self
.description
[:], self
._mapname
)
2900 def callproc(self
, proc
, *args
):
2902 raise InterfaceError
, "callproc failed - the cursor is closed."
2904 if self
.conn
is None:
2905 raise Error
, "connection is closed."
2907 if self
.closed
== 0:
2908 raise InterfaceError
, "callproc() failed - cursor is active."
2910 if self
.conn
.autocommit
:
2913 if not self
.conn
.inTransaction
:
2914 self
.conn
._Connection
__setupTransaction
()
2916 proc
= self
.__unicodeConvert
(proc
)
2917 args
= self
.__unicodeConvert
(args
)
2919 _qstr
= "select %s(" % proc
2920 for _i
in range(len(args
)):
2921 _qstr
= '%s%s, ' % (_qstr
, _quote(args
[_i
]))
2923 _qstr
= '%s)' % _qstr
2925 _qstr
= '%s)' % _qstr
[:-2]
2927 _nl
= len(self
.conn
.notices
)
2930 self
.res
= self
.conn
.conn
.query(_qstr
)
2931 self
._rows
_ = self
.res
.ntuples
2933 if type(self
.res
) is not PgResultType
:
2934 self
.__dict
__['rowcount'] = -1
2936 self
.__dict
__['oidValue'] = self
.res
.oidValue
2937 if self
.res
.resultType
== RESULT_DQL
:
2939 elif self
.res
.resultType
== RESULT_DML
:
2940 self
.__dict
__['rowcount'] = self
.res
.cmdTuples
2942 self
.__dict
__['rowcount'] = -1
2943 except OperationalError
, msg
:
2944 # Uh-oh. A fatal error occurred. This means the current trans-
2945 # action has been aborted. Try to recover to a sane state.
2946 if self
.conn
.inTransaction
:
2947 self
.conn
.conn
.query('END WORK')
2948 self
.conn
.__dict
__["inTransaction"] = 0
2949 self
.conn
._Connection
__closeCursors
()
2950 raise OperationalError
, msg
2951 except InternalError
, msg
:
2952 # An internal error occured. Try to get to a sane state.
2953 self
.conn
.__dict
__["inTransaction"] = 0
2954 self
.conn
._Connection
__closeCursors
_()
2956 raise InternalError
, msg
2958 if len(self
.conn
.notices
) != _nl
:
2959 _drop
= self
.conn
.notices
[-1]
2960 if _drop
.find('transaction is aborted') > 0:
2961 raise Warning, self
.conn
.notices
.pop()
2963 self
._rows
_ = self
.res
.ntuples
2965 self
.__dict
__['rowcount'] = -1 # New query - no fetch occured yet.
2972 raise InterfaceError
, "The cursor is already closed."
2974 # Dis-associate ourselves from our cursor.
2977 _cc
= self
.conn
.cursors
2981 # We have additional cursors, garbage collect them.
2982 _cc
._Connection
__gcCursors
()
2984 del _cc
.data
[id(self
)]
2990 def execute(self
, query
, *parms
):
2992 raise InterfaceError
, "execute failed - the cursor is closed."
2994 if self
.conn
is None:
2995 raise Error
, "connection is closed."
2997 if self
.closed
== 0:
2998 if re_DQL
.search(query
):
2999 # A SELECT has already been executed with this cursor object,
3000 # which means a PostgreSQL portal (may) have been opened.
3001 # Trying to open another portal will cause an error to occur,
3002 # so we asusme that the developer is done with the previous
3003 # SELECT and reset the cursor object to it's inital state.
3007 if self
.conn
.autocommit
:
3010 _badQuery
= (self
.conn
.version
< 70100) and \
3011 (re_DRT
.search(query
) or re_DRI
.search(query
))
3012 if not self
.conn
.inTransaction
:
3014 pass # PostgreSQL version < 7.1 and not in transaction,
3015 # so DROP TABLE/INDEX is ok.
3017 self
.conn
._Connection
__setupTransaction
()
3019 if re_DQL
.search(query
) and \
3020 not (noPostgresCursor
or re_4UP
.search(query
)):
3021 _qstr
= 'DECLARE "%s" CURSOR FOR %s' % (self
.name
, query
)
3023 elif _badQuery
and self
.conn
.inTransaction
:
3024 raise NotSupportedError
, \
3025 "DROP [TABLE|INDEX] within a transaction"
3026 if not self
.conn
.inTransaction
:
3028 pass # not in transaction so DROP TABLE/INDEX is ok.
3030 self
.conn
._Connection
__setupTransaction
()
3032 _nl
= len(self
.conn
.notices
)
3035 _qstr
= self
.__unicodeConvert
(_qstr
)
3037 # If there are no paramters, just execute the query.
3038 self
.res
= self
.conn
.conn
.query(_qstr
)
3040 if len(parms
) == 1 and \
3041 (type(parms
[0]) in [DictType
, ListType
, TupleType
] or \
3042 isinstance(parms
[0], PgResultSet
)):
3043 parms
= (self
.__unicodeConvert
(parms
[0]),)
3044 parms
= _quoteall(parms
[0])
3046 parms
= self
.__unicodeConvert
(parms
)
3047 parms
= tuple(map(_quote
, parms
));
3048 self
.res
= self
.conn
.conn
.query(_qstr
% parms
)
3049 self
._rows
_ = self
.res
.ntuples
3051 self
.__dict
__['rowcount'] = -1 # New query - no fetch occured yet.
3052 if type(self
.res
) is not PgResultType
:
3053 self
.__dict
__['rowcount'] = -1
3055 self
.__dict
__['oidValue'] = self
.res
.oidValue
3056 if self
.res
.resultType
== RESULT_DQL
:
3058 elif self
.res
.resultType
== RESULT_DML
:
3059 self
.__dict
__['rowcount'] = self
.res
.cmdTuples
3061 self
.__dict
__['rowcount'] = -1
3062 except OperationalError
, msg
:
3063 # Uh-oh. A fatal error occurred. This means the current trans-
3064 # action has been aborted. Try to recover to a sane state.
3065 if self
.conn
.inTransaction
:
3066 _n
= len(self
.conn
.notices
)
3067 self
.conn
.conn
.query('ROLLBACK WORK')
3068 if len(self
.conn
.notices
) != _n
:
3069 raise Warning, self
.conn
.notices
.pop()
3070 self
.conn
.__dict
__["inTransaction"] = 0
3071 self
.conn
._Connection
__closeCursors
()
3072 raise OperationalError
, msg
3073 except InternalError
, msg
:
3074 # An internal error occured. Try to get to a sane state.
3075 self
.conn
.__dict
__["inTransaction"] = 0
3076 self
.conn
._Connection
__closeCursors
_()
3078 raise InternalError
, msg
3080 if len(self
.conn
.notices
) != _nl
:
3081 _drop
= self
.conn
.notices
[-1]
3082 if _drop
.find('transaction is aborted') > 0:
3083 raise Warning, self
.conn
.notices
.pop()
3085 if self
.res
.resultType
== RESULT_DQL
:
3087 elif _qstr
[:8] == 'DECLARE ':
3088 # Ok -- we've created a cursor, we will pre-fetch the first row in
3089 # order to make the description array. Note: the first call to
3090 # fetchXXX will return the pre-fetched record.
3091 self
.res
= self
.conn
.conn
.query('FETCH 1 FROM "%s"' % self
.name
)
3092 self
._rows
_ = self
.res
.ntuples
3096 if len(self
.conn
.notices
) != _nl
:
3097 _drop
= self
.conn
.notices
[-1]
3098 if _drop
.find('transaction is aborted') > 0:
3099 raise Warning, self
.conn
.notices
.pop()
3101 def executemany(self
, query
, parm_sequence
):
3103 raise InterfaceError
, "executemany failed - the cursor is closed."
3105 if self
.conn
is None:
3106 raise Error
, "connection is closed."
3108 for _i
in parm_sequence
:
3109 self
.execute(query
, _i
)
3113 raise InterfaceError
, "fetchone failed - the cursor is closed."
3115 if self
.conn
is None:
3116 raise Error
, "connection is closed."
3118 if self
.res
is None:
3120 "fetchone() failed - cursor does not contain a result."
3121 elif self
.res
.resultType
!= RESULT_DQL
:
3122 if self
.closed
is None:
3124 "fetchone() Failed - cursor does not contain any rows."
3126 if self
._idx
_ < self
._rows
_:
3127 pass # Still data in result buffer, use it.
3128 elif self
.closed
== 0:
3129 _nl
= len(self
.conn
.notices
)
3130 self
.res
= self
.conn
.conn
.query('FETCH 1 FROM "%s"' % self
.name
)
3131 self
._rows
_ = self
.res
.ntuples
3134 if len(self
.conn
.notices
) != _nl
:
3135 _drop
= self
.conn
.notices
[-1]
3136 if _drop
.find('transaction is aborted') > 0:
3137 raise Warning, self
.conn
.notices
.pop()
3139 return self
.__fetchOneRow
()
3141 def fetchmany(self
, sz
=None):
3143 raise InterfaceError
, "fetchmany failed - the cursor is closed."
3145 if self
.conn
is None:
3146 raise Error
, "connection is closed."
3148 if self
.res
is None:
3150 "fetchmany() failed - cursor does not contain a result."
3151 elif self
.res
.resultType
!= RESULT_DQL
:
3152 if self
.close
is None:
3154 "fetchmany() Failed - cursor does not contain any rows."
3159 self
.__dict
__["arraysize"] = abs(sz
)
3162 return self
.fetchall()
3166 # While there are still results in the PgResult object, append them
3167 # to the list of results.
3168 while self
._idx
_ < self
._rows
_ and sz
> 0:
3169 _list
.append(self
.__fetchOneRow
())
3172 # If still need more results to fullfill the request, fetch them from
3173 # the PostgreSQL portal.
3174 if self
.closed
== 0 and sz
> 0:
3175 _nl
= len(self
.conn
.notices
)
3176 self
.res
= self
.conn
.conn
.query('FETCH %d FROM "%s"' %
3178 self
._rows
_ = self
.res
.ntuples
3181 if len(self
.conn
.notices
) != _nl
:
3182 _drop
= self
.conn
.notices
[-1]
3183 if _drop
.find('transaction is aborted') > 0:
3184 raise Warning, self
.conn
.notices
.pop()
3186 return self
.__fetchManyRows
(sz
, _list
)
3190 raise InterfaceError
, "fetchall failed - the cursor is closed."
3192 if self
.conn
is None:
3193 raise Error
, "connection is closed."
3195 if self
.res
is None:
3197 "fetchall() failed - cursor does not contain a result."
3198 elif self
.res
.resultType
!= RESULT_DQL
:
3199 if self
.closed
is None:
3201 "fetchall() Failed - cursor does not contain any rows."
3205 # While there are still results in the PgResult object, append them
3206 # to the list of results.
3207 while self
._idx
_ < self
._rows
_:
3208 _list
.append(self
.__fetchOneRow
())
3210 # Fetch the remaining results from the PostgreSQL portal.
3211 if self
.closed
== 0:
3212 _nl
= len(self
.conn
.notices
)
3213 self
.res
= self
.conn
.conn
.query('FETCH ALL FROM "%s"' % self
.name
)
3214 self
._rows
_ = self
.res
.ntuples
3217 if len(self
.conn
.notices
) != _nl
:
3218 _drop
= self
.conn
.notices
[-1]
3219 if _drop
.find('transaction is aborted') > 0:
3220 raise Warning, self
.conn
.notices
.pop()
3222 return self
.__fetchManyRows
(self
._rows
_, _list
)
3226 raise InterfaceError
, "rewind failed - the cursor is closed."
3228 if self
.conn
is None:
3229 raise Error
, "connection is closed."
3231 if self
.res
is None:
3232 raise Error
, "rewind() failed - cursor does not contain a result."
3233 elif self
.res
.resultType
!= RESULT_DQL
:
3234 if self
.closed
is None:
3236 "rewind() Failed - cursor does not contain any rows."
3238 if self
.closed
== 0:
3239 _nl
= len(self
.conn
.notices
)
3240 self
.res
= self
.conn
.conn
.query('MOVE BACKWARD ALL IN "%s"' %
3243 if len(self
.conn
.notices
) != _nl
:
3244 _drop
= self
.conn
.notices
[-1]
3245 if _drop
.find('transaction is aborted') > 0:
3246 raise Warning, self
.conn
.notices
.pop()
3248 self
.__dict
__["rowcount"] = -1
3251 def setinputsizes(self
, sizes
):
3253 raise InterfaceError
, "setinputsize failed - the cursor is closed."
3255 def setoutputsize(self
, size
, column
=None):
3257 raise InterfaceError
, "setoutputsize failed - the cursor is closed."