From e5bdc26e1423689c0ab3204931335787737946ea Mon Sep 17 00:00:00 2001 From: Mark Huang Date: Wed, 8 Nov 2006 21:37:49 +0000 Subject: [PATCH] This commit was generated by cvs2svn to compensate for changes in r431, which included commits to RCS files with non-trunk default branches. --- psycopg2/AUTHORS | 8 + psycopg2/ChangeLog | 1219 ++++++++++++ psycopg2/INSTALL | 48 + psycopg2/LICENSE | 60 + psycopg2/MANIFEST | 222 +++ psycopg2/MANIFEST.in | 12 + psycopg2/PKG-INFO | 35 + psycopg2/README | 39 + psycopg2/ZPsycopgDA/DA.py | 375 ++++ psycopg2/ZPsycopgDA/__init__.py | 31 + psycopg2/ZPsycopgDA/db.py | 206 ++ psycopg2/ZPsycopgDA/dtml/add.dtml | 96 + psycopg2/ZPsycopgDA/dtml/browse.dtml | 11 + psycopg2/ZPsycopgDA/dtml/edit.dtml | 67 + psycopg2/ZPsycopgDA/dtml/table_info.dtml | 7 + psycopg2/ZPsycopgDA/icons/bin.gif | Bin 0 -> 924 bytes psycopg2/ZPsycopgDA/icons/date.gif | Bin 0 -> 930 bytes psycopg2/ZPsycopgDA/icons/datetime.gif | Bin 0 -> 925 bytes psycopg2/ZPsycopgDA/icons/field.gif | Bin 0 -> 915 bytes psycopg2/ZPsycopgDA/icons/float.gif | Bin 0 -> 929 bytes psycopg2/ZPsycopgDA/icons/int.gif | Bin 0 -> 918 bytes psycopg2/ZPsycopgDA/icons/stable.gif | Bin 0 -> 884 bytes psycopg2/ZPsycopgDA/icons/table.gif | Bin 0 -> 878 bytes psycopg2/ZPsycopgDA/icons/text.gif | Bin 0 -> 918 bytes psycopg2/ZPsycopgDA/icons/time.gif | Bin 0 -> 926 bytes psycopg2/ZPsycopgDA/icons/view.gif | Bin 0 -> 893 bytes psycopg2/ZPsycopgDA/icons/what.gif | Bin 0 -> 894 bytes psycopg2/ZPsycopgDA/pool.py | 51 + psycopg2/debian/changelog | 12 + psycopg2/debian/control | 51 + psycopg2/debian/copyright | 10 + psycopg2/debian/rules | 4 + psycopg2/doc/ChangeLog-1.x | 1744 +++++++++++++++++ psycopg2/doc/HACKING | 43 + psycopg2/doc/SUCCESS | 114 ++ psycopg2/doc/TODO | 33 + psycopg2/doc/api-screen.css | 138 ++ psycopg2/doc/api/epydoc.css | 138 ++ psycopg2/doc/api/index.html | 15 + .../api/private/__builtin__.list-class.html | 817 ++++++++ .../api/private/__builtin__.object-class.html | 270 +++ .../api/private/__builtin__.type-class.html | 384 ++++ .../api/private/datetime.tzinfo-class.html | 239 +++ psycopg2/doc/api/private/epydoc.css | 138 ++ .../private/exceptions.Exception-class.html | 128 ++ .../exceptions.StandardError-class.html | 102 + psycopg2/doc/api/private/frames.html | 15 + psycopg2/doc/api/private/help.html | 231 +++ psycopg2/doc/api/private/index.html | 15 + psycopg2/doc/api/private/indices.html | 666 +++++++ psycopg2/doc/api/private/psycopg2-module.html | 336 ++++ .../api/private/psycopg2.DataError-class.html | 103 + .../private/psycopg2.DatabaseError-class.html | 110 ++ .../doc/api/private/psycopg2.Error-class.html | 105 + .../psycopg2.IntegrityError-class.html | 103 + .../psycopg2.InterfaceError-class.html | 101 + .../private/psycopg2.InternalError-class.html | 103 + .../psycopg2.NotSupportedError-class.html | 103 + .../psycopg2.OperationalError-class.html | 103 + .../psycopg2.ProgrammingError-class.html | 103 + .../api/private/psycopg2.Warning-class.html | 99 + .../api/private/psycopg2._psycopg-module.html | 1072 ++++++++++ .../psycopg2._psycopg.ISQLQuote-class.html | 221 +++ .../psycopg2._psycopg.connection-class.html | 405 ++++ .../psycopg2._psycopg.cursor-class.html | 599 ++++++ .../private/psycopg2.extensions-module.html | 418 ++++ .../api/private/psycopg2.extras-module.html | 91 + .../psycopg2.extras.DictConnection-class.html | 202 ++ .../psycopg2.extras.DictCursor-class.html | 359 ++++ .../psycopg2.extras.DictRow-class.html | 376 ++++ .../private/psycopg2.extras.SQL_IN-class.html | 171 ++ .../doc/api/private/psycopg2.pool-module.html | 126 ++ ...pg2.pool.AbstractConnectionPool-class.html | 247 +++ ...2.pool.PersistentConnectionPool-class.html | 237 +++ .../psycopg2.pool.PoolError-class.html | 99 + ...copg2.pool.SimpleConnectionPool-class.html | 222 +++ ...pg2.pool.ThreadedConnectionPool-class.html | 236 +++ .../api/private/psycopg2.psycopg1-module.html | 121 ++ .../psycopg2.psycopg1.connection-class.html | 221 +++ .../psycopg2.psycopg1.cursor-class.html | 308 +++ .../doc/api/private/psycopg2.tz-module.html | 193 ++ ...psycopg2.tz.FixedOffsetTimezone-class.html | 273 +++ .../psycopg2.tz.LocalTimezone-class.html | 209 ++ psycopg2/doc/api/private/toc-everything.html | 134 ++ .../doc/api/private/toc-psycopg2-module.html | 58 + .../private/toc-psycopg2._psycopg-module.html | 78 + .../toc-psycopg2.extensions-module.html | 47 + .../private/toc-psycopg2.extras-module.html | 32 + .../api/private/toc-psycopg2.pool-module.html | 40 + .../private/toc-psycopg2.psycopg1-module.html | 34 + .../api/private/toc-psycopg2.tz-module.html | 37 + psycopg2/doc/api/private/toc.html | 39 + psycopg2/doc/api/private/trees.html | 196 ++ .../api/public/__builtin__.list-class.html | 817 ++++++++ .../api/public/__builtin__.object-class.html | 267 +++ .../api/public/__builtin__.type-class.html | 384 ++++ .../doc/api/public/datetime.tzinfo-class.html | 239 +++ psycopg2/doc/api/public/epydoc.css | 138 ++ .../public/exceptions.Exception-class.html | 128 ++ .../exceptions.StandardError-class.html | 102 + psycopg2/doc/api/public/frames.html | 15 + psycopg2/doc/api/public/help.html | 231 +++ psycopg2/doc/api/public/index.html | 15 + psycopg2/doc/api/public/indices.html | 418 ++++ psycopg2/doc/api/public/psycopg2-module.html | 335 ++++ .../api/public/psycopg2.DataError-class.html | 103 + .../public/psycopg2.DatabaseError-class.html | 110 ++ .../doc/api/public/psycopg2.Error-class.html | 105 + .../public/psycopg2.IntegrityError-class.html | 103 + .../public/psycopg2.InterfaceError-class.html | 101 + .../public/psycopg2.InternalError-class.html | 103 + .../psycopg2.NotSupportedError-class.html | 103 + .../psycopg2.OperationalError-class.html | 103 + .../psycopg2.ProgrammingError-class.html | 103 + .../api/public/psycopg2.Warning-class.html | 99 + .../api/public/psycopg2._psycopg-module.html | 1001 ++++++++++ .../public/psycopg2.extensions-module.html | 418 ++++ .../api/public/psycopg2.extras-module.html | 91 + .../psycopg2.extras.DictConnection-class.html | 137 ++ .../psycopg2.extras.DictCursor-class.html | 205 ++ .../public/psycopg2.extras.DictRow-class.html | 376 ++++ .../public/psycopg2.extras.SQL_IN-class.html | 171 ++ .../doc/api/public/psycopg2.pool-module.html | 126 ++ ...pg2.pool.AbstractConnectionPool-class.html | 169 ++ ...2.pool.PersistentConnectionPool-class.html | 210 ++ .../public/psycopg2.pool.PoolError-class.html | 99 + ...copg2.pool.SimpleConnectionPool-class.html | 139 ++ ...pg2.pool.ThreadedConnectionPool-class.html | 209 ++ .../api/public/psycopg2.psycopg1-module.html | 121 ++ .../psycopg2.psycopg1.connection-class.html | 156 ++ .../psycopg2.psycopg1.cursor-class.html | 161 ++ .../doc/api/public/psycopg2.tz-module.html | 193 ++ ...psycopg2.tz.FixedOffsetTimezone-class.html | 213 ++ .../psycopg2.tz.LocalTimezone-class.html | 196 ++ psycopg2/doc/api/public/toc-everything.html | 90 + .../doc/api/public/toc-psycopg2-module.html | 57 + .../public/toc-psycopg2._psycopg-module.html | 73 + .../toc-psycopg2.extensions-module.html | 47 + .../public/toc-psycopg2.extras-module.html | 32 + .../api/public/toc-psycopg2.pool-module.html | 40 + .../public/toc-psycopg2.psycopg1-module.html | 34 + .../api/public/toc-psycopg2.tz-module.html | 37 + psycopg2/doc/api/public/toc.html | 38 + psycopg2/doc/api/public/trees.html | 174 ++ psycopg2/doc/async.txt | 67 + psycopg2/doc/extensions.html | 219 +++ psycopg2/doc/extensions.rst | 260 +++ psycopg2/examples/binary.py | 89 + psycopg2/examples/copy_from.py | 178 ++ psycopg2/examples/copy_to.py | 104 + psycopg2/examples/cursor.py | 63 + psycopg2/examples/dialtone.py | 144 ++ psycopg2/examples/dict.py | 45 + psycopg2/examples/dt.py | 99 + psycopg2/examples/encoding.py | 105 + psycopg2/examples/fetch.py | 81 + psycopg2/examples/lastrowid.py | 59 + psycopg2/examples/mogrify.py | 47 + psycopg2/examples/myfirstrecipe.py | 122 ++ psycopg2/examples/notify.py | 43 + psycopg2/examples/simple.py | 53 + psycopg2/examples/somehackers.jpg | Bin 0 -> 22565 bytes psycopg2/examples/threads.py | 160 ++ psycopg2/examples/tz.py | 69 + psycopg2/examples/usercast.py | 126 ++ psycopg2/examples/whereareyou.jpg | Bin 0 -> 34980 bytes psycopg2/lib/__init__.py | 72 + psycopg2/lib/extensions.py | 69 + psycopg2/lib/extras.py | 235 +++ psycopg2/lib/pool.py | 236 +++ psycopg2/lib/psycopg1.py | 87 + psycopg2/lib/tz.py | 100 + psycopg2/psycopg/adapter_asis.c | 227 +++ psycopg2/psycopg/adapter_asis.h | 51 + psycopg2/psycopg/adapter_binary.c | 382 ++++ psycopg2/psycopg/adapter_binary.h | 53 + psycopg2/psycopg/adapter_datetime.c | 461 +++++ psycopg2/psycopg/adapter_datetime.h | 107 + psycopg2/psycopg/adapter_list.c | 297 +++ psycopg2/psycopg/adapter_list.h | 49 + psycopg2/psycopg/adapter_mxdatetime.c | 446 +++++ psycopg2/psycopg/adapter_mxdatetime.h | 94 + psycopg2/psycopg/adapter_pboolean.c | 238 +++ psycopg2/psycopg/adapter_pboolean.h | 51 + psycopg2/psycopg/adapter_qstring.c | 393 ++++ psycopg2/psycopg/adapter_qstring.h | 53 + psycopg2/psycopg/config.h | 118 ++ psycopg2/psycopg/connection.h | 97 + psycopg2/psycopg/connection_int.c | 303 +++ psycopg2/psycopg/connection_type.c | 422 ++++ psycopg2/psycopg/cursor.h | 103 + psycopg2/psycopg/cursor_int.c | 47 + psycopg2/psycopg/cursor_type.c | 1553 +++++++++++++++ psycopg2/psycopg/microprotocols.c | 161 ++ psycopg2/psycopg/microprotocols.h | 60 + psycopg2/psycopg/microprotocols_proto.c | 216 ++ psycopg2/psycopg/microprotocols_proto.h | 45 + psycopg2/psycopg/pgtypes.h | 65 + psycopg2/psycopg/pgversion.h | 2 + psycopg2/psycopg/pqpath.c | 883 +++++++++ psycopg2/psycopg/pqpath.h | 41 + psycopg2/psycopg/psycopg.h | 142 ++ psycopg2/psycopg/psycopgmodule.c | 672 +++++++ psycopg2/psycopg/python.h | 43 + psycopg2/psycopg/typecast.c | 563 ++++++ psycopg2/psycopg/typecast.h | 85 + psycopg2/psycopg/typecast_array.c | 258 +++ psycopg2/psycopg/typecast_basic.c | 141 ++ psycopg2/psycopg/typecast_binary.c | 191 ++ psycopg2/psycopg/typecast_binary.h | 47 + psycopg2/psycopg/typecast_builtins.c | 60 + psycopg2/psycopg/typecast_datetime.c | 279 +++ psycopg2/psycopg/typecast_mxdatetime.c | 231 +++ psycopg2/scripts/buildtypes.py | 124 ++ psycopg2/scripts/ext2html.py | 169 ++ psycopg2/scripts/makedocs.py | 15 + psycopg2/scripts/maketypes.sh | 41 + psycopg2/setup.cfg | 46 + psycopg2/setup.py | 293 +++ psycopg2/tests/dbapi20.py | 850 ++++++++ psycopg2/tests/extras_dictcursor.py | 47 + psycopg2/tests/test_psycopg2_dbapi20.py | 35 + psycopg2/tests/types_basic.py | 87 + 223 files changed, 39768 insertions(+) create mode 100644 psycopg2/AUTHORS create mode 100644 psycopg2/ChangeLog create mode 100644 psycopg2/INSTALL create mode 100644 psycopg2/LICENSE create mode 100644 psycopg2/MANIFEST create mode 100644 psycopg2/MANIFEST.in create mode 100644 psycopg2/PKG-INFO create mode 100644 psycopg2/README create mode 100644 psycopg2/ZPsycopgDA/DA.py create mode 100644 psycopg2/ZPsycopgDA/__init__.py create mode 100644 psycopg2/ZPsycopgDA/db.py create mode 100644 psycopg2/ZPsycopgDA/dtml/add.dtml create mode 100644 psycopg2/ZPsycopgDA/dtml/browse.dtml create mode 100644 psycopg2/ZPsycopgDA/dtml/edit.dtml create mode 100644 psycopg2/ZPsycopgDA/dtml/table_info.dtml create mode 100644 psycopg2/ZPsycopgDA/icons/bin.gif create mode 100644 psycopg2/ZPsycopgDA/icons/date.gif create mode 100644 psycopg2/ZPsycopgDA/icons/datetime.gif create mode 100644 psycopg2/ZPsycopgDA/icons/field.gif create mode 100644 psycopg2/ZPsycopgDA/icons/float.gif create mode 100644 psycopg2/ZPsycopgDA/icons/int.gif create mode 100644 psycopg2/ZPsycopgDA/icons/stable.gif create mode 100644 psycopg2/ZPsycopgDA/icons/table.gif create mode 100644 psycopg2/ZPsycopgDA/icons/text.gif create mode 100644 psycopg2/ZPsycopgDA/icons/time.gif create mode 100644 psycopg2/ZPsycopgDA/icons/view.gif create mode 100644 psycopg2/ZPsycopgDA/icons/what.gif create mode 100644 psycopg2/ZPsycopgDA/pool.py create mode 100644 psycopg2/debian/changelog create mode 100644 psycopg2/debian/control create mode 100644 psycopg2/debian/copyright create mode 100755 psycopg2/debian/rules create mode 100644 psycopg2/doc/ChangeLog-1.x create mode 100644 psycopg2/doc/HACKING create mode 100644 psycopg2/doc/SUCCESS create mode 100644 psycopg2/doc/TODO create mode 100644 psycopg2/doc/api-screen.css create mode 100644 psycopg2/doc/api/epydoc.css create mode 100644 psycopg2/doc/api/index.html create mode 100644 psycopg2/doc/api/private/__builtin__.list-class.html create mode 100644 psycopg2/doc/api/private/__builtin__.object-class.html create mode 100644 psycopg2/doc/api/private/__builtin__.type-class.html create mode 100644 psycopg2/doc/api/private/datetime.tzinfo-class.html create mode 100644 psycopg2/doc/api/private/epydoc.css create mode 100644 psycopg2/doc/api/private/exceptions.Exception-class.html create mode 100644 psycopg2/doc/api/private/exceptions.StandardError-class.html create mode 100644 psycopg2/doc/api/private/frames.html create mode 100644 psycopg2/doc/api/private/help.html create mode 100644 psycopg2/doc/api/private/index.html create mode 100644 psycopg2/doc/api/private/indices.html create mode 100644 psycopg2/doc/api/private/psycopg2-module.html create mode 100644 psycopg2/doc/api/private/psycopg2.DataError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.DatabaseError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.Error-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.IntegrityError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.InterfaceError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.InternalError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.NotSupportedError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.OperationalError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.ProgrammingError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.Warning-class.html create mode 100644 psycopg2/doc/api/private/psycopg2._psycopg-module.html create mode 100644 psycopg2/doc/api/private/psycopg2._psycopg.ISQLQuote-class.html create mode 100644 psycopg2/doc/api/private/psycopg2._psycopg.connection-class.html create mode 100644 psycopg2/doc/api/private/psycopg2._psycopg.cursor-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.extensions-module.html create mode 100644 psycopg2/doc/api/private/psycopg2.extras-module.html create mode 100644 psycopg2/doc/api/private/psycopg2.extras.DictConnection-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.extras.DictCursor-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.extras.DictRow-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.extras.SQL_IN-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.pool-module.html create mode 100644 psycopg2/doc/api/private/psycopg2.pool.AbstractConnectionPool-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.pool.PersistentConnectionPool-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.pool.PoolError-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.pool.SimpleConnectionPool-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.pool.ThreadedConnectionPool-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.psycopg1-module.html create mode 100644 psycopg2/doc/api/private/psycopg2.psycopg1.connection-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.psycopg1.cursor-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.tz-module.html create mode 100644 psycopg2/doc/api/private/psycopg2.tz.FixedOffsetTimezone-class.html create mode 100644 psycopg2/doc/api/private/psycopg2.tz.LocalTimezone-class.html create mode 100644 psycopg2/doc/api/private/toc-everything.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2-module.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2._psycopg-module.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2.extensions-module.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2.extras-module.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2.pool-module.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2.psycopg1-module.html create mode 100644 psycopg2/doc/api/private/toc-psycopg2.tz-module.html create mode 100644 psycopg2/doc/api/private/toc.html create mode 100644 psycopg2/doc/api/private/trees.html create mode 100644 psycopg2/doc/api/public/__builtin__.list-class.html create mode 100644 psycopg2/doc/api/public/__builtin__.object-class.html create mode 100644 psycopg2/doc/api/public/__builtin__.type-class.html create mode 100644 psycopg2/doc/api/public/datetime.tzinfo-class.html create mode 100644 psycopg2/doc/api/public/epydoc.css create mode 100644 psycopg2/doc/api/public/exceptions.Exception-class.html create mode 100644 psycopg2/doc/api/public/exceptions.StandardError-class.html create mode 100644 psycopg2/doc/api/public/frames.html create mode 100644 psycopg2/doc/api/public/help.html create mode 100644 psycopg2/doc/api/public/index.html create mode 100644 psycopg2/doc/api/public/indices.html create mode 100644 psycopg2/doc/api/public/psycopg2-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.DataError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.DatabaseError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.Error-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.IntegrityError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.InterfaceError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.InternalError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.NotSupportedError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.OperationalError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.ProgrammingError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.Warning-class.html create mode 100644 psycopg2/doc/api/public/psycopg2._psycopg-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.extensions-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.extras-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.extras.DictConnection-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.extras.DictCursor-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.extras.DictRow-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.extras.SQL_IN-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.pool-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.pool.AbstractConnectionPool-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.pool.PersistentConnectionPool-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.pool.PoolError-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.pool.SimpleConnectionPool-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.pool.ThreadedConnectionPool-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.psycopg1-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.psycopg1.connection-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.psycopg1.cursor-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.tz-module.html create mode 100644 psycopg2/doc/api/public/psycopg2.tz.FixedOffsetTimezone-class.html create mode 100644 psycopg2/doc/api/public/psycopg2.tz.LocalTimezone-class.html create mode 100644 psycopg2/doc/api/public/toc-everything.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2-module.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2._psycopg-module.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2.extensions-module.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2.extras-module.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2.pool-module.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2.psycopg1-module.html create mode 100644 psycopg2/doc/api/public/toc-psycopg2.tz-module.html create mode 100644 psycopg2/doc/api/public/toc.html create mode 100644 psycopg2/doc/api/public/trees.html create mode 100644 psycopg2/doc/async.txt create mode 100644 psycopg2/doc/extensions.html create mode 100644 psycopg2/doc/extensions.rst create mode 100644 psycopg2/examples/binary.py create mode 100644 psycopg2/examples/copy_from.py create mode 100644 psycopg2/examples/copy_to.py create mode 100644 psycopg2/examples/cursor.py create mode 100644 psycopg2/examples/dialtone.py create mode 100644 psycopg2/examples/dict.py create mode 100644 psycopg2/examples/dt.py create mode 100644 psycopg2/examples/encoding.py create mode 100644 psycopg2/examples/fetch.py create mode 100644 psycopg2/examples/lastrowid.py create mode 100644 psycopg2/examples/mogrify.py create mode 100644 psycopg2/examples/myfirstrecipe.py create mode 100644 psycopg2/examples/notify.py create mode 100644 psycopg2/examples/simple.py create mode 100644 psycopg2/examples/somehackers.jpg create mode 100644 psycopg2/examples/threads.py create mode 100644 psycopg2/examples/tz.py create mode 100644 psycopg2/examples/usercast.py create mode 100644 psycopg2/examples/whereareyou.jpg create mode 100644 psycopg2/lib/__init__.py create mode 100644 psycopg2/lib/extensions.py create mode 100644 psycopg2/lib/extras.py create mode 100644 psycopg2/lib/pool.py create mode 100644 psycopg2/lib/psycopg1.py create mode 100644 psycopg2/lib/tz.py create mode 100644 psycopg2/psycopg/adapter_asis.c create mode 100644 psycopg2/psycopg/adapter_asis.h create mode 100644 psycopg2/psycopg/adapter_binary.c create mode 100644 psycopg2/psycopg/adapter_binary.h create mode 100644 psycopg2/psycopg/adapter_datetime.c create mode 100644 psycopg2/psycopg/adapter_datetime.h create mode 100644 psycopg2/psycopg/adapter_list.c create mode 100644 psycopg2/psycopg/adapter_list.h create mode 100644 psycopg2/psycopg/adapter_mxdatetime.c create mode 100644 psycopg2/psycopg/adapter_mxdatetime.h create mode 100644 psycopg2/psycopg/adapter_pboolean.c create mode 100644 psycopg2/psycopg/adapter_pboolean.h create mode 100644 psycopg2/psycopg/adapter_qstring.c create mode 100644 psycopg2/psycopg/adapter_qstring.h create mode 100644 psycopg2/psycopg/config.h create mode 100644 psycopg2/psycopg/connection.h create mode 100644 psycopg2/psycopg/connection_int.c create mode 100644 psycopg2/psycopg/connection_type.c create mode 100644 psycopg2/psycopg/cursor.h create mode 100644 psycopg2/psycopg/cursor_int.c create mode 100644 psycopg2/psycopg/cursor_type.c create mode 100644 psycopg2/psycopg/microprotocols.c create mode 100644 psycopg2/psycopg/microprotocols.h create mode 100644 psycopg2/psycopg/microprotocols_proto.c create mode 100644 psycopg2/psycopg/microprotocols_proto.h create mode 100644 psycopg2/psycopg/pgtypes.h create mode 100644 psycopg2/psycopg/pgversion.h create mode 100644 psycopg2/psycopg/pqpath.c create mode 100644 psycopg2/psycopg/pqpath.h create mode 100644 psycopg2/psycopg/psycopg.h create mode 100644 psycopg2/psycopg/psycopgmodule.c create mode 100644 psycopg2/psycopg/python.h create mode 100644 psycopg2/psycopg/typecast.c create mode 100644 psycopg2/psycopg/typecast.h create mode 100644 psycopg2/psycopg/typecast_array.c create mode 100644 psycopg2/psycopg/typecast_basic.c create mode 100644 psycopg2/psycopg/typecast_binary.c create mode 100644 psycopg2/psycopg/typecast_binary.h create mode 100644 psycopg2/psycopg/typecast_builtins.c create mode 100644 psycopg2/psycopg/typecast_datetime.c create mode 100644 psycopg2/psycopg/typecast_mxdatetime.c create mode 100644 psycopg2/scripts/buildtypes.py create mode 100755 psycopg2/scripts/ext2html.py create mode 100755 psycopg2/scripts/makedocs.py create mode 100755 psycopg2/scripts/maketypes.sh create mode 100644 psycopg2/setup.cfg create mode 100644 psycopg2/setup.py create mode 100644 psycopg2/tests/dbapi20.py create mode 100644 psycopg2/tests/extras_dictcursor.py create mode 100644 psycopg2/tests/test_psycopg2_dbapi20.py create mode 100644 psycopg2/tests/types_basic.py diff --git a/psycopg2/AUTHORS b/psycopg2/AUTHORS new file mode 100644 index 0000000..44c77fc --- /dev/null +++ b/psycopg2/AUTHORS @@ -0,0 +1,8 @@ +Main authors: + Federico Di Gregorio + +For the win32 port: + Jason Erickson (most of his changes are still in 2.0) + +Additional Help: + diff --git a/psycopg2/ChangeLog b/psycopg2/ChangeLog new file mode 100644 index 0000000..b273e20 --- /dev/null +++ b/psycopg2/ChangeLog @@ -0,0 +1,1219 @@ +2006-09-02 Federico Di Gregorio + + * Release 2.0.5.1. + + * psycopg/cursor_type.c: applied patch from Jason Erickson to + build on MSVC and older gcc. + +2006-09-01 Federico Di Gregorio + + * Release 2.0.5. + + * Fixed patch from #119, see tracker for details. + + * Preparing release 2.0.5. + + * psycopg/psycopgmodule.c: fixed filling of connection errors + to include OperationalError. + + * setup.py: removed pydatetime option from initialize_options + to make sure that the value in setup.cfg is used. + + * psycopg/psycopgmodule.c: applied patch from jdahlin (#120) + to have .connect() accept either a string or int as the port + parameter. + + * psycopg/adapter_binary.c: applied patch from jdahlin (#119) + to fix the segfault on empty binary buffers. + + * psycopg/connection_type.c: added .status attribute to expose + the internal status. + + * psycopg/pqpath.c: applied patch from intgr (#117) to fix + segfault on null queries. + + * psycopg/cursor_type.c: applied patch from intgr (#116) to + fix bad keyword naming and segfault in .executemany(). + + * ZPsycopgDA/DA.py: applied ImageFile patch from Charlie + Clark. + + * lib/pool.py: applied logging patch from Charlie Clark. + It will probably get a makeup and be moved to the top-level + module later. + +2006-08-02 Federico Di Gregorio + + * Release 2.0.4. + + * Fixed bug in float conversion (check for NULL string was + erroneously removed in 2.0.3!) + +2006-07-31 Federico Di Gregorio + + * Release 2.0.3. + + * psycopg/cursor_type.c: applied patch from jbellis (#113) to + allow column selection in .copy_from(). + + * psycopg/psycopgmodule.c: fixed memory leak in custom exceptions + (applied patch from #114). + +2006-07-26 Federico Di Gregorio + + * psycopg/adapter_datetime.c (pydatetime_str): fixed error + in conversion of microseconds for intervals and better algo + (thanks to Mario Frasca.) + +2006-06-18 Federico Di Gregorio + + * psycopg/adapter_binary.c: same as below. + + * psycopg/adapter_qstring.c: does not segfault anymore if + .getquoted() is called without preparing the qstring with + the connection. + +2006-06-15 Federico Di Gregorio + + * psycopg/typecast_basic.c: fixed problem with bogus + conversion when importing gtk (that was crazy, I didn't + understand why it happened but the new code just fixes it.) + + * ZPsycopgDA/db.py: better type analisys, using an hash + instead of a series of if (variation on patch from Charlie + Clark.) + +2006-06-11 Federico Di Gregorio + + * Release 2.0.2. + + * psycopg/typecast_array.c (typecast_array_cleanup): fixed a + problem with typecast_array_cleanup always returning the new + string length shorter by 1 (Closes: #93). + + * psycopg/adapter_binary.c: as below. + + * psycopg/adapter_qstring.c: wrapped #warning in #ifdef __GCC__ + because other compilers don't have it and it will just break + compilation (patch from jason, our great win32 builder). + + * psycopg/adapter_list.c: applied patch to adapt an empty list + into an empty array and not to NULL (from iGGy, closes: #108). + + * psycopg/cursor_type.c: applied patch from wkv to avoid + under-allocating query space when the parameters are not of the + right type (Closes: #110). + + * psycopg/connection_int.c: applied patch from wkv to avoid off + by one allocation of connection encoding string (Closes: #109). + +2006-06-09 Federico Di Gregorio + + * Release 2.0.1. + + * Fixed some buglets in ZPsycopgDA (was unable to load due + to shorter version number in psycopg module.) + +2006-06-08 Federico Di Gregorio + + * Release 2.0. + + * ZPsycopgDA/DA.py: removed Browse table for 2.0 release; we'll + add it back later. + +2006-05-26 Federico Di Gregorio + + * Applied better PostgreSQL patch from AA. + +2006-05-24 Federico Di Gregorio + + * Enabled 8.1.4 security fix only when the version is >= 8.1.4, fall + back to old code otherwise. + + * psycopg/adapter_qstring.c: now quote using PQescapeStringConn if + available. + + * psycopg/adapter_binary.c: now quote using PQescapeByteaConn if + available. + +2006-04-38 Federico Di Gregorio + + * setup.py: fixed little problem with mx_include_dir as suggested + by kvc (this closes #102). + +2006-04-24 Federico Di Gregorio + + * psycopg/adapter_pboolean.c: added the possibility to format boolean + values as "true" and "false" instead of "'t'" and "'f'". + +2006-03-08 Federico Di Gregorio + + * lib/extras.py: added .next() to DictCursot to support iteration. + +2006-03-02 Federico Di Gregorio + + * psycopg/typecast_array.c (typecast_array_tokenize): removed cast + to build without warnings on 64 bit arches. + +2006-02-11 Federico Di Gregorio + + * Release 2.0 beta 8. + + * psycopg/config.h: applied patch from Jason to fix handle leak on + win32, as documented in #92. + +2006-02-11 Federico Di Gregorio + + * Release 2.0 beta 7. + + * psycopg/psycopgmodule.c: applied fix for memory overflow in + connect() (reported by solt, #91.) + + * setup.py: applied patch from lbruno. + +2006-01-11 Federico Di Gregorio + + * setup.py: does not report an error in pg_config unless the pg_config + was explicitly set (allows for building with old options.) + +2006-01-06 Daniele Varrazzo + + * setup.py: libpq.dll not used anymore. win32 setup uses pg_config too. + +2006-01-05 Federico Di Gregorio + + * psycopg/psycopgmodule.c (psyco_set_error): added function to set extra + parameters on ProgrammingError instances. Also modified all occurances of + PyErr_SetString(ProgrammingError,...) to psycopg_set_error(). + + * setup.{cfg,py}: we now use pg_config to locate PostgreSQL libraries + and headers (modified patch from lbruno, see #70.) + +2006-01-01 Federico Di Gregorio + + * Preparing release 2 beta 7. + + * MANIFEST.in: we now distrbute pre-built documentation (still need + to add to setup.py the code necessary to build docs as part of the + build process.) + + * psycopg/connection_int.c: PostgreSQL encoding names are now force + uppercase (after all PostgreSQL documentation reports them this way.) + +2005-12-11 Federico Di Gregorio + + * psycopg/typecast_array.c (typecast_array_cleanup): added functio + to cleanup the "[...]=" part of an array result. This probably will + need some more work for nested arrays but it fixed every test I was + able to write. (Closes: #80) + +2005-12-11 Federico Di Gregorio + + * setup.py: half-applied patch from Tavis to specify mx_include_dir + in setup.cfg. + + * psycopg/typecast.c (typecast_parse_time): cz limit in the while + loop is 6, not 5. This solve the problem with "fractionary" time zones + and fixes #78. + +2005-12-06 Federico Di Gregorio + + * lib/extras.py: added .callproc() to DictCursor as suggested + by Philip Semanchuk. + +2005-11-29 Federico Di Gregorio + + * MANIFEST.in: added docs/async.txt. (Closes: #75) + +2005-11-26 Daniele Varrazzo + + * psycopg/psycopgmodule.c: fixed exceptions refcount. + + * Fixed lots of doctrings and added Epydoc-generated docs support. + +2005-11-24 Federico Di Gregorio + + * sandbox: added all the test and creash-me files to the repository. + + * psycopg/typecast.c (typecast_dealloc): now directly calls + PyObject_Del to avoid to segfault. + +2005-11-20 Federico Di Gregorio + + * psycopg/typecast.c: fixed problem with microseconds conversion by + applying slightly modified patch from Ronnie Mackay. + +2005-11-19 Federico Di Gregorio + + * lib/extensions.py: COMMITED -> COMMITTED. (Closes: #73) + + * doc/extensions.rst: included Daniele's work after minor cosmetic changes + like using the new constants instead of numbers for transaction isolation + levels. + +2005-11-17 Federico Di Gregorio + + * ZPsycopgDA/pool.py: fixed connections leak by using the new name + (PersistentConnectionPool) for the old connection pool class. + +2005-11-16 Federico Di Gregorio + + * Preparing release 2.0 beta 6. + + * psycopg/adapter_mxdatetime.c: fixed all problems with mx conversions. + + * psycopg/typecast.c: now the timezone is set correctly even if there + are no microseconds and/or the offset is 0; + + * examples/encoding.py: fixed example by using python utf8 encoding for + the whole file. + + * lib/__init__.py: very nice hack from Harald Armin Massa to allow + py2exe and similar tools to do their work without problems. + +2005-11-15 Federico Di Gregorio + + * psycopg/psycopgmodule.c: now bails out with correct exception when one + of the needed modules can't be imported (should fix #32.) + +2005-11-14 Federico Di Gregorio + + * psycopg/typecast.c: added typecast_parse_date and typecast_parse_time + functions to do locale-safe date/time parsing. This would probably also + speed-up psycopg a little bit. + +2005-11-07 Federico Di Gregorio + + * psycopg/pqpath.c: fixed problem with uninitialized value (all this was + started by replacing calloc() calls with PyMem_Malloc().) + +2005-11-04 Federico Di Gregorio + + * psycopg/typecast.c: a lot of changes: + - made typecast a new-style type + - removed coerce code and implemented the richcompare protocol that + allows to compare objects of different types + - much better __cmp__ method that allows to compare two typecast + objects and returns True if any two of the mapped oids match + - any object that can be used as an int works as right-hand operand + in __cmp__ operations + + * psycopg/typecast_datetime.c: now typecast_PYINTERVAL_cast limit the + scan to 'len' characters in the string (should fix #65.) + +2005-11-03 Federico Di Gregorio + + * Applied patch from Daniele Varazzo to enable Decimal on Python + 2.3 when the module is available (run-time check, nice.) + +2005-10-26 Federico Di Gregorio + + * setup.cfg: added include_dirs line for SUSE 9.3. + +2005-10-22 Federico Di Gregorio + + * psycopg/cursor_type.c: added support for named cursors: + - .fetchXXX() methods now execute a FETCH if the cursor is named + - .execute() executes a DECLARE if the cursor is named + - .execute() fails if a named cursor is used in autocommit + - .executemany() can't be called on named cursors + - .scroll() executes a MOVE if the cursor is named + - .close() executes a CLOSE if the cursor is named + Also, a "transaction mark" was added to both the connection and the + cursor and an exception is raised when using a named cursor unless the + two marks correspond. + + * psycopg/connection_int.c: snprintf->PyOS_snprintf. + + * psycopg/psycopgmodule.c: snprintf->PyOS_snprintf. + + * psycopg/cursor_type.c: changed self->query type from C string to + PyObject* to better manage queries in named cursors. + + * psycopg/psycopgmodule.c: cleaned up exception names (now the errors + is printed as psycopg2.Error and not as the confusing + psycopg2._psycopg.Error.) + +2005-10-20 Federico Di Gregorio + + * lib/pool.py: renamed ThreadedConnectionPool to PersistentConnectionPool + and added a connection pool that allows multiple connections per thread + as ThreadedConnectionPool (courtesy of Daniele Varrazzo.) + +2005-10-19 Federico Di Gregorio + + * Releasing 2.0 beta 5. + + * psycopg/adapter_mxdatetime.c: reverted to old strftime method to format + mx.DateTime objects; the new method didn't worked in some corner-cases. + This makes impossible to have more than 2 decimal places for seconds but + at least we get the time right every time. + +2005-10-18 Federico Di Gregorio + + * NOTIFY is back end working. + + * psycopg/connection_type.c: fixed problem with initialization of + notifies list (also fixed small memory leak in connection dealloc.) + + * examples/notify.py: added NOTIFY example. + + * psycopg/cursor_type.c: added per-cursor type-casters dictionaries. + +2005-10-18 Federico Di Gregorio + + * psycopg/typecast.c: temporary fix to typecasting objects to return + False for any comparaison except an integer in self.values (i.e., we + don't raise an exception anymore on a coerce error.) Epydoc is now + happy. + + * psycopg/config.h: ZETA config.h patch from Charlie Clark. + + * examples/threads.py: fixed small typo: psycopg -> psycopg2. + + * Big cleanup of unsigned chars to tame gcc 4. + + * Big cleanup of module names (i.e., psycopg2._psycopg everywhere.) + + * psycopg/config.h: added fake localtime_r for platforms missing it + + * psycopg/cursor_type.c: cursors now have a FixedOffsetTimezone + tzinfo_factory by default. + + * psycopg/adapter_datetime.c: added tzinfo argument to psycopg2.Time and + psycopg2.Timestamp. Also now TimestampFromTicks sets the tzinfo object + to psycopg2.tz.LOCAL. + +2005-10-17 Federico Di Gregorio + + * psycopg/adapter_datetime.c: we now use localtime() instead of gmtime() + to accound for the local time-zone in timestamps. + + * psycopg/connection_type.c: fixed docstring for .cursor(). + + * psycopg/psycopgmodule.c: added useful docstring for .connect(). + +2005-10-08 Federico Di Gregorio + + * psycopg/connection_type.c: isolation level upper bound set to 2. + + * lib/psycopg1.py: explicitly set isolation level to 2 on .connect() + to mimic psycopg 1 behaviour. + + * psycopg/connection_int.c: now set isolation level from + default_transaction_isolation backend environment value. + + * psycopg/pqpath.c: removed serialization level 3: now everybody + (except me) has to use the mnemonics defined in psycopg2.extensions. + + * lib/extensions.py: Added mnemonics for serialization levels. + +2005-10-02 Federico Di Gregorio + + * psycopg/cursor_type.c (psyco_curs_callproc): applied callproc + patch from Matt Goodall (added a check on _psyco_curs_execute + return value and substituted malloc/free with PyMem versions.) + +2005-10-01 Federico Di Gregorio + + * psycopg/connection_int.c: fixed segfault by moving PyErr_Format + after GIL acquisition (closes: #50). + + * psycopg/connection_type.c: applied patch from Matt Goodall to + fix some doc strings. + +2005-09-23 Federico Di Gregorio + + * lib/pool.py: applied patch from piro to avoid the scan of the + whole connection array on getconn(). + +2005-09-12 Federico Di Gregorio + + * lib/pool.py: Applied psycopg->psycopg2 patch to from bug #35. + + * ZpsycopgDA/db.py: fixed problem with OperationalError that + resulted in cryptic message to Zope users ("'OperationalError' is + not defined".) + +2005-08-23 Federico Di Gregorio + + * setup.py: applied patch from Daniele Varrazzo to avoid segfaults + when compiling with migw for Python 2.4.x. + + * psycopg/adapter_mxdatetime.c (mxdatetime_str): ported code from 1.1.x + to convert mxDateTime object preserving the precision of fractional + seconds. + +2005-08-22 Federico Di Gregorio + + * ZPsycopgDA/*.py: psycopg -> psycopg2. + + * setup.py: modified to install the module components under + psycopg2 on windows too (thanks to Daniele Varrazzo.) + +2005-08-07 Federico Di Gregorio + + * psycopg/config.h: added __sun__ to the symbols checked for round() + +2005-07-21 Federico Di Gregorio + + * psycopg/adapter_datetime.c (psyco_XXXFromTicks): fixed the 1900 + years offset reported by Jeroen van Dongen (see ticket #33). + +2005-07-17 Federico Di Gregorio + + * Release 2.0 beta 4. + + * lib/extras.py (DictConnection.cursor): added DictConnection to + make easier to retrieve data in DictRows. + +2005-06-24 Federico Di Gregorio + + * psycopg/typecast_datetime.c (typecast_PYINTERVAL_cast): applied patch + from Geert Jansen to fix interval bug due to overflow. + +2005-06-18 Federico Di Gregorio + + * setup.cfg: some clarifications and include_dirs example for Mandrake. + + * ZPsycopgDA/DA.py: DTMLFile -> HTMLFile everywhere to fix zope + cut&paste problems. + + * MANIFEST.in: added missing files to do bdist_rpm. + + * lib/psycopg1.py: fixed .dictfetchrow() to return None if fetchone() + returns None instead of raising an exception. + + * ZPsycopgDA/icons: replaced corrupted icons with good ones. + +2005-06-13 Federico Di Gregorio + + * psycopg/psycopgmodule.c (psyco_connect): changed the port keyword + parameter type to int (instead of string); this should fix #23. + + * psycopg/cursor_type.c (_psyco_curs_execute): now checks for + empty queries and raise a ProgrammingError if appropriate (closes: + #24). + + * setup.py: psycopg module renamed to psycopg2. + +2005-06-02 Federico Di Gregorio + + * psycopg/cursor_type.c (_psyco_curs_execute): fixed segfault when + not passing string or unicode to .execute(). + +2005-06-01 Federico Di Gregorio + + * examples/fetch.py: added example about using DECLARE CURSOR. + + * psycopg/adapter_datetime.c (psyco_TimestampFromTicks): "Hmmm, + looks like someone forgot that C expects months to start counting + from 0, but the Python date routines start counting from 1." That + was me: fixed. + +2005-05-31 Federico Di Gregorio + + * psycopg/cursor_type.c (_psyco_curs_execute): if a + UnicodeEncodeError is raised during the converion of a unicode + query we let it propagate insead of segfaulting. + +2005-5-27 Federico Di Gregorio, + + * tests/types_basic.py: fixed float and binary tests. + +2005-05-26 Federico Di Gregorio + + * Release 2.0b3. + + * ZPsycopgDA/db.py (DB.convert_description): isolated description + conversion (and fixed the conversion as per #18). + + * ZPsycopgDA/DA.py: fixed again; this time Zope should work for + real. :/ Also fixed the type-casters (psycopg 2 added the extra + cursor parameter) as reported in #18. + + * psycopg/psycopgmodule.c (init_psycopg): fixed Python 2.2 build. + +2005-05-19 Federico Di Gregorio + + * Release 2.0b2. + + * lib/extras.py (DictRow): Some extra methods for DictRow. + + * psycopg/cursor_type.c (_psyco_curs_execute): added explict check + to avoid using None as bound variables (very importand for cursor + subclasses calling cursor.execute(self, query, None). + +2005-05-18 Federico Di Gregorio + + * ZPsycopgDA/DA.py (ALLOWED_PSYCOPG_VERSIONS): updated to work + with 2.0b2 only (will support only the exact version untill final + 2.0 release.) + + * setup.py: Applied combined patch from Daniele Varrazzo and Jason + Erickson to build on win32 using MSVC or mingw. + +2005-05-15 Federico Di Gregorio + + * psycopg/microprotocols.c (microprotocols_adapt): fixed memory + leak on None as suggested by gh (closes: #16). + +2005-05-10 Federico Di Gregorio + + * lib/extras.py (DictRow): we now save a reference to the index + itself and not to the cursor to avoid problems while accessing + DictRow objects after reusing the cursor for a different query + (using Kevin Jacobs db_row would be much better but DictRow is + just an example, right?) + +2005-05-09 Federico Di Gregorio + + * Release 2.0 beta 1. + + * psycopg/typecast_datetime.c (typecast_PYDATETIME_cast): fixed a + typo (pyDateTimeModuleP->pyDateTimeTypeP) that was causing errors + with infinite datetime values. + + * psycopg/adapter_binary.c (binary_str): Py_XINCREF on the buffer + that can be NULL on error. + + * psycopg/typecast_binary.*: applied slightly modified + chunk/buffer object patch to allow round-trip of buffer objects + (BYTEA columns.) + + * psycopg/cursor_type.c (psyco_curs_executemany): applied slightly + fixed patch from wrobell to allow iterators in .executemany(). + +2005-04-18 Federico Di Gregorio + + * MANIFEST.in: included debian directory. + +2005-04-10 Federico Di Gregorio + + * psycopg/adapter_list.*: added list adapter. + + * psycopg/microprotocols.c (microprotocol_getquoted): moved + _mogrify_getquoted into utility function in the microprotocols + library. + + * setup.py: Added extensive error message on missing datetime + headers. + + * Applied mingw patch from Daniele Varazzo. + +2005-04-03 Federico Di Gregorio + + * lib/psycopg1.py (connection.autocommit): added compatibility + .autocommit() method. + + * psycopg/psycopgmodule.c (psyco_connect): factory -> + connection_factory. + + * lib/psycopg1.py: added psycopg 1.1.x compatibility module. + +2005-03-29 Federico Di Gregorio + + * Applied patch to fix tuple count. + + * psycopg/pqpath.c (pq_is_busy): Staring from bug report from + Jason Erickson fixed segfaults due to calling Python function + without holding the GIL. + +2005-03-24 Federico Di Gregorio + + * psycopg/adapter_binary.c (binary_escape): propagated Andrea's + fix to binary adapter. + + * psycopg/adapter_qstring.c (qstring_quote): applied patch from + Andrea Arcangeli to fix allocation failures (>4Gb) on 64 bit + arches. + + * psycopg/typecast_array.c (typecast_array_tokenize): much better + tokenization code. + +2005-03-23 Federico Di Gregorio + + * psycopg/typecast_basic.c: all the basic casters now respect the + passed string length. + + * psycopg/typecast.c (typecast_cast): set curs->caster to self + during the type-casting. + + * psycopg/cursor_type.c: added "typecaster" attribute to the + cursor (this is safe, cursors can't be shared among threads and + the attribute is RO.) + +2005-03-22 Federico Di Gregorio + + * psycopg/typecast_array.c: added some more structure to implement + array typecasting. + + * scripts/buildtypes.py: new version to include array data. + +2005-03-15 Federico Di Gregorio + + * lib/extensions.py: Added AsIs import. + +2005-03-12 Federico Di Gregorio + + * psycopg/cursor.h: removed "qattr", not used anymore and added + "cast", holding the typecaster currently in use. + + * Release 1.99.13. + + * psycopg/cursor_type.c (psyco_curs_executemany): implemented as a + wrapper to extract python arguments and then call + _psyco_curs_execute(). + + * psycopg/cursor_type.c (_psyco_curs_execute): splitted away + python argument parsing from the real execute code, to later allow + for .executemany(). + + * psycopg/cursor_type.c (_psyco_curs_buildrow_fill): modified to + call typecast_cast(). + + * psycopg/typecast.c (typecast_call/typecast_cast): modified + typecast_call to use the new typecast_cast that avoids one string + conversion on every cast. + +2005-03-04 Federico Di Gregorio + + * Release 1.99.12.1. + + * psycopg/adapter_asis.c (asis_str): changed call to PyObject_Repr + to PyObject_Str to avoid problems with long integers. + +2005-03-03 Federico Di Gregorio + + * psycopg/typecast.h: added array casting functions. + + * scripts/maketypes.sh: does not generate pgversion.h anymore. + + * Updated all examples for the release. + +2005-03-02 Federico Di Gregorio + + * Release 1.99.12. + + * psycopg/adapter_*.c: added __conform__ to all adapters. + + * psycopg/adapter_qstring.c (qstring_quote): we now use + PyString_AsStringAndSize() instead of strlen() that would stop at + the first embedded \0 (but note that libpq quoting function will + truncate the string anyway!) + + * COPY TO implemented using both old and new (v3) protocol. + + * psycopg/pqpath.c (_pq_copy_out_v3): implemented and working. + + * psycopg/cursor_type.c (psyco_curs_copy_to): added cursor object + interface for copy_to. + + * COPY FROM implemented using both old and new (v3) protocol. + + * psycopg/config.h (Dprintf): declaration for asprintf is gone. + + * psycopg/pqpath.c (_pq_copy_in_v3): implemented. + +2005-03-01 Federico Di Gregorio + + * setup.py: now we generate a slighly more verbose version string + that embeds some of the compile options, to facilitate users' bug + reports. + + * psycopg/cursor_type.c (psyco_curs_copy_from): we now use + PyOS_snprintf instead of asprintf. On some platforms this can be + bad (win32).. if that's your case, get a better platform. :/ + + * psycopg/microprotocols.c (microprotocols_adapt): fixed small + typo that made adaptation using __conform__ impossible. + +2005-02-28 Federico Di Gregorio + + * lib/extras.py: removed AsIs adapter (now a built-in); also + removed prepare() method from the adapters that don't use it to + avoid an extra method call at mogrification time. + + * psycopg/psycopgmodule.c (psyco_adapters_init): added + initialization of the AsIs adapter (adapts int, long, float and + *wonder* None!) + + * psycopg/cursor_type.c (_mogrify_getquoted): reorganized the code + to adapt and then call .getquoted() to obtain the quoted data into + this new function. + +2005-2-27 Federico Di Gregorio + + * examples/myfirstrecipe.py: fixed adapter registration. + +2005-2-7 Federico Di Gregorio + + * setup.py: added patch by Valentino Volonghi to build on MacOS X. + +2005-01-29 Federico Di Gregorio + + * psycopg/pqpath.c (_pq_fetch_tuples): fixed scale-related + segfault (*fourth* mail from Andrea. Another couple like this and + psycopg 2 will exit alpha at warp speed.) + + * psycopg/pqpath.c (pq_fetch): _pq_copy_out_3 -> _pq_copy_out_v3 + (second and third mail from Andrea. :/) + + * psycopg/cursor_type.c (_psyco_curs_has_write_check): added check + on .write() attribute, fixed compilation problems (first mail from + Andrea Arcangeli.) + +2005-01-20 Federico Di Gregorio + + * lib/extensions.py (register_adapter): added register_adapter + function, exported ISQLQuote in psycopg.extensions. + +2005-01-18 Federico Di Gregorio + + * psycopg/pqpath.c (_pq_fetch_tuples): ported scale/precision fix + from psycopg 1.1. + + * LICENSE: detailed licensing information. Re-licensed some parts + under BSD-like to allow integration is pysqlite. + +2005-01-13 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB.query + ): ported ZPsycopgDA connection fix + from psycopg 1.1. + + * lib/*.py: added pydoc-friendly messages. + +2005-01-12 Federico Di Gregorio + + * Added debian directory (thanks to W. Borgert who sent initial + patch based on cdbs.) + +2004-12-20 Federico Di Gregorio + + * psycopg/pqpath.c (pq_execute): removed multiple calls to + pq_fetch in syncronous DBAPI compatibility mode to solve rowcount + problem. + +2004-12-14 Federico Di Gregorio + + * Mm.. release 1.99.11. + + * psycopg/cursor_type.c (_psyco_curs_prefetch): fixed bug in + interaction between the .isready() method and + _psyco_curs_prefetch: isready now store away the pgres but leave + prefetch do its work. + + * psycopg/*.c: changed the names of most of the psycopg's built-in + types to replect their position in the psycopg._psycopg module. + +2004-12-10 Federico Di Gregorio + + * psycopg/cursor_type.c: now *all* write or async accesses to the + connection object are arbitrated using the connection lock. + + * psycopg/cursor_type.c (psyco_curs_isready): now we reset the + current async cursor if it is ready, to allow other cursors to + .execute() without raising the "transaction in progress" error. + + * psycopg/pqpath.c (pq_is_busy): gained status of high-level + function with its own blocking and locking. + + * psycopg/cursor.h (EXC_IF_CURS_CLOSED): also checks the + connection (a closed connection implies a closed cursor.) + + * psycopg/cursor_type.c: cursor's connection is correctly + INCREFfed and DECREFfed. + + * psycopg/connection_type.c: removed the cursors list from the + connection object. It is not necessary anymore for the connection + to know about the cursors and the reference counting will keep the + connection alive (but possibly closed) until all cursors are + garbage collected. + +2004-11-20 Federico Di Gregorio + + * psycopg/cursor_type.c (_mogrify): ported %% fix from 1.1.15. + +2004-11-20 Federico Di Gregorio + + * psycopg/cursor_type.c (psyco_curs_execute): added check to raise an + exception if a cursor tries to .execute() while an async query is + already in execution froma different cursor. + +2004-11-20 Federico Di Gregorio + + * psycopg/connection_type.c (psyco_conn_cursor): renamed 'cursor' + argument to 'cursor_factory'. + +2004-11-19 Federico Di Gregorio + + * psycopg/cursor_type.c (_psyco_curs_buildrow_fill): now standard + tuples are filled using PyTuple_SET_ITEM while extended types + (created via row_factory) are filled using PySequence_SetItem. + + * psycopg/cursor_type.c: changed cursor attribute name from + tuple_factory to row_factory. + +2004-10-14 Federico Di Gregorio + + * psycopg/cursor_type.c (_psyco_curs_buildrow_fill): now we use + PySequence_SetItem to avoid problems with containers created from + cursor's .tuple_factory attribute. + + * lib/extras.py (DictCursor.execute): fixed stupid bug with cursor + setting self.tuplefactory instead of self.tuple_factory. + +2004-10-02 Federico Di Gregorio + + * Release 1.99.10. + + * psycopg/cursor_type.c (_psyco_curs_buildrow_*): unified normal + and factory code into the _psyco_curs_buildrow_fill function; no + more memory leaks here. + + * psycopg/config.h (round): added check for __FreeBSD__ (that + should be defined when compiling with gcc, I hope.) + + * setup.py: removed a lot of code now in setup.cfg. + +2004-09-24 Federico Di Gregorio + + * psycopg/cursor_type.c (cursor_dealloc): fixed small memory leak + due to missing disposal of self->pgres. + +2004-9-14 Federico Di Gregorio + + * examples/dialtone.py: Added adapt() example by Valentino + Volonghi. + +2004-09-14 Federico Di Gregorio + + * psycopg/microprotocols.c (microprotocols_adapt): lots of changes + to the microprotocols layer (it is not micro anymore); + implementing almost all the PEP 246. The adapter registry is now + indexed by (type, protocol) and not by type alone. + +2004-09-13 Federico Di Gregorio + + * psycopg/cursor_type.c (_mogrify): and qattr is gone. + +2004-09-05 Federico Di Gregorio + + * Release 1.99.9 (or, the "twisting by the pool" release). + + * psycopg/pqpath.c (_pq_fetch_tuples): changed to "static void" + instead of "static int", no ways for this function to fail. + +2004-09-04 Federico Di Gregorio + + * psycopg/pqpath.c (_pq_fetch_tuples): ported rowcount fix from + 1.1.15. + + * ZPsycopgDA/*: ZPsycopgDA back in action, using the new pooling + code. + +2004-08-29 Federico Di Gregorio + + * psycopg/typecast_basic.c (typecast_DECIMAL_cast): added DECIMAL + typecaster; it even works :). + + * scripts/buildtypes.py (basic_types): added DECIMAL typecaster + for the NUMERIC oid. + + * examples/threads.py: updated threads example to use pooling code. + + * lib/pool.py: added very simple and thread-safe connection + pooling class. + + * psycopg/cursor_type.c (psyco_curs_fetchmany): fixed problem with + .fetchall() and .fetchmany() returning None instead of [] on empty + result sets. + + * Release 1.99.8. + +2004-08-28 Federico Di Gregorio + + * psycopg/cursor_type.c (psyco_curs_execute): added processing of + unicode queries. + + * examples/encoding.py: much better encoding example, also using + the new UNICODE typecaster. + + * psycopg/typecast_basic.c (typecast_UNICODE_cast): added UNICODE + typecaster. + + * lib/extensions.py: the encodings dictionary is not available by + default but can be accessed from the psycopg.extensions module. + + * psycopg/adapter_qstring.h: remove encoding information from + qstring adapter and moved it into psycopg module. + +2004-08-26 Federico Di Gregorio + + * psycopg/cursor_type.c (_psyco_curs_prefetch): added check for + asynchronous fetch by wrong cursor. + + * psycopg/pqpath.c (pq_fetch): fixed backend status message (bug + reported by Daniele Varrazzo.) + +2004-07-29 Federico Di Gregorio + + * psycopg/typecast_basic.c (typecast_BINARY_cast): reverted to + using strings instead of buffers when converting postgresql binary + objects (should *temporarily* fix corruption bug reported on + win32.) + +2004-07-21 Federico Di Gregorio + + * psycopg/cursor_type.c: removed __iter__ and next methods from + object methods and moved them where they do belong (tp_iter and + tp_iternext.) Bug reported by Daniele Varrazzo (again!) + +2004-07-19 Federico Di Gregorio + + * psycopg/typecast_datetime.c (typecast_PYINTERVAL_cast): replaced + round() with micro() when rounding seconds (fixes bugs reported by + Daniele Varrazzo.) + +2004-07-16 Federico Di Gregorio + + * psycopg/pqpath.c (pq_set_critical): allow for a custom message + insted of the one from PQerrorMessage. + (pq_resolve_critical): added argument to specify if connection is + to be closed (used to not close it during COPY FROM/TO criticals.) + + * psycopg/cursor_type.c (psyco_curs_fileno, psyco_curs_isready): + added extension methods related to async queries. + +2004-07-15 Federico Di Gregorio + + * Release 1.99.7. + + * examples/tz.py: added example about time zones. + + * psycopg/typecast_datetime.c (typecast_PYDATETIME_cast): create + FixedOffsetTimezone for postgresql "timestamp with time zone" + types. + + * lib/tz.py: added (even more than) needed tzinfo classes. + + * psycopg/typecast.c (typecast_call): changed typecast call code + to take the additional cursor parameter, needed for + cursor-dependent type casting (tzinfo & friends.) + + * psycopg/cursor_type.c (_psyco_curs_buildrow_with_factory): added + use of tuple factories to fetcXXX methods. + + * lib/extras.py: little extra goodies for psycopg. + +2004-07-14 Federico Di Gregorio + + * Release 1.99.6. + + * psycopg/connection_type.c: added .dsn attribute to connection + objects. + + * psycopg/cursor_type.c (psyco_curs_mogrify): added .mogrify() + method. + + * psycopg/adapter_qstring.c: copy the connection encoding only if + wrapped object is unicode and added table of encodings. + +2004-07-13 Federico Di Gregorio + + * psycopg/cursor_type.c (_mogrify): moved Dprintf statement to + avoid dereferencing empty pointer (from 1.1.x) + (psyco_curs_execute): now we save the query in self->query instead + of freeing the memory ASAP. + (cursorObject_members): and we finally export the saved query + through the cursor members interface. that's all folks. + + * lib/extensions.py: added extensions module to clearly separate + psycopg own extensions from DBAPI-2.0 + +2004-07-10 Federico Di Gregorio + + * psycopg/typecast_datetime.c: ported interval fix from 1.1.x. + +2004-05-16 Federico Di Gregorio + + * psycopg/typecast_datetime.c (typecast_*_cast): fixed Value error + when seconds > 59 by setting minutes += 1 and seconds -= 60 + (reported by Marcel Gsteiger.) + +2004-04-24 Federico Di Gregorio + + * ported time interval patch by Ross Cohen from 1.1.12. + +2004-04-19 Federico Di Gregorio + + * psycopg/typecast_datetime.c (typecast_PYDATE_cast): applied + patch from Jason Erickson: min and max taken from datetime.Date + type. + +2004-04-18 Federico Di Gregorio + + * Applied changes from Jason Erickson to build on win32; see his + (slightly edited) entry below. (Still builds on Linux :) + + * psycopg/*.c: removed inclusion of pthread.h from all files + except psycopg/config.h to build on win32 without faking the file. + +2004-04-15 Jason Erickson + + * setup.py: Various changes. The critical ones: + - Make an empty pthread.h file so all the code doing an + #include will find something. + - Appended the winsock2 library and the PostgreSQL library to + the library path. + - Setup the include path. + - Have the PSYCOPG_VERSION macro be included with quotes. + + * config.h: Added/Cleaned up Win32 includes, defines, stub functions. + + * typecast.h: Removed ';' after PyObject_HEAD in the + typecastObject structure since Microsoft Visual Studio does not + like it. + +2004-04-15 Federico Di Gregorio + + * Release 1.99.5 (bug-fixing and reorganization) + + * setup.py et al.: moved psycopg to psycopg._psycopg to make + easier to provide high level python-only utilities (like the + promised pooling code). psycopg/__init__.py imports _psycopg and + make all the default DBAPI-2.0 stuff available. + +2004-04-14 Federico Di Gregorio + + * psycopg/psycopgmodule.c (initpsycopg): wrapped initialization of + date/time adapters in #ifdefs to have psycopg compile without mx + or builtin datetime. + +2004-04-10 Federico Di Gregorio + + * Release 1.99.4. + +2004-04-09 Federico Di Gregorio + + * psycopg/typecast_builtins.c: changed DATE to not include + DATETIME types anymore. + + * psycopg/adapter_datetime.c (pydatetime_str): switched from + strftime to isoformat to preserve fractional seconds. + +2004-04-08 Federico Di Gregorio + + * psycopg/psycopgmodule.c (psyco_connect): ported sslmode + parameter from 1.1 branch. + + * psycopg/adapter_datetime.*: added python built-in datetime + adapters. also added the datetime typecasters (still using mx as + default). + + * psycopg/typecast.h: removed aliases, they now live in the right + typecast_xxx.c file. + +2004-03-08 Federico Di Gregorio + + * Release 1.99.3 (alpha 4). + + * examples/lastrowid.py: and the .lastrowid example is in. + + * psycopg/cursor_type.c (_mogrify): added call to .prepare() + method in both dict and sequence path. + + * psycopg/connection_int.c (conn_set_client_encoding): added + encoding-change code. + + * psycopg/adapter_qstring.c (qstring_quote): added hard-coded + support for utf8 and latin1 encodings. + +2004-03-01 Federico Di Gregorio + + * psycopg/connection_int.c (conn_close): does not use libpq + functions on NULL pgconn (this can happen when conn_close is + called after a failed PQconnect.) + +2004-02-29 Federico Di Gregorio + + * Release 1.99.2 (alpha 3). + + * psycopg/cursor_type.c: added .rownumber and .connection + attributes. Also added .scroll(), .next() and .__iter__() methods + (see DBAPI2-.0 extensions on PEP.) + + * psycopg/connection_type.c (psyco_conn_set_isolation_level): + added connection method .set_isolation_level(). Also added all + error objects to the connection (see DBAPI2-.0 extensions on PEP.) + + * psycopg/connection_int.c (conn_switch_isolation_level): added + isolation level switching code. + + * setup.py: removed all references to PSYCOPG_NEWSTYLE: support + for python < 2.2 has been dropped. + + * typecast_basic.c (typecast_BINARY_cast): now binary objects are + returned as true buffers. + + * adapter_binary.*: added adapter for buffers and binary (bytea) + objects. + + * Release 1.99.1 (alpha 2). + + * adapter_mxdatetime.*: added adapters for all mx.DateTime types. + +2004-02-28 Federico Di Gregorio + + * cursor_type.c (_mogrify): complete rework of the mogrification + code to use the microprotocols_adapt function. + + * typecast_basic.c (typecast_BOOLEAN_cast): we now return real + Py_True and Py_False values. + + * microprotocols.h: added very simple microprotocols + implementation to allow for python->postgresql types registry. + +2004-01-05 Federico Di Gregorio + + * connection_int.c (conn_commit/conn_rollback): added code to + commit/rollback and connection methods. + +2004-01-04 Federico Di Gregorio + + * cursor_type.c (psyco_curs_fetchone): added fetchone method. + +2004-01-03 Federico Di Gregorio + + * added (empty) INSTALL file. + + * cursor_type.c (cursor_dealloc): added qattr for custom object + quoting using a callable attribute. + (_mogrify): ported new, fixed mogrification code from 1.1.12. + +2003-08-01 Federico Di Gregorio + + * cursor_type.c (_mogrify_sequence): added sequence mogrification, + can be done better, on the dict model. + +2003-07-28 Federico Di Gregorio + + * typeobj_qstring.c: added quoted strings (can use both own code, + like psycopg 1.x or PQescapeString from lipq.) + +2003-07-21 Federico Di Gregorio + + * connection_type.c (psyco_conn_close): added .close() + method. wow. + + * cursor_*.c: added basic cursor interface (new-style.) + +2003-07-20 Federico Di Gregorio + + * psycopg/*: beginning of new source layout. if you think this + changelog is somewhat empty, you're right. look at + doc/ChangeLog-1.x for psycopg 1.x changelog just before the + branch. + + diff --git a/psycopg2/INSTALL b/psycopg2/INSTALL new file mode 100644 index 0000000..873dbfa --- /dev/null +++ b/psycopg2/INSTALL @@ -0,0 +1,48 @@ +Compiling and installing psycopg +******************************** + +** Important note: if you plan to use psyopg2 in a multithreaed application + make sure that your libpq has been compiled with the --with-thread-safety + option. psycopg2 will work correctly even with a non-thread-safe libpq but + libpq will leak memory. + +While psycopg 1.x used autoconf for its build process psycopg 2 switched to +the more pythoning setup.py. Currently both psycopg's author and distutils +have some limitations so the file setup.cfg is almost unused and most build +options are hidden in setup.py. Before building psycopg look at setup.cfg file +and change any settings to follow your system (or taste); then: + + python setup.py build + +to build in the local directory; and: + + python setup.py install + +to install system-wide. + + +Using setuptools and EasyInstall +================================ + +If setuptools are installed on your system you can easily create an egg for +psycopg and install it. Download the source distribution (if you're reading +this file you probably already have) and then edit setup.cfg to your taste +and build from the source distribution top-level directory using: + + easy_install . + + +Compiling under Windows with mingw32 +==================================== + +You can compile psycopg under Windows platform with mingw32 +(http://www.mingw.org/) compiler. MinGW is also shipped with IDEs such as +Dev-C++ (http://www.bloodshed.net/devcpp.html) and Code::Blocks +(http://www.codeblocks.org). gcc binaries should be in your PATH. + +You need a PostgreSQL with include and libary files installed. At least v8.0 is required. + +First you need to create a libpython2X.a as described in +http://starship.python.net/crew/kernr/mingw32/Notes.html. Then run: + + python setup.py build_ext --compiler=mingw32 install diff --git a/psycopg2/LICENSE b/psycopg2/LICENSE new file mode 100644 index 0000000..b20b282 --- /dev/null +++ b/psycopg2/LICENSE @@ -0,0 +1,60 @@ +psycopg and the GPL +=================== + +psycopg is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. See file COPYING for details. + +As a special exception, specific permission is granted for the GPLed +code in this distribition to be linked to OpenSSL and PostgreSQL libpq +without invoking GPL clause 2(b). + +Note that the GPL was chosen to avoid proprietary adapters based on +psycopg code. Using psycopg in a proprietary product (even bundling +psycopg with the proprietary product) is fine as long as: + + 1. psycopg is called from Python only using only the provided API + (i.e., no linking with C code and no C modules based on it); and + + 2. all the other points of the GPL are respected (you offer a copy + of psycopg's source code, and so on.) + +Alternative licenses +==================== + +If you prefer you can use the Zope Database Adapter ZPsycopgDA (i.e., +every file inside the ZPsycopgDA directory) user the ZPL license as +published on the Zope web site, http://www.zope.org/Resources/ZPL. + +Also, the following BSD-like license applies (at your option) to the +files following the pattern psycopg/adapter*.{h,c} and +psycopg/microprotocol*.{h,c}: + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product documentation + would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source distribution. + +psycopg is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +Proprietary licenses +==================== + +A non-exclusive license is available for companies that want to include +psycopg in their proprietary products without respecting the spirit of the +GPL. The price of the license is one day of development done by the author, +at the consulting fee he applies to his usual customers at the day of the +request. diff --git a/psycopg2/MANIFEST b/psycopg2/MANIFEST new file mode 100644 index 0000000..c8538ea --- /dev/null +++ b/psycopg2/MANIFEST @@ -0,0 +1,222 @@ +AUTHORS +ChangeLog +INSTALL +LICENSE +MANIFEST +MANIFEST.in +README +setup.cfg +setup.py +ZPsycopgDA/DA.py +ZPsycopgDA/__init__.py +ZPsycopgDA/db.py +ZPsycopgDA/pool.py +ZPsycopgDA/dtml/add.dtml +ZPsycopgDA/dtml/browse.dtml +ZPsycopgDA/dtml/edit.dtml +ZPsycopgDA/dtml/table_info.dtml +ZPsycopgDA/icons/bin.gif +ZPsycopgDA/icons/date.gif +ZPsycopgDA/icons/datetime.gif +ZPsycopgDA/icons/field.gif +ZPsycopgDA/icons/float.gif +ZPsycopgDA/icons/int.gif +ZPsycopgDA/icons/stable.gif +ZPsycopgDA/icons/table.gif +ZPsycopgDA/icons/text.gif +ZPsycopgDA/icons/time.gif +ZPsycopgDA/icons/view.gif +ZPsycopgDA/icons/what.gif +debian/changelog +debian/control +debian/copyright +debian/rules +doc/ChangeLog-1.x +doc/HACKING +doc/SUCCESS +doc/TODO +doc/api-screen.css +doc/async.txt +doc/extensions.html +doc/extensions.rst +doc/api/epydoc.css +doc/api/index.html +doc/api/private/__builtin__.list-class.html +doc/api/private/__builtin__.object-class.html +doc/api/private/__builtin__.type-class.html +doc/api/private/datetime.tzinfo-class.html +doc/api/private/epydoc.css +doc/api/private/exceptions.Exception-class.html +doc/api/private/exceptions.StandardError-class.html +doc/api/private/frames.html +doc/api/private/help.html +doc/api/private/index.html +doc/api/private/indices.html +doc/api/private/psycopg2-module.html +doc/api/private/psycopg2.DataError-class.html +doc/api/private/psycopg2.DatabaseError-class.html +doc/api/private/psycopg2.Error-class.html +doc/api/private/psycopg2.IntegrityError-class.html +doc/api/private/psycopg2.InterfaceError-class.html +doc/api/private/psycopg2.InternalError-class.html +doc/api/private/psycopg2.NotSupportedError-class.html +doc/api/private/psycopg2.OperationalError-class.html +doc/api/private/psycopg2.ProgrammingError-class.html +doc/api/private/psycopg2.Warning-class.html +doc/api/private/psycopg2._psycopg-module.html +doc/api/private/psycopg2._psycopg.ISQLQuote-class.html +doc/api/private/psycopg2._psycopg.connection-class.html +doc/api/private/psycopg2._psycopg.cursor-class.html +doc/api/private/psycopg2.extensions-module.html +doc/api/private/psycopg2.extras-module.html +doc/api/private/psycopg2.extras.DictConnection-class.html +doc/api/private/psycopg2.extras.DictCursor-class.html +doc/api/private/psycopg2.extras.DictRow-class.html +doc/api/private/psycopg2.extras.SQL_IN-class.html +doc/api/private/psycopg2.pool-module.html +doc/api/private/psycopg2.pool.AbstractConnectionPool-class.html +doc/api/private/psycopg2.pool.PersistentConnectionPool-class.html +doc/api/private/psycopg2.pool.PoolError-class.html +doc/api/private/psycopg2.pool.SimpleConnectionPool-class.html +doc/api/private/psycopg2.pool.ThreadedConnectionPool-class.html +doc/api/private/psycopg2.psycopg1-module.html +doc/api/private/psycopg2.psycopg1.connection-class.html +doc/api/private/psycopg2.psycopg1.cursor-class.html +doc/api/private/psycopg2.tz-module.html +doc/api/private/psycopg2.tz.FixedOffsetTimezone-class.html +doc/api/private/psycopg2.tz.LocalTimezone-class.html +doc/api/private/toc-everything.html +doc/api/private/toc-psycopg2-module.html +doc/api/private/toc-psycopg2._psycopg-module.html +doc/api/private/toc-psycopg2.extensions-module.html +doc/api/private/toc-psycopg2.extras-module.html +doc/api/private/toc-psycopg2.pool-module.html +doc/api/private/toc-psycopg2.psycopg1-module.html +doc/api/private/toc-psycopg2.tz-module.html +doc/api/private/toc.html +doc/api/private/trees.html +doc/api/public/__builtin__.list-class.html +doc/api/public/__builtin__.object-class.html +doc/api/public/__builtin__.type-class.html +doc/api/public/datetime.tzinfo-class.html +doc/api/public/epydoc.css +doc/api/public/exceptions.Exception-class.html +doc/api/public/exceptions.StandardError-class.html +doc/api/public/frames.html +doc/api/public/help.html +doc/api/public/index.html +doc/api/public/indices.html +doc/api/public/psycopg2-module.html +doc/api/public/psycopg2.DataError-class.html +doc/api/public/psycopg2.DatabaseError-class.html +doc/api/public/psycopg2.Error-class.html +doc/api/public/psycopg2.IntegrityError-class.html +doc/api/public/psycopg2.InterfaceError-class.html +doc/api/public/psycopg2.InternalError-class.html +doc/api/public/psycopg2.NotSupportedError-class.html +doc/api/public/psycopg2.OperationalError-class.html +doc/api/public/psycopg2.ProgrammingError-class.html +doc/api/public/psycopg2.Warning-class.html +doc/api/public/psycopg2._psycopg-module.html +doc/api/public/psycopg2.extensions-module.html +doc/api/public/psycopg2.extras-module.html +doc/api/public/psycopg2.extras.DictConnection-class.html +doc/api/public/psycopg2.extras.DictCursor-class.html +doc/api/public/psycopg2.extras.DictRow-class.html +doc/api/public/psycopg2.extras.SQL_IN-class.html +doc/api/public/psycopg2.pool-module.html +doc/api/public/psycopg2.pool.AbstractConnectionPool-class.html +doc/api/public/psycopg2.pool.PersistentConnectionPool-class.html +doc/api/public/psycopg2.pool.PoolError-class.html +doc/api/public/psycopg2.pool.SimpleConnectionPool-class.html +doc/api/public/psycopg2.pool.ThreadedConnectionPool-class.html +doc/api/public/psycopg2.psycopg1-module.html +doc/api/public/psycopg2.psycopg1.connection-class.html +doc/api/public/psycopg2.psycopg1.cursor-class.html +doc/api/public/psycopg2.tz-module.html +doc/api/public/psycopg2.tz.FixedOffsetTimezone-class.html +doc/api/public/psycopg2.tz.LocalTimezone-class.html +doc/api/public/toc-everything.html +doc/api/public/toc-psycopg2-module.html +doc/api/public/toc-psycopg2._psycopg-module.html +doc/api/public/toc-psycopg2.extensions-module.html +doc/api/public/toc-psycopg2.extras-module.html +doc/api/public/toc-psycopg2.pool-module.html +doc/api/public/toc-psycopg2.psycopg1-module.html +doc/api/public/toc-psycopg2.tz-module.html +doc/api/public/toc.html +doc/api/public/trees.html +examples/binary.py +examples/copy_from.py +examples/copy_to.py +examples/cursor.py +examples/dialtone.py +examples/dict.py +examples/dt.py +examples/encoding.py +examples/fetch.py +examples/lastrowid.py +examples/mogrify.py +examples/myfirstrecipe.py +examples/notify.py +examples/simple.py +examples/somehackers.jpg +examples/threads.py +examples/tz.py +examples/usercast.py +examples/whereareyou.jpg +lib/__init__.py +lib/extensions.py +lib/extras.py +lib/pool.py +lib/psycopg1.py +lib/tz.py +psycopg/adapter_asis.c +psycopg/adapter_asis.h +psycopg/adapter_binary.c +psycopg/adapter_binary.h +psycopg/adapter_datetime.c +psycopg/adapter_datetime.h +psycopg/adapter_list.c +psycopg/adapter_list.h +psycopg/adapter_mxdatetime.c +psycopg/adapter_mxdatetime.h +psycopg/adapter_pboolean.c +psycopg/adapter_pboolean.h +psycopg/adapter_qstring.c +psycopg/adapter_qstring.h +psycopg/config.h +psycopg/connection.h +psycopg/connection_int.c +psycopg/connection_type.c +psycopg/cursor.h +psycopg/cursor_int.c +psycopg/cursor_type.c +psycopg/microprotocols.c +psycopg/microprotocols.h +psycopg/microprotocols_proto.c +psycopg/microprotocols_proto.h +psycopg/pgtypes.h +psycopg/pgversion.h +psycopg/pqpath.c +psycopg/pqpath.h +psycopg/psycopg.h +psycopg/psycopgmodule.c +psycopg/python.h +psycopg/typecast.c +psycopg/typecast.h +psycopg/typecast_array.c +psycopg/typecast_basic.c +psycopg/typecast_binary.c +psycopg/typecast_binary.h +psycopg/typecast_builtins.c +psycopg/typecast_datetime.c +psycopg/typecast_mxdatetime.c +scripts/buildtypes.py +scripts/ext2html.py +scripts/makedocs.py +scripts/maketypes.sh +tests/dbapi20.py +tests/extras_dictcursor.py +tests/test_psycopg2_dbapi20.py +tests/types_basic.py diff --git a/psycopg2/MANIFEST.in b/psycopg2/MANIFEST.in new file mode 100644 index 0000000..457004c --- /dev/null +++ b/psycopg2/MANIFEST.in @@ -0,0 +1,12 @@ +recursive-include psycopg *.c *.h +recursive-include lib *.py +recursive-include tests *.py +recursive-include ZPsycopgDA *.py *.gif *.dtml +recursive-include examples *.py somehackers.jpg whereareyou.jpg +recursive-include debian * +recursive-include doc TODO HACKING SUCCESS ChangeLog-1.x async.txt +recursive-include scripts *.py *.sh +include scripts/maketypes.sh scripts/buildtypes.py +include AUTHORS README INSTALL LICENSE ChangeLog +include PKG-INFO MANIFEST.in MANIFEST setup.py setup.cfg +recursive-include doc *.rst *.css *.html diff --git a/psycopg2/PKG-INFO b/psycopg2/PKG-INFO new file mode 100644 index 0000000..2fab953 --- /dev/null +++ b/psycopg2/PKG-INFO @@ -0,0 +1,35 @@ +Metadata-Version: 1.0 +Name: psycopg2 +Version: 2.0.5.1 +Summary: Python-PostgreSQL Database Adapter +Home-page: http://initd.org/tracker/psycopg +Author: Federico Di Gregorio +Author-email: fog@initd.org +License: GPL with exceptions or ZPL +Download-URL: http://initd.org/pub/software/psycopg2 +Description: psycopg is a PostgreSQL database adapter for the Python programming + language. This is version 2, a complete rewrite of the original code to + provide new-style classes for connection and cursor objects and other sweet + candies. Like the original, psycopg 2 was written with the aim of being + very small and fast, and stable as a rock. + + psycopg is different from the other database adapter because it was + designed for heavily multi-threaded applications that create and destroy + lots of cursors and make a conspicuous number of concurrent INSERTs or + UPDATEs. psycopg 2 also provide full asycronous operations for the really + brave programmer. + +Platform: any +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU General Public License (GPL) +Classifier: License :: OSI Approved :: Zope Public License +Classifier: Programming Language :: Python +Classifier: Programming Language :: C +Classifier: Programming Language :: SQL +Classifier: Topic :: Database +Classifier: Topic :: Database :: Front-Ends +Classifier: Topic :: Software Development +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: Unix diff --git a/psycopg2/README b/psycopg2/README new file mode 100644 index 0000000..4e4a0e9 --- /dev/null +++ b/psycopg2/README @@ -0,0 +1,39 @@ +psycopg - Python-PostgreSQL Database Adapter +******************************************** + +psycopg is a PostgreSQL database adapter for the Python programming +language. This is version 2, a complete rewrite of the original code to +provide new-style classes for connection and cursor objects and other +sweet candies. Like the original, psycopg 2 was written with the aim of +being very small and fast, and stable as a rock. + +psycopg is different from the other database adapter because it was +designed for heavily multi-threaded applications that create and destroy +lots of cursors and make a conspicuous number of concurrent INSERTs or +UPDATEs. psycopg 2 also provide full asycronous operations for the really +brave programmer. + +There are confirmed reports of psycopg 1.x compiling and running on Linux +and FreeBSD on i386, Solaris, MacOS X and win32 architectures. psycopg 2 +does not introduce build-wise incompatible changes so it should be able to +compile on all architectures just as its predecessor did. + +Now go read the INSTALL file. More information about psycopg extensions to +the DBAPI-2.0 is available in the files located in the doc/ direcory. + +psycopg is free software ("free as in freedom" but I like beer too.) +Licensing information is available in the LICENSE file. + + +Contributors +------------ + +A short list of contributors to psycopg2 follows (if you feel you belong +to this list and you can't find yourself here just drop me a mail): + + * Kudos to piro for all the documentation work. + + * Peter Fein contributed a logging connection/cursor class that even if it + was not used directly heavily influenced the implementation currently in + psycopg2.extras. + diff --git a/psycopg2/ZPsycopgDA/DA.py b/psycopg2/ZPsycopgDA/DA.py new file mode 100644 index 0000000..2a0f4dd --- /dev/null +++ b/psycopg2/ZPsycopgDA/DA.py @@ -0,0 +1,375 @@ +# ZPsycopgDA/DA.py - ZPsycopgDA Zope product: Database Connection +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# Or, at your option this program (ZPsycopgDA) can be distributed under the +# Zope Public License (ZPL) Version 1.0, as published on the Zope web site, +# http://www.zope.org/Resources/ZPL. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the LICENSE file for details. + + +ALLOWED_PSYCOPG_VERSIONS = ('2.0.1', '2.0.2', '2.0.3', '2.0.4', '2.0.5') + +import sys +import time +import db +import re + +import Acquisition +import Shared.DC.ZRDB.Connection + +from db import DB +from Globals import HTMLFile +from ExtensionClass import Base +from App.Dialogs import MessageDialog +from DateTime import DateTime + +# Build Zope version in a float for later cheks +import App +zope_version = App.version_txt.getZopeVersion() +zope_version = float("%s.%s" %(zope_version[:2])) + +# ImageFile is deprecated in Zope >= 2.9 +if zope_version < 2.9: + from ImageFile import ImageFile +else: + from App.ImageFile import ImageFile + +# import psycopg and functions/singletons needed for date/time conversions + +import psycopg2 +from psycopg2 import NUMBER, STRING, ROWID, DATETIME +from psycopg2.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN, DATE +from psycopg2.extensions import TIME, INTERVAL +from psycopg2.extensions import new_type, register_type + + +# add a new connection to a folder + +manage_addZPsycopgConnectionForm = HTMLFile('dtml/add',globals()) + +def manage_addZPsycopgConnection(self, id, title, connection_string, + zdatetime=None, tilevel=2, + check=None, REQUEST=None): + """Add a DB connection to a folder.""" + self._setObject(id, Connection(id, title, connection_string, + zdatetime, check, tilevel)) + if REQUEST is not None: return self.manage_main(self, REQUEST) + + +# the connection object + +class Connection(Shared.DC.ZRDB.Connection.Connection): + """ZPsycopg Connection.""" + _isAnSQLConnection = 1 + + id = 'Psycopg2_database_connection' + database_type = 'Psycopg2' + meta_type = title = 'Z Psycopg 2 Database Connection' + icon = 'misc_/conn' + + def __init__(self, id, title, connection_string, + zdatetime, check=None, tilevel=2, encoding=''): + self.zdatetime = zdatetime + self.id = str(id) + self.edit(title, connection_string, zdatetime, + check=check, tilevel=tilevel, encoding=encoding) + + def factory(self): + return DB + + ## connection parameters editing ## + + def edit(self, title, connection_string, + zdatetime, check=None, tilevel=2, encoding=''): + self.title = title + self.connection_string = connection_string + self.zdatetime = zdatetime + self.tilevel = tilevel + self.encoding = encoding + + self.set_type_casts() + + if check: self.connect(self.connection_string) + + manage_properties = HTMLFile('dtml/edit', globals()) + + def manage_edit(self, title, connection_string, + zdatetime=None, check=None, tilevel=2, encoding='UTF-8', + REQUEST=None): + """Edit the DB connection.""" + self.edit(title, connection_string, zdatetime, + check=check, tilevel=tilevel, encoding=encoding) + if REQUEST is not None: + msg = "Connection edited." + return self.manage_main(self,REQUEST,manage_tabs_message=msg) + + def connect(self, s): + try: + self._v_database_connection.close() + except: + pass + + # check psycopg version and raise exception if does not match + if psycopg2.__version__[:5] not in ALLOWED_PSYCOPG_VERSIONS: + raise ImportError("psycopg version mismatch (imported %s)" % + psycopg2.__version__) + + self.set_type_casts() + self._v_connected = '' + dbf = self.factory() + + # TODO: let the psycopg exception propagate, or not? + self._v_database_connection = dbf( + self.connection_string, self.tilevel, self.encoding) + self._v_database_connection.open() + self._v_connected = DateTime() + + return self + + def set_type_casts(self): + # note that in both cases order *is* important + if self.zdatetime: + # use zope internal datetime routines + register_type(ZDATETIME) + register_type(ZDATE) + register_type(ZTIME) + else: + # use the standard + register_type(DATETIME) + register_type(DATE) + register_type(TIME) + + ## browsing and table/column management ## + + manage_options = Shared.DC.ZRDB.Connection.Connection.manage_options + # + ( + # {'label': 'Browse', 'action':'manage_browse'},) + + #manage_tables = HTMLFile('dtml/tables', globals()) + #manage_browse = HTMLFile('dtml/browse', globals()) + + info = None + + def table_info(self): + return self._v_database_connection.table_info() + + + def __getitem__(self, name): + if name == 'tableNamed': + if not hasattr(self, '_v_tables'): self.tpValues() + return self._v_tables.__of__(self) + raise KeyError, name + + def tpValues(self): + res = [] + conn = self._v_database_connection + for d in conn.tables(rdb=0): + try: + name = d['TABLE_NAME'] + b = TableBrowser() + b.__name__ = name + b._d = d + b._c = c + try: + b.icon = table_icons[d['TABLE_TYPE']] + except: + pass + r.append(b) + except: + pass + return res + + +## database connection registration data ## + +classes = (Connection,) + +meta_types = ({'name':'Z Psycopg 2 Database Connection', + 'action':'manage_addZPsycopgConnectionForm'},) + +folder_methods = { + 'manage_addZPsycopgConnection': manage_addZPsycopgConnection, + 'manage_addZPsycopgConnectionForm': manage_addZPsycopgConnectionForm} + +__ac_permissions__ = ( + ('Add Z Psycopg Database Connections', + ('manage_addZPsycopgConnectionForm', 'manage_addZPsycopgConnection')),) + +# add icons + +misc_={'conn': ImageFile('Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif')} + +for icon in ('table', 'view', 'stable', 'what', 'field', 'text', 'bin', + 'int', 'float', 'date', 'time', 'datetime'): + misc_[icon] = ImageFile('icons/%s.gif' % icon, globals()) + + +## zope-specific psycopg typecasters ## + +# convert an ISO timestamp string from postgres to a Zope DateTime object +def _cast_DateTime(iso, curs): + if iso: + return DateTime(re.split("GMT\+?|GMT-?", iso)[0]) + + # this will split us into [date, time, GMT/AM/PM(if there)] + # dt = str.split(' ') + # if len(dt) > 1: + # # we now should split out any timezone info + # dt[1] = dt[1].split('-')[0] + # dt[1] = dt[1].split('+')[0] + # return DateTime(' '.join(dt[:2])) + # else: + # return DateTime(dt[0]) + +# convert an ISO date string from postgres to a Zope DateTime object +def _cast_Date(iso, curs): + if iso: + return DateTime(iso) + +# Convert a time string from postgres to a Zope DateTime object. +# NOTE: we set the day as today before feeding to DateTime so +# that it has the same DST settings. +def _cast_Time(iso, curs): + if iso: + return DateTime(time.strftime('%Y-%m-%d %H:%M:%S', + time.localtime(time.time())[:3]+ + time.strptime(iso[:8], "%H:%M:%S")[3:])) + +# NOTE: we don't cast intervals anymore because they are passed +# untouched to Zope. +def _cast_Interval(iso, curs): + return iso + +ZDATETIME = new_type((1184, 1114), "ZDATETIME", _cast_DateTime) +ZINTERVAL = new_type((1186,), "ZINTERVAL", _cast_Interval) +ZDATE = new_type((1082,), "ZDATE", _cast_Date) +ZTIME = new_type((1083,), "ZTIME", _cast_Time) + + +## table browsing helpers ## + +class TableBrowserCollection(Acquisition.Implicit): + pass + +class Browser(Base): + def __getattr__(self, name): + try: + return self._d[name] + except KeyError: + raise AttributeError, name + +class values: + def len(self): + return 1 + + def __getitem__(self, i): + try: + return self._d[i] + except AttributeError: + pass + self._d = self._f() + return self._d[i] + +class TableBrowser(Browser, Acquisition.Implicit): + icon = 'what' + Description = check = '' + info = HTMLFile('table_info', globals()) + menu = HTMLFile('table_menu', globals()) + + def tpValues(self): + v = values() + v._f = self.tpValues_ + return v + + def tpValues_(self): + r=[] + tname=self.__name__ + for d in self._c.columns(tname): + b=ColumnBrowser() + b._d=d + try: b.icon=field_icons[d['Type']] + except: pass + b.TABLE_NAME=tname + r.append(b) + return r + + def tpId(self): return self._d['TABLE_NAME'] + def tpURL(self): return "Table/%s" % self._d['TABLE_NAME'] + def Name(self): return self._d['TABLE_NAME'] + def Type(self): return self._d['TABLE_TYPE'] + + manage_designInput=HTMLFile('designInput',globals()) + def manage_buildInput(self, id, source, default, REQUEST=None): + "Create a database method for an input form" + args=[] + values=[] + names=[] + columns=self._columns + for i in range(len(source)): + s=source[i] + if s=='Null': continue + c=columns[i] + d=default[i] + t=c['Type'] + n=c['Name'] + names.append(n) + if s=='Argument': + values.append("'" % + (n, vartype(t))) + a='%s%s' % (n, boboType(t)) + if d: a="%s=%s" % (a,d) + args.append(a) + elif s=='Property': + values.append("'" % + (n, vartype(t))) + else: + if isStringType(t): + if find(d,"\'") >= 0: d=join(split(d,"\'"),"''") + values.append("'%s'" % d) + elif d: + values.append(str(d)) + else: + raise ValueError, ( + 'no default was given for %s' % n) + +class ColumnBrowser(Browser): + icon='field' + + def check(self): + return ('\t' % + (self.TABLE_NAME, self._d['Name'])) + def tpId(self): return self._d['Name'] + def tpURL(self): return "Column/%s" % self._d['Name'] + def Description(self): + d=self._d + if d['Scale']: + return " %(Type)s(%(Precision)s,%(Scale)s) %(Nullable)s" % d + else: + return " %(Type)s(%(Precision)s) %(Nullable)s" % d + +table_icons={ + 'TABLE': 'table', + 'VIEW':'view', + 'SYSTEM_TABLE': 'stable', + } + +field_icons={ + NUMBER.name: 'i', + STRING.name: 'text', + DATETIME.name: 'date', + INTEGER.name: 'int', + FLOAT.name: 'float', + BOOLEAN.name: 'bin', + ROWID.name: 'int' + } diff --git a/psycopg2/ZPsycopgDA/__init__.py b/psycopg2/ZPsycopgDA/__init__.py new file mode 100644 index 0000000..0af0ceb --- /dev/null +++ b/psycopg2/ZPsycopgDA/__init__.py @@ -0,0 +1,31 @@ +# ZPsycopgDA/__init__.py - ZPsycopgDA Zope product +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# Or, at your option this program (ZPsycopgDA) can be distributed under the +# Zope Public License (ZPL) Version 1.0, as published on the Zope web site, +# http://www.zope.org/Resources/ZPL. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the LICENSE file for details. + +__doc__ = "ZPsycopg Database Adapter Registration." +__version__ = '2.0' + +import DA + +def initialize(context): + context.registerClass( + DA.Connection, + permission = 'Add Z Psycopg 2 Database Connections', + constructors = (DA.manage_addZPsycopgConnectionForm, + DA.manage_addZPsycopgConnection), + icon = SOFTWARE_HOME + '/Shared/DC/ZRDB/www/DBAdapterFolder_icon.gif') diff --git a/psycopg2/ZPsycopgDA/db.py b/psycopg2/ZPsycopgDA/db.py new file mode 100644 index 0000000..9a0b4b0 --- /dev/null +++ b/psycopg2/ZPsycopgDA/db.py @@ -0,0 +1,206 @@ +# ZPsycopgDA/db.py - query execution +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# Or, at your option this program (ZPsycopgDA) can be distributed under the +# Zope Public License (ZPL) Version 1.0, as published on the Zope web site, +# http://www.zope.org/Resources/ZPL. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the LICENSE file for details. + +from Shared.DC.ZRDB.TM import TM +from Shared.DC.ZRDB import dbi_db + +from ZODB.POSException import ConflictError + +import site +import pool + +import psycopg2 +from psycopg2.extensions import INTEGER, LONGINTEGER, FLOAT, BOOLEAN, DATE, TIME +from psycopg2 import NUMBER, STRING, ROWID, DATETIME + + +# the DB object, managing all the real query work + +class DB(TM, dbi_db.DB): + + _p_oid = _p_changed = _registered = None + + def __init__(self, dsn, tilevel, enc='utf-8'): + self.dsn = dsn + self.tilevel = tilevel + self.encoding = enc + self.failures = 0 + self.calls = 0 + self.make_mappings() + + def getconn(self, create=True): + conn = pool.getconn(self.dsn) + conn.set_isolation_level(int(self.tilevel)) + return conn + + def putconn(self, close=False): + try: + conn = pool.getconn(self.dsn, False) + except AttributeError: + pass + pool.putconn(self.dsn, conn, close) + + def getcursor(self): + conn = self.getconn() + return conn.cursor() + + def _finish(self, *ignored): + try: + conn = self.getconn(False) + conn.commit() + self.putconn() + except AttributeError: + pass + + def _abort(self, *ignored): + try: + conn = self.getconn(False) + conn.rollback() + self.putconn() + except AttributeError: + pass + + def open(self): + # this will create a new pool for our DSN if not already existing, + # then get and immediately release a connection + self.getconn() + self.putconn() + + def close(self): + # FIXME: if this connection is closed we flush all the pool associated + # with the current DSN; does this makes sense? + pool.flushpool(self.dsn) + + def sortKey(self): + return 1 + + def make_mappings(self): + """Generate the mappings used later by self.convert_description().""" + self.type_mappings = {} + for t, s in [(INTEGER,'i'), (LONGINTEGER, 'i'), (NUMBER, 'n'), + (BOOLEAN,'n'), (ROWID, 'i'), + (DATETIME, 'd'), (DATE, 'd'), (TIME, 'd')]: + for v in t.values: + self.type_mappings[v] = (t, s) + + def convert_description(self, desc, use_psycopg_types=False): + """Convert DBAPI-2.0 description field to Zope format.""" + items = [] + for name, typ, width, ds, p, scale, null_ok in desc: + m = self.type_mappings.get(typ, (STRING, 's')) + items.append({ + 'name': name, + 'type': use_psycopg_types and m[0] or m[1], + 'width': width, + 'precision': p, + 'scale': scale, + 'null': null_ok, + }) + return items + + ## tables and rows ## + + def tables(self, rdb=0, _care=('TABLE', 'VIEW')): + self._register() + c = self.getcursor() + c.execute( + "SELECT t.tablename AS NAME, 'TABLE' AS TYPE " + " FROM pg_tables t WHERE tableowner <> 'postgres' " + "UNION SELECT v.viewname AS NAME, 'VIEW' AS TYPE " + " FROM pg_views v WHERE viewowner <> 'postgres' " + "UNION SELECT t.tablename AS NAME, 'SYSTEM_TABLE\' AS TYPE " + " FROM pg_tables t WHERE tableowner = 'postgres' " + "UNION SELECT v.viewname AS NAME, 'SYSTEM_TABLE' AS TYPE " + "FROM pg_views v WHERE viewowner = 'postgres'") + res = [] + for name, typ in c.fetchall(): + if typ in _care: + res.append({'TABLE_NAME': name, 'TABLE_TYPE': typ}) + self.putconn() + return res + + def columns(self, table_name): + self._register() + c = self.getcursor() + try: + r = c.execute('SELECT * FROM "%s" WHERE 1=0' % table_name) + except: + return () + self.putconn() + return self.convert_description(c.description, True) + + ## query execution ## + + def query(self, query_string, max_rows=None, query_data=None): + self._register() + self.calls = self.calls+1 + + desc = () + res = [] + nselects = 0 + + c = self.getcursor() + + try: + for qs in [x for x in query_string.split('\0') if x]: + if type(qs) == unicode: + if self.encoding: + qs = qs.encode(self.encoding) + try: + if query_data: + c.execute(qs, query_data) + else: + c.execute(qs) + except psycopg2.OperationalError, e: + try: + self.close() + except: + pass + self.open() + try: + if query_data: + c.execute(qs, query_data) + else: + c.execute(qs) + except (psycopg2.ProgrammingError, + psycopg2.IntegrityError), e: + if e.args[0].find("concurrent update") > -1: + raise ConflictError + raise e + except (psycopg2.ProgrammingError, psycopg2.IntegrityError), e: + if e.args[0].find("concurrent update") > -1: + raise ConflictError + raise e + if c.description is not None: + nselects += 1 + if c.description != desc and nselects > 1: + raise psycopg2.ProgrammingError( + 'multiple selects in single query not allowed') + if max_rows: + res = c.fetchmany(max_rows) + else: + res = c.fetchall() + desc = c.description + self.failures = 0 + + except StandardError, err: + self._abort() + raise err + + return self.convert_description(desc), res diff --git a/psycopg2/ZPsycopgDA/dtml/add.dtml b/psycopg2/ZPsycopgDA/dtml/add.dtml new file mode 100644 index 0000000..c718ded --- /dev/null +++ b/psycopg2/ZPsycopgDA/dtml/add.dtml @@ -0,0 +1,96 @@ + + + + +

+A Zope Psycopg 2 Database Connection is used to connect and execute +queries on a PostgreSQL database. +

+ +

+In the form below Connection String (also called the Data Source Name +or DSN for short) is a string... (TODO: finish docs) +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Id +
+
+ +
+
+ Title +
+
+ +
+
+ Connection string +
+
+ +
+
+ Connect immediately +
+
+ +
+
+ Use Zope's internal DateTime +
+
+ +
+
+ Transaction isolation level +
+
+ +
+
+ +
+
+
+ + diff --git a/psycopg2/ZPsycopgDA/dtml/browse.dtml b/psycopg2/ZPsycopgDA/dtml/browse.dtml new file mode 100644 index 0000000..deffd0a --- /dev/null +++ b/psycopg2/ZPsycopgDA/dtml/browse.dtml @@ -0,0 +1,11 @@ + + <dtml-var title_or_id >tables + + + + <dtml-var Type> + + + + diff --git a/psycopg2/ZPsycopgDA/dtml/edit.dtml b/psycopg2/ZPsycopgDA/dtml/edit.dtml new file mode 100644 index 0000000..7cb371f --- /dev/null +++ b/psycopg2/ZPsycopgDA/dtml/edit.dtml @@ -0,0 +1,67 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+ Title +
+
+ +
+
+ Connection string +
+
+ +
+
+ Use Zope's internal DateTime +
+
+ checked="YES" /> +
+
+ Transaction isolation level +
+
+ +
+
+ +
+
+
+ + diff --git a/psycopg2/ZPsycopgDA/dtml/table_info.dtml b/psycopg2/ZPsycopgDA/dtml/table_info.dtml new file mode 100644 index 0000000..639c23f --- /dev/null +++ b/psycopg2/ZPsycopgDA/dtml/table_info.dtml @@ -0,0 +1,7 @@ + + + + owned by +
+ + diff --git a/psycopg2/ZPsycopgDA/icons/bin.gif b/psycopg2/ZPsycopgDA/icons/bin.gif new file mode 100644 index 0000000000000000000000000000000000000000..e4691265687b23c83b3032da963526c0b3a8e526 GIT binary patch literal 924 zcmZ?wbhEHbRA3Nb_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vf!21X7Uj|~eBHnR!}M68(b(20pl(XK~A zaM6J-e&eh=I|L6N?NpHMnqqND>Cj{it{|4q1*smLy4qDN8;VkVCt3I=JvlM?`I#vW z{>NmzwyX$TB(J`!hO;p9kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vgP21X7Uj|~eBHnR!}I4qcO;7}XCv{8x2 z#6?alOp0N5PHbF!w1->POC-}U#kE6Ra8*p@hevL`a-Nfpa2#0b+szYOkRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vfU21X7Uj|~eBHnR!}C^R@cbZX-hH|yaD zT;#;Uq-l5O#KvUz9tIh+Co2kGduN%ZT-=-?&BVdM GU=0Ad>`i|F literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/field.gif b/psycopg2/ZPsycopgDA/icons/field.gif new file mode 100644 index 0000000000000000000000000000000000000000..9bf8692be6c734783164f7c8df4a99c7696c6635 GIT binary patch literal 915 zcmZ?wbhEHbRA3Nb_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?ve>21X7Uj|~eBHnR!}M4Xtg@K77StXWKl zL&A|x3FEXi91j*9>z5YnlBv9q?9!^vxn$0Xi^{Ik44lhYJcHFv&Q=n9ap&ab<>%*H v=_cKI8IT@0U8^une6?JLt4=KqQ4PCmwN?4T`h;dS76xkoP%cQ! literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/float.gif b/psycopg2/ZPsycopgDA/icons/float.gif new file mode 100644 index 0000000000000000000000000000000000000000..dd427299369f706417724103e20b3b5c89480ffd GIT binary patch literal 929 zcmZ?wbhEHbRA3Nb_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vfk21X7Uj|~eBHnR!}M64)S=*+|=>(-(n zxadG9zj4-`6CaXX+a#6!L^1^zo}A1ksub~aqSDD}TDDC!9fixz&S1zYx+5vH)PIV0 zGncH_mW+UzBC4BGc1(E|#Ntt!Boir^b#7Y3?0Y&tFQs|R3SF$lb!yAP6U)VWSHkRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vg121X7Uj|~eBHnR!}M4Xt=aHx%2-e`(N zpn_|MgmIEfg5lyL-SXy2GM=9lJXjQ!t>$P59dMn>6~C_K#Kon@W?RTkyAvt2^!$8> yX0ER{3zL1O2v6KL<>ZuSLH%x%t8`vXQ4N_DlC1VsGEg&Yy7S>KS55^525SI%rbtNu literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/stable.gif b/psycopg2/ZPsycopgDA/icons/stable.gif new file mode 100644 index 0000000000000000000000000000000000000000..acdd37df61c44de3b08fa95c8302e6702a423da5 GIT binary patch literal 884 zcmZ?wbhEHb6krfw_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vfq21X7Uj|~b8%p5{mF*`0WIJF4~TlGj3 zD!I0a>1&-?A;{?7%jeuBqbbD5$fOoH&!@BK(W&WL;k$ZfPFm{TVvs#Ar*pEJ&pfNz NQ!1V&DGm$_)&Ox}G%ElA literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/table.gif b/psycopg2/ZPsycopgDA/icons/table.gif new file mode 100644 index 0000000000000000000000000000000000000000..cce83beaf96b7d4e6147e7c6a18c975c541df349 GIT binary patch literal 878 zcmZ?wbhEHb6krfw_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?q{u21X7Uj|~ePSXej|LS_^!Jk-pkY?Q-M z_{gc9gC|R;B2ejAm#n%Si-6IS6TQ-cD`HMgdU|l0LFm4on?-78r<&!bsjL)MKR-{B InTf#~0OKh&NdN!< literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/text.gif b/psycopg2/ZPsycopgDA/icons/text.gif new file mode 100644 index 0000000000000000000000000000000000000000..a2e5aab6f29769c52dff27f822fc9da76f0be924 GIT binary patch literal 918 zcmZ?wbhEHbRA3Nb_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vg121X7Uj|~eBHnR!}M4S+4Jlx7B?=G`RG y&0MlxAuIf5SWJ{FJ-PXD&;(^sH`|{jtFF#9^1sG&YeJGAgX`h0UJeBX25SJ2OGq*R literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/time.gif b/psycopg2/ZPsycopgDA/icons/time.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d089150008c5f5e5d35771e238266d2e0f37cc5 GIT binary patch literal 926 zcmZ?wbhEHbRA3Nb_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vg921X7Uj|~eBHnR!}M4SkC=+w@`snNm_ zxadHapmElnA0HOE^$1C~)kp|39-6GdALer4(_)VkRPi6k zYyb-U2XaQiXb23W5K#Qd!U*z?4u}Bd2?vfS21X7Uj|~b8>?}e`DjOywI@28Bd|4!>#Jt%g($=P-b8;NIuo#QLyZ6GhflGJ1-T~{N~xz XGO=ovyg0YWtysus)#L;R1_o;Yx92&e literal 0 HcmV?d00001 diff --git a/psycopg2/ZPsycopgDA/icons/what.gif b/psycopg2/ZPsycopgDA/icons/what.gif new file mode 100644 index 0000000000000000000000000000000000000000..8b5516e397d2684c0ee4628ddd2730964e07bee0 GIT binary patch literal 894 zcmZ?wbhEHb6krfw_|Cxa9|##30s;aW8X689H~{1{FgP$UEMRbGXkch?U~u>kRPi6k zYyb-U2XaQiXb23W5K#Qd!pOkD%Af=C6DUtOa6~gOa>z(5Sa7hBMOGsu +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# Or, at your option this program (ZPsycopgDA) can be distributed under the +# Zope Public License (ZPL) Version 1.0, as published on the Zope web site, +# http://www.zope.org/Resources/ZPL. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. +# +# See the LICENSE file for details. + +# all the connections are held in a pool of pools, directly accessible by the +# ZPsycopgDA code in db.py + +import threading +import psycopg2.pool + +_connections_pool = {} +_connections_lock = threading.Lock() + +def getpool(dsn, create=True): + _connections_lock.acquire() + try: + if not _connections_pool.has_key(dsn) and create: + _connections_pool[dsn] = \ + psycopg2.pool.PersistentConnectionPool(4, 200, dsn) + finally: + _connections_lock.release() + return _connections_pool[dsn] + +def flushpool(dsn): + _connections_lock.acquire() + try: + _connections_pool[dsn].closeall() + del _connections_pool[dsn] + finally: + _connections_lock.release() + +def getconn(dsn, create=True): + return getpool(dsn, create=create).getconn() + +def putconn(dsn, conn, close=False): + getpool(dsn).putconn(conn, close=close) diff --git a/psycopg2/debian/changelog b/psycopg2/debian/changelog new file mode 100644 index 0000000..44d83dc --- /dev/null +++ b/psycopg2/debian/changelog @@ -0,0 +1,12 @@ +psycopg2 (1.99.12.1-1) experimental; urgency=low + + * Adapted from patches sent by W. Borgert. + * Renamed source package to psycopg2. + + -- Federico Di Gregorio Fri, 4 Mar 2005 13:11:43 +0100 + +psycopg2 (1.99.11-0.1) unstable; urgency=low + + * Experimental package. + + -- W. Borgert Sun, 09 Jan 2005 10:14:09 +0000 diff --git a/psycopg2/debian/control b/psycopg2/debian/control new file mode 100644 index 0000000..9c63676 --- /dev/null +++ b/psycopg2/debian/control @@ -0,0 +1,51 @@ +Source: psycopg2 +Section: python +Priority: optional +Build-depends: postgresql-dev, debhelper (>> 3), python2.3-dev, cdbs +Maintainer: Federico Di Gregorio +Standards-Version: 3.6.1.1 + +Package: python-psycopg2 +Architecture: any +Section: python +Depends: python (>= 2.3), python (<< 2.4), python2.3-psycopg2 +Description: Python module for PostgreSQL [dummy package] + psycopg is a PostgreSQL database adapter for the Python programming + language. It was written from scratch with the aim of being very small + and fast, and stable as a rock. The main advantages of psycopg are that + it supports the full Python DBAPI-2.0 and being thread safe at level 2. + . + psycopg 2 is the next generation psycopg, implementing a much better + type system and even more DBAPI extensions: + . + * support for Python datetime and Decimal types; + * complete implementation of adapt() from PEP 246 to convert Python + types to PostgreSQL ones; + * COPY FROM/COPY TO support; + * inehritable connection and cursor objects and support for connection + and cursor factories; + * automatic encoding conversion and support for unicode queries. + . + This dummy package just depends on the right, default version of Python + and psycopg 2. + +Package: python2.3-psycopg2 +Architecture: any +Section: python +Depends: ${shlibs:Depends}, python2.3 +Description: Python 2.3 module for PostgreSQL + psycopg is a PostgreSQL database adapter for the Python programming + language. It was written from scratch with the aim of being very small + and fast, and stable as a rock. The main advantages of psycopg are that + it supports the full Python DBAPI-2.0 and being thread safe at level 2. + . + psycopg 2 is the next generation psycopg, implementing a much better + type system and even more DBAPI extensions: + . + * support for Python datetime and Decimal types; + * complete implementation of adapt() from PEP 246 to convert Python + types to PostgreSQL ones; + * COPY FROM/COPY TO support; + * inehritable connection and cursor objects and support for connection + and cursor factories; + * automatic encoding conversion and support for unicode queries. diff --git a/psycopg2/debian/copyright b/psycopg2/debian/copyright new file mode 100644 index 0000000..c631915 --- /dev/null +++ b/psycopg2/debian/copyright @@ -0,0 +1,10 @@ +psycopg 2 can be downloaded from: + + http://initd.org/pub/software/psycopg/ALPHA/ + +Copyright (c) 2001-2005 Federico Di Gregorio + +This program is distributed under the GNU GPL. + +On Debian GNU/Linux systems, the complete text of the GNU General +Public License can be found in '/usr/share/common-licenses/GPL'. diff --git a/psycopg2/debian/rules b/psycopg2/debian/rules new file mode 100755 index 0000000..98ad46f --- /dev/null +++ b/psycopg2/debian/rules @@ -0,0 +1,4 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/python-distutils.mk diff --git a/psycopg2/doc/ChangeLog-1.x b/psycopg2/doc/ChangeLog-1.x new file mode 100644 index 0000000..dadfc1b --- /dev/null +++ b/psycopg2/doc/ChangeLog-1.x @@ -0,0 +1,1744 @@ +2003-07-26 Federico Di Gregorio + + * Release 1.1.7. + + * ZPsycopgDA/db.py: added _cursor method that checks for self.db + before returning a new cursor. Should fix problem reported with + Zope 2.7. + +2003-07-23 Federico Di Gregorio + + * cursor.c: applied notify and fileno patch from Vsevolod Lobko. + +2003-07-20 Federico Di Gregorio + + * cursor.c (_mogrify_dict): applied (slightly modofied) patch from + Tobias Sargeant: now .execute() accept not only dictionaries but + every type that has a __getitem__ method. + +2003-07-13 Federico Di Gregorio + + * Release 1.1.6. + + * cursor.c (psyco_curs_scroll): added scroll method, patch from + Jason D.Hildebrand. + + * typemod.c (new_psyco_quotedstringobject): discard NUL characters + (\0) in quoted strings (fix problem reported by Richard Taylor.) + +2003-07-10 Federico Di Gregorio + + * Added python-taylor.txt in doc directory: very nice introduction + to DBAPI programming by Richard Taylor. + +2003-07-09 Federico Di Gregorio + + * cursor.c (_psyco_curs_execute): another MT problem exposed and + fixed by Sebastien Bigaret (self->keeper->status still LOCKED + after a fatal error during PQexec call.) + +2003-06-23 Federico Di Gregorio + + * Release 1.1.5.1. + + * ZPsycopgDA/db.py (DB.query): stupid error making ZPsycopgDA + unusable fixed (else->except). + +2003-06-22 Federico Di Gregorio + + * Release 1.1.5 candidate. + + * cursor.c (psyco_curs_copy_to): now any object with the write + method can be used as a copy_to target. + +2003-06-20 Federico Di Gregorio + + * cursor.c (psyco_curs_copy_from): applied patch to allow copy_to + from any object having a "readline" attribute (patch from Lex + Berezhny.) (psyco_curs_copy_from): another patch from Lex to make + psycopg raise an error on COPY FROM errors. + + * ZPsycopgDA/db.py (DB.query): if a query raise an exception, + first self._abort() is called to rollback current + "sub-transaction". this is a backward-compatible change for + people that think continuing to work in the same zope transaction + after an exception is a Good Thing (TM). + + * finally updated check_types.expected. checked by hand the + conversions work the right way. + + * doc/examples/work.py: fixed example. note that it is a long time + (at least two releases) that psycopg does not END a transaction + initiated explicitly by the user while in autocommit mode. + +2003-06-19 Federico Di Gregorio + + * cursor.c (_mogrify_dict): fixed dictionary mogrification (patch + by Vsevolod Lobko.) (_psyco_curs_execute): fixed keeper status + trashing problem by letting only one thread at time play with + keeper->status (as suggested by Sebastien Bigaret.) + +2003-05-07 Federico Di Gregorio + + * Release 1.1.4. + + * cursor.c: Added "statusmessage" attribute that holds the backend + message (modified lots of functions, look for self->status). + +2003-05-06 Federico Di Gregorio + + * typemod.c (new_psyco_datetimeobject): moved Py_INCREF into + XXX_FromMx functions, to fix memory leak reported by Jim Crumpler. + +2003-04-11 Federico Di Gregorio + + * module.h (PyObject_TypeCheck): fixed leak in python 2.1 + (Guido van Rossum). + +2003-04-08 Federico Di Gregorio + + * buildtypes.py (basic_types): removed LXTEXT (never user, does + not exists anymore.) + +2003-04-07 Federico Di Gregorio + + * setup.py: added very lame setup.py script. + +2003-04-02 Federico Di Gregorio + + * Release 1.3. + + * psycopg.spec: Added (but modified) spec file by William + K. Volkman (again, this change was lost somewhere in time...) + +2003-04-01 Federico Di Gregorio + + * cursor.c (_psyco_curs_execute): psycopg was reporting everything + as IntegrityError; reported and fix suggested by Amin Abdulghani. + +2003-03-21 Federico Di Gregorio + + * cursor.c (psyco_curs_fetchone): debug statements sometimes made + psycopg segfault: fixed by a patch by Ken Simpson. + +2003-03-18 Federico Di Gregorio + + * cursor.c (alloc_keeper): patch from Dieter Maurer to unlock GIL + whaile calling PQconnectdb(). + +2003-03-05 Federico Di Gregorio + + * Release 1.1.2. + + * Applied cygwin patch from Hajime Nakagami. + +2003-02-25 Federico Di Gregorio + + * Release 1.1.2pre1. + + * cursor.c: added .lastrowid attribute to cursors (lastoid is + deprecated and will be removed sometime in the future.) + + * cursor.c (begin_pgconn): implemented various isolation levels + (also, in abort_pgconn, commit_pgconn.) + + * Added keyword parameters to psycopg.connect(): all take strings + (even port): database, host, port, user, password. + + * configure.in: fixed test for postgres version > 7.2. + + * cursor.c (_psyco_curs_execute): removed if on pgerr in default + case (if we enter default pgerr can't be one of the cased ones.) + Also applied slightly modified patch from William K. Volkman. + +2003-02-24 Federico Di Gregorio + + * Merged in changes from 1.0.15.1 (see below for merged + ChangeLog.) + +2003-02-14 Federico Di Gregorio + + * Release 1.0.15.1. + + * cursor.c (_mogrify_fmt): in some cases we where removing one + character too much from the format string, resulting in BIG BAD + BUG. Fixed. + +2003-02-13 Federico Di Gregorio + + * Release 1.0.15. + + * connection.c (_psyco_conn_close): now call dispose_pgconn on all + cursors, to make sure all phisical connections to the db are + closed (problem first reported by Amin Abdulghani.) + + * DBAPI-2.0 fixed mainly due to Stuart Bishop: + - cursor.c (psyco_curs_setinputsizes): removed PARSEARGS, as + this method does nothing. + - cursor.c (psyco_curs_setoutputsize): .setoutputsize was + spelled .setoutputsizes! fixed. Also removed PARSEARGS, as this + method does nothing. + +2003-02-12 Federico Di Gregorio + + * module.h (Dprintf): check on __APPLE__ to avoid variadic macros + on macos x (as reported by Stuart Bishop, btw, why gcc seems to + not support them on macos?) + + * cursor.c (_mogrify_fmt): non-alphabetic characters are dropped + after the closing ")" until a real alphabetic, formatting one is + found. (Fix bug reported by Randall Randall.) + +2003-02-05 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): patched again to take into + account leading zeroes. + +2003-02-02 Federico Di Gregorio + + * Makefile.pre.in: applied patch from Albert Chin-A-Young to + define BLDSHARED. + + * README: added explicit permission to link with OpenSSL. + +2003-01-30 Federico Di Gregorio + + * config.h.in: applied patch from Albert Chin-A-Young to fix + asprintf prototype. + +2003-01-29 Federico Di Gregorio + + * cursor.c (_mogrify_seq): fixed little refcount leak, as + suggested by Yves Bastide. + +2003-01-24 Federico Di Gregorio + + * Merged-in changes from 1.0.14.2 (emacs diff mode is great..) + + * Release 1.0.14.2. + + * ZPsycopgDA/db.py (DB.query): back to allowing up to 1000 db + errors before trying to reopen the connection by ourselves. + + * ZPsycopgDA/db.py: a false (None preferred, 0 allowed) max_rows + value now means "fetch all results". + +2003-01-22 Federico Di Gregorio + + * cursor.c (psyco_curs_fetchone): fixed little memory leak + reported by Dieter Maurer. + +2003-01-20 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB.tables/columns): added registration with + Zope's transaction machinery. + + * Release 1.0.14.1. + + * ZPsycopgDA/db.py: applied some fixes and cleanups by Dieter + Maurer (serialization problem were no more correctly detected!) + + * Release 1.0.14. + + * Merged in 1.0.14. + + * Import of 1.1.1 done. + + * Moved everything to cvs HEAD. + +2003-01-20 Federico Di Gregorio + + * ZPsycopgDA/connectionAdd.dtml: fixed typo (thanks to Andrew + Veitch.) + + * typeobj.c (psyco_INTERVAL_cast): applied patch from Karl Putland + to fix problems with fractional seconds. + +2002-12-03 Federico Di Gregorio + + * Release 1.0.14-pre2. + + * module.h: added macro for PyObject_TypeCheck if python version <2.2. + + * typeobj.c (psyco_DBAPITypeObject_coerce): added error message to + coercion errors. + +2002-12-02 Federico Di Gregorio + + * Release 1.0.14-pre1. + + * ZPsycopgDA/db.py (DB.sortKey): added sortKey(). + + * ZPsycopgDA/DA.py: applied a patch that was lost on hard disk + (sic), if you sent me a patch names psycopg-1.0.13.diff modifying + DA.py imports and want your name here, send me an email. :) + [btw, the patch fix the ImageFile import, getting it from Globals + as it is right.] + + * typeobj.c (psyco_DBAPITypeObject_coerce): Fixed coerce segfault + by checking explicitly for all the allowed types. + +2002-11-25 Federico Di Gregorio + + * doc/examples/*.py: added .rollback() to all exceptions before + deleteing the old table. + + * cursor.c: Apllied patch from John Goerzen (fix memory leak in + executemany). + +2002-10-25 Federico Di Gregorio + + * Release 1.0.13. + + * connection.c (_psyco_conn_close): remove cursors from the list + starting from last and moving backward (as suggested by Jeremy + Hylton; this is not such a big gain because python lists are + *linked* lists, but not removing the element 0 makes the code a + little bit clear.) + + * cursor.c (_psyco_curs_execute): now IntegrityError is raised + instead of ProgrammingError when adding NULL values to a non-NULL + column (suggested by Edmund Lian) and on referential integrity + violation (as per debian bug #165791.) + + * typeobj.c (psyco_DATE_cast): now we use 999999 instead of + 5867440 for very large (both signs) dates. This allow to re-insert + the DateTime object into postgresql (suggested by Zahid Malik.) + +2002-09-13 Federico Di Gregorio + + * Release 1.0.12. + + * Removed code to support COPY FROM/TO, will be added to new 1.1 + branch to be released next week. + + * cursor.c (_mogrify_seq): Fixed memory leak reported by Menno + Smits (values obtained by calling PySequence_GetItem are *new* + references!) + +2002-09-07 Federico Di Gregorio + + * cursor.c (_psyco_curs_execute): Added skeleton to support COPY + FROM/TO. + +2002-09-06 Federico Di Gregorio + + * configure.in: if libcrypt can't be found we probably are on + MacOS X: check for libcrypto, as suggested by Aparajita Fishman. + +2002-09-03 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB.columns): Applied patch from Dieter Maurer + to allow the DA-browser to work with mixed case table names. + +2002-08-30 Federico Di Gregorio + + * ZPsycopgDA/DA.py (cast_DateTime): Applied patch from Yury to fix + timestamps (before they were returned with time always set to 0.) + +2002-08-26 Federico Di Gregorio + + * Release 1.0.11.1 (to fix a %&£$"! bug in ZPsycopgDA not + accepting psycopg 1.0.11 as a valid version. + + * Release 1.0.11. + +2002-08-22 Federico Di Gregorio + + * Release 1.0.11pre2. + + * cursor.c (_psyco_curs_execute): fixed IntegrityError as reported + by Andy Dustman. (psyco_curs_execute): converting TypeError to + ProgrammingError on wrong number of % and/or aeguments. + + * doc/examples/integrity.py: added example and check for + IntegrityError. + +2002-08-08 Federico Di Gregorio + + * Release 1.0.11pre1. + +2002-08-06 Federico Di Gregorio + + * ZPsycopgDA/DA.py (cast_DateTime): patched as suggested by Tom + Jenkins; now it shouldwork with time zones too. + +2002-08-01 Federico Di Gregorio + + * ZPsycopgDA/DA.py (cast_DateTime): fixed problem with missing + AM/PM, as reported by Tom Jenkins. + +2002-07-23 Federico Di Gregorio + + * Fixed buglets reported by Mike Coleman. + +2002-07-22 Federico Di Gregorio + + * Release 1.0.10. + +2002-07-14 Federico Di Gregorio + + * Release 1.0.10pre2. + + * typeobj.c (psyco_LONGINTEGER_cast): fixed bad segfault by + INCREFfing Py_None when it is the result of a NULL conversion. + +2002-07-04 Federico Di Gregorio + + * Release 1.0.10pre1. + + * buildtypes.py (basic_types): added TIMESTAMPTZ to the types + converted by the DATE builtin. + + * ZPsycopgDA/DA.py (Connection.connect): Added version check. + +2002-07-03 Federico Di Gregorio + + * typeobj.c (psyco_XXX_cast): fixed bug reported by multiple users + by appliying Matt patch. + +2002-06-30 Federico Di Gregorio + + * ZPsycopgDA/DA.py (Connection.set_type_casts): applied patch from + Tom Jenkins to parse dates with TZ. + +2002-06-20 Federico Di Gregorio + + * Preparing for release 1.0.9. + + * Makefile.pre.in (dist): now we really include psycopg.spec. + +2002-06-17 Federico Di Gregorio + + * ZPsycopgDA/db.py (_finish, _abort): fixed problem with + connection left in invalid state by applying Tom Jenkins patch. + +2002-06-06 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB._abort): fixed exception raising after an + error in execute triggerer deletion of self.db. + +2002-05-16 Federico Di Gregorio + + * cursor.c (psyco_curs_fetchone): None values passed to the + internal typecasters. + + * typeobj.c: added management of None to all the builtin + typecasters. + +2002-04-29 Federico Di Gregorio + + * ZPsycopgDA/DA.py (cast_Time): applied 'seconds as a float' patch + from Jelle. + +2002-04-23 Federico Di Gregorio + + * Release 1.0.8. + + * Makefile.pre.in: we now include win32 related files in the + distribution. + + * connection.c (psyco_conn_destroy): fixed segfault reported by + Scott Leerssen (we were double calling _psyco_conn_close().) + + * typemod.c (new_psyco_quotedstringobject): fixed memory stomping + catched by assert(); thanks to Matt Hoskins for reporting this + one. + +2002-04-22 Federico Di Gregorio + + * configure.in: grmpf. we need a VERSION file for windows, we'll + use it for configue and debian/rules too. + + * Integrated win32 changes from Jason Erickson. Moved his + Readme.txt to README.win32, removed VERSION and DATE, patched + source where required. Renamed HISTORY to ChangeLog.win32, hoping + Jason will start adding changes to the real ChangeLog file. + +2002-04-07 Federico Di Gregorio + + * Release 1.0.7.1. + + * configure.in: fixed little bug as reported by ron. + +2002-04-05 Federico Di Gregorio + + * Release 1.0.7? + + * typemod.c (new_psyco_bufferobject): fixed encoding problem (0xff + now encoded as \377 and not \777.) Also encoding *all* chars as + quoted octal values to prevent "Invalid UNICODE character sequence + found" errors. + + * Release 1.0.7. (Real this time.) (Ok, it was a joke....) + +2002-04-03 Federico Di Gregorio + + * configure.in: fixed problem with postgres versions in the format + 7.2.x (sic.) + + * connection.c (psyco_conn_destroy): moved most of the destroy + stuff into its own function (_psyco_conn_close) and added a call + to it from psyco_conn_close. This should fix the "psycopg does not + release postgres connections on .close()" problem. + +2002-03-29 Federico Di Gregorio + + * Release 1.0.7. Delayed. + + * buildtypes.py (basic_types): added TIMESTAMPTZ postgres type to + the list of valid DATETIME types (incredible luck, no changes to + the parse are needed!) + + * typeobj.c (psyco_DATE_cast): fixed wrong managment of sign in + infinity. + +2002-03-27 Federico Di Gregorio + + * configure.in (INSTALLOPTS): added AC_PROG_CPP test, now uses + AC_TRY_CPP to test for _all_ required mx includes. + +2002-03-19 Federico Di Gregorio + + * configure.in: added check for both pg_config.h and config.h to + detect postgres version. + + * cursor.c: now None values are correctly handled when the format + string is not %s but %d, etc. + +2002-03-08 Federico Di Gregorio + + * ZPsycopgDA/DA.py: added MessageDialog import suggested by + Guido. + +2002-03-07 Federico Di Gregorio + + * psycopg.spec: added RPM specs by William K. Volkman. + + * Release 1.0.6. + + * configure.in: imported changes to allow postgres 7.2 builds from + unstable branch. + +2002-03-04 Federico Di Gregorio + + * Release 1.0.5. + + * applied table browser patch from Andy Dustman. + +2002-02-26 Federico Di Gregorio + + * typeobj.c (psyco_DATE_cast): added management of infinity + values, this can be done in a better way, by accessing the + MaxDateTime and MinDateTime constants of the mx.DateTime module. + +2002-02-20 Federico Di Gregorio + + * configure.in: Release 1.0.4. + +2002-02-12 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB.columns): fixed select to reenable column + expansion in table browsing. + + * ZPsycopgDA/__init__.py: removed code that made psycopg think + double. + +2002-02-11 Federico Di Gregorio + + * cursor.c (_mogrify_dict): removed Py_DECREF of Py_None, + references returned by PyDict_Next() are borrowed (thanks to + Michael Lausch for this one.) + +2002-02-08 Federico Di Gregorio + + * A little bug slipped in ZPsycopgDA, releasing 1.0.3 immediately. + + * Release 1.0.2. + + * tests/check_types.py (TYPES): added check for hundredths of a + second. + +2002-02-07 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): patched to correct wrong + interpretation of hundredths of a second (patch from + A. R. Beresford, kudos!) + +2002-01-31 Federico Di Gregorio + + * FAQ: added. + +2002-01-16 Federico Di Gregorio + + * Preparing for release 1.0.1. + + * cursor.c (alloc_keeper): removed ALLOW_THREADS wrapper around + PQconnectdb: libpq calls crypt() that is *not* reentrant. + +2001-12-19 Federico Di Gregorio + + * typeobj.c (psyco_DBAPITypeObject_cmp): added check to simply + return false when two type objects are compared (type objects are + meaned to be compared to integers!) + + * typeobj.c: fixed the memory leak reported by the guys at + racemi, for real this time. (added about 5 DECREFS and 2 INCREFS, + ouch!) + +2001-12-17 Federico Di Gregorio + + * typeobj.c (psyco_DBAPITypeObject_cmp): fixed memory leak by + using PyTuple_GET_ITEM (we are sure the tuple has at least one + element, we built it, after all...) (many thanks to Scott Leerssen + for reporting the *exact line* for this one.) + +2001-12-13 Federico Di Gregorio + + * cursor.c: fixed memory leak due to extra strdup (thanks + to Leonardo Rochael Almeida.) + +2001-11-14 Federico Di Gregorio + + * Release 1.0. + + * doc/README: added explanation about guide work in progess but + examples working. + + * debian/*: lots of changes to release 1.0 in debian too. + +2001-11-12 Federico Di Gregorio + + * RELEASE-1.0: added release file, to celebrate 1.0. + + * tests/zope/typecheck.zexp: regression test on types for zope. + +2001-11-11 Federico Di Gregorio + + * ZPsycopgDA/DA.py (cast_Interval): removed typecast of interval + into zope DateTime. intervals are reported as strings when using + zope DateTime and as DateTimeDeltas when using mx. + +2001-11-09 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): complete rewrite of the + interval parsing code. now we don't use sscanf anymore and all is + done with custom code in a very tight and fast loop. + +2001-11-08 Federico Di Gregorio + + * ZPsycopgDA/DA.py (Connection.set_type_casts): added mx INTERVAL + type restore. + + * ZPsycopgDA/db.py (DB.query): now we return column names even if + there are no rows in the result set. also, cleaned up a little bit + the code. + +2001-11-7 Federico Di Gregorio, + + * Makefile.pre.in: fixed small problem with zcat on True64 + (thank you stefan.) + +2001-11-06 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB.query): added fix for concurrent update + from Chris Kratz. + +2001-11-05 Federico Di Gregorio + + * cursor.c: now we include postgres.h if InvalidOid is still + undefined after all other #includes. + + * README: clarified use of configure args related to python + versions. + + * aclocal.m4: patched to work with symlinks installations (thanks + to Stuart Bishop.) + + * cursor.c (_psyco_curs_execute): now reset the keeper's status to + the old value and not to BEGIN (solve problem with autocommit not + switching back.) + +2001-11-01 Federico Di Gregorio + + * doc/examples/dt.py: added example on how to use the date and + time constructors. + + * Makefile.pre.in (dist-zope): removed dependencies on GNU install + and tar commands. Also a little general cleanup on various targets. + + * ZPsycopgDA/DA.py: fixed mx.DateTime importing. + +2001-10-31 Federico Di Gregorio + + * typemod.c (psyco_xxxFromMx): fixed bug in argument parsing (we + weren't usigng the right type object.) + + * aclocal.m4: now builds OPT and LDFLAGS on the values of the env + variables instead of overwriting them. + + * Makefile.pre.in (CFLAGS): removed -Wall, you can add it back at + compile time with OPT="-Wall" ./configure ... + + * Setup.in (OPT): removed -Wall. + +2001-10-30 Michele Comitini + + * module.h: ANSI C compatibility patch from Daniel Plagge. + +2001-10-30 Federico Di Gregorio + + * README: added common building problems and solutions. + + * configure.in: removed check for install command, already done by + james's aclocal.m4 for python. removed install-sh. removed -s from + INSTALLOPTS. + +2001-10-29 Federico Di Gregorio + + * Makefile.pre.in (dist): removed examples/ directory from + distribution. + + * merge with cvs head. preparing to fork again on PSYCOPG-1-0 (i + admit BRANCH_1_0 was quite a silly name.) + + * doc/examples/usercast.py: now works. + + * connection.c (curs_rollbackall): fixed little bug (exposed by + the deadlock below) by changing KEEPER_READY to KEEPER_READY. + + * doc/examples/commit.py: deadlock problem solved, was the + example script, _not_ psycopg. pew... :) + + * examples/*: removed the examples moved to doc/examples/. + + * doc/examples/commit.py,dictfetch.py: moved from examples/ and + changed to work for 1.0. unfortunately commit.py locks psycopg!!! + +2001-10-24 Federico Di Gregorio + + * modified all files neede for the 1.0 release. + + * configure.in (MXFLAGS): removed electric fence support. + + * Makefile.pre.in (dist): now we remove CVS working files before + packing the tarball. + + * tests: files in this directory are not coding examples, but + regression tests. we need a sufficient number of tests to follow + every single code path in psycopg at least once. first test is + about datatypes. + + * doc/examples: moved new example code to examples directory, old + tests and code samples will stay in examples/ until the manual will + be finished. + +2001-10-16 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): completely revised interval + casting code. (psyco_TIME_cast): we use the unix epoch when the + date is undefined. + + * cursor.c (psyco_curs_executemany): modified sanity check to + accept sequences of tuples too and not just dictionaries. + +2001-10-15 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): fixed bug caused by wrong + parsing on '1 day' (no hours, minutes and seconds.) + +2001-10-15 Michele Comitini + + * cursor.c (_execute): use the correct cast functions even on + retrival of binary cursors. + +2001-10-12 Federico Di Gregorio + + * typemod.c (new_psyco_bufferobject): space not quoted anymore, + smarter formula to calculate realloc size. + + * cursor.c (psyco_curs_fetchone): removed static tuple (using + static variable in multithreaded code is *crazy*, why did i do it? + who knows...) + + * typeobj.c (psyco_init_types): exports the binary converter (will + be used in cursor.c:_execute.) + + * typeobj.h: added export of psyco_binary_cast object. + +2001-10-05 Federico Di Gregorio + + * cursor.c (_psyco_curs_execute): added missing Py_XDECREF on + casts list. + + * Makefile.pre.in (dist): added install-sh file to the + distribution. + + * replaced PyMem_DEL with PyObject_Del where necessary. + + * connection.c (psyco_conn_destroy): added missing + pthread_mutex_destroy on keeper lock. + +2001-10-01 Michele Comitini + + * typemod.c(new_psyco_bufferobject()): using unsigned char for + binary objects to avoid too many chars escaped. A quick and + simple formula to avoid memory wasting and too much reallocating + for the converted object. Needs _testing_, but it is faster. + + * cursor.c: #include + + * module.h: now debugging should be active only when asked by + ./configure --enable-devel + +2001-09-29 Federico Di Gregorio + + * cursor.c (new_psyco_cursobject): added locking of connection, + still unsure if necessary. + +2001-09-26 Federico Di Gregorio + + * configure.in: changed DEBUG into PSYCOTIC_DEBUG, to allow other + includes (postgres.h) to use the former. better compiler checks: + inline, ansi, gcc specific extensions. removed MXMODULE: we don't + need it anymore. + + * general #include cleanup, should compile on MacOS X too. + + * typeobj.c (psyco_DATE_cast): uses sscanf. should be faster too. + (psyco_TIME_cast): dixit. + + * applied patch from Daniel Plagge (SUN cc changes.) + +2001-09-22 Federico Di Gregorio + + * ZPsycopgDA/db.py (DB._finish, DB._begin): fix for the + self.db == None problem. + +2001-09-19 Michele Comitini + + * typemod.c (new_psyco_bufferobject): better memory managment + (now it allocates only needed space dinamically). + + * typeobj.c (psyco_BINARY_cast): ripped a useless check, now + it assumes that binary streams come out from the db correctly + escaped. Should be a lot faster. + +2001-09-18 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): fixed interval conversion + (hours were incorrectly converted into seconds.) + +2001-09-17 Federico Di Gregorio + + * cursor.c (_mogrify_seq, _mogrify_dict): added check for None + value and conversion of None -> NULL (fixes bug reported by Hamish + Lawson.) + +2001-09-12 Federico Di Gregorio + + * module.c: added handles to new date and time conversion + functions (see below.) + + * typemod.c (psyco_XXXFromMx): added conversion functions that + simply wrap the mxDateTime objects instead of creating + them. DBAPI-2.0 extension, off-curse. + +2001-09-10 Federico Di Gregorio + + * buildtypes.py: solved hidden bug by changing from dictionary to + list, to maintain ordering of types. sometimes (and just + sometimes) the type definitions were printed unsorted, resulting + is psycopg initializing the type system using the type objects in + the wrong order. you were getting float values from an int4 + column? be happy, this is now fixed... + + * cursor.c (psyco_curs_lastoid): added method to get oid of the + last inserted row (it was sooo easy, it even works...) + +2001-09-08 Federico Di Gregorio + + * typeobj.c (psyco_INTERVAL_cast): added casting function for the + postgres INTERVAL and TINTERVAL types (create a DateTimeDelta + object.) + +2001-09-05 Federico Di Gregorio + + * cursor.c: moved all calls to begin_pgconn to a single call in + _psyco_curs_execute, to leave the connection in a not-idle status + after a commit or a rollback. this should free a lot of resources + on the backend side. kudos to the webware-discuss mailing list + members and to Clark C. Evans who suggested a nice solution. + + * connection.c (curs_rollbackall, curs_commitall): removed calls + to begin_pgconn, see above. + + * module.c (initpsycopg): cleaned up mxDateTime importing; we now + use the right function from mxDateTime.h. Is not necessary anymore + to include our own mx headers. This makes psycopg to depend on + mxDateTime >= 2.0.0. + +2001-09-04 Federico Di Gregorio + + * doc/*.tex: added documentation directory and skeleton of the + psycopg guide. + +2001-09-03 Federico Di Gregorio + + * merged in changes from HEAD (mostly mcm fixes to binary + objects.) + + * preparing for release 0.99.6. + +2001-09-03 Michele Comitini + + * typemod.c: much faster Binary encoding routine. + + * typeobj.c: much faster Binary decoding routine. + +2001-08-28 Michele Comitini + + * typemod.c: Working binary object to feed data to bytea type + fields. + + * typeobj.c: Added BINARY typecast to extract data from + bytea type fields. + + * cursor.c: Added handling for SQL binary cursors. + +2001-08-3 Michele Comitini + + * cursor.c: fixed DATESTYLE problem thanx to Steve Drees. + +2001-07-26 Federico Di Gregorio + + * Makefile.pre.in: applied change suggested by Stefan H. Holek to + clobber and distclean targets. + +2001-07-23 Federico Di Gregorio + + * ZPsycopgDA/db.py: fixed little bugs exposed by multiple select + changes, not we correctly import ListType and we don't override + the type() function with a variable. + +2001-07-17 Federico Di Gregorio + + * configure.in: Release 0.99.5. + +2001-07-12 Federico Di Gregorio + + * debian/* fixed some little packaging problems. + +2001-07-11 Federico Di Gregorio + + * cursor.c, typeobj.c: removed some Py_INCREF on PyDict_SetItem + keys and values to avoid memory leaks. + +2001-07-03 Federico Di Gregorio + + * cursor.c (_mogrify_dict): added dictionary mogrification: all + Strings in the dictionary are translated into QuotedStrings. it + even works... (_mogrify_seq): added sequence mogrification and + code to automagically mogrify all strings passed to .execute(). + +2001-07-02 Federico Di Gregorio + + * Release 0.99.4. + + * typemod.c: added QuotedString class and methods. + + * module.c: added QuotedString method to module psycopg. + + * typemod.c: changed Binary objects into something usefull. now + the buffer object quotes the input by translatin every char into + its octal representation. this consumes 4x memory but guarantees + that even binary data containing '\0' can go into the Binary + object. + + * typemod.h: added definition of QuotedString object. + +2001-06-28 Federico Di Gregorio + + * ZPsycopgDA/db.py, ZPsycopgDA/DABase.py: applied patch sent by + yury to fix little buglet. + +2001-06-22 Federico Di Gregorio + + * Release 0.99.3. + + * connection.c (new_psyco_connobject): now we strdup dsn, as a fix + for the problem reported by Jack Moffitt. + + * Ok, this will be the stable branch from now on... + + * Merged in stuff from 0.99.3. About to re-branch with a better + name (BRANCH_1_0) + +2001-06-20 Federico Di Gregorio + + * Release 0.99.3. Showstoppers for 1.0 are: + - documentation + - mxDateTime module loading + - bug reported by Yury. + + * Integrated patches from Michele: + - searching for libcrypt in configure now works + - removed memory leak in asprintf.c + +2001-06-15 Federico Di Gregorio + + * ZPsycopgDA/__init__.py (initialize): applied patch from Jelle to + resolve problem with Zope 2.4.0a1. + +2001-06-14 Federico Di Gregorio + + * configure.in: added code to check for missing functions (only + asprintf at now.) + + * asprintf.c: added compatibility code for oses that does not have + the asprintf() function. + +2001-06-10 Federico Di Gregorio + + * Branched PSYCOPG_0_99_3. Development will continue on the cvs + HEAD, final adjustements and bugfixing should go to this newly + created branch. + +2001-06-08 Michele Comitini + + * ZPsycopgDA/DA.py: DateTime casts simplified and corrected + as suggested by Yury. + +2001-06-05 Federico Di Gregorio + + * Release 0.99.2. + + * Makefile.pre.in (dist): added typemod.h and typemod.c to + distribution. + + * cursor.c (commit_pgconn, abort_pgconn, begin_pgconn): resolved + segfault reported by Andre by changing PyErr_SetString invokations + into pgconn_set_critical. the problem was that the python + interpreter simply segfaults when we touch its internal data (like + exception message) inside an ALLOW_THREADS wrapper. + + * now that we are 100% DBAPI-2.0 compliant is time for the + one-dot-o release (at last!) Para-pa-pa! This one is tagged + PSYCOPG_0_99_1 but you can call it 1.0pre1, if you better like. + (A very long text just to say 'Release 0.99.1') + + * typemod.[ch]: to reach complete DBAPI-2.0 compliance we + introduce some new objects returned by the constructors Date(), + Time(), Binary(), etc. Those objects are module-to-database only, + the type system still takes care of the database-to-python + conversion. + +2001-06-01 Federico Di Gregorio + + * Release 0.5.5. + + * module.h: better error message when trying to commit on a + cursor derived from serialized connection. + + * ZPsycopgDA/db.py (DB.close): now self.cursor is set to None when + the connection is closed. + + * module.c (initpsycopg): added missing (sic) DBAPI module + parameters (paramstyle, apilevel, threadsafety, etc...) + +2001-05-24 Michele Comitini + + * ZPsycopgDA: Support for Zope's internal DateTime, option + to leave mxDateTime is available on the management interface so + to switch with little effort :). + + * cursor.c: more aggressive cleanup of postgres results + to avoid the risk of memory leaking. + + * typeobj.c, connection.c: deleted some Py_INCREF which + wasted memory. + +2001-05-18 Federico Di Gregorio + + * Release 0.5.4. + +2001-05-17 Michele Comitini + + * ZPsycopgDA/db.py: The connection closed by the management + interface of zope now raises error instead of reopening itself. + + * cursor.c (psyco_curs_close): does not try to free the cursor + list, as it caused a segfault on subsequent operations on the same + cursor. + +2001-05-07 Federico Di Gregorio + + * Release 0.5.3. + + * Merged in changes from me and mcm. + +2001-05-06 Michele Comitini + + * ZPsycopgDA/db.py (DB.close): Fixes a bug report by Andre + Shubert, which was still open since there was a tiny typo in + method definition. + + * ZPsycopgDA/DA.py (Connection.sql_quote__): overriding standard + sql_quote__ method to provide correct quoting (thank to Philip + Mayers and Casey Duncan for this bug report). + +2001-05-04 Federico Di Gregorio + + * ZPsycopgDA/db.py: added .close() method (as suffested by Andre + Schubert.) + +2001-05-04 Michele Comitini + + * module.h: working on a closed object now raises an + InterfaceError. + + * ZPsycopgDA/db.py: fixed problems with dead connections detection. + + * ZPsycopgDA/__init__.py: corrected SOFTWARE_HOME bug for zope + icon. + +2001-05-04 Federico Di Gregorio + + * examples/thread_test.py: now that the serialization bug is + fixed, it is clear that thread_test.py is bugged! added a commit() + after the creation of the first table to avoid loosing it on the + exception raised by the CREATE of an existing table_b. + +2001-05-03 Federico Di Gregorio + + * connection.c (psyco_conn_cursor): reverted to old locking + policy, the new caused a nasty deadlock. apparently the multiple + connection problem has been solved as a side-effect of the other + fixes... (?!) + + * module.h: removes stdkeeper field from connobject, we don't need + it anymore. + + * cursor.c (dispose_pgconn): now sets self->keeper to NULL to + avoid decrementing the keeper refcnt two times when the cursor is + first closed and then destroyed. + + * connection.c (psyco_conn_cursor): fixed little bug in cursor + creation: now the connection is locked for the entire duration of + the cursor creation, to avoid a new cursor to be created with a + new keeper due to a delay in assigning the stdmanager cursor. + + * cursor.c: added calls to pgconn_set_critical() and to + EXC_IFCRITICAL() where we expect problems. Still segfaults but at + least raise an exception... + + * cursor.c (psyco_curs_autocommit): added exception if the + cursor's keeper is shared between more than 1 cursor. + + * module.h (EXC_IFCRITICAL): added this macro that call + pgconn_resolve_critical) on critical errors. + + * cursor.c (alloc_keeper): added check for pgres == NULL. + + * cursor.c (psyco_curs_destroy): merged psyco_curs_destroy() and + psyco_curs_close(): now both call _psyco_curs_close() and destroy + does only some extra cleanup. + +2001-05-03 Michele Comitini + + * ZPsycopgDA/db.py: Some cleanup to bring the zope product up to + date with the python module. Some bugs found thanks to Andre + Schubert. Now the ZDA should rely on the new serialized version + of psycopg. + + * cursor.c: while looking for problems in the ZDA some come out + here, with the inability to handle dropping connection correctly. + This leads to segfaults and is not fixed yet for lack of time. + Some problems found in cursors not willing to share the same + connection even if they should. Hopefully it should be fixed + soon. + +2001-04-26 Federico Di Gregorio + + * fixed bug reported by Andre Schubert by adding a new cast + function for long integers (int8 postgresql type.) at now they are + converted to python LongIntegers: not sure f simply convert to + floats. + + * michele applied patch from Ivo van der Wijk to make zpsycopgda + behave better when INSTANCE_HOME != SOFTWARE_HOME. + + * cursor.c (_psyco_curs_execute): also fill the 'columns' field. + + * module.h: added a 'columns' field to cursobject, to better + support the new dictionary fetch functions (dictfetchone(), + dictfetchmany(), dictfetchall().) + + * cursor.c: added the afore-mentioned functions (function names + are not definitive, they will follow decisions on the DBAPI SIG.) + +2001-04-03 Federico Di Gregorio + + * Release 0.5.1. + + * mcm fixed a nasty bug by correcting a typo in module.h. + +2001-03-30 Federico Di Gregorio + + * module.c (psyco_connect): added `serialized' named argument to + the .connect() method (takes 1 or 0 and initialize the connection + to the right serialization state.) + + * Makefile.pre.in (dist): fixed little bug, a missing -f argument + to rm. + + * examples/thread_test.py: removed all extension cruft. + + * examples/thread_test_x.py: this one uses extensions like the + per-cursor commit, autocommit, etc. + + * README (psycopg): added explanation on how .serialize() works. + + * connection.c (psyco_conn_serialize): added cursor serialization + and .serialize() method on the connection object. now we are + definitely DBAPI-2.0 compliant. + +2001-03-20 Federico Di Gregorio + + * cursor.c (_psyco_curs_execute): replaced some fields in + description with None, as suggested on the DB-SIG ML. + + * something like one hundred of little changes to allow cursors + share the same postgres connection. added connkeeper object and + pthread mutexes (both in connobject and connkeeper.) apparently it + works. this one will be 0.5.0, i think. + +2001-03-19 Michele Comitini + + * cursor.c: added mutexes, they do not interact well with python + threads :(. + +2001-03-16 Michele Comitini + + * ZPsycopgDA/db.py (ZDA): some fixes in table browsing. + +2001-03-16 Federico Di Gregorio + + * suite/tables.postgresql (TABLE_DESCRIPTIONS): fixed some typos + introduced by copying by hand the type values from pg_type.h. + + * suite/*: added some (badly) structured code to test for + DBAPI-2.0 compliance. + + * cursor.c (pgconn_notice_callback): now the NOTICE processor only + prints NOTICEs when psycopg has been compiled with the + --enable-devel switch. + + * connection.c: removed 'autocommit' attribute, now is a method as + specified in the DBAPI-2.0 document. + +2001-03-15 Federico Di Gregorio + + * connection.c (curs_commitall): splitted for cycle in two to + avoid the "bad snapshot" problem. + +2001-03-14 Federico Di Gregorio + + * Release 0.4.6. + + * cursor.c (_psyco_curs_execute): fixed nasty bug, there was an + free(query) left from before the execute/callproc split. + + * Preparing for 0.4.6. + +2001-03-13 Federico Di Gregorio + + * cursor.c (psyco_curs_execute): fixed some memory leaks in + argument parsing (the query string was not free()ed.) + (psyco_curs_callproc): implemented callproc() method on cursors. + (_psyco_curs_execute): this is the function that does the real + stuff for callproc() and execute(). + (pgconn_notice_*): added translation of notices into python + exceptions (do we really want that?) + + * configure.in: removed some cruft (old comments and strncasecmp() + check) + +2001-03-12 Federico Di Gregorio + + * examples/thread_test.py: added moronic argument parsing: now you + can give the dsn string on the command line... :( + + * Release 0.4.5. + +2001-03-10 Federico Di Gregorio + + * cursor.c (request_pgconn): added code to set datestyle to ISO on + new connections (many thanks to Yury for the code, + i changed it just a little bit to raise an exception on error.) + +2001-03-09 Federico Di Gregorio + + * Release 0.4.4. + + * ZPsycopgDA/db.py: michele fixed a nasty bug here. + +2001-03-08 Federico Di Gregorio + + * Release 0.4.3. + +2001-03-07 Federico Di Gregorio + + * Makefile.pre.in (dist): typeobj_builtins.c included for people + without pg_type.h. if you encounter type-casting problems like + results cast to the wrong type, simply "rm typeobj_builtins.c" and + rebuild. + + * typeobj.c (psyco_*_cast): removed RETURNIFNULL() macro from all + the builtin casting functions. (psyco_STRING_cast) does not create + a new string anymore, simply Py_INCREF its argument and return it. + + * cursor.c (psyco_curs_fetchone): removed strdup() call. added + PQgetisnull() test to differentiate between real NULLs and empty + strings. + + * Removed cursor.py (mcm, put tests in examples) and fixed some + typos in the dtml code. + +2001-03-04 Michele Comitini + + * examples/commit_test.py: Modifications to test argument passing + and string substitution to cursor functions, nothing more. + + * ZPsycopgDA/db.py: now it exploits some of the good features of + the psycopg driver, such as connection reusage and type + comparison. Code is smaller although it handles (and + reports) errors much better. + + * cursor.c: corrected a bug that left a closed cursor in the + cursor list of the connection. Now cursors are removed from the + lists either when they are close or when they are destroyed. + Better connection (TCP) error reporting and handling. + + +2001-03-02 Federico Di Gregorio + + * examples commit_test.py: added code to test autocommit. + + * examples/thread_test.py (ab_select): modified select thread to + test autocommit mode. + + * Release 0.4.1. + + * module.h, connection.c, cursor.c: added autocommit support. + +2001-02-28 Federico Di Gregorio + + * Release 0.4. + +2001-02-27 Michele Comitini + + * cursor.py: cut some unuseful code in psyco_curs_fetchmany() and + psyco_curs_fetchall() inserted an assert in case someting goes + wrong. + +2001-02-27 Federico Di Gregorio + + * debian/*: various changes to build both the python module and + the zope db adapter in different packages (respectively + python-psycopg and zope-psycopgda.) + + * examples/type_test.py: better and more modular tests. + + * typeobj.c: added DATE, TIME, DATETIME, BOOLEAN, BINARY and ROWID + types. (RETURNIFNULL) added NULL-test to builtin conversion + functions (using the RETURNIFNULL macro.) + +2001-02-26 Federico Di Gregorio + + * releasing 0.3 (added NEWS file.) + +2001-02-26 Michele Comitini + + * cursor.c: fetchmany() some cleanup done. + + * ZPsycopgDA/db.py, ZPsycopgDA/__init__.py, : fixes to make the + ZDA work some way. WARNING WARNING WARNING the zda is still + alpha code, but we need some feed back on it so please give it + a try. + +2001-02-26 Federico Di Gregorio + + * typeobj.c (psyco_STRING_cast): fixed bad bad bad bug. we + returned the string without coping it and the type-system was more + than happy to Py_DECREF() it and trash the whole system. fixed at + last! + + * module.h (Dprintf): added pid to every Dprintf() call, to + facilitate multi-threaded debug. + +2001-02-26 Michele Comitini + + * module.c: added code so that DateTime package need not to be + loaded to have mxDateTime. This should avoid clashing with + DateTime from the zope distribution. + + * cursor.c: setting error message in fetchmany when no more tuples + are left. This has to be fixed in fetch and fetchall to. + +2001-02-26 Federico Di Gregorio + + * configure.in: stepped up version to 0.3, ready to release + tomorrow morning. added check for path to DateTime module. + + * examples/usercast_test.py: generate some random boxes and + points, select the boxes with at least one point inside and print + them converting the PostgeSQL output using a user-specified cast + object. nice. + +2001-02-24 Federico Di Gregorio + + * cursor.c (psyco_curs_fetchone): now an error in the python + callback when typecasting results raise the correct exception. + + * typeobj.c (psyco_DBAPITypeObject_call): removed extra Py_INCREF(). + +2001-02-23 Federico Di Gregorio + + * replaced every single instance of the string 'pgpy' with 'psyco' + (this was part of the general cleanup.) + + * type_test.py: added this little test program to the distribution + (use the new_type() method to create new instances of the type + objects.) + + * typeobj.c: general cleanup. fixed some bugs related to + refcounting (again!) + + * cursor.c: general cleanup. (request_pgconn) simplified by adding + a support function (_extract_pgconn.) + + * connection.c: general cleanup. replaced some ifs with asserts() + in utility functions when errors depend on programming errors and + not on runtime exceptions. (pgpy_conn_destroy) fixed little bug + when deleting available connections from the list. + + * module.h: general cleanup. + + * typeobj.h: general cleanup, better comments, made some function + declarations extern. + + * module.c: general cleanup, double-checked every function for + memory leaks. (pgpy_connect) removed unused variable 'connection'. + +2001-02-22 Federico Di Gregorio + + * typeobj.c: fixed lots of bugs, added NUMBER type object. now the + basic tests in type_test.py work pretty well. + + * cursor.c (pgpy_curs_fetchmany): fixed little bug, fetchmany() + reported one less row than available. + + * fixed lots of bugs in typeobj.c, typeobj.h, cursor.c. apparently + now the type system works. it is time to clean up things a little + bit. + +2001-02-21 Federico Di Gregorio + + * typeobj.c: separated type objects stuff from module.c + + * typeobj.h: separated type objects stuff from module.h + +2001-02-19 Federico Di Gregorio + + * cursor.c (pgpy_curs_fetchmany): now check size and adjust it to + be lesser or equal than the nuber of available rows. + +2001-02-18 Michele Comitini + + * module.c, module.h: added optional args maxconn and minconn to + connection functions + + * cursor.c: better error checking in request_pgconn. + + * connection.c: changed new_connect_obj to take as optional args + maxconn and minconn. Added the corresponding ro attributes to + connection objects. + + * cursor.py: added some code to stress test cursor reusage. + + * cursor.c: some fixes on closed cursors. + + * connection.c: corrections on some assert calls. + +2001-02-16 Federico Di Gregorio + + * configure.in: added --enable-priofile sqitch. changed VERSION to + 0.2: preparing for a new release. + + * cursor.c: added a couple of asserts. + +2001-02-16 Michele Comitini + + * cursor.c, connection.c: fixed the assert problem: assert must + take just the value to be tested! no assignemente must be done in + the argument of assert() otherwise is wiped when NDEBUG is set. + + * module.h: some syntax error fixed. Error in allocating a tuple + corrected in macro DBAPITypeObject_NEW(). + + * module.c: pgpy_DBAPITypeObject_init() is not declared static anymore. + + * cursor.c: executemany() now does not create and destroy tuples + for each list item, so it is much faster. + +2001-02-14 Michele Comitini + + * cursor.c: added again Py_DECREF on the cpcon after disposing + it. assert() with -DNDEBUG makes the driver segfault while it + should not. + + +2001-02-13 Federico Di Gregorio + + * some of the memory leak were memprof errors, bleah. resumed some + old code, fixed segfault, fixed other bugs, improved speed. almost + ready for a new release. + + * connection.c (pgpy_conn_destroy): replaced some impossible ifs + with aseert()s. + + * cursor.c (pgpy_curs_close): added Py_DECREF() to + self->descritpion to prevent a memory leak after an execute(). + + * connection.c (pgpy_conn_destroy): always access first element of + lists inside for cycles because removing items from the list makes + higher indices invalid. + + * cursor.c (dispose_pgconn): fixed memory leak, there was a + missing Py_DECREF() after the addition of the C object wrapping + the postgresql connection to the list of available connections. + + * cursor.c (dispose_pgconn): fixed another memory leak: an + orphaned cursor should call PQfinish() on its postgresql + connection because it has no python connection to give the + postgresql ine back. + + * cursor.c (pgpy_curs_execute): added Py_DECREF() of description + tuple after adding it to self->description. this one fixes the + execute() memory leak. + + * cursor.c (pgpy_curs_fetchall): added missing Py_DECREF() on row + data (obtained from fetchone().) this fixes the last memory leak. + (thread_test.py now runs without leaking memory!) + +2001-02-12 Federico Di Gregorio + + * INSTALL: removed wok cruft from head of this file. + + * debian/rules: debianized the sources. python-psycopg is about to + enter debian. mxDateTime header locally included until the + maintainer of python-mxdatetime includes them in his package + (where they do belong.) + + * autogen.sh: added option --dont-run-configure. + +2001-02-09 Federico Di Gregorio + + * module.c (initpsycopg): changed name of init function to match + new module name (also changed all the exception definitions.) + + * README: updated psycopg description (we have a new name!) + + * Ready for 0.1 release. + +2001-02-07 Michele Comitini + + * cursor.c: now executemany takes sequences and not just + tuples + +2001-02-07 Federico Di Gregorio + + * Makefile.pre.in: now dist target includes test programs + (thread_test.py) and README and INSTALL files. + + * configure.in: changed --with-devel to --enable-devel. little + cosmetical fixes to the option management. + + * connection.c, module.c, cursor.c, module.h: removed 'postgres/' + from #include directive. it is ./configure task to find the right + directory. + + * thread_test.py: added thread testing program. + +2001-02-07 Michele Comitini + + * cursor.c: added code to allow threads during PQexec() calls. + + * cursor.c: added begin_pgconn to rollback() and commit() + so that the cursror is not in autocommit mode. + + * cursor.c: added rollback() and commit() methods to cursor + objects. + + +2001-02-07 Federico Di Gregorio + + * connection.c (pgpy_conn_destroy): always delete item at index + 0 and not i (because items shift in the list while deleting and + accessing items at len(list)/2 segfaults.) + +2001-02-07 Michele Comitini + + * connection.c: added some more checking to avoid + clearing of already cleared pgresults. Calling curs_closall() + in conn_destroy() since cursors have to live even without + their parent connection, otherwise explicit deletion of + object referencing to those cursors can cause arbitrary code + to be executed. + + * cursor.c: some more checking to avoid trying to close + already close pgconnections. + +2001-02-06 Federico Di Gregorio + + * Makefile.pre.in (CFLAGS): added -Wall to catch bad programming + habits. + + * cursor.c, connection.c: lots of fixes to the destroy stuff. now + all the cursor are destroyed *before* the connection goes away. + + * cursor.c (request_pgconn): another idiot error done by not + replacing dsn with owner_conn->dsn. fixed. + (dispose_pgconn): commented if to guarantee that the connection is + returned to the pool of available connections. + + * merged changes done by mcm. + + * cursor.c: general cleanup and better debugging/error + messages. changed xxx_conn into xxx_pgconn where still + missing. some pretty big changes to the way pgconn_request() + allocates new connections. + + * connection.c: removed all 'register' integers. obsolete, gcc + does a much better job optimizing cycles than a programmer + specifying how to use registers. + + * module.h: some general cleanup and better definition of DPrintf + macro. now the DEBUG variable can be specified at configure time by + the --with-devel switch to ./configure. + +2001-02-02 Michele Comitini + + * cursor.c (Repository): Added functions for managing a connection + pool. Segfaults. + + * configure.in (Repository): removed check for mxdatetime headers. + +2001-01-24 Federico Di Gregorio + + * first checkout from shinning new init.d cvs. + + * autotoolized build system. note that the mx headers are missing + from the cvs, you should get them someplace else (this is the + right way to do it, just require the headers in the configure + script.) + +2001-01-21 Michele Comitini + + * cursor.c (Repository): commit, abort, begin functions now check + the right exit status of the command. + + * connection.c (Repository): working commit() and rollback() + methods. + +2001-01-20 Michele Comitini + + * module.h (Repository): added member to cursor struct to handle + queries without output tuples. + + * cursor.c (Repository): new working methods: executemany, + fetchone, fetchmany, fetchall. + +2001-01-18 Michele Comitini + + * cursor.c (Repository): close working. destroy calling close. + close frees pg structures correctly. + + * connection.c (Repository): close method working. destroy seems + working. + +2001-01-17 Michele Comitini + + * cursor.c (Repository): now each python cursor has its own + connection. Each cursor works in a transaction block. + + * connection.c (Repository): added cursor list to connection + object + +2001-01-14 Michele Comitini + + * cursor.c (Repository): Beginning of code to implement cursor + functionalities as specified in DBA API 2.0, through the use of + transactions not cursors. + + * connection.c (Repository): Added some error checking code for pg + connection (will be moved to cursor?). + +2001-01-13 Michele Comitini + + * connection.c (Repository): Added error checking in connection + code to fail if connection to the db could not be opened. + + * module.h (Repository): New macro to help creating + DBAPITypeObjects. + + * module.c (Repository): DBAPITypeObject __cmp__ function is now + very simplified using recursion. + + * module.h (Repository): "DBAPIObject" changed to + "DBAPITypeObject". + + * module.c (Repository): Fixes for coerce function of DBAPIObjects + by Federico Di Gregorio . + (Repository): Clean up and better naming for DBAPITypeObjects. + +2001-01-08 Michele Comitini + + * module.c (Repository): Corrected the exception hierarcy + + * connection.c (Repository): Begun to use the connection objects + of libpq + +2001-01-07 Michele Comitini + + * module.c (Repository): Added the Date/Time functions. + +2001-01-06 Michele Comitini + + * cursor.c (Repository): Skeleton of cursor interface. All + methods and attributes of cursor objects are now available + in python. They do nothing now. + +2001-01-05 Michele Comitini + + * module.c (Repository): Test version; module loaded with + exception defined. + +2001-01-05 Michele Comitini + + * Setup.in (Repository): Setup file. + + * Makefile.pre.in (Repository): from the python source. + +2001-01-05 Michele Comitini + + * module.c: Written some code for defining exceptions. + + * module.h: Static variable for exceptions. + +2001-01-04 Michele Comitini + + * Changelog: pre-release just a few prototypes to get started. + + diff --git a/psycopg2/doc/HACKING b/psycopg2/doc/HACKING new file mode 100644 index 0000000..f60474c --- /dev/null +++ b/psycopg2/doc/HACKING @@ -0,0 +1,43 @@ +General information +******************* + +Some help to people wanting to hack on psycopg. First of all, note that +*every* function in the psycopg module source code is prefixed by one of the +following words: + + psyco is used for function directly callable from python (i.e., functions + in the psycopg module itself.) the only notable exception is the + source code for the module itself, that uses "psyco" even for C-only + functions. + + conn is used for functions related to connection objects. + + curs is used for functions related to cursor objects. + + typecast is used for typecasters and utility function related to + typecaster creation and registration. + +Pythonic definition of types and functions available from python are defined +in *_type.c files. Internal functions, callable only from C are located in +*_int.c files and extensions to the DBAPI can be found in the *_ext.c files. + + +Patches +******* + +If you submit a patch, please send a diff generated with the "-u" switch. +Also note that I don't like that much cosmetic changes (like renaming +already existing variables) and I will rewrap the patch to 78 columns +anyway, so it is much better if you do that beforehand. + + +The type system +*************** + +Simple types, like integers and strings, are converted to python base types +(the conversion functions are in typecast_base.c). Complex types are +converted to ad-hoc types, defined in the typeobj_*.{c,h} files. The +conversion function are in the other typecast_*.c files. typecast.c defines +the basic utility functions (available through the psycopg module) used when +defining new typecasters from C and python. + diff --git a/psycopg2/doc/SUCCESS b/psycopg2/doc/SUCCESS new file mode 100644 index 0000000..9ae91f5 --- /dev/null +++ b/psycopg2/doc/SUCCESS @@ -0,0 +1,114 @@ +From: Jack Moffitt +To: Psycopg Mailing List +Subject: Re: [Psycopg] preparing for 1.0 +Date: 22 Oct 2001 11:16:21 -0600 + +www.vorbis.com is serving from 5-10k pages per day with psycopg serving +data for most of that. + +I plan to use it for several of our other sites, so that number will +increase. + +I've never had a single problem (that wasn't my fault) besides those +segfaults, and those are now gone as well, and I've been using psycopg +since June (around 0.99.2?). + +jack. + + +From: Yury Don +To: Psycopg Mailing List +Subject: Re: [Psycopg] preparing for 1.0 +Date: 23 Oct 2001 09:53:11 +0600 + +We use psycopg and psycopg zope adapter since fisrt public +release (it seems version 0.4). Now it works on 3 our sites and in intranet +applications. We had few problems, but all problems were quckly +solved. The strong side of psycopg is that it's code is well organized +and easy to understand. When I found a problem with non-ISO datestyle in first +version of psycopg, it took for me 15 or 20 minutes to learn code and +to solve the problem, even thouth my knowledge of c were poor. + +BTW, segfault with dictfetchall on particular data set (see [Psycopg] +dictfetchXXX() problems) disappeared in 0.99.8pre2. + +-- +Best regards, +Yury Don + + +From: Tom Jenkins +To: Federico Di Gregorio +Cc: Psycopg Mailing List +Subject: Re: [Psycopg] preparing for 1.0 +Date: 23 Oct 2001 08:25:52 -0400 + +The US Govt Department of Labor's Office of Disability Employment +Policy's DisabilityDirect website is run on zope and zpsycopg. + + +From: Scott Leerssen +To: Federico Di Gregorio +Subject: Re: [Psycopg] preparing for 1.0 +Date: 23 Oct 2001 09:56:10 -0400 + +Racemi's load management software infrastructure uses psycopg to handle +complex server allocation decisions, plus storage and access of +environmental conditions and accounting records for potentially +thousands of servers. Psycopg has, to this point, been the only +Python/PostGreSQL interface that could handle the scaling required for +our multithreaded applications. + +Scott + + +From: Andre Schubert +To: Federico Di Gregorio +Cc: Psycopg Mailing List +Subject: Re: [Psycopg] preparing for 1.0 +Date: 23 Oct 2001 11:46:07 +0200 + +i have changed the psycopg version to 0.99.8pre2 on all devel-machines +and all segfaults are gone. after my holiday i wil change to 0.99.8pre2 +or 1.0 on our production-server. +this server contains several web-sites which are all connected to +postgres over ZPsycopgDA. + +thanks as + + +From: Fred Wilson Horch +To: +Subject: [Psycopg] Success story for psycopg +Date: 23 Oct 2001 10:59:17 -0400 + +Due to various quirks of PyGreSQL and PoPy, EcoAccess has been looking for +a reliable, fast and relatively bug-free Python-PostgreSQL interface for +our project. + +Binary support in psycopg, along with the umlimited tuple size in +PostgreSQL 7.1, allowed us to quickly prototype a database-backed file +storage web application, which we're using for file sharing among our +staff and volunteers. Using a database backend instead of a file system +allows us to easily enrich the meta-information associated with each file +and simplifies our data handling routines. + +We've been impressed by the responsiveness of the psycopg team to bug +reports and feature requests, and we're looking forward to using psycopg +as the Python interface for additional database-backed web applications. + +Keep up the good work! +-- +Fred Wilson Horch mailto:fhorch@ecoaccess.org +Executive Director, EcoAccess http://ecoaccess.org/ + + +From: Damon Fasching +To: Michele Comitini +Cc: fog@debian.org +Subject: Re: How does one create a database within Python using psycopg? +Date: 25 Feb 2002 17:39:41 -0800 + +[snip] +btw I checked out 4 different Python-PostgreSQL packages. psycopg is the +only one which built and imported w/o any trouble! (At least for me.) diff --git a/psycopg2/doc/TODO b/psycopg2/doc/TODO new file mode 100644 index 0000000..b20b276 --- /dev/null +++ b/psycopg2/doc/TODO @@ -0,0 +1,33 @@ +TODO list for psycopg 2 or later +******************************** + +Move items to the DONE section only after writing a test for the +implementation. Also add a note on how the item was resolved. +(Obviously I was joking about the test..) + +* Find a better way to compile the type-casting code instead of including it + in typecast.c directy. (Including is not that bad, but the need to touch + psycopg/typecast.c every time is bad bad bad.) + +* executemany() should _not_ take the async flag, remove it and force multiple + queries to be synchronous. + +* Fix all the docstrings. + +* Support the protocols API fully. + +* Unify the common code in typecast_datetime.c and typecast_mxdatetime.c. + +* Port typecasters to new-style classes. + +* Write a complete postgresql<->python encodings table. + +* Implement binary typecasters (should be easy, but it will take time.) + +DONE +==== + +* Convert type-casters to new-style types in Python 2.2+. + +* callproc() never worked, fix it or remove it and raise right exception. + [Removed callproc code, now an exception is raised.] diff --git a/psycopg2/doc/api-screen.css b/psycopg2/doc/api-screen.css new file mode 100644 index 0000000..22e8f7e --- /dev/null +++ b/psycopg2/doc/api-screen.css @@ -0,0 +1,138 @@ +/* Based on the Epydoc "default.css" +** with some missing reST-related classes +** and Python syntax support (from SilverCity) +*/ + +/* Body color */ +body { background: #ffffff; color: #000000; } + +/* Tables */ +table.summary, table.details, table.index + { background: #e8f0f8; color: #000000; } +tr.summary, tr.details, tr.index + { background: #70b0f0; color: #000000; + text-align: left; font-size: 120%; } +tr.group { background: #c0e0f8; color: #000000; + text-align: left; font-size: 120%; + font-style: italic; } + +/* Documentation page titles */ +h2.module { margin-top: 0.2em; } +h2.class { margin-top: 0.2em; } + +/* Headings */ +h1.heading { font-size: +140%; font-style: italic; + font-weight: bold; } +h2.heading { font-size: +125%; font-style: italic; + font-weight: bold; } +h3.heading { font-size: +110%; font-style: italic; + font-weight: normal; } + +/* Base tree */ +pre.base-tree { font-size: 80%; margin: 0; } + +/* TOC */ +p.toc { margin: 0; } + +/* Details Sections */ +table.func-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.func-detail { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +table.var-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.var-details { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +/* Function signatures */ +.sig { background: transparent; color: #000000; + font-weight: bold; } +.sig-name { background: transparent; color: #006080; } +.sig-arg, .sig-kwarg, .sig-vararg + { background: transparent; color: #008060; } +.sig-default { background: transparent; color: #602000; } +.summary-sig { background: transparent; color: #000000; } +.summary-sig-name { background: transparent; color: #204080; } +.summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg + { background: transparent; color: #008060; } + +/* Doctest blocks */ +.py-src { background: transparent; color: #000000; } +.py-prompt { background: transparent; color: #005050; + font-weight: bold;} +.py-string { background: transparent; color: #006030; } +.py-comment { background: transparent; color: #003060; } +.py-keyword { background: transparent; color: #600000; } +.py-output { background: transparent; color: #404040; } +div.code-block, +pre.literal-block, +pre.doctestblock { background: #f4faff; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +table pre.doctestblock + { background: #dce4ec; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +div.code-block { font-family: monospace; } + +/* Variable values */ +pre.variable { background: #dce4ec; color: #000000; + padding: .5em; margin: 0; + border: 1px solid #708890; } +.variable-linewrap { background: transparent; color: #604000; } +.variable-ellipsis { background: transparent; color: #604000; } +.variable-quote { background: transparent; color: #604000; } +.re { background: transparent; color: #000000; } +.re-char { background: transparent; color: #006030; } +.re-op { background: transparent; color: #600000; } +.re-group { background: transparent; color: #003060; } +.re-ref { background: transparent; color: #404040; } + +/* Navigation bar */ +table.navbar { background: #a0c0ff; color: #0000ff; + border: 2px groove #c0d0d0; } +th.navbar { background: #a0c0ff; color: #0000ff; } +th.navselect { background: #70b0ff; color: #000000; } +.nomargin { margin: 0; } + +/* Links */ +a:link { background: transparent; color: #0000ff; } +a:visited { background: transparent; color: #204080; } +a.navbar:link { background: transparent; color: #0000ff; + text-decoration: none; } +a.navbar:visited { background: transparent; color: #204080; + text-decoration: none; } + +/* Admonitions */ +div.warning, +div.note { background-color: #c0e0f8; + border: thin solid black; + padding: 1em; + margin-left: 1em; + margin-right: 1em; } +div.warning .first, +div.note .first { font-family: sans-serif; + font-size: 110%; + margin-right: 0.5em; } + +/* Lists */ +ul { margin-top: 0; } + +/* Python syntax */ +.p_character { color: olive; } +.p_classname { color: blue; font-weight: bold; } +.p_commentblock {color: gray; font-style: italic; } +.p_commentline { color: green; font-style: italic; } +.p_default {} +.p_defname { color: #009999; font-weight: bold; } +.p_identifier { color: black; } +.p_number { color: #009999; } +.p_operator { color: black; } +.p_string { color: #7F007F; } +.p_stringeol { color: #7F007F; } +.p_triple { color: #7F0000; } +.p_tripledouble { color: #7F0000; } +.p_word { color: navy; font-weight: bold; } diff --git a/psycopg2/doc/api/epydoc.css b/psycopg2/doc/api/epydoc.css new file mode 100644 index 0000000..22e8f7e --- /dev/null +++ b/psycopg2/doc/api/epydoc.css @@ -0,0 +1,138 @@ +/* Based on the Epydoc "default.css" +** with some missing reST-related classes +** and Python syntax support (from SilverCity) +*/ + +/* Body color */ +body { background: #ffffff; color: #000000; } + +/* Tables */ +table.summary, table.details, table.index + { background: #e8f0f8; color: #000000; } +tr.summary, tr.details, tr.index + { background: #70b0f0; color: #000000; + text-align: left; font-size: 120%; } +tr.group { background: #c0e0f8; color: #000000; + text-align: left; font-size: 120%; + font-style: italic; } + +/* Documentation page titles */ +h2.module { margin-top: 0.2em; } +h2.class { margin-top: 0.2em; } + +/* Headings */ +h1.heading { font-size: +140%; font-style: italic; + font-weight: bold; } +h2.heading { font-size: +125%; font-style: italic; + font-weight: bold; } +h3.heading { font-size: +110%; font-style: italic; + font-weight: normal; } + +/* Base tree */ +pre.base-tree { font-size: 80%; margin: 0; } + +/* TOC */ +p.toc { margin: 0; } + +/* Details Sections */ +table.func-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.func-detail { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +table.var-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.var-details { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +/* Function signatures */ +.sig { background: transparent; color: #000000; + font-weight: bold; } +.sig-name { background: transparent; color: #006080; } +.sig-arg, .sig-kwarg, .sig-vararg + { background: transparent; color: #008060; } +.sig-default { background: transparent; color: #602000; } +.summary-sig { background: transparent; color: #000000; } +.summary-sig-name { background: transparent; color: #204080; } +.summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg + { background: transparent; color: #008060; } + +/* Doctest blocks */ +.py-src { background: transparent; color: #000000; } +.py-prompt { background: transparent; color: #005050; + font-weight: bold;} +.py-string { background: transparent; color: #006030; } +.py-comment { background: transparent; color: #003060; } +.py-keyword { background: transparent; color: #600000; } +.py-output { background: transparent; color: #404040; } +div.code-block, +pre.literal-block, +pre.doctestblock { background: #f4faff; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +table pre.doctestblock + { background: #dce4ec; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +div.code-block { font-family: monospace; } + +/* Variable values */ +pre.variable { background: #dce4ec; color: #000000; + padding: .5em; margin: 0; + border: 1px solid #708890; } +.variable-linewrap { background: transparent; color: #604000; } +.variable-ellipsis { background: transparent; color: #604000; } +.variable-quote { background: transparent; color: #604000; } +.re { background: transparent; color: #000000; } +.re-char { background: transparent; color: #006030; } +.re-op { background: transparent; color: #600000; } +.re-group { background: transparent; color: #003060; } +.re-ref { background: transparent; color: #404040; } + +/* Navigation bar */ +table.navbar { background: #a0c0ff; color: #0000ff; + border: 2px groove #c0d0d0; } +th.navbar { background: #a0c0ff; color: #0000ff; } +th.navselect { background: #70b0ff; color: #000000; } +.nomargin { margin: 0; } + +/* Links */ +a:link { background: transparent; color: #0000ff; } +a:visited { background: transparent; color: #204080; } +a.navbar:link { background: transparent; color: #0000ff; + text-decoration: none; } +a.navbar:visited { background: transparent; color: #204080; + text-decoration: none; } + +/* Admonitions */ +div.warning, +div.note { background-color: #c0e0f8; + border: thin solid black; + padding: 1em; + margin-left: 1em; + margin-right: 1em; } +div.warning .first, +div.note .first { font-family: sans-serif; + font-size: 110%; + margin-right: 0.5em; } + +/* Lists */ +ul { margin-top: 0; } + +/* Python syntax */ +.p_character { color: olive; } +.p_classname { color: blue; font-weight: bold; } +.p_commentblock {color: gray; font-style: italic; } +.p_commentline { color: green; font-style: italic; } +.p_default {} +.p_defname { color: #009999; font-weight: bold; } +.p_identifier { color: black; } +.p_number { color: #009999; } +.p_operator { color: black; } +.p_string { color: #7F007F; } +.p_stringeol { color: #7F007F; } +.p_triple { color: #7F0000; } +.p_tripledouble { color: #7F0000; } +.p_word { color: navy; font-weight: bold; } diff --git a/psycopg2/doc/api/index.html b/psycopg2/doc/api/index.html new file mode 100644 index 0000000..419bbcf --- /dev/null +++ b/psycopg2/doc/api/index.html @@ -0,0 +1,15 @@ + + + + + API Documentation + + + + + + + + + diff --git a/psycopg2/doc/api/private/__builtin__.list-class.html b/psycopg2/doc/api/private/__builtin__.list-class.html new file mode 100644 index 0000000..c8217a7 --- /dev/null +++ b/psycopg2/doc/api/private/__builtin__.list-class.html @@ -0,0 +1,817 @@ + + + + + __builtin__.list + + + + + + + + + + + + + + + + + + + +
+ + Module __builtin__ :: + Class list +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type list

+ +
+object --+
+         |
+        list
+

+ +
Known Subclasses:
+
+ DictRow
+ +
+ +

list() -> new list +list(sequence) -> new list initialized from sequence's items

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __add__(x, + y) +
+Return x+y...
 __contains__(x, + y) +
+Return y in x...
 __delitem__(x, + y) +
+Return del x[y]...
 __delslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __eq__(x, + y) +
+Return x==y...
 __ge__(x, + y) +
+Return x>=y...
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __getitem__(x, + y) +
+Return x[y]...
 __getslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __gt__(x, + y) +
+Return x>y...
 __hash__(x) +
+Return hash(x)...
 __iadd__(x, + y) +
+Return x+=y...
 __imul__(x, + y) +
+Return x*=y...
 __iter__(x) +
+Return iter(x)...
 __le__(x, + y) +
+Return x<=y...
 __len__(x) +
+Return len(x)...
 __lt__(x, + y) +
+Return x<y...
 __mul__(x, + n) +
+Return x*n...
 __ne__(x, + y) +
+Return x!=y...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __rmul__(x, + n) +
+Return n*x...
 __setitem__(x, + i, + y) +
+Return x[i]=y...
 __setslice__(x, + i, + j, + y) +
+Use of negative indices is not supported.
 append(L, + object) +
+append object to end
 count(L, + value) +
+return number of occurrences of value
 extend(L, + iterable) +
+extend list by appending elements from the iterable
 index(...) +
+L.index(value, [start, [stop]]) -> integer -- return first index of value
 insert(L, + index, + object) +
+insert object before index
 pop(L, + index) +
+remove and return item at index (default last)
 remove(L, + value) +
+remove first occurrence of value
 reverse(L) +
+reverse IN PLACE
 sort(L, + cmpfunc) +
+stable sort IN PLACE; cmpfunc(x, y) -> -1, 0, 1
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__add__(x, + y) +
(Addition operator) +

+
+
Returns:
+
+
+x+y
+
+
+
+
+
+ + +
+

__contains__(x, + y) +
(In operator) +

+
+
Returns:
+
+
+y in x
+
+
+
+
+
+ + +
+

__delitem__(x, + y) +
(Index deletion operator) +

+
+
Returns:
+
+
+del x[y]
+
+
+
+
+
+ + +
+

__delslice__(x, + i, + j) +
(Slice deletion operator) +

+

Use of negative indices is not supported.

+
+
Returns:
+
+
+del x[i:j]
+
+
+
+
+
+ + +
+

__eq__(x, + y) +
(Equality operator) +

+
+
Returns:
+
+
+x==y
+
+
+
+
+
+ + +
+

__ge__(x, + y) +
(Greater-than-or-equals operator) +

+
+
Returns:
+
+
+x>=y
+
+
+
+
+
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
Overrides:
+
__builtin__.object.__getattribute__
+
+
+
+ + +
+

__getitem__(x, + y) +
(Indexing operator) +

+
+
Returns:
+
+
+x[y]
+
+
+
+
+
+ + +
+

__getslice__(x, + i, + j) +
(Slicling operator) +

+

Use of negative indices is not supported.

+
+
Returns:
+
+
+x[i:j]
+
+
+
+
+
+ + +
+

__gt__(x, + y) +
(Greater-than operator) +

+
+
Returns:
+
+
+x>y
+
+
+
+
+
+ + +
+

__hash__(x) +
(Hashing function) +

+
+
Returns:
+
+
+hash(x)
+
+
+
+
Overrides:
+
__builtin__.object.__hash__
+
+
+
+ + +
+

__iadd__(x, + y) +

+
+
Returns:
+
+
+x+=y
+
+
+
+
+
+ + +
+

__imul__(x, + y) +

+
+
Returns:
+
+
+x*=y
+
+
+
+
+
+ + +
+

__iter__(x) +

+
+
Returns:
+
+
+iter(x)
+
+
+
+
+
+ + +
+

__le__(x, + y) +
(Less-than-or-equals operator) +

+
+
Returns:
+
+
+x<=y
+
+
+
+
+
+ + +
+

__len__(x) +
(Length operator) +

+
+
Returns:
+
+
+len(x)
+
+
+
+
+
+ + +
+

__lt__(x, + y) +
(Less-than operator) +

+
+
Returns:
+
+
+x<y
+
+
+
+
+
+ + +
+

__mul__(x, + n) +

+
+
Returns:
+
+
+x*n
+
+
+
+
+
+ + +
+

__ne__(x, + y) +
(Inequality operator) +

+
+
Returns:
+
+
+x!=y
+
+
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
Overrides:
+
__builtin__.object.__repr__
+
+
+
+ + +
+

__rmul__(x, + n) +

+
+
Returns:
+
+
+n*x
+
+
+
+
+
+ + +
+

__setitem__(x, + i, + y) +
(Index assignment operator) +

+
+
Returns:
+
+
+x[i]=y
+
+
+
+
+
+ + +
+

__setslice__(x, + i, + j, + y) +
(Slice assignment operator) +

+

Use of negative indices is not supported.

+
+
Returns:
+
+
+x[i:j]=y
+
+
+
+
+
+ + +
+

append(L, + object) +

+

append object to end

+
+
+
+ + +
+

count(L, + value) +

+

return number of occurrences of value

+
+
Returns:
+
+
+integer
+
+
+
+
+
+ + +
+

extend(L, + iterable) +

+

extend list by appending elements from the iterable

+
+
+
+ + +
+

index(...) +

+

L.index(value, [start, [stop]]) -> integer -- return first index of value

+
+
+
+ + +
+

insert(L, + index, + object) +

+

insert object before index

+
+
+
+ + +
+

pop(L, + index=...) +

+

remove and return item at index (default last)

+
+
Returns:
+
+
+item
+
+
+
+
+
+ + +
+

remove(L, + value) +

+

remove first occurrence of value

+
+
+
+ + +
+

reverse(L) +

+

reverse IN PLACE

+
+
+
+ + +
+

sort(L, + cmpfunc=None) +

+

stable sort IN PLACE; cmpfunc(x, y) -> -1, 0, 1

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/__builtin__.object-class.html b/psycopg2/doc/api/private/__builtin__.object-class.html new file mode 100644 index 0000000..08d0af6 --- /dev/null +++ b/psycopg2/doc/api/private/__builtin__.object-class.html @@ -0,0 +1,270 @@ + + + + + __builtin__.object + + + + + + + + + + + + + + + + + + + +
+ + Module __builtin__ :: + Class object +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type object

+ +
Known Subclasses:
+
+ AbstractConnectionPool, + list, + SQL_IN, + type, + tzinfo, + connection, + cursor, + ISQLQuote
+ +
+ +

The most base type

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + + + +
Class Variable Summary
type__class__ = __builtin__.type

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
+
+ + +
+

__delattr__(...) +

+

x.__delattr__('name') <==> del x.name

+
+
+
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
+
+ + +
+

__hash__(x) +
(Hashing function) +

+
+
Returns:
+
+
+hash(x)
+
+
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
+
+ + +
+

__reduce__(...) +

+

helper for pickle

+
+
+
+ + +
+

__reduce_ex__(...) +

+

helper for pickle

+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
+
+ + +
+

__setattr__(...) +

+

x.__setattr__('name', value) <==> x.name = value

+
+
+
+ + +
+

__str__(x) +
(Informal representation operator) +

+
+
Returns:
+
+
+str(x)
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/__builtin__.type-class.html b/psycopg2/doc/api/private/__builtin__.type-class.html new file mode 100644 index 0000000..b388e76 --- /dev/null +++ b/psycopg2/doc/api/private/__builtin__.type-class.html @@ -0,0 +1,384 @@ + + + + + __builtin__.type + + + + + + + + + + + + + + + + + + + +
+ + Module __builtin__ :: + Class type +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type type

+ +
+object --+
+         |
+        type
+

+ +
+ +

type(object) -> the object's type +type(name, bases, dict) -> a new type

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __call__(x, + ...) +
+Return x(...)...
 __cmp__(x, + y) +
+Return cmp(x,y)...
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
list of immediate subclasses__subclasses__() +
listmro() +
+return a type's method resolution order
    Inherited from object
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __str__(x) +
+Return str(x)...

+ + + + + + + + + + + + + +
Property Summary
 __base__
 __basicsize__
 __dictoffset__
 __flags__
 __itemsize__
 __mro__
 __weakrefoffset__

+ + + + + + + + + + +
Class Variable Summary
tuple__bases__ = (<type 'object'>,) +
str__name__ = 'type' +

+ + + + + + +
Method Details
+ + +
+

__call__(x, + ...) +
(Call operator) +

+
+
Returns:
+
+
+x(...)
+
+
+
+
+
+ + +
+

__cmp__(x, + y) +
(Comparison operator) +

+
+
Returns:
+
+
+cmp(x,y)
+
+
+
+
+
+ + +
+

__delattr__(...) +

+

x.__delattr__('name') <==> del x.name

+
+
Overrides:
+
__builtin__.object.__delattr__
+
+
+
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
Overrides:
+
__builtin__.object.__getattribute__
+
+
+
+ + +
+

__hash__(x) +
(Hashing function) +

+
+
Returns:
+
+
+hash(x)
+
+
+
+
Overrides:
+
__builtin__.object.__hash__
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
Overrides:
+
__builtin__.object.__repr__
+
+
+
+ + +
+

__setattr__(...) +

+

x.__setattr__('name', value) <==> x.name = value

+
+
Overrides:
+
__builtin__.object.__setattr__
+
+
+
+ + +
+

__subclasses__() +

+
+
Returns:
+
+list of immediate subclasses
+
+
+
+ + +
+

mro() +

+

return a type's method resolution order

+
+
Returns:
+
+list
+
+
+
+
+ + + + + + +
Class Variable Details
+
+ +

__bases__

+
+
+
+
+
Type:
+
+ tuple + +
+
Value:
+
+
+(<type 'object'>,)                                                     
+
+
+
+
+
+ +

__name__

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'type'                                                                 
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/datetime.tzinfo-class.html b/psycopg2/doc/api/private/datetime.tzinfo-class.html new file mode 100644 index 0000000..337ac1a --- /dev/null +++ b/psycopg2/doc/api/private/datetime.tzinfo-class.html @@ -0,0 +1,239 @@ + + + + + datetime.tzinfo + + + + + + + + + + + + + + + + + + + +
+ + Module datetime :: + Class tzinfo +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type tzinfo

+ +
+object --+
+         |
+        tzinfo
+

+ +
Known Subclasses:
+
+ FixedOffsetTimezone, + LocalTimezone
+ +
+ +

Abstract base class for time zone info objects.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+-> (cls, state)
 dst(...) +
+datetime -> DST offset in minutes east of UTC.
 fromutc(...) +
+datetime in UTC -> datetime in local time.
 tzname(...) +
+datetime -> string name of time zone.
 utcoffset(...) +
+datetime -> minutes east of UTC (negative for west of UTC).
    Inherited from object
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __hash__(x) +
+Return hash(x)...
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
Overrides:
+
__builtin__.object.__getattribute__
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__reduce__(...) +

+

-> (cls, state)

+
+
Overrides:
+
__builtin__.object.__reduce__
+
+
+
+ + +
+

dst(...) +

+

datetime -> DST offset in minutes east of UTC.

+
+
+
+ + +
+

fromutc(...) +

+

datetime in UTC -> datetime in local time.

+
+
+
+ + +
+

tzname(...) +

+

datetime -> string name of time zone.

+
+
+
+ + +
+

utcoffset(...) +

+

datetime -> minutes east of UTC (negative for west of UTC).

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/epydoc.css b/psycopg2/doc/api/private/epydoc.css new file mode 100644 index 0000000..22e8f7e --- /dev/null +++ b/psycopg2/doc/api/private/epydoc.css @@ -0,0 +1,138 @@ +/* Based on the Epydoc "default.css" +** with some missing reST-related classes +** and Python syntax support (from SilverCity) +*/ + +/* Body color */ +body { background: #ffffff; color: #000000; } + +/* Tables */ +table.summary, table.details, table.index + { background: #e8f0f8; color: #000000; } +tr.summary, tr.details, tr.index + { background: #70b0f0; color: #000000; + text-align: left; font-size: 120%; } +tr.group { background: #c0e0f8; color: #000000; + text-align: left; font-size: 120%; + font-style: italic; } + +/* Documentation page titles */ +h2.module { margin-top: 0.2em; } +h2.class { margin-top: 0.2em; } + +/* Headings */ +h1.heading { font-size: +140%; font-style: italic; + font-weight: bold; } +h2.heading { font-size: +125%; font-style: italic; + font-weight: bold; } +h3.heading { font-size: +110%; font-style: italic; + font-weight: normal; } + +/* Base tree */ +pre.base-tree { font-size: 80%; margin: 0; } + +/* TOC */ +p.toc { margin: 0; } + +/* Details Sections */ +table.func-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.func-detail { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +table.var-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.var-details { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +/* Function signatures */ +.sig { background: transparent; color: #000000; + font-weight: bold; } +.sig-name { background: transparent; color: #006080; } +.sig-arg, .sig-kwarg, .sig-vararg + { background: transparent; color: #008060; } +.sig-default { background: transparent; color: #602000; } +.summary-sig { background: transparent; color: #000000; } +.summary-sig-name { background: transparent; color: #204080; } +.summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg + { background: transparent; color: #008060; } + +/* Doctest blocks */ +.py-src { background: transparent; color: #000000; } +.py-prompt { background: transparent; color: #005050; + font-weight: bold;} +.py-string { background: transparent; color: #006030; } +.py-comment { background: transparent; color: #003060; } +.py-keyword { background: transparent; color: #600000; } +.py-output { background: transparent; color: #404040; } +div.code-block, +pre.literal-block, +pre.doctestblock { background: #f4faff; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +table pre.doctestblock + { background: #dce4ec; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +div.code-block { font-family: monospace; } + +/* Variable values */ +pre.variable { background: #dce4ec; color: #000000; + padding: .5em; margin: 0; + border: 1px solid #708890; } +.variable-linewrap { background: transparent; color: #604000; } +.variable-ellipsis { background: transparent; color: #604000; } +.variable-quote { background: transparent; color: #604000; } +.re { background: transparent; color: #000000; } +.re-char { background: transparent; color: #006030; } +.re-op { background: transparent; color: #600000; } +.re-group { background: transparent; color: #003060; } +.re-ref { background: transparent; color: #404040; } + +/* Navigation bar */ +table.navbar { background: #a0c0ff; color: #0000ff; + border: 2px groove #c0d0d0; } +th.navbar { background: #a0c0ff; color: #0000ff; } +th.navselect { background: #70b0ff; color: #000000; } +.nomargin { margin: 0; } + +/* Links */ +a:link { background: transparent; color: #0000ff; } +a:visited { background: transparent; color: #204080; } +a.navbar:link { background: transparent; color: #0000ff; + text-decoration: none; } +a.navbar:visited { background: transparent; color: #204080; + text-decoration: none; } + +/* Admonitions */ +div.warning, +div.note { background-color: #c0e0f8; + border: thin solid black; + padding: 1em; + margin-left: 1em; + margin-right: 1em; } +div.warning .first, +div.note .first { font-family: sans-serif; + font-size: 110%; + margin-right: 0.5em; } + +/* Lists */ +ul { margin-top: 0; } + +/* Python syntax */ +.p_character { color: olive; } +.p_classname { color: blue; font-weight: bold; } +.p_commentblock {color: gray; font-style: italic; } +.p_commentline { color: green; font-style: italic; } +.p_default {} +.p_defname { color: #009999; font-weight: bold; } +.p_identifier { color: black; } +.p_number { color: #009999; } +.p_operator { color: black; } +.p_string { color: #7F007F; } +.p_stringeol { color: #7F007F; } +.p_triple { color: #7F0000; } +.p_tripledouble { color: #7F0000; } +.p_word { color: navy; font-weight: bold; } diff --git a/psycopg2/doc/api/private/exceptions.Exception-class.html b/psycopg2/doc/api/private/exceptions.Exception-class.html new file mode 100644 index 0000000..3064c51 --- /dev/null +++ b/psycopg2/doc/api/private/exceptions.Exception-class.html @@ -0,0 +1,128 @@ + + + + + exceptions.Exception + + + + + + + + + + + + + + + + + + + +
+ + Module exceptions :: + Class Exception +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class Exception

+ +
Known Subclasses:
+
+ StandardError
+ +
+ +

Common base class for all exceptions.

+
+ + + + + + + + + + + + +
Method Summary
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+
+
+
+ + +
+

__getitem__(...) +
(Indexing operator) +

+
+
+
+ + +
+

__str__(...) +
(Informal representation operator) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/exceptions.StandardError-class.html b/psycopg2/doc/api/private/exceptions.StandardError-class.html new file mode 100644 index 0000000..1b491dd --- /dev/null +++ b/psycopg2/doc/api/private/exceptions.StandardError-class.html @@ -0,0 +1,102 @@ + + + + + exceptions.StandardError + + + + + + + + + + + + + + + + + + + +
+ + Module exceptions :: + Class StandardError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class StandardError

+ +
+Exception --+
+            |
+           StandardError
+

+ +
Known Subclasses:
+
+ Error, + Warning
+ +
+ +

Base class for all standard Python exceptions.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/frames.html b/psycopg2/doc/api/private/frames.html new file mode 100644 index 0000000..ffd6536 --- /dev/null +++ b/psycopg2/doc/api/private/frames.html @@ -0,0 +1,15 @@ + + + + + API Documentation + + + + + + + + + diff --git a/psycopg2/doc/api/private/help.html b/psycopg2/doc/api/private/help.html new file mode 100644 index 0000000..21f2560 --- /dev/null +++ b/psycopg2/doc/api/private/help.html @@ -0,0 +1,231 @@ + + + + + Help + + + + + + + + + + + + + + + + + + + +
+ + + +
[show private | hide private]
[frames | no frames]
+ +

API Documentation

+ +

This document contains the API (Application Programming Interface) +documentation for this project. Documentation for the Python +objects defined by the project is divided into separate pages for each +package, module, and class. The API documentation also includes two +pages containing information about the project as a whole: a trees +page, and an index page.

+ +

Object Documentation

+ +

Each Package Documentation page contains:

+
    +
  • A description of the package.
  • +
  • A list of the modules and sub-packages contained by the + package.
  • +
  • A summary of the classes defined by the package.
  • +
  • A summary of the functions defined by the package.
  • +
  • A summary of the variables defined by the package.
  • +
  • A detailed description of each function defined by the + package.
  • +
  • A detailed description of each variable defined by the + package.
  • +
+ +

Each Module Documentation page contains:

+
    +
  • A description of the module.
  • +
  • A summary of the classes defined by the module.
  • +
  • A summary of the functions defined by the module.
  • +
  • A summary of the variables defined by the module.
  • +
  • A detailed description of each function defined by the + module.
  • +
  • A detailed description of each variable defined by the + module.
  • +
+ +

Each Class Documentation page contains:

+
    +
  • A class inheritance diagram.
  • +
  • A list of known subclasses.
  • +
  • A description of the class.
  • +
  • A summary of the methods defined by the class.
  • +
  • A summary of the instance variables defined by the class.
  • +
  • A summary of the class (static) variables defined by the + class.
  • +
  • A detailed description of each method defined by the + class.
  • +
  • A detailed description of each instance variable defined by the + class.
  • +
  • A detailed description of each class (static) variable defined + by the class.
  • +
+ +

Project Documentation

+ +

The Trees page contains the module and class hierarchies:

+
    +
  • The module hierarchy lists every package and module, with + modules grouped into packages. At the top level, and within each + package, modules and sub-packages are listed alphabetically.
  • +
  • The class hierarchy lists every class, grouped by base + class. If a class has more than one base class, then it will be + listed under each base class. At the top level, and under each base + class, classes are listed alphabetically.
  • +
+ +

The Index page contains indices of terms and + identifiers:

+
    +
  • The term index lists every term indexed by any object's + documentation. For each term, the index provides links to each + place where the term is indexed.
  • +
  • The identifier index lists the (short) name of every package, + module, class, method, function, variable, and parameter. For each + identifier, the index provides a short description, and a link to + its documentation.
  • +
+ +

The Table of Contents

+ +

The table of contents occupies the two frames on the left side of +the window. The upper-left frame displays the project +contents, and the lower-left frame displays the module +contents:

+ + + + + + + + + +
+ Project
Contents
...
+ API
Documentation
Frame


+
+ Module
Contents
 
...
  +

+ +

The project contents frame contains a list of all packages +and modules that are defined by the project. Clicking on an entry +will display its contents in the module contents frame. Clicking on a +special entry, labeled "Everything," will display the contents of +the entire project.

+ +

The module contents frame contains a list of every +submodule, class, type, exception, function, and variable defined by a +module or package. Clicking on an entry will display its +documentation in the API documentation frame. Clicking on the name of +the module, at the top of the frame, will display the documentation +for the module itself.

+ +

The "frames" and "no frames" buttons below the top +navigation bar can be used to control whether the table of contents is +displayed or not.

+ +

The Navigation Bar

+ +

A navigation bar is located at the top and bottom of every page. +It indicates what type of page you are currently viewing, and allows +you to go to related pages. The following table describes the labels +on the navigation bar. Note that not some labels (such as +[Parent]) are not displayed on all pages.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LabelHighlighted when...Links to...
[Parent](never highlighted) the parent of the current package
[Package]viewing a packagethe package containing the current object +
[Module]viewing a modulethe module containing the current object +
[Class]viewing a class the class containing the current object
[Trees]viewing the trees page the trees page
[Index]viewing the index page the index page
[Help]viewing the help page the help page
+ +

The "show private" and "hide private" buttons below +the top navigation bar can be used to control whether documentation +for private objects is displayed. Private objects are usually defined +as objects whose (short) names begin with a single underscore, but do +not end with an underscore. For example, "_x", +"__pprint", and "epydoc.epytext._tokenize" +are private objects; but "re.sub", +"__init__", and "type_" are not. However, +if a module defines the "__all__" variable, then its +contents are used to decide which objects are private.

+ +

A timestamp below the bottom navigation bar indicates when each +page was last updated.

+ + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/index.html b/psycopg2/doc/api/private/index.html new file mode 100644 index 0000000..ffd6536 --- /dev/null +++ b/psycopg2/doc/api/private/index.html @@ -0,0 +1,15 @@ + + + + + API Documentation + + + + + + + + + diff --git a/psycopg2/doc/api/private/indices.html b/psycopg2/doc/api/private/indices.html new file mode 100644 index 0000000..6a224a1 --- /dev/null +++ b/psycopg2/doc/api/private/indices.html @@ -0,0 +1,666 @@ + + + + + Index + + + + + + + + + + + + + + + + + + + +
+ + + +
[show private | hide private]
[frames | no frames]
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Identifier Index
__add__Method in class __builtin__.list
__base__member_descriptor in class __builtin__.type
__bases__Variable in class __builtin__.type
__basicsize__member_descriptor in class __builtin__.type
__build_dictMethod in class psycopg2.psycopg1.cursor
__call__Method in class __builtin__.type
typeClass in module __builtin__
__cmp__Method in class __builtin__.type
__contains__Method in class __builtin__.list
__delattr__Method in class __builtin__.object
__delattr__Method in class __builtin__.type
__delitem__Method in class __builtin__.list
__delslice__Method in class __builtin__.list
__dictoffset__member_descriptor in class __builtin__.type
__eq__Method in class __builtin__.list
__flags__member_descriptor in class __builtin__.type
__ge__Method in class __builtin__.list
__getattribute__Method in class __builtin__.list
__getattribute__Method in class __builtin__.object
__getattribute__Method in class __builtin__.type
__getattribute__Method in class datetime.tzinfo
__getitem__Method in class __builtin__.list
__getitem__Method in class exceptions.Exception
__getitem__Method in class psycopg2.extras.DictRow
__getslice__Method in class __builtin__.list
__gt__Method in class __builtin__.list
__hash__Method in class __builtin__.list
__hash__Method in class __builtin__.object
__hash__Method in class __builtin__.type
__iadd__Method in class __builtin__.list
__imul__Method in class __builtin__.list
__init__Method in class __builtin__.list
__init__Method in class __builtin__.object
__init__Method in class exceptions.Exception
__init__Method in class psycopg2._psycopg.ISQLQuote
__init__Method in class psycopg2._psycopg.connection
__init__Method in class psycopg2._psycopg.cursor
__init__Method in class psycopg2.extras.DictRow
__init__Method in class psycopg2.extras.SQL_IN
__init__Method in class psycopg2.pool.AbstractConnectionPool
__init__Method in class psycopg2.pool.PersistentConnectionPool
__init__Method in class psycopg2.pool.ThreadedConnectionPool
__init__Method in class psycopg2.tz.FixedOffsetTimezone
__itemsize__member_descriptor in class __builtin__.type
__iter__Method in class __builtin__.list
__iter__Method in class psycopg2._psycopg.cursor
__le__Method in class __builtin__.list
__len__Method in class __builtin__.list
__lt__Method in class __builtin__.list
__mro__member_descriptor in class __builtin__.type
__mul__Method in class __builtin__.list
__name__Variable in class __builtin__.type
__ne__Method in class __builtin__.list
__new__Method in class __builtin__.list
__new__Method in class __builtin__.object
__new__Method in class __builtin__.type
__new__Method in class datetime.tzinfo
__new__Method in class psycopg2._psycopg.ISQLQuote
__new__Method in class psycopg2._psycopg.connection
__new__Method in class psycopg2._psycopg.cursor
__reduce__Method in class __builtin__.object
__reduce__Method in class datetime.tzinfo
__reduce_ex__Method in class __builtin__.object
__repr__Method in class __builtin__.list
__repr__Method in class __builtin__.object
__repr__Method in class __builtin__.type
__repr__Method in class psycopg2._psycopg.connection
__repr__Method in class psycopg2._psycopg.cursor
__rmul__Method in class __builtin__.list
__setattr__Method in class __builtin__.object
__setattr__Method in class __builtin__.type
__setitem__Method in class __builtin__.list
__setslice__Method in class __builtin__.list
__str__Method in class __builtin__.object
__str__Method in class exceptions.Exception
__str__Method in class psycopg2._psycopg.connection
__str__Method in class psycopg2._psycopg.cursor
__subclasses__Method in class __builtin__.type
__version__Variable in module psycopg2._psycopg
__weakrefoffset__member_descriptor in class __builtin__.type
_build_indexMethod in class psycopg2.extras.DictCursor
_C_APIVariable in module psycopg2._psycopg
_closeallMethod in class psycopg2.pool.AbstractConnectionPool
_connectMethod in class psycopg2.pool.AbstractConnectionPool
__query_executedVariable in class psycopg2.extras.DictCursor
_getconnMethod in class psycopg2.pool.AbstractConnectionPool
_getkeyMethod in class psycopg2.pool.AbstractConnectionPool
_isdstMethod in class psycopg2.tz.LocalTimezone
_nameVariable in class psycopg2.tz.FixedOffsetTimezone
_offsetVariable in class psycopg2.tz.FixedOffsetTimezone
_psycopgModule in package psycopg2
_putconnMethod in class psycopg2.pool.AbstractConnectionPool
_wrappedmember_descriptor in class psycopg2._psycopg.ISQLQuote
AbstractConnectionPoolClass in module psycopg2.pool
adaptFunction in module psycopg2.extensions
adaptersVariable in module psycopg2._psycopg
apilevelVariable in module psycopg2._psycopg
appendMethod in class __builtin__.list
arraysizemember_descriptor in class psycopg2._psycopg.cursor
AsIsFunction in module psycopg2.extensions
autocommitMethod in class psycopg2.psycopg1.connection
BinaryFunction in package psycopg2
BINARYVariable in module psycopg2._psycopg
binary_typesVariable in module psycopg2._psycopg
binary_typesmember_descriptor in class psycopg2._psycopg.cursor
BINARYARRAYVariable in module psycopg2._psycopg
BOOLEANVariable in module psycopg2._psycopg
BooleanFunction in module psycopg2.extensions
BOOLEANARRAYVariable in module psycopg2._psycopg
callprocMethod in class psycopg2._psycopg.cursor
callprocMethod in class psycopg2.extras.DictCursor
closeMethod in class psycopg2._psycopg.connection
closeMethod in class psycopg2._psycopg.cursor
closeallMethod in class psycopg2.pool.PersistentConnectionPool
closeallMethod in class psycopg2.pool.ThreadedConnectionPool
closedmember_descriptor in class psycopg2._psycopg.connection
commitMethod in class psycopg2._psycopg.connection
connectFunction in package psycopg2
connectFunction in module psycopg2.psycopg1
connectionClass in module psycopg2._psycopg
connectionmember_descriptor in class psycopg2._psycopg.cursor
connectionClass in module psycopg2.psycopg1
copy_fromMethod in class psycopg2._psycopg.cursor
copy_toMethod in class psycopg2._psycopg.cursor
countMethod in class __builtin__.list
cursorMethod in class psycopg2._psycopg.connection
cursorClass in module psycopg2._psycopg
cursorMethod in class psycopg2.extras.DictConnection
cursorMethod in class psycopg2.psycopg1.connection
cursorClass in module psycopg2.psycopg1
DatabaseErrorClass in package psycopg2
DatabaseErrormember_descriptor in class psycopg2._psycopg.connection
DataErrorClass in package psycopg2
DataErrormember_descriptor in class psycopg2._psycopg.connection
DateFunction in package psycopg2
DATEVariable in module psycopg2._psycopg
DATEARRAYVariable in module psycopg2._psycopg
DateFromPyFunction in module psycopg2.extensions
DateFromTicksFunction in package psycopg2
DATETIMEVariable in module psycopg2._psycopg
DATETIMEARRAYVariable in module psycopg2._psycopg
dbgFunction in module psycopg2.pool
DECIMALVariable in module psycopg2._psycopg
DECIMALARRAYVariable in module psycopg2._psycopg
descriptionmember_descriptor in class psycopg2._psycopg.cursor
DictConnectionClass in module psycopg2.extras
DictCursorClass in module psycopg2.extras
dictfetchallMethod in class psycopg2.psycopg1.cursor
dictfetchmanyMethod in class psycopg2.psycopg1.cursor
dictfetchoneMethod in class psycopg2.psycopg1.cursor
DictRowClass in module psycopg2.extras
dsnmember_descriptor in class psycopg2._psycopg.connection
dstMethod in class datetime.tzinfo
dstMethod in class psycopg2.tz.FixedOffsetTimezone
dstMethod in class psycopg2.tz.LocalTimezone
DSTDIFFVariable in module psycopg2.tz
encodingmember_descriptor in class psycopg2._psycopg.connection
encodingsVariable in module psycopg2._psycopg
ErrorClass in package psycopg2
Errormember_descriptor in class psycopg2._psycopg.connection
ExceptionClass in module exceptions
executeMethod in class psycopg2._psycopg.cursor
executeMethod in class psycopg2.extras.DictCursor
executemanyMethod in class psycopg2._psycopg.cursor
extendMethod in class __builtin__.list
extensionsModule in package psycopg2
extrasModule in package psycopg2
fetchallMethod in class psycopg2._psycopg.cursor
fetchallMethod in class psycopg2.extras.DictCursor
fetchmanyMethod in class psycopg2._psycopg.cursor
fetchmanyMethod in class psycopg2.extras.DictCursor
fetchoneMethod in class psycopg2._psycopg.cursor
fetchoneMethod in class psycopg2.extras.DictCursor
filenoMethod in class psycopg2._psycopg.cursor
FixedOffsetTimezoneClass in module psycopg2.tz
FLOATVariable in module psycopg2._psycopg
FLOATARRAYVariable in module psycopg2._psycopg
fromutcMethod in class datetime.tzinfo
getMethod in class psycopg2.extras.DictRow
getbinaryMethod in class psycopg2._psycopg.ISQLQuote
getbufferMethod in class psycopg2._psycopg.ISQLQuote
getconnMethod in class psycopg2.pool.PersistentConnectionPool
getconnMethod in class psycopg2.pool.ThreadedConnectionPool
getquotedMethod in class psycopg2._psycopg.ISQLQuote
getquotedMethod in class psycopg2.extras.SQL_IN
has_keyMethod in class psycopg2.extras.DictRow
indexMethod in class __builtin__.list
insertMethod in class __builtin__.list
INTEGERVariable in module psycopg2._psycopg
INTEGERARRAYVariable in module psycopg2._psycopg
IntegrityErrorClass in package psycopg2
IntegrityErrormember_descriptor in class psycopg2._psycopg.connection
InterfaceErrorClass in package psycopg2
InterfaceErrormember_descriptor in class psycopg2._psycopg.connection
InternalErrorClass in package psycopg2
InternalErrormember_descriptor in class psycopg2._psycopg.connection
INTERVALVariable in module psycopg2._psycopg
INTERVALARRAYVariable in module psycopg2._psycopg
IntervalFromPyFunction in module psycopg2.extensions
isolation_levelmember_descriptor in class psycopg2._psycopg.connection
ISOLATION_LEVEL_AUTOCOMMITVariable in module psycopg2.extensions
ISOLATION_LEVEL_READ_COMMITTEDVariable in module psycopg2.extensions
ISOLATION_LEVEL_READ_UNCOMMITTEDVariable in module psycopg2.extensions
ISOLATION_LEVEL_REPEATABLE_READVariable in module psycopg2.extensions
ISOLATION_LEVEL_SERIALIZABLEVariable in module psycopg2.extensions
ISQLQuoteClass in module psycopg2._psycopg
isreadyMethod in class psycopg2._psycopg.cursor
itemsMethod in class psycopg2.extras.DictRow
keysMethod in class psycopg2.extras.DictRow
lastrowidmember_descriptor in class psycopg2._psycopg.cursor
listClass in module __builtin__
ListFunction in module psycopg2._psycopg
LOCALVariable in module psycopg2.tz
LocalTimezoneClass in module psycopg2.tz
LONGINTEGERVariable in module psycopg2._psycopg
LONGINTEGERARRAYVariable in module psycopg2._psycopg
mogrifyMethod in class psycopg2._psycopg.cursor
mroMethod in class __builtin__.type
namemember_descriptor in class psycopg2._psycopg.cursor
new_typeFunction in module psycopg2.extensions
nextMethod in class psycopg2._psycopg.cursor
nextsetMethod in class psycopg2._psycopg.cursor
noticesmember_descriptor in class psycopg2._psycopg.connection
notifiesmember_descriptor in class psycopg2._psycopg.connection
NotSupportedErrorClass in package psycopg2
NotSupportedErrormember_descriptor in class psycopg2._psycopg.connection
NUMBERVariable in module psycopg2._psycopg
objectClass in module __builtin__
OperationalErrorClass in package psycopg2
OperationalErrormember_descriptor in class psycopg2._psycopg.connection
paramstyleVariable in module psycopg2._psycopg
PersistentConnectionPoolClass in module psycopg2.pool
poolModule in package psycopg2
PoolErrorClass in module psycopg2.pool
popMethod in class __builtin__.list
ProgrammingErrorClass in package psycopg2
ProgrammingErrormember_descriptor in class psycopg2._psycopg.connection
psycopg1Module in package psycopg2
psycopg2Package
putconnMethod in class psycopg2.pool.PersistentConnectionPool
putconnMethod in class psycopg2.pool.ThreadedConnectionPool
PYDATEVariable in module psycopg2._psycopg
PYDATETIMEVariable in module psycopg2._psycopg
PYINTERVALVariable in module psycopg2._psycopg
PYTIMEVariable in module psycopg2._psycopg
querymember_descriptor in class psycopg2._psycopg.cursor
QuotedStringFunction in module psycopg2.extensions
register_adapterFunction in module psycopg2.extensions
register_typeFunction in module psycopg2.extensions
removeMethod in class __builtin__.list
reverseMethod in class __builtin__.list
rollbackMethod in class psycopg2._psycopg.connection
row_factorymember_descriptor in class psycopg2._psycopg.cursor
rowcountmember_descriptor in class psycopg2._psycopg.cursor
ROWIDVariable in module psycopg2._psycopg
ROWIDARRAYVariable in module psycopg2._psycopg
rownumbermember_descriptor in class psycopg2._psycopg.cursor
scrollMethod in class psycopg2._psycopg.cursor
set_client_encodingMethod in class psycopg2._psycopg.connection
set_isolation_levelMethod in class psycopg2._psycopg.connection
setinputsizesMethod in class psycopg2._psycopg.cursor
setoutputsizeMethod in class psycopg2._psycopg.cursor
SimpleConnectionPoolClass in module psycopg2.pool
sortMethod in class __builtin__.list
SQL_INClass in module psycopg2.extras
StandardErrorClass in module exceptions
statusmessagemember_descriptor in class psycopg2._psycopg.cursor
STDOFFSETVariable in module psycopg2.tz
STRINGVariable in module psycopg2._psycopg
string_typesmember_descriptor in class psycopg2._psycopg.cursor
string_typesVariable in module psycopg2._psycopg
STRINGARRAYVariable in module psycopg2._psycopg
ThreadedConnectionPoolClass in module psycopg2.pool
threadsafetyVariable in module psycopg2._psycopg
TimeFunction in package psycopg2
TIMEVariable in module psycopg2._psycopg
TIMEARRAYVariable in module psycopg2._psycopg
TimeFromPyFunction in module psycopg2.extensions
TimeFromTicksFunction in package psycopg2
TimestampFunction in package psycopg2
TimestampFromPyFunction in module psycopg2.extensions
TimestampFromTicksFunction in package psycopg2
typeClass in module __builtin__
typecastermember_descriptor in class psycopg2._psycopg.cursor
tzModule in package psycopg2
tzinfoClass in module datetime
tzinfo_factorymember_descriptor in class psycopg2._psycopg.cursor
tznameMethod in class datetime.tzinfo
tznameMethod in class psycopg2.tz.FixedOffsetTimezone
tznameMethod in class psycopg2.tz.LocalTimezone
UNICODEVariable in module psycopg2._psycopg
UNICODEARRAYVariable in module psycopg2._psycopg
utcoffsetMethod in class datetime.tzinfo
utcoffsetMethod in class psycopg2.tz.FixedOffsetTimezone
utcoffsetMethod in class psycopg2.tz.LocalTimezone
valuesMethod in class psycopg2.extras.DictRow
WarningClass in package psycopg2
Warningmember_descriptor in class psycopg2._psycopg.connection
ZEROVariable in module psycopg2.tz
+
+ + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2-module.html b/psycopg2/doc/api/private/psycopg2-module.html new file mode 100644 index 0000000..dd7e92d --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2-module.html @@ -0,0 +1,336 @@ + + + + + psycopg2 + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Package psycopg2

+ +

A Python driver for PostgreSQL

+

psycopg is a PostgreSQL database adapter for the Python programming +language. This is version 2, a complete rewrite of the original code to +provide new-style classes for connection and cursor objects and other sweet +candies. Like the original, psycopg 2 was written with the aim of being very +small and fast, and stable as a rock.

+

Homepage: http://initd.org/projects/psycopg2

+
+ + + + + + +
Submodules
    +
  • extensions: psycopg extensions to the DBAPI-2.0
  • +
  • extras: Miscellaneous goodies for psycopg2
  • +
  • pool: Connection pooling for psycopg2
  • +
  • psycopg1: psycopg 1.1.x compatibility module
  • +
  • tz: tzinfo implementations for psycopg2
  • +
  • _psycopg: psycopg PostgreSQL driver
  • +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Exceptions
+ DatabaseErrorError related to the database engine.
+ DataErrorError related to problems with the processed data.
+ ErrorBase class for error exceptions.
+ IntegrityErrorError related to database integrity.
+ InterfaceErrorError related to the database interface.
+ InternalErrorThe database encountered an internal error.
+ NotSupportedErrorA not supported datbase API was called.
+ OperationalErrorError related to database operation (disconnect, memory allocation etc).
+ ProgrammingErrorError related to database programming (SQL error, table not found etc).
+ WarningA database warning.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Function Summary
    Connections creation
extensions.connectionconnect(dsn, + ...) +
+Create a new database connection.
    Value objects constructors
new binary objectBinary(buffer) +
+Build an object capable to hold a bynary string value.
new dateDate(year, + month, + day) +
+Build an object holding a date value.
new dateDateFromTicks(ticks) +
+Build an object holding a date value from the given ticks value.
new timeTime(hour, + minutes, + seconds, + tzinfo) +
+Build an object holding a time value.
new timeTimeFromTicks(ticks) +
+Build an object holding a time value from the given ticks value.
new timestampTimestamp(year, + month, + day, + hour, + minutes, + seconds, + tzinfo) +
+Build an object holding a timestamp value.
new timestampTimestampFromTicks(ticks) +
+Build an object holding a timestamp value from the given ticks value.

+ + + + + + +
Function Details
+ + +
+

connect(dsn, + ...) +

+

Create a new database connection.

+

This function supports two different but equivalent sets of arguments. +A single data source name or dsn string can be used to specify the +connection parameters, as follows:

+
+psycopg2.connect("dbname=xxx user=xxx ...")
+
+

If dsn is not provided it is possible to pass the parameters as +keyword arguments; e.g.:

+
+psycopg2.connect(database='xxx', user='xxx', ...)
+
+

The full list of available parameters is:

+
    +
  • dbname -- database name (only in 'dsn')
  • +
  • database -- database name (only as keyword argument)
  • +
  • host -- host address (defaults to UNIX socket if not provided)
  • +
  • port -- port number (defaults to 5432 if not provided)
  • +
  • user -- user name used to authenticate
  • +
  • password -- password used to authenticate
  • +
  • sslmode -- SSL mode (see PostgreSQL documentation)
  • +
+

If the connection_factory keyword argument is not provided this +function always return an instance of the connection class. +Else the given sub-class of extensions.connection will be used to +instantiate the connection object.

+
+
Returns:
+
+New database connection
           + (type=extensions.connection) +
+
+
+
+ + +
+

Binary(buffer) +

+

Build an object capable to hold a bynary string value.

+
+
Returns:
+
+new binary object
+
+
+
+ + +
+

Date(year, + month, + day) +

+

Build an object holding a date value.

+
+
Returns:
+
+new date
+
+
+
+ + +
+

DateFromTicks(ticks) +

+

Build an object holding a date value from the given ticks value.

+

Ticks are the number of seconds since the epoch; see the documentation of the standard Python time module for details).

+
+
Returns:
+
+new date
+
+
+
+ + +
+

Time(hour, + minutes, + seconds, + tzinfo=None) +

+

Build an object holding a time value.

+
+
Returns:
+
+new time
+
+
+
+ + +
+

TimeFromTicks(ticks) +

+

Build an object holding a time value from the given ticks value.

+

Ticks are the number of seconds since the epoch; see the documentation of the standard Python time module for details).

+
+
Returns:
+
+new time
+
+
+
+ + +
+

Timestamp(year, + month, + day, + hour, + minutes, + seconds, + tzinfo=None) +

+

Build an object holding a timestamp value.

+
+
Returns:
+
+new timestamp
+
+
+
+ + +
+

TimestampFromTicks(ticks) +

+

Build an object holding a timestamp value from the given ticks value.

+

Ticks are the number of seconds since the epoch; see the documentation of the standard Python time module for details).

+
+
Returns:
+
+new timestamp
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.DataError-class.html b/psycopg2/doc/api/private/psycopg2.DataError-class.html new file mode 100644 index 0000000..5805400 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.DataError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.DataError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class DataError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class DataError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       DataError
+

+ +
+ +

Error related to problems with the processed data.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.DatabaseError-class.html b/psycopg2/doc/api/private/psycopg2.DatabaseError-class.html new file mode 100644 index 0000000..adc28d4 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.DatabaseError-class.html @@ -0,0 +1,110 @@ + + + + + psycopg2.DatabaseError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class DatabaseError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class DatabaseError

+ +
+Exception --+        
+            |        
+StandardError --+    
+                |    
+            Error --+
+                    |
+                   DatabaseError
+

+ +
Known Subclasses:
+
+ DataError, + IntegrityError, + InternalError, + NotSupportedError, + OperationalError, + ProgrammingError
+ +
+ +

Error related to the database engine.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.Error-class.html b/psycopg2/doc/api/private/psycopg2.Error-class.html new file mode 100644 index 0000000..33bff57 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.Error-class.html @@ -0,0 +1,105 @@ + + + + + psycopg2.Error + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class Error +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class Error

+ +
+Exception --+    
+            |    
+StandardError --+
+                |
+               Error
+

+ +
Known Subclasses:
+
+ DatabaseError, + InterfaceError, + PoolError
+ +
+ +

Base class for error exceptions.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.IntegrityError-class.html b/psycopg2/doc/api/private/psycopg2.IntegrityError-class.html new file mode 100644 index 0000000..c1804f6 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.IntegrityError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.IntegrityError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class IntegrityError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class IntegrityError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       IntegrityError
+

+ +
+ +

Error related to database integrity.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.InterfaceError-class.html b/psycopg2/doc/api/private/psycopg2.InterfaceError-class.html new file mode 100644 index 0000000..099ee90 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.InterfaceError-class.html @@ -0,0 +1,101 @@ + + + + + psycopg2.InterfaceError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class InterfaceError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class InterfaceError

+ +
+Exception --+        
+            |        
+StandardError --+    
+                |    
+            Error --+
+                    |
+                   InterfaceError
+

+ +
+ +

Error related to the database interface.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.InternalError-class.html b/psycopg2/doc/api/private/psycopg2.InternalError-class.html new file mode 100644 index 0000000..5390de5 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.InternalError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.InternalError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class InternalError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class InternalError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       InternalError
+

+ +
+ +

The database encountered an internal error.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.NotSupportedError-class.html b/psycopg2/doc/api/private/psycopg2.NotSupportedError-class.html new file mode 100644 index 0000000..c677f5b --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.NotSupportedError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.NotSupportedError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class NotSupportedError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class NotSupportedError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       NotSupportedError
+

+ +
+ +

A not supported datbase API was called.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.OperationalError-class.html b/psycopg2/doc/api/private/psycopg2.OperationalError-class.html new file mode 100644 index 0000000..6cca463 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.OperationalError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.OperationalError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class OperationalError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class OperationalError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       OperationalError
+

+ +
+ +

Error related to database operation (disconnect, memory allocation etc).

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.ProgrammingError-class.html b/psycopg2/doc/api/private/psycopg2.ProgrammingError-class.html new file mode 100644 index 0000000..9fcd4ef --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.ProgrammingError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.ProgrammingError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class ProgrammingError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class ProgrammingError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       ProgrammingError
+

+ +
+ +

Error related to database programming (SQL error, table not found etc).

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.Warning-class.html b/psycopg2/doc/api/private/psycopg2.Warning-class.html new file mode 100644 index 0000000..741c9a7 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.Warning-class.html @@ -0,0 +1,99 @@ + + + + + psycopg2.Warning + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class Warning +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class Warning

+ +
+Exception --+    
+            |    
+StandardError --+
+                |
+               Warning
+

+ +
+ +

A database warning.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2._psycopg-module.html b/psycopg2/doc/api/private/psycopg2._psycopg-module.html new file mode 100644 index 0000000..6e4cb25 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2._psycopg-module.html @@ -0,0 +1,1072 @@ + + + + + psycopg2._psycopg + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module _psycopg +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2._psycopg

+ +

psycopg PostgreSQL driver

+
+ + + + + + + + + + + +
Classes
+ connectionconnection(dsn, ...) -> new connection object
+ cursorA database cursor.
+ ISQLQuoteAbstract ISQLQuote protocol

+ + + + + + + + +
Function Summary
new quoted listList(list, + enc) +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Variable Summary
str__version__ = '2.0b7 (dt ext pq3)' +
PyCObject_C_API = <PyCObject object at 0x0076A320> +
dictadapters = {(<type 'bool'>, <type 'psycopg2._psycopg.ISQ... +
strapilevel = '2.0' +
typeBINARY = <psycopg2._psycopg.type object at 0x00847A00> +
dictbinary_types = {} +
typeBINARYARRAY = <psycopg2._psycopg.type object at 0x00847C... +
typeBOOLEAN = <psycopg2._psycopg.type object at 0x00847880> +
typeBOOLEANARRAY = <psycopg2._psycopg.type object at 0x00847... +
typeDATE = <psycopg2._psycopg.type object at 0x00847960> +
typeDATEARRAY = <psycopg2._psycopg.type object at 0x00847C20... +
typeDATETIME = <psycopg2._psycopg.type object at 0x008478C0> +
typeDATETIMEARRAY = <psycopg2._psycopg.type object at 0x0084... +
typeDECIMAL = <psycopg2._psycopg.type object at 0x008477A0> +
typeDECIMALARRAY = <psycopg2._psycopg.type object at 0x00847... +
dictencodings = {'UTF8': 'utf_8', 'LATIN-1': 'latin_1', 'SQL... +
typeFLOAT = <psycopg2._psycopg.type object at 0x00847740> +
typeFLOATARRAY = <psycopg2._psycopg.type object at 0x00847AE... +
typeINTEGER = <psycopg2._psycopg.type object at 0x00847700> +
typeINTEGERARRAY = <psycopg2._psycopg.type object at 0x00847... +
typeINTERVAL = <psycopg2._psycopg.type object at 0x008479A0> +
typeINTERVALARRAY = <psycopg2._psycopg.type object at 0x0084... +
typeLONGINTEGER = <psycopg2._psycopg.type object at 0x008476... +
typeLONGINTEGERARRAY = <psycopg2._psycopg.type object at 0x0... +
typeNUMBER = <psycopg2._psycopg.type object at 0x00847680> +
strparamstyle = 'pyformat' +
typePYDATE = <psycopg2._psycopg.type object at 0x00847DC0> +
typePYDATETIME = <psycopg2._psycopg.type object at 0x00847D2... +
typePYINTERVAL = <psycopg2._psycopg.type object at 0x00847DE... +
typePYTIME = <psycopg2._psycopg.type object at 0x00847D60> +
typeROWID = <psycopg2._psycopg.type object at 0x00847A60> +
typeROWIDARRAY = <psycopg2._psycopg.type object at 0x00847CC... +
typeSTRING = <psycopg2._psycopg.type object at 0x00847820> +
dictstring_types = {1028: <psycopg2._psycopg.type object at ... +
typeSTRINGARRAY = <psycopg2._psycopg.type object at 0x00847B... +
intthreadsafety = 2                                                                     
typeTIME = <psycopg2._psycopg.type object at 0x00847900> +
typeTIMEARRAY = <psycopg2._psycopg.type object at 0x00847BE0... +
typeUNICODE = <psycopg2._psycopg.type object at 0x008477E0> +
typeUNICODEARRAY = <psycopg2._psycopg.type object at 0x00847... +

+ + + + + + +
Function Details
+ + +
+

List(list, + enc) +

+
+
Returns:
+
+new quoted list
+
+
+
+
+ + + + + + +
Variable Details
+
+ +

__version__

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'2.0b7 (dt ext pq3)'                                                   
+
+
+
+
+
+ +

_C_API

+
+
+
+
+
Type:
+
+ PyCObject + +
+
Value:
+
+
+<PyCObject object at 0x0076A320>                                       
+
+
+
+
+
+ +

adapters

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{(<type 'datetime.timedelta'>, <type 'psycopg2._psycopg.ISQLQuote'>): \
+<built-in function IntervalFromPy>,
+ (<type 'datetime.date'>, <type 'psycopg2._psycopg.ISQLQuote'>): <buil\
+t-in function DateFromPy>,
+ (<type 'datetime.time'>, <type 'psycopg2._psycopg.ISQLQuote'>): <buil\
+t-in function TimeFromPy>,
+ (<type 'datetime.datetime'>, <type 'psycopg2._psycopg.ISQLQuote'>): <\
+built-in function TimestampFromPy>,
+...                                                                    
+
+
+
+
+
+ +

apilevel

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'2.0'                                                                  
+
+
+
+
+
+ +

BINARY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847A00>                          
+
+
+
+
+
+ +

binary_types

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{}                                                                     
+
+
+
+
+
+ +

BINARYARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847CA0>                          
+
+
+
+
+
+ +

BOOLEAN

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847880>                          
+
+
+
+
+
+ +

BOOLEANARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847BA0>                          
+
+
+
+
+
+ +

DATE

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847960>                          
+
+
+
+
+
+ +

DATEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847C20>                          
+
+
+
+
+
+ +

DATETIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x008478C0>                          
+
+
+
+
+
+ +

DATETIMEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847BC0>                          
+
+
+
+
+
+ +

DECIMAL

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x008477A0>                          
+
+
+
+
+
+ +

DECIMALARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847B20>                          
+
+
+
+
+
+ +

encodings

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{'LATIN-1': 'latin_1',
+ 'LATIN1': 'latin_1',
+ 'SQL_ASCII': 'ascii',
+ 'UNICODE': 'utf_8',
+ 'UTF8': 'utf_8'}                                                      
+
+
+
+
+
+ +

FLOAT

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847740>                          
+
+
+
+
+
+ +

FLOATARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847AE0>                          
+
+
+
+
+
+ +

INTEGER

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847700>                          
+
+
+
+
+
+ +

INTEGERARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847AC0>                          
+
+
+
+
+
+ +

INTERVAL

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x008479A0>                          
+
+
+
+
+
+ +

INTERVALARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847C60>                          
+
+
+
+
+
+ +

LONGINTEGER

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x008476C0>                          
+
+
+
+
+
+ +

LONGINTEGERARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847AA0>                          
+
+
+
+
+
+ +

NUMBER

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847680>                          
+
+
+
+
+
+ +

paramstyle

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'pyformat'                                                             
+
+
+
+
+
+ +

PYDATE

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847DC0>                          
+
+
+
+
+
+ +

PYDATETIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847D20>                          
+
+
+
+
+
+ +

PYINTERVAL

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847DE0>                          
+
+
+
+
+
+ +

PYTIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847D60>                          
+
+
+
+
+
+ +

ROWID

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847A60>                          
+
+
+
+
+
+ +

ROWIDARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847CC0>                          
+
+
+
+
+
+ +

STRING

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847820>                          
+
+
+
+
+
+ +

string_types

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{16: <psycopg2._psycopg.type object at 0x00847880>,
+ 17: <psycopg2._psycopg.type object at 0x00847A00>,
+ 18: <psycopg2._psycopg.type object at 0x00847820>,
+ 19: <psycopg2._psycopg.type object at 0x00847820>,
+ 20: <psycopg2._psycopg.type object at 0x008476C0>,
+ 21: <psycopg2._psycopg.type object at 0x00847700>,
+ 23: <psycopg2._psycopg.type object at 0x00847700>,
+ 25: <psycopg2._psycopg.type object at 0x00847820>,
+...                                                                    
+
+
+
+
+
+ +

STRINGARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847B60>                          
+
+
+
+
+
+ +

threadsafety

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+2                                                                     
+
+
+
+
+
+ +

TIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847900>                          
+
+
+
+
+
+ +

TIMEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847BE0>                          
+
+
+
+
+
+ +

UNICODE

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x008477E0>                          
+
+
+
+
+
+ +

UNICODEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00847B40>                          
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2._psycopg.ISQLQuote-class.html b/psycopg2/doc/api/private/psycopg2._psycopg.ISQLQuote-class.html new file mode 100644 index 0000000..3a7db8e --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2._psycopg.ISQLQuote-class.html @@ -0,0 +1,221 @@ + + + + + psycopg2._psycopg.ISQLQuote + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module _psycopg :: + Class ISQLQuote +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type ISQLQuote

+ +
+object --+
+         |
+        ISQLQuote
+

+ +
+ +

Abstract ISQLQuote protocol

+

An object conform to this protocol should expose a getquoted() method +returning the SQL representation of the object.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 getbinary() +
+return SQL-quoted binary representation of this object
 getbuffer() +
+return this object
 getquoted() +
+return SQL-quoted representation of this object
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + + +
Property Summary
 _wrapped

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

getbinary() +

+

return SQL-quoted binary representation of this object

+
+
+
+ + +
+

getbuffer() +

+

return this object

+
+
+
+ + +
+

getquoted() +

+

return SQL-quoted representation of this object

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2._psycopg.connection-class.html b/psycopg2/doc/api/private/psycopg2._psycopg.connection-class.html new file mode 100644 index 0000000..0b6076e --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2._psycopg.connection-class.html @@ -0,0 +1,405 @@ + + + + + psycopg2._psycopg.connection + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module _psycopg :: + Class connection +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type connection

+ +
+object --+
+         |
+        connection
+

+ +
Known Subclasses:
+
+ connection, + DictConnection
+ +
+ +

connection(dsn, ...) -> new connection object

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __str__(x) +
+Return str(x)...
 close() +
+Close the connection.
 commit() +
+Commit all changes to database.
extensions.cursorcursor(cursor_factory) +
+new cursor
 rollback() +
+Roll back all changes done to database.
 set_client_encoding(encoding) +
+Set client encoding to encoding.
 set_isolation_level(level) +
+Switch isolation level to level.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + + + + + + + + + + + + + + + + + + + +
Property Summary
 closed: True if the connection is closed.
 dsn: The current connection string.
 encoding: The current client encoding.
 isolation_level: The current isolation level.
 notices
 notifies
    DBAPI-2.0 errors
 Error: Base class for error exceptions.
 Warning: A database warning.
 InterfaceError: Error related to the database interface.
 DatabaseError: Error related to the database engine.
 InternalError: The database encountered an internal error.
 OperationalError: Error related to database operation (disconnect, memory allocation etc).
 ProgrammingError: Error related to database programming (SQL error, table not found etc).
 IntegrityError: Error related to database integrity.
 DataError: Error related to problems with the processed data.
 NotSupportedError: A not supported datbase API was called.

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
Overrides:
+
__builtin__.object.__repr__
+
+
+
+ + +
+

__str__(x) +
(Informal representation operator) +

+
+
Returns:
+
+
+str(x)
+
+
+
+
Overrides:
+
__builtin__.object.__str__
+
+
+
+ + +
+

close() +

+

Close the connection.

+
+
+
+ + +
+

commit() +

+

Commit all changes to database.

+
+
+
+ + +
+

cursor(cursor_factory=extensions.cursor) +

+

new cursor

+

Return a new cursor.

+

The cursor_factory argument can be used to +create non-standard cursors by passing a class different from the +default. Note that the new class should be a sub-class of +extensions.cursor.

+
+
Returns:
+
+extensions.cursor
+
+
+
+ + +
+

rollback() +

+

Roll back all changes done to database.

+
+
+
+ + +
+

set_client_encoding(encoding) +

+

Set client encoding to encoding.

+
+
+
+ + +
+

set_isolation_level(level) +

+

Switch isolation level to level.

+
+
+
+
+ + + + + + +
Property Details
+
+ + +

Error

+

Base class for error exceptions.

+
+ + +

Warning

+

A database warning.

+
+ + +

InterfaceError

+

Error related to the database interface.

+
+ + +

DatabaseError

+

Error related to the database engine.

+
+ + +

InternalError

+

The database encountered an internal error.

+
+ + +

OperationalError

+

Error related to database operation (disconnect, memory allocation etc).

+
+ + +

ProgrammingError

+

Error related to database programming (SQL error, table not found etc).

+
+ + +

IntegrityError

+

Error related to database integrity.

+
+ + +

DataError

+

Error related to problems with the processed data.

+
+ + +

NotSupportedError

+

A not supported datbase API was called.

+
+ + +

closed

+

True if the connection is closed.

+
+ + +

dsn

+

The current connection string.

+
+ + +

encoding

+

The current client encoding.

+
+ + +

isolation_level

+

The current isolation level.

+

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2._psycopg.cursor-class.html b/psycopg2/doc/api/private/psycopg2._psycopg.cursor-class.html new file mode 100644 index 0000000..d3947aa --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2._psycopg.cursor-class.html @@ -0,0 +1,599 @@ + + + + + psycopg2._psycopg.cursor + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module _psycopg :: + Class cursor +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type cursor

+ +
+object --+
+         |
+        cursor
+

+ +
Known Subclasses:
+
+ cursor, + DictCursor
+ +
+ +

A database cursor.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __iter__(x) +
+Return iter(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __str__(x) +
+Return str(x)...
 callproc(procname, + parameters, + async) +
+Execute stored procedure.
 close() +
+Close the cursor.
 copy_from(file, + table, + sep, + null) +
+Copy table from file.
 copy_to(file, + table, + sep, + null) +
+Copy table to file.
 execute(query, + vars, + async) +
+Execute query with bound vars.
 executemany(query, + vars_list, + async) +
+Execute many queries with bound vars.
list of tuplefetchall() +
+Return all the remaining rows of a query result set.
list of tuplefetchmany(size) +
+Return the next size rows of a query result set in the form of a list +of tuples (by default) or using the sequence factory previously set in +the row_factory attribute.
tuple or Nonefetchone() +
+Return the next row of a query result set in the form of a tuple (by +default) or using the sequence factory previously set in the +row_factory attribute.
intfileno() +
+Return file descriptor associated to database connection.
boolisready() +
+Return True if data is ready after an async query.
strmogrify(query, + vars) +
+Return query after vars binding.
 next(x) +
+Return the next value, or raise StopIteration...
 nextset() +
+Skip to next set of data.
 scroll(value, + mode) +
+Scroll to new position according to mode.
 setinputsizes(sizes) +
+Set memory areas before execute.
 setoutputsize(size, + column) +
+Set column buffer size.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + + + + + + + + + + + + + + + +
Property Summary
 arraysize: Number of records fetchmany() must fetch if not explicitely specified.
 binary_types
 connection: The connection where the cursor comes from.
 description: Cursor description as defined in DBAPI-2.0.
 lastrowid: The oid of the last row inserted by the cursor.
 name
 query: The last query text sent to the backend.
 row_factory
 rowcount: Number of rows read from the backend in the last command.
 rownumber: The current row position.
 statusmessage: The return message of the last command.
 string_types
 typecaster
 tzinfo_factory

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__iter__(x) +

+
+
Returns:
+
+
+iter(x)
+
+
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
Overrides:
+
__builtin__.object.__repr__
+
+
+
+ + +
+

__str__(x) +
(Informal representation operator) +

+
+
Returns:
+
+
+str(x)
+
+
+
+
Overrides:
+
__builtin__.object.__str__
+
+
+
+ + +
+

callproc(procname, + parameters=None, + async=0) +

+

Execute stored procedure.

+
+
+
+ + +
+

close() +

+

Close the cursor.

+
+
+
+ + +
+

copy_from(file, + table, + sep='\t', + null='\N') +

+

Copy table from file.

+
+
+
+ + +
+

copy_to(file, + table, + sep='\t', + null='\N') +

+

Copy table to file.

+
+
+
+ + +
+

execute(query, + vars=None, + async=0) +

+

Execute query with bound vars.

+
+
+
+ + +
+

executemany(query, + vars_list=(), + async=0) +

+

Execute many queries with bound vars.

+
+
+
+ + +
+

fetchall() +

+

Return all the remaining rows of a query result set.

+

Rows are returned in the form of a list of tuples (by default) or using +the sequence factory previously set in the row_factory attribute. +Return None when no more data is available.

+
+
Returns:
+
+list of tuple
+
+
+
+ + +
+

fetchmany(size=self.arraysize) +

+

Return the next size rows of a query result set in the form of a list +of tuples (by default) or using the sequence factory previously set in +the row_factory attribute. Return None when no more data is available.

+
+
Returns:
+
+list of tuple
+
+
+
+ + +
+

fetchone() +

+

Return the next row of a query result set in the form of a tuple (by +default) or using the sequence factory previously set in the +row_factory attribute. Return None when no more data is available.

+
+
Returns:
+
+tuple or None
+
+
+
+ + +
+

fileno() +

+

Return file descriptor associated to database connection.

+
+
Returns:
+
+int
+
+
+
+ + +
+

isready() +

+

Return True if data is ready after an async query.

+
+
Returns:
+
+bool
+
+
+
+ + +
+

mogrify(query, + vars=None) +

+

Return query after vars binding.

+
+
Returns:
+
+str
+
+
+
+ + +
+

next(x) +

+
+
Returns:
+
+
+the next value, or raise StopIteration
+
+
+
+
+
+ + +
+

nextset() +

+

Skip to next set of data.

+

This method is not supported (PostgreSQL does not have multiple data +sets) and will raise a NotSupportedError exception.

+
+
+
+ + +
+

scroll(value, + mode='relative') +

+

Scroll to new position according to mode.

+
+
+
+ + +
+

setinputsizes(sizes) +

+

Set memory areas before execute.

+

This method currently does nothing but it is safe to call it.

+
+
+
+ + +
+

setoutputsize(size, + column=None) +

+

Set column buffer size.

+

This method currently does nothing but it is safe to call it.

+
+
+
+
+ + + + + + +
Property Details
+
+ + +

arraysize

+

Number of records fetchmany() must fetch if not explicitely specified.

+
+ + +

connection

+

The connection where the cursor comes from.

+
+ + +

description

+

Cursor description as defined in DBAPI-2.0.

+
+ + +

lastrowid

+

The oid of the last row inserted by the cursor.

+
+ + +

query

+

The last query text sent to the backend.

+
+ + +

rowcount

+

Number of rows read from the backend in the last command.

+
+ + +

rownumber

+

The current row position.

+
+ + +

statusmessage

+

The return message of the last command.

+

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.extensions-module.html b/psycopg2/doc/api/private/psycopg2.extensions-module.html new file mode 100644 index 0000000..a78fd66 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.extensions-module.html @@ -0,0 +1,418 @@ + + + + + psycopg2.extensions + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extensions +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.extensions

+ +

psycopg extensions to the DBAPI-2.0

+

This module holds all the extensions to the DBAPI-2.0 provided by psycopg.

+
    +
  • connection -- the new-type inheritable connection class
  • +
  • cursor -- the new-type inheritable cursor class
  • +
  • adapt() -- exposes the PEP-246 compatible adapting mechanism used +by psycopg to adapt Python types to PostgreSQL ones
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function Summary
objectadapt(obj, + protocol, + alternate) +
+adapt obj to given protocol
new AsIs wrapper objectAsIs(obj) +
new boolean valueBoolean(obj) +
new wrapperDateFromPy(datetime.date) +
new wrapperIntervalFromPy(datetime.timedelta) +
new type objectnew_type(oids, + name, + adapter) +
+Create a new binding object.
new quoted stringQuotedString(str, + enc) +
 register_adapter(typ, + callable) +
+Register 'callable' as an ISQLQuote adapter for type 'typ'.
Noneregister_type(obj) +
+register obj with psycopg type system
new wrapperTimeFromPy(datetime.time) +
new wrapperTimestampFromPy(datetime.datetime) +

+ + + + + + + + + + + + + + + + +
Variable Summary
intISOLATION_LEVEL_AUTOCOMMIT = 0                                                                     
intISOLATION_LEVEL_READ_COMMITTED = 1                                                                     
intISOLATION_LEVEL_READ_UNCOMMITTED = 1                                                                     
intISOLATION_LEVEL_REPEATABLE_READ = 2                                                                     
intISOLATION_LEVEL_SERIALIZABLE = 2                                                                     

+ + + + + + +
Function Details
+ + +
+

adapt(obj, + protocol, + alternate) +

+

adapt obj to given protocol

+
+
Returns:
+
+object
+
+
+
+ + +
+

AsIs(obj) +

+
+
Returns:
+
+new AsIs wrapper object
+
+
+
+ + +
+

Boolean(obj) +

+
+
Returns:
+
+new boolean value
+
+
+
+ + +
+

DateFromPy(datetime.date) +

+
+
Returns:
+
+new wrapper
+
+
+
+ + +
+

IntervalFromPy(datetime.timedelta) +

+
+
Returns:
+
+new wrapper
+
+
+
+ + +
+

new_type(oids, + name, + adapter) +

+

Create a new binding object. The object can be used with the +register_type() function to bind PostgreSQL objects to python objects.

+
+
Parameters:
+
oids - + Tuple of oid of the PostgreSQL types to convert. +
+
name - + Name for the new type +
+
adapter - + Callable to perform type conversion. +It must have the signature fun(value, cur) where value is +the string representation returned by PostgreSQL (None if NULL) +and cur is the cursor from which data are read. +
+
+
Returns:
+
+new type object
+
+
+
+ + +
+

QuotedString(str, + enc) +

+
+
Returns:
+
+new quoted string
+
+
+
+ + +
+

register_adapter(typ, + callable) +

+

Register 'callable' as an ISQLQuote adapter for type 'typ'.

+
+
+
+ + +
+

register_type(obj) +

+

register obj with psycopg type system

+
+
Parameters:
+
obj - + A type adapter created by new_type() +
+
+
Returns:
+
+None
+
+
+
+ + +
+

TimeFromPy(datetime.time) +

+
+
Returns:
+
+new wrapper
+
+
+
+ + +
+

TimestampFromPy(datetime.datetime) +

+
+
Returns:
+
+new wrapper
+
+
+
+
+ + + + + + +
Variable Details
+
+ +

ISOLATION_LEVEL_AUTOCOMMIT

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+0                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_READ_COMMITTED

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+1                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_READ_UNCOMMITTED

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+1                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_REPEATABLE_READ

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+2                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_SERIALIZABLE

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+2                                                                     
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.extras-module.html b/psycopg2/doc/api/private/psycopg2.extras-module.html new file mode 100644 index 0000000..463fc22 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.extras-module.html @@ -0,0 +1,91 @@ + + + + + psycopg2.extras + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.extras

+ +

Miscellaneous goodies for psycopg2

+

This module is a generic place used to hold little helper functions +and classes untill a better place in the distribution is found.

+
+ + + + + + + + + + + + + +
Classes
+ DictConnectionA connection that uses DictCursor automatically.
+ DictCursorA cursor that keeps a list of column name -> index mappings.
+ DictRowA row object that allow by-colun-name access to data.
+ SQL_INAdapt any iterable to an SQL quotable object.

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.extras.DictConnection-class.html b/psycopg2/doc/api/private/psycopg2.extras.DictConnection-class.html new file mode 100644 index 0000000..73989b5 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.extras.DictConnection-class.html @@ -0,0 +1,202 @@ + + + + + psycopg2.extras.DictConnection + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class DictConnection +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type DictConnection

+ +
+object --+    
+         |    
+connection --+
+             |
+            DictConnection
+

+ +
+ +

A connection that uses DictCursor automatically.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 cursor(self) +
    Inherited from connection
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __str__(x) +
+Return str(x)...
 close() +
+Close the connection.
 commit() +
+Commit all changes to database.
 rollback() +
+Roll back all changes done to database.
 set_client_encoding(encoding) +
+Set client encoding to encoding.
 set_isolation_level(level) +
+Switch isolation level to level.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + + + + + + + + + + + + + + + + + + + +
Property Summary
    Inherited from connection
 closed: True if the connection is closed.
 DatabaseError: Error related to the database engine.
 DataError: Error related to problems with the processed data.
 dsn: The current connection string.
 encoding: The current client encoding.
 Error: Base class for error exceptions.
 IntegrityError: Error related to database integrity.
 InterfaceError: Error related to the database interface.
 InternalError: The database encountered an internal error.
 isolation_level: The current isolation level.
 notices
 notifies
 NotSupportedError: A not supported datbase API was called.
 OperationalError: Error related to database operation (disconnect, memory allocation etc).
 ProgrammingError: Error related to database programming (SQL error, table not found etc).
 Warning: A database warning.

+ + + + + + +
Method Details
+ + +
+

cursor(self) +

+
+
Overrides:
+
psycopg2._psycopg.connection.cursor
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.extras.DictCursor-class.html b/psycopg2/doc/api/private/psycopg2.extras.DictCursor-class.html new file mode 100644 index 0000000..80a05c9 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.extras.DictCursor-class.html @@ -0,0 +1,359 @@ + + + + + psycopg2.extras.DictCursor + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class DictCursor +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type DictCursor

+ +
+object --+    
+         |    
+    cursor --+
+             |
+            DictCursor
+

+ +
+ +

A cursor that keeps a list of column name -> index mappings.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 callproc(self, + procname, + vars) +
 execute(self, + query, + vars, + async) +
 fetchall(self) +
 fetchmany(self, + size) +
 fetchone(self) +
 _build_index(self) +
    Inherited from cursor
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __iter__(x) +
+Return iter(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __str__(x) +
+Return str(x)...
 close() +
+Close the cursor.
 copy_from(file, + table, + sep, + null) +
+Copy table from file.
 copy_to(file, + table, + sep, + null) +
+Copy table to file.
 executemany(query, + vars_list, + async) +
+Execute many queries with bound vars.
intfileno() +
+Return file descriptor associated to database connection.
boolisready() +
+Return True if data is ready after an async query.
strmogrify(query, + vars) +
+Return query after vars binding.
 next(x) +
+Return the next value, or raise StopIteration...
 nextset() +
+Skip to next set of data.
 scroll(value, + mode) +
+Scroll to new position according to mode.
 setinputsizes(sizes) +
+Set memory areas before execute.
 setoutputsize(size, + column) +
+Set column buffer size.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + + + + + + + + + + + + + + + + + +
Property Summary
    Inherited from cursor
 arraysize: Number of records fetchmany() must fetch if not explicitely specified.
 binary_types
 connection: The connection where the cursor comes from.
 description: Cursor description as defined in DBAPI-2.0.
 lastrowid: The oid of the last row inserted by the cursor.
 name
 query: The last query text sent to the backend.
 row_factory
 rowcount: Number of rows read from the backend in the last command.
 rownumber: The current row position.
 statusmessage: The return message of the last command.
 string_types
 typecaster
 tzinfo_factory

+ + + + + + + + +
Class Variable Summary
int_DictCursor__query_executed = 0                                                                     

+ + + + + + +
Method Details
+ + +
+

callproc(self, + procname, + vars=None) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.callproc
+
+
+
+ + +
+

execute(self, + query, + vars=None, + async=0) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.execute
+
+
+
+ + +
+

fetchall(self) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.fetchall
+
+
+
+ + +
+

fetchmany(self, + size=None) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.fetchmany
+
+
+
+ + +
+

fetchone(self) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.fetchone
+
+
+
+ + +
+

_build_index(self) +

+
+
+
+
+ + + + + + +
Class Variable Details
+
+ +

_DictCursor__query_executed

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+0                                                                     
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.extras.DictRow-class.html b/psycopg2/doc/api/private/psycopg2.extras.DictRow-class.html new file mode 100644 index 0000000..db74990 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.extras.DictRow-class.html @@ -0,0 +1,376 @@ + + + + + psycopg2.extras.DictRow + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class DictRow +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type DictRow

+ +
+object --+    
+         |    
+      list --+
+             |
+            DictRow
+

+ +
+ +

A row object that allow by-colun-name access to data.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + cursor) +
 __getitem__(self, + x) +
 get(self, + x, + default) +
 has_key(self, + x) +
 items(self) +
 keys(self) +
 values(self) +
    Inherited from list
 __add__(x, + y) +
+Return x+y...
 __contains__(x, + y) +
+Return y in x...
 __delitem__(x, + y) +
+Return del x[y]...
 __delslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __eq__(x, + y) +
+Return x==y...
 __ge__(x, + y) +
+Return x>=y...
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __getslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __gt__(x, + y) +
+Return x>y...
 __hash__(x) +
+Return hash(x)...
 __iadd__(x, + y) +
+Return x+=y...
 __imul__(x, + y) +
+Return x*=y...
 __iter__(x) +
+Return iter(x)...
 __le__(x, + y) +
+Return x<=y...
 __len__(x) +
+Return len(x)...
 __lt__(x, + y) +
+Return x<y...
 __mul__(x, + n) +
+Return x*n...
 __ne__(x, + y) +
+Return x!=y...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __rmul__(x, + n) +
+Return n*x...
 __setitem__(x, + i, + y) +
+Return x[i]=y...
 __setslice__(x, + i, + j, + y) +
+Use of negative indices is not supported.
 append(L, + object) +
+append object to end
 count(L, + value) +
+return number of occurrences of value
 extend(L, + iterable) +
+extend list by appending elements from the iterable
 index(...) +
+L.index(value, [start, [stop]]) -> integer -- return first index of value
 insert(L, + index, + object) +
+insert object before index
 pop(L, + index) +
+remove and return item at index (default last)
 remove(L, + value) +
+remove first occurrence of value
 reverse(L) +
+reverse IN PLACE
 sort(L, + cmpfunc) +
+stable sort IN PLACE; cmpfunc(x, y) -> -1, 0, 1
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + cursor) +
(Constructor) +

+
+
Overrides:
+
__builtin__.list.__init__
+
+
+
+ + +
+

__getitem__(self, + x) +
(Indexing operator) +

+
+
Overrides:
+
__builtin__.list.__getitem__
+
+
+
+ + +
+

get(self, + x, + default=None) +

+
+
+
+ + +
+

has_key(self, + x) +

+
+
+
+ + +
+

items(self) +

+
+
+
+ + +
+

keys(self) +

+
+
+
+ + +
+

values(self) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.extras.SQL_IN-class.html b/psycopg2/doc/api/private/psycopg2.extras.SQL_IN-class.html new file mode 100644 index 0000000..6b7009b --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.extras.SQL_IN-class.html @@ -0,0 +1,171 @@ + + + + + psycopg2.extras.SQL_IN + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class SQL_IN +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type SQL_IN

+ +
+object --+
+         |
+        SQL_IN
+

+ +
+ +

Adapt any iterable to an SQL quotable object.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + seq) +
 __str__(self) +
 getquoted(self) +
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + +
Method Details
+ + +
+

__init__(self, + seq) +
(Constructor) +

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__str__(self) +
(Informal representation operator) +

+
+
+
+ + +
+

getquoted(self) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.pool-module.html b/psycopg2/doc/api/private/psycopg2.pool-module.html new file mode 100644 index 0000000..64e53c1 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.pool-module.html @@ -0,0 +1,126 @@ + + + + + psycopg2.pool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.pool

+ +

Connection pooling for psycopg2

+

This module implements thread-safe (and not) connection pools.

+
+ + + + + + + + + + + + + +
Classes
+ AbstractConnectionPoolGeneric key-based pooling code.
+ PersistentConnectionPoolA pool that assigns persistent connections to different threads.
+ SimpleConnectionPoolA connection pool that can't be shared across different threads.
+ ThreadedConnectionPoolA connection pool that works with the threading module.

+ + + + + + + + +
Exceptions
+ PoolError 

+ + + + + + + + +
Function Summary
 dbg(*args) +

+ + + + + + +
Function Details
+ + +
+

dbg(*args) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.pool.AbstractConnectionPool-class.html b/psycopg2/doc/api/private/psycopg2.pool.AbstractConnectionPool-class.html new file mode 100644 index 0000000..be79964 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.pool.AbstractConnectionPool-class.html @@ -0,0 +1,247 @@ + + + + + psycopg2.pool.AbstractConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class AbstractConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type AbstractConnectionPool

+ +
+object --+
+         |
+        AbstractConnectionPool
+

+ +
Known Subclasses:
+
+ PersistentConnectionPool, + SimpleConnectionPool, + ThreadedConnectionPool
+ +
+ +

Generic key-based pooling code.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the connection pool.
 _closeall(self) +
+Close all connections.
 _connect(self, + key) +
+Create a new connection and assign it to 'key' if not None.
 _getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 _getkey(self) +
+Return a new unique key.
 _putconn(self, + conn, + key, + close) +
+Put away a connection.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + minconn, + maxconn, + *args, + **kwargs) +
(Constructor) +

+

Initialize the connection pool.

+

New 'minconn' connections are created immediately calling 'connfunc' +with given parameters. The connection pool will support a maximum of +about 'maxconn' connections.

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

_closeall(self) +

+

Close all connections.

+

Note that this can lead to some code fail badly when trying to use +an already closed connection. If you call .closeall() make sure +your code can deal with it.

+
+
+
+ + +
+

_connect(self, + key=None) +

+

Create a new connection and assign it to 'key' if not None.

+
+
+
+ + +
+

_getconn(self, + key=None) +

+

Get a free connection and assign it to 'key' if not None.

+
+
+
+ + +
+

_getkey(self) +

+

Return a new unique key.

+
+
+
+ + +
+

_putconn(self, + conn, + key=None, + close=False) +

+

Put away a connection.

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.pool.PersistentConnectionPool-class.html b/psycopg2/doc/api/private/psycopg2.pool.PersistentConnectionPool-class.html new file mode 100644 index 0000000..4656713 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.pool.PersistentConnectionPool-class.html @@ -0,0 +1,237 @@ + + + + + psycopg2.pool.PersistentConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class PersistentConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type PersistentConnectionPool

+ +
+            object --+    
+                     |    
+AbstractConnectionPool --+
+                         |
+                        PersistentConnectionPool
+

+ +
+ +

A pool that assigns persistent connections to different threads.

+

Note that this connection pool generates by itself the required keys +using the current thread id. This means that untill a thread put away +a connection it will always get the same connection object by successive +.getconn() calls. This also means that a thread can't use more than one +single connection from the pool.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the threading lock.
 closeall(self) +
+Close all connections (even the one currently in use.)
 getconn(self) +
+Generate thread id and return a connection.
 putconn(self, + conn, + close) +
+Put away an unused connection.
    Inherited from AbstractConnectionPool
 _closeall(self) +
+Close all connections.
 _connect(self, + key) +
+Create a new connection and assign it to 'key' if not None.
 _getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 _getkey(self) +
+Return a new unique key.
 _putconn(self, + conn, + key, + close) +
+Put away a connection.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + minconn, + maxconn, + *args, + **kwargs) +
(Constructor) +

+

Initialize the threading lock.

+
+
Overrides:
+
psycopg2.pool.AbstractConnectionPool.__init__
+
+
+
+ + +
+

closeall(self) +

+

Close all connections (even the one currently in use.)

+
+
+
+ + +
+

getconn(self) +

+

Generate thread id and return a connection.

+
+
+
+ + +
+

putconn(self, + conn=None, + close=False) +

+

Put away an unused connection.

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.pool.PoolError-class.html b/psycopg2/doc/api/private/psycopg2.pool.PoolError-class.html new file mode 100644 index 0000000..83a85cf --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.pool.PoolError-class.html @@ -0,0 +1,99 @@ + + + + + psycopg2.pool.PoolError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class PoolError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class PoolError

+ +
+Exception --+        
+            |        
+StandardError --+    
+                |    
+            Error --+
+                    |
+                   PoolError
+

+ +
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.pool.SimpleConnectionPool-class.html b/psycopg2/doc/api/private/psycopg2.pool.SimpleConnectionPool-class.html new file mode 100644 index 0000000..06c9bb6 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.pool.SimpleConnectionPool-class.html @@ -0,0 +1,222 @@ + + + + + psycopg2.pool.SimpleConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class SimpleConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type SimpleConnectionPool

+ +
+            object --+    
+                     |    
+AbstractConnectionPool --+
+                         |
+                        SimpleConnectionPool
+

+ +
+ +

A connection pool that can't be shared across different threads.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 closeall(self) +
+Close all connections.
 getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 putconn(self, + conn, + key, + close) +
+Put away a connection.
    Inherited from AbstractConnectionPool
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the connection pool.
 _closeall(self) +
+Close all connections.
 _connect(self, + key) +
+Create a new connection and assign it to 'key' if not None.
 _getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 _getkey(self) +
+Return a new unique key.
 _putconn(self, + conn, + key, + close) +
+Put away a connection.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

closeall(self) +

+

Close all connections.

+

Note that this can lead to some code fail badly when trying to use +an already closed connection. If you call .closeall() make sure +your code can deal with it.

+
+
+
+ + +
+

getconn(self, + key=None) +

+

Get a free connection and assign it to 'key' if not None.

+
+
+
+ + +
+

putconn(self, + conn, + key=None, + close=False) +

+

Put away a connection.

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.pool.ThreadedConnectionPool-class.html b/psycopg2/doc/api/private/psycopg2.pool.ThreadedConnectionPool-class.html new file mode 100644 index 0000000..1ad34cb --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.pool.ThreadedConnectionPool-class.html @@ -0,0 +1,236 @@ + + + + + psycopg2.pool.ThreadedConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class ThreadedConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type ThreadedConnectionPool

+ +
+            object --+    
+                     |    
+AbstractConnectionPool --+
+                         |
+                        ThreadedConnectionPool
+

+ +
+ +

A connection pool that works with the threading module.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the threading lock.
 closeall(self) +
+Close all connections (even the one currently in use.)
 getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 putconn(self, + conn, + key, + close) +
+Put away an unused connection.
    Inherited from AbstractConnectionPool
 _closeall(self) +
+Close all connections.
 _connect(self, + key) +
+Create a new connection and assign it to 'key' if not None.
 _getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 _getkey(self) +
+Return a new unique key.
 _putconn(self, + conn, + key, + close) +
+Put away a connection.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + minconn, + maxconn, + *args, + **kwargs) +
(Constructor) +

+

Initialize the threading lock.

+
+
Overrides:
+
psycopg2.pool.AbstractConnectionPool.__init__
+
+
+
+ + +
+

closeall(self) +

+

Close all connections (even the one currently in use.)

+
+
+
+ + +
+

getconn(self, + key=None) +

+

Get a free connection and assign it to 'key' if not None.

+
+
+
+ + +
+

putconn(self, + conn=None, + key=None, + close=False) +

+

Put away an unused connection.

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.psycopg1-module.html b/psycopg2/doc/api/private/psycopg2.psycopg1-module.html new file mode 100644 index 0000000..f535cb9 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.psycopg1-module.html @@ -0,0 +1,121 @@ + + + + + psycopg2.psycopg1 + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module psycopg1 +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.psycopg1

+ +

psycopg 1.1.x compatibility module

+

This module uses the new style connection and cursor types to build a psycopg +1.1.1.x compatibility layer. It should be considered a temporary hack to run +old code while porting to psycopg 2. Import it as follows:

+
+from psycopg2 import psycopg1 as psycopg
+
+
+ + + + + + + + + +
Classes
+ connectionpsycopg 1.1.x connection.
+ cursorpsycopg 1.1.x cursor.

+ + + + + + + + +
Function Summary
new psycopg 1.1.x compatible connection objectconnect(dsn, + ...) +

+ + + + + + +
Function Details
+ + +
+

connect(dsn, + ...) +

+
+
Returns:
+
+new psycopg 1.1.x compatible connection object
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.psycopg1.connection-class.html b/psycopg2/doc/api/private/psycopg2.psycopg1.connection-class.html new file mode 100644 index 0000000..6d52ff8 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.psycopg1.connection-class.html @@ -0,0 +1,221 @@ + + + + + psycopg2.psycopg1.connection + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module psycopg1 :: + Class connection +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type connection

+ +
+object --+    
+         |    
+connection --+
+             |
+            connection
+

+ +
+ +

psycopg 1.1.x connection.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
switch autocommit on (1) or off (0)autocommit(on_off) +
new psycopg 1.1.x compatible cursor objectcursor() +
    Inherited from connection
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __str__(x) +
+Return str(x)...
 close() +
+Close the connection.
 commit() +
+Commit all changes to database.
 rollback() +
+Roll back all changes done to database.
 set_client_encoding(encoding) +
+Set client encoding to encoding.
 set_isolation_level(level) +
+Switch isolation level to level.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + + + + + + + + + + + + + + + + + + + +
Property Summary
    Inherited from connection
 closed: True if the connection is closed.
 DatabaseError: Error related to the database engine.
 DataError: Error related to problems with the processed data.
 dsn: The current connection string.
 encoding: The current client encoding.
 Error: Base class for error exceptions.
 IntegrityError: Error related to database integrity.
 InterfaceError: Error related to the database interface.
 InternalError: The database encountered an internal error.
 isolation_level: The current isolation level.
 notices
 notifies
 NotSupportedError: A not supported datbase API was called.
 OperationalError: Error related to database operation (disconnect, memory allocation etc).
 ProgrammingError: Error related to database programming (SQL error, table not found etc).
 Warning: A database warning.

+ + + + + + +
Method Details
+ + +
+

autocommit(on_off=1) +

+
+
Returns:
+
+switch autocommit on (1) or off (0)
+
+
+
+ + +
+

cursor() +

+
+
Returns:
+
+new psycopg 1.1.x compatible cursor object
+
+
Overrides:
+
psycopg2._psycopg.connection.cursor
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.psycopg1.cursor-class.html b/psycopg2/doc/api/private/psycopg2.psycopg1.cursor-class.html new file mode 100644 index 0000000..17d22e0 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.psycopg1.cursor-class.html @@ -0,0 +1,308 @@ + + + + + psycopg2.psycopg1.cursor + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module psycopg1 :: + Class cursor +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type cursor

+ +
+object --+    
+         |    
+    cursor --+
+             |
+            cursor
+

+ +
+ +

psycopg 1.1.x cursor.

+

Note that this cursor implements the exact procedure used by psycopg 1 to +build dictionaries out of result rows. The DictCursor in the +psycopg.extras modules implements a much better and faster algorithm.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 dictfetchall(self) +
 dictfetchmany(self, + size) +
 dictfetchone(self) +
 __build_dict(self, + row) +
    Inherited from cursor
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __iter__(x) +
+Return iter(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __str__(x) +
+Return str(x)...
 callproc(procname, + parameters, + async) +
+Execute stored procedure.
 close() +
+Close the cursor.
 copy_from(file, + table, + sep, + null) +
+Copy table from file.
 copy_to(file, + table, + sep, + null) +
+Copy table to file.
 execute(query, + vars, + async) +
+Execute query with bound vars.
 executemany(query, + vars_list, + async) +
+Execute many queries with bound vars.
list of tuplefetchall() +
+Return all the remaining rows of a query result set.
list of tuplefetchmany(size) +
+Return the next size rows of a query result set in the form of a list +of tuples (by default) or using the sequence factory previously set in +the row_factory attribute.
tuple or Nonefetchone() +
+Return the next row of a query result set in the form of a tuple (by +default) or using the sequence factory previously set in the +row_factory attribute.
intfileno() +
+Return file descriptor associated to database connection.
boolisready() +
+Return True if data is ready after an async query.
strmogrify(query, + vars) +
+Return query after vars binding.
 next(x) +
+Return the next value, or raise StopIteration...
 nextset() +
+Skip to next set of data.
 scroll(value, + mode) +
+Scroll to new position according to mode.
 setinputsizes(sizes) +
+Set memory areas before execute.
 setoutputsize(size, + column) +
+Set column buffer size.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + + + + + + + + + + + + + + + + + +
Property Summary
    Inherited from cursor
 arraysize: Number of records fetchmany() must fetch if not explicitely specified.
 binary_types
 connection: The connection where the cursor comes from.
 description: Cursor description as defined in DBAPI-2.0.
 lastrowid: The oid of the last row inserted by the cursor.
 name
 query: The last query text sent to the backend.
 row_factory
 rowcount: Number of rows read from the backend in the last command.
 rownumber: The current row position.
 statusmessage: The return message of the last command.
 string_types
 typecaster
 tzinfo_factory

+ + + + + + +
Method Details
+ + +
+

dictfetchall(self) +

+
+
+
+ + +
+

dictfetchmany(self, + size) +

+
+
+
+ + +
+

dictfetchone(self) +

+
+
+
+ + +
+

__build_dict(self, + row) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.tz-module.html b/psycopg2/doc/api/private/psycopg2.tz-module.html new file mode 100644 index 0000000..9b8244a --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.tz-module.html @@ -0,0 +1,193 @@ + + + + + psycopg2.tz + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module tz +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.tz

+ +

tzinfo implementations for psycopg2

+

This module holds two different tzinfo implementations that can be used as +the 'tzinfo' argument to datetime constructors, directly passed to psycopg +functions or used to set the .tzinfo_factory attribute in cursors.

+
+ + + + + + + + + +
Classes
+ FixedOffsetTimezoneFixed offset in minutes east from UTC.
+ LocalTimezonePlatform idea of local timezone.

+ + + + + + + + + + + + + + +
Variable Summary
timedeltaDSTDIFF = datetime.timedelta(0, 3600) +
LocalTimezoneLOCAL = <psycopg2.tz.LocalTimezone object at 0x00847090> +
timedeltaSTDOFFSET = datetime.timedelta(0, 3600) +
timedeltaZERO = datetime.timedelta(0) +

+ + + + + + +
Variable Details
+
+ +

DSTDIFF

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0, 3600)                                            
+
+
+
+
+
+ +

LOCAL

+
+
+
+
+
Type:
+
+ LocalTimezone + +
+
Value:
+
+
+<psycopg2.tz.LocalTimezone object at 0x00847090>                       
+
+
+
+
+
+ +

STDOFFSET

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0, 3600)                                            
+
+
+
+
+
+ +

ZERO

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0)                                                  
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.tz.FixedOffsetTimezone-class.html b/psycopg2/doc/api/private/psycopg2.tz.FixedOffsetTimezone-class.html new file mode 100644 index 0000000..4e6d658 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.tz.FixedOffsetTimezone-class.html @@ -0,0 +1,273 @@ + + + + + psycopg2.tz.FixedOffsetTimezone + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module tz :: + Class FixedOffsetTimezone +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type FixedOffsetTimezone

+ +
+object --+    
+         |    
+    tzinfo --+
+             |
+            FixedOffsetTimezone
+

+ +
+ +

Fixed offset in minutes east from UTC.

+

This is exactly the implementation found in Python 2.3.x documentation, +with a small change to the __init__ method to allow for pickling and a +default name in the form 'sHH:MM' ('s' is the sign.)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + offset, + name) +
 dst(self, + dt) +
 tzname(self, + dt) +
 utcoffset(self, + dt) +
    Inherited from tzinfo
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+-> (cls, state)
 fromutc(...) +
+datetime in UTC -> datetime in local time.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __hash__(x) +
+Return hash(x)...
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + + + + + +
Class Variable Summary
NoneType_name = None                                                                  
timedelta_offset = datetime.timedelta(0) +

+ + + + + + +
Method Details
+ + +
+

__init__(self, + offset=None, + name=None) +
(Constructor) +

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

dst(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.dst
+
+
+
+ + +
+

tzname(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.tzname
+
+
+
+ + +
+

utcoffset(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.utcoffset
+
+
+
+
+ + + + + + +
Class Variable Details
+
+ +

_name

+
+
+
+
+
Type:
+
+ NoneType + +
+
Value:
+
+
+None                                                                  
+
+
+
+
+
+ +

_offset

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0)                                                  
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/psycopg2.tz.LocalTimezone-class.html b/psycopg2/doc/api/private/psycopg2.tz.LocalTimezone-class.html new file mode 100644 index 0000000..0954549 --- /dev/null +++ b/psycopg2/doc/api/private/psycopg2.tz.LocalTimezone-class.html @@ -0,0 +1,209 @@ + + + + + psycopg2.tz.LocalTimezone + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module tz :: + Class LocalTimezone +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type LocalTimezone

+ +
+object --+    
+         |    
+    tzinfo --+
+             |
+            LocalTimezone
+

+ +
+ +

Platform idea of local timezone.

+

This is the exact implementation from the Pyhton 2.3 documentation.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 dst(self, + dt) +
 tzname(self, + dt) +
 utcoffset(self, + dt) +
 _isdst(self, + dt) +
    Inherited from tzinfo
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+-> (cls, state)
 fromutc(...) +
+datetime in UTC -> datetime in local time.
    Inherited from object
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __hash__(x) +
+Return hash(x)...
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

dst(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.dst
+
+
+
+ + +
+

tzname(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.tzname
+
+
+
+ + +
+

utcoffset(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.utcoffset
+
+
+
+ + +
+

_isdst(self, + dt) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/private/toc-everything.html b/psycopg2/doc/api/private/toc-everything.html new file mode 100644 index 0000000..2b60e36 --- /dev/null +++ b/psycopg2/doc/api/private/toc-everything.html @@ -0,0 +1,134 @@ + + + + + Everything + + + + +

Everything

+
+ + +

All Classes

+

psycopg2._psycopg.connection

+

psycopg2._psycopg.cursor

+

psycopg2._psycopg.ISQLQuote

+

psycopg2.extras.DictConnection

+

psycopg2.extras.DictCursor

+

psycopg2.extras.DictRow

+

psycopg2.extras.SQL_IN

+

psycopg2.pool.AbstractConnectionPool

+

psycopg2.pool.PersistentConnectionPool

+

psycopg2.pool.SimpleConnectionPool

+

psycopg2.pool.ThreadedConnectionPool

+

psycopg2.psycopg1.connection

+

psycopg2.psycopg1.cursor

+

psycopg2.tz.FixedOffsetTimezone

+

psycopg2.tz.LocalTimezone

+ + +

All Exceptions

+

psycopg2.DatabaseError

+

psycopg2.DataError

+

psycopg2.Error

+

psycopg2.IntegrityError

+

psycopg2.InterfaceError

+

psycopg2.InternalError

+

psycopg2.NotSupportedError

+

psycopg2.OperationalError

+

psycopg2.pool.PoolError

+

psycopg2.ProgrammingError

+

psycopg2.Warning

+ + +

All Functions

+

adapt

+

AsIs

+

Binary

+

Boolean

+

connect

+

connect

+

Date

+

DateFromPy

+

DateFromTicks

+

dbg

+

IntervalFromPy

+

List

+

new_type

+

QuotedString

+

register_adapter

+

register_type

+

Time

+

TimeFromPy

+

TimeFromTicks

+

Timestamp

+

TimestampFromPy

+

TimestampFromTicks

+ + +

All Variables

+

__version__

+

_C_API

+

adapters

+

apilevel

+

BINARY

+

binary_types

+

BINARYARRAY

+

BOOLEAN

+

BOOLEANARRAY

+

DATE

+

DATEARRAY

+

DATETIME

+

DATETIMEARRAY

+

DECIMAL

+

DECIMALARRAY

+

DSTDIFF

+

encodings

+

FLOAT

+

FLOATARRAY

+

INTEGER

+

INTEGERARRAY

+

INTERVAL

+

INTERVALARRAY

+

ISOLATION_LEVEL_AUTOCOMMIT

+

ISOLATION_LEVEL_READ_COMMITTED

+

ISOLATION_LEVEL_READ_UNCOMMITTED

+

ISOLATION_LEVEL_REPEATABLE_READ

+

ISOLATION_LEVEL_SERIALIZABLE

+

LOCAL

+

LONGINTEGER

+

LONGINTEGERARRAY

+

NUMBER

+

paramstyle

+

PYDATE

+

PYDATETIME

+

PYINTERVAL

+

PYTIME

+

ROWID

+

ROWIDARRAY

+

STDOFFSET

+

STRING

+

string_types

+

STRINGARRAY

+

threadsafety

+

TIME

+

TIMEARRAY

+

UNICODE

+

UNICODEARRAY

+

ZERO

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2-module.html b/psycopg2/doc/api/private/toc-psycopg2-module.html new file mode 100644 index 0000000..e07c73c --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2-module.html @@ -0,0 +1,58 @@ + + + + + psycopg2 + + + + +

psycopg2

+
+ + +

Modules

+

_psycopg

+

extensions

+

extras

+

pool

+

psycopg1

+

tz

+ + +

Exceptions

+

DatabaseError

+

DataError

+

Error

+

IntegrityError

+

InterfaceError

+

InternalError

+

NotSupportedError

+

OperationalError

+

ProgrammingError

+

Warning

+ + +

Functions

+

Binary

+

connect

+

Date

+

DateFromTicks

+

Time

+

TimeFromTicks

+

Timestamp

+

TimestampFromTicks

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2._psycopg-module.html b/psycopg2/doc/api/private/toc-psycopg2._psycopg-module.html new file mode 100644 index 0000000..49975f5 --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2._psycopg-module.html @@ -0,0 +1,78 @@ + + + + + psycopg2._psycopg + + + + +

_psycopg

+
+ + +

Classes

+

connection

+

cursor

+

ISQLQuote

+ + +

Functions

+

List

+ + +

Variables

+

__version__

+

_C_API

+

adapters

+

apilevel

+

BINARY

+

binary_types

+

BINARYARRAY

+

BOOLEAN

+

BOOLEANARRAY

+

DATE

+

DATEARRAY

+

DATETIME

+

DATETIMEARRAY

+

DECIMAL

+

DECIMALARRAY

+

encodings

+

FLOAT

+

FLOATARRAY

+

INTEGER

+

INTEGERARRAY

+

INTERVAL

+

INTERVALARRAY

+

LONGINTEGER

+

LONGINTEGERARRAY

+

NUMBER

+

paramstyle

+

PYDATE

+

PYDATETIME

+

PYINTERVAL

+

PYTIME

+

ROWID

+

ROWIDARRAY

+

STRING

+

string_types

+

STRINGARRAY

+

threadsafety

+

TIME

+

TIMEARRAY

+

UNICODE

+

UNICODEARRAY

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2.extensions-module.html b/psycopg2/doc/api/private/toc-psycopg2.extensions-module.html new file mode 100644 index 0000000..2e7c983 --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2.extensions-module.html @@ -0,0 +1,47 @@ + + + + + psycopg2.extensions + + + + +

extensions

+
+ + +

Functions

+

adapt

+

AsIs

+

Boolean

+

DateFromPy

+

IntervalFromPy

+

new_type

+

QuotedString

+

register_adapter

+

register_type

+

TimeFromPy

+

TimestampFromPy

+ + +

Variables

+

ISOLATION_LEVEL_AUTOCOMMIT

+

ISOLATION_LEVEL_READ_COMMITTED

+

ISOLATION_LEVEL_READ_UNCOMMITTED

+

ISOLATION_LEVEL_REPEATABLE_READ

+

ISOLATION_LEVEL_SERIALIZABLE

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2.extras-module.html b/psycopg2/doc/api/private/toc-psycopg2.extras-module.html new file mode 100644 index 0000000..505d1d8 --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2.extras-module.html @@ -0,0 +1,32 @@ + + + + + psycopg2.extras + + + + +

extras

+
+ + +

Classes

+

DictConnection

+

DictCursor

+

DictRow

+

SQL_IN

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2.pool-module.html b/psycopg2/doc/api/private/toc-psycopg2.pool-module.html new file mode 100644 index 0000000..2b2a8cc --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2.pool-module.html @@ -0,0 +1,40 @@ + + + + + psycopg2.pool + + + + +

pool

+
+ + +

Classes

+

AbstractConnectionPool

+

PersistentConnectionPool

+

SimpleConnectionPool

+

ThreadedConnectionPool

+ + +

Exceptions

+

PoolError

+ + +

Functions

+

dbg

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2.psycopg1-module.html b/psycopg2/doc/api/private/toc-psycopg2.psycopg1-module.html new file mode 100644 index 0000000..20971b2 --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2.psycopg1-module.html @@ -0,0 +1,34 @@ + + + + + psycopg2.psycopg1 + + + + +

psycopg1

+
+ + +

Classes

+

connection

+

cursor

+ + +

Functions

+

connect

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc-psycopg2.tz-module.html b/psycopg2/doc/api/private/toc-psycopg2.tz-module.html new file mode 100644 index 0000000..fce1191 --- /dev/null +++ b/psycopg2/doc/api/private/toc-psycopg2.tz-module.html @@ -0,0 +1,37 @@ + + + + + psycopg2.tz + + + + +

tz

+
+ + +

Classes

+

FixedOffsetTimezone

+

LocalTimezone

+ + +

Variables

+

DSTDIFF

+

LOCAL

+

STDOFFSET

+

ZERO

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/toc.html b/psycopg2/doc/api/private/toc.html new file mode 100644 index 0000000..1e31df5 --- /dev/null +++ b/psycopg2/doc/api/private/toc.html @@ -0,0 +1,39 @@ + + + + + Table of Contents + + + + +

Table of Contents

+
+

Everything

+ + +

Packages

+

psycopg2

+ + +

Modules

+

psycopg2._psycopg

+

psycopg2.extensions

+

psycopg2.extras

+

psycopg2.pool

+

psycopg2.psycopg1

+

psycopg2.tz

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/private/trees.html b/psycopg2/doc/api/private/trees.html new file mode 100644 index 0000000..5907cfa --- /dev/null +++ b/psycopg2/doc/api/private/trees.html @@ -0,0 +1,196 @@ + + + + + Module and Class Hierarchies + + + + + + + + + + + + + + + + + + + +
+ + + +
[show private | hide private]
[frames | no frames]
+ + +

Module Hierarchy

+
    +
  • psycopg2: A Python driver for PostgreSQL
      +
    • _psycopg: psycopg PostgreSQL driver
    • +
    • extensions: psycopg extensions to the DBAPI-2.0
    • +
    • extras: Miscellaneous goodies for psycopg2
    • +
    • pool: Connection pooling for psycopg2
    • +
    • psycopg1: psycopg 1.1.x compatibility module
    • +
    • tz: tzinfo implementations for psycopg2
    • +
    +
  • +
+ + +

Class Hierarchy

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/__builtin__.list-class.html b/psycopg2/doc/api/public/__builtin__.list-class.html new file mode 100644 index 0000000..4ede43e --- /dev/null +++ b/psycopg2/doc/api/public/__builtin__.list-class.html @@ -0,0 +1,817 @@ + + + + + __builtin__.list + + + + + + + + + + + + + + + + + + + +
+ + Module __builtin__ :: + Class list +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type list

+ +
+object --+
+         |
+        list
+

+ +
Known Subclasses:
+
+ DictRow
+ +
+ +

list() -> new list +list(sequence) -> new list initialized from sequence's items

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __add__(x, + y) +
+Return x+y...
 __contains__(x, + y) +
+Return y in x...
 __delitem__(x, + y) +
+Return del x[y]...
 __delslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __eq__(x, + y) +
+Return x==y...
 __ge__(x, + y) +
+Return x>=y...
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __getitem__(x, + y) +
+Return x[y]...
 __getslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __gt__(x, + y) +
+Return x>y...
 __hash__(x) +
+Return hash(x)...
 __iadd__(x, + y) +
+Return x+=y...
 __imul__(x, + y) +
+Return x*=y...
 __iter__(x) +
+Return iter(x)...
 __le__(x, + y) +
+Return x<=y...
 __len__(x) +
+Return len(x)...
 __lt__(x, + y) +
+Return x<y...
 __mul__(x, + n) +
+Return x*n...
 __ne__(x, + y) +
+Return x!=y...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __rmul__(x, + n) +
+Return n*x...
 __setitem__(x, + i, + y) +
+Return x[i]=y...
 __setslice__(x, + i, + j, + y) +
+Use of negative indices is not supported.
 append(L, + object) +
+append object to end
 count(L, + value) +
+return number of occurrences of value
 extend(L, + iterable) +
+extend list by appending elements from the iterable
 index(...) +
+L.index(value, [start, [stop]]) -> integer -- return first index of value
 insert(L, + index, + object) +
+insert object before index
 pop(L, + index) +
+remove and return item at index (default last)
 remove(L, + value) +
+remove first occurrence of value
 reverse(L) +
+reverse IN PLACE
 sort(L, + cmpfunc) +
+stable sort IN PLACE; cmpfunc(x, y) -> -1, 0, 1
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__add__(x, + y) +
(Addition operator) +

+
+
Returns:
+
+
+x+y
+
+
+
+
+
+ + +
+

__contains__(x, + y) +
(In operator) +

+
+
Returns:
+
+
+y in x
+
+
+
+
+
+ + +
+

__delitem__(x, + y) +
(Index deletion operator) +

+
+
Returns:
+
+
+del x[y]
+
+
+
+
+
+ + +
+

__delslice__(x, + i, + j) +
(Slice deletion operator) +

+

Use of negative indices is not supported.

+
+
Returns:
+
+
+del x[i:j]
+
+
+
+
+
+ + +
+

__eq__(x, + y) +
(Equality operator) +

+
+
Returns:
+
+
+x==y
+
+
+
+
+
+ + +
+

__ge__(x, + y) +
(Greater-than-or-equals operator) +

+
+
Returns:
+
+
+x>=y
+
+
+
+
+
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
Overrides:
+
__builtin__.object.__getattribute__
+
+
+
+ + +
+

__getitem__(x, + y) +
(Indexing operator) +

+
+
Returns:
+
+
+x[y]
+
+
+
+
+
+ + +
+

__getslice__(x, + i, + j) +
(Slicling operator) +

+

Use of negative indices is not supported.

+
+
Returns:
+
+
+x[i:j]
+
+
+
+
+
+ + +
+

__gt__(x, + y) +
(Greater-than operator) +

+
+
Returns:
+
+
+x>y
+
+
+
+
+
+ + +
+

__hash__(x) +
(Hashing function) +

+
+
Returns:
+
+
+hash(x)
+
+
+
+
Overrides:
+
__builtin__.object.__hash__
+
+
+
+ + +
+

__iadd__(x, + y) +

+
+
Returns:
+
+
+x+=y
+
+
+
+
+
+ + +
+

__imul__(x, + y) +

+
+
Returns:
+
+
+x*=y
+
+
+
+
+
+ + +
+

__iter__(x) +

+
+
Returns:
+
+
+iter(x)
+
+
+
+
+
+ + +
+

__le__(x, + y) +
(Less-than-or-equals operator) +

+
+
Returns:
+
+
+x<=y
+
+
+
+
+
+ + +
+

__len__(x) +
(Length operator) +

+
+
Returns:
+
+
+len(x)
+
+
+
+
+
+ + +
+

__lt__(x, + y) +
(Less-than operator) +

+
+
Returns:
+
+
+x<y
+
+
+
+
+
+ + +
+

__mul__(x, + n) +

+
+
Returns:
+
+
+x*n
+
+
+
+
+
+ + +
+

__ne__(x, + y) +
(Inequality operator) +

+
+
Returns:
+
+
+x!=y
+
+
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
Overrides:
+
__builtin__.object.__repr__
+
+
+
+ + +
+

__rmul__(x, + n) +

+
+
Returns:
+
+
+n*x
+
+
+
+
+
+ + +
+

__setitem__(x, + i, + y) +
(Index assignment operator) +

+
+
Returns:
+
+
+x[i]=y
+
+
+
+
+
+ + +
+

__setslice__(x, + i, + j, + y) +
(Slice assignment operator) +

+

Use of negative indices is not supported.

+
+
Returns:
+
+
+x[i:j]=y
+
+
+
+
+
+ + +
+

append(L, + object) +

+

append object to end

+
+
+
+ + +
+

count(L, + value) +

+

return number of occurrences of value

+
+
Returns:
+
+
+integer
+
+
+
+
+
+ + +
+

extend(L, + iterable) +

+

extend list by appending elements from the iterable

+
+
+
+ + +
+

index(...) +

+

L.index(value, [start, [stop]]) -> integer -- return first index of value

+
+
+
+ + +
+

insert(L, + index, + object) +

+

insert object before index

+
+
+
+ + +
+

pop(L, + index=...) +

+

remove and return item at index (default last)

+
+
Returns:
+
+
+item
+
+
+
+
+
+ + +
+

remove(L, + value) +

+

remove first occurrence of value

+
+
+
+ + +
+

reverse(L) +

+

reverse IN PLACE

+
+
+
+ + +
+

sort(L, + cmpfunc=None) +

+

stable sort IN PLACE; cmpfunc(x, y) -> -1, 0, 1

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/__builtin__.object-class.html b/psycopg2/doc/api/public/__builtin__.object-class.html new file mode 100644 index 0000000..e9638da --- /dev/null +++ b/psycopg2/doc/api/public/__builtin__.object-class.html @@ -0,0 +1,267 @@ + + + + + __builtin__.object + + + + + + + + + + + + + + + + + + + +
+ + Module __builtin__ :: + Class object +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type object

+ +
Known Subclasses:
+
+ AbstractConnectionPool, + list, + SQL_IN, + type, + tzinfo
+ +
+ +

The most base type

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + + + +
Class Variable Summary
type__class__ = __builtin__.type

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+

x.__init__(...) initializes x; see x.__class__.__doc__ for signature

+
+
+
+ + +
+

__delattr__(...) +

+

x.__delattr__('name') <==> del x.name

+
+
+
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
+
+ + +
+

__hash__(x) +
(Hashing function) +

+
+
Returns:
+
+
+hash(x)
+
+
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
+
+ + +
+

__reduce__(...) +

+

helper for pickle

+
+
+
+ + +
+

__reduce_ex__(...) +

+

helper for pickle

+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
+
+ + +
+

__setattr__(...) +

+

x.__setattr__('name', value) <==> x.name = value

+
+
+
+ + +
+

__str__(x) +
(Informal representation operator) +

+
+
Returns:
+
+
+str(x)
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/__builtin__.type-class.html b/psycopg2/doc/api/public/__builtin__.type-class.html new file mode 100644 index 0000000..7af340f --- /dev/null +++ b/psycopg2/doc/api/public/__builtin__.type-class.html @@ -0,0 +1,384 @@ + + + + + __builtin__.type + + + + + + + + + + + + + + + + + + + +
+ + Module __builtin__ :: + Class type +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type type

+ +
+object --+
+         |
+        type
+

+ +
+ +

type(object) -> the object's type +type(name, bases, dict) -> a new type

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __call__(x, + ...) +
+Return x(...)...
 __cmp__(x, + y) +
+Return cmp(x,y)...
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
list of immediate subclasses__subclasses__() +
listmro() +
+return a type's method resolution order
    Inherited from object
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __str__(x) +
+Return str(x)...

+ + + + + + + + + + + + + +
Property Summary
 __base__
 __basicsize__
 __dictoffset__
 __flags__
 __itemsize__
 __mro__
 __weakrefoffset__

+ + + + + + + + + + +
Class Variable Summary
tuple__bases__ = (<type 'object'>,) +
str__name__ = 'type' +

+ + + + + + +
Method Details
+ + +
+

__call__(x, + ...) +
(Call operator) +

+
+
Returns:
+
+
+x(...)
+
+
+
+
+
+ + +
+

__cmp__(x, + y) +
(Comparison operator) +

+
+
Returns:
+
+
+cmp(x,y)
+
+
+
+
+
+ + +
+

__delattr__(...) +

+

x.__delattr__('name') <==> del x.name

+
+
Overrides:
+
__builtin__.object.__delattr__
+
+
+
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
Overrides:
+
__builtin__.object.__getattribute__
+
+
+
+ + +
+

__hash__(x) +
(Hashing function) +

+
+
Returns:
+
+
+hash(x)
+
+
+
+
Overrides:
+
__builtin__.object.__hash__
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__repr__(x) +
(Representation operator) +

+
+
Returns:
+
+
+repr(x)
+
+
+
+
Overrides:
+
__builtin__.object.__repr__
+
+
+
+ + +
+

__setattr__(...) +

+

x.__setattr__('name', value) <==> x.name = value

+
+
Overrides:
+
__builtin__.object.__setattr__
+
+
+
+ + +
+

__subclasses__() +

+
+
Returns:
+
+list of immediate subclasses
+
+
+
+ + +
+

mro() +

+

return a type's method resolution order

+
+
Returns:
+
+list
+
+
+
+
+ + + + + + +
Class Variable Details
+
+ +

__bases__

+
+
+
+
+
Type:
+
+ tuple + +
+
Value:
+
+
+(<type 'object'>,)                                                     
+
+
+
+
+
+ +

__name__

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'type'                                                                 
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/datetime.tzinfo-class.html b/psycopg2/doc/api/public/datetime.tzinfo-class.html new file mode 100644 index 0000000..080afa2 --- /dev/null +++ b/psycopg2/doc/api/public/datetime.tzinfo-class.html @@ -0,0 +1,239 @@ + + + + + datetime.tzinfo + + + + + + + + + + + + + + + + + + + +
+ + Module datetime :: + Class tzinfo +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type tzinfo

+ +
+object --+
+         |
+        tzinfo
+

+ +
Known Subclasses:
+
+ FixedOffsetTimezone, + LocalTimezone
+ +
+ +

Abstract base class for time zone info objects.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+-> (cls, state)
 dst(...) +
+datetime -> DST offset in minutes east of UTC.
 fromutc(...) +
+datetime in UTC -> datetime in local time.
 tzname(...) +
+datetime -> string name of time zone.
 utcoffset(...) +
+datetime -> minutes east of UTC (negative for west of UTC).
    Inherited from object
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __hash__(x) +
+Return hash(x)...
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__getattribute__(...) +

+

x.__getattribute__('name') <==> x.name

+
+
Overrides:
+
__builtin__.object.__getattribute__
+
+
+
+ + +
+

__new__(T, + S, + ...) +

+
+
Returns:
+
+
+a new object with type S, a subtype of T
+
+
+
+
Overrides:
+
__builtin__.object.__new__
+
+
+
+ + +
+

__reduce__(...) +

+

-> (cls, state)

+
+
Overrides:
+
__builtin__.object.__reduce__
+
+
+
+ + +
+

dst(...) +

+

datetime -> DST offset in minutes east of UTC.

+
+
+
+ + +
+

fromutc(...) +

+

datetime in UTC -> datetime in local time.

+
+
+
+ + +
+

tzname(...) +

+

datetime -> string name of time zone.

+
+
+
+ + +
+

utcoffset(...) +

+

datetime -> minutes east of UTC (negative for west of UTC).

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/epydoc.css b/psycopg2/doc/api/public/epydoc.css new file mode 100644 index 0000000..22e8f7e --- /dev/null +++ b/psycopg2/doc/api/public/epydoc.css @@ -0,0 +1,138 @@ +/* Based on the Epydoc "default.css" +** with some missing reST-related classes +** and Python syntax support (from SilverCity) +*/ + +/* Body color */ +body { background: #ffffff; color: #000000; } + +/* Tables */ +table.summary, table.details, table.index + { background: #e8f0f8; color: #000000; } +tr.summary, tr.details, tr.index + { background: #70b0f0; color: #000000; + text-align: left; font-size: 120%; } +tr.group { background: #c0e0f8; color: #000000; + text-align: left; font-size: 120%; + font-style: italic; } + +/* Documentation page titles */ +h2.module { margin-top: 0.2em; } +h2.class { margin-top: 0.2em; } + +/* Headings */ +h1.heading { font-size: +140%; font-style: italic; + font-weight: bold; } +h2.heading { font-size: +125%; font-style: italic; + font-weight: bold; } +h3.heading { font-size: +110%; font-style: italic; + font-weight: normal; } + +/* Base tree */ +pre.base-tree { font-size: 80%; margin: 0; } + +/* TOC */ +p.toc { margin: 0; } + +/* Details Sections */ +table.func-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.func-detail { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +table.var-details { background: #e8f0f8; color: #000000; + border: 2px groove #c0d0d0; + padding: 0 1em 0 1em; margin: 0.4em 0 0 0; } +h3.var-details { background: transparent; color: #000000; + margin: 0 0 1em 0; } + +/* Function signatures */ +.sig { background: transparent; color: #000000; + font-weight: bold; } +.sig-name { background: transparent; color: #006080; } +.sig-arg, .sig-kwarg, .sig-vararg + { background: transparent; color: #008060; } +.sig-default { background: transparent; color: #602000; } +.summary-sig { background: transparent; color: #000000; } +.summary-sig-name { background: transparent; color: #204080; } +.summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg + { background: transparent; color: #008060; } + +/* Doctest blocks */ +.py-src { background: transparent; color: #000000; } +.py-prompt { background: transparent; color: #005050; + font-weight: bold;} +.py-string { background: transparent; color: #006030; } +.py-comment { background: transparent; color: #003060; } +.py-keyword { background: transparent; color: #600000; } +.py-output { background: transparent; color: #404040; } +div.code-block, +pre.literal-block, +pre.doctestblock { background: #f4faff; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +table pre.doctestblock + { background: #dce4ec; color: #000000; + padding: .5em; margin: 1em; + border: 1px solid #708890; } +div.code-block { font-family: monospace; } + +/* Variable values */ +pre.variable { background: #dce4ec; color: #000000; + padding: .5em; margin: 0; + border: 1px solid #708890; } +.variable-linewrap { background: transparent; color: #604000; } +.variable-ellipsis { background: transparent; color: #604000; } +.variable-quote { background: transparent; color: #604000; } +.re { background: transparent; color: #000000; } +.re-char { background: transparent; color: #006030; } +.re-op { background: transparent; color: #600000; } +.re-group { background: transparent; color: #003060; } +.re-ref { background: transparent; color: #404040; } + +/* Navigation bar */ +table.navbar { background: #a0c0ff; color: #0000ff; + border: 2px groove #c0d0d0; } +th.navbar { background: #a0c0ff; color: #0000ff; } +th.navselect { background: #70b0ff; color: #000000; } +.nomargin { margin: 0; } + +/* Links */ +a:link { background: transparent; color: #0000ff; } +a:visited { background: transparent; color: #204080; } +a.navbar:link { background: transparent; color: #0000ff; + text-decoration: none; } +a.navbar:visited { background: transparent; color: #204080; + text-decoration: none; } + +/* Admonitions */ +div.warning, +div.note { background-color: #c0e0f8; + border: thin solid black; + padding: 1em; + margin-left: 1em; + margin-right: 1em; } +div.warning .first, +div.note .first { font-family: sans-serif; + font-size: 110%; + margin-right: 0.5em; } + +/* Lists */ +ul { margin-top: 0; } + +/* Python syntax */ +.p_character { color: olive; } +.p_classname { color: blue; font-weight: bold; } +.p_commentblock {color: gray; font-style: italic; } +.p_commentline { color: green; font-style: italic; } +.p_default {} +.p_defname { color: #009999; font-weight: bold; } +.p_identifier { color: black; } +.p_number { color: #009999; } +.p_operator { color: black; } +.p_string { color: #7F007F; } +.p_stringeol { color: #7F007F; } +.p_triple { color: #7F0000; } +.p_tripledouble { color: #7F0000; } +.p_word { color: navy; font-weight: bold; } diff --git a/psycopg2/doc/api/public/exceptions.Exception-class.html b/psycopg2/doc/api/public/exceptions.Exception-class.html new file mode 100644 index 0000000..d7e7ba4 --- /dev/null +++ b/psycopg2/doc/api/public/exceptions.Exception-class.html @@ -0,0 +1,128 @@ + + + + + exceptions.Exception + + + + + + + + + + + + + + + + + + + +
+ + Module exceptions :: + Class Exception +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class Exception

+ +
Known Subclasses:
+
+ StandardError
+ +
+ +

Common base class for all exceptions.

+
+ + + + + + + + + + + + +
Method Summary
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + +
Method Details
+ + +
+

__init__(...) +
(Constructor) +

+
+
+
+ + +
+

__getitem__(...) +
(Indexing operator) +

+
+
+
+ + +
+

__str__(...) +
(Informal representation operator) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/exceptions.StandardError-class.html b/psycopg2/doc/api/public/exceptions.StandardError-class.html new file mode 100644 index 0000000..ab0a1c3 --- /dev/null +++ b/psycopg2/doc/api/public/exceptions.StandardError-class.html @@ -0,0 +1,102 @@ + + + + + exceptions.StandardError + + + + + + + + + + + + + + + + + + + +
+ + Module exceptions :: + Class StandardError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class StandardError

+ +
+Exception --+
+            |
+           StandardError
+

+ +
Known Subclasses:
+
+ Error, + Warning
+ +
+ +

Base class for all standard Python exceptions.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/frames.html b/psycopg2/doc/api/public/frames.html new file mode 100644 index 0000000..ffd6536 --- /dev/null +++ b/psycopg2/doc/api/public/frames.html @@ -0,0 +1,15 @@ + + + + + API Documentation + + + + + + + + + diff --git a/psycopg2/doc/api/public/help.html b/psycopg2/doc/api/public/help.html new file mode 100644 index 0000000..0e9a1cf --- /dev/null +++ b/psycopg2/doc/api/public/help.html @@ -0,0 +1,231 @@ + + + + + Help + + + + + + + + + + + + + + + + + + + +
+ + + +
[show private | hide private]
[frames | no frames]
+ +

API Documentation

+ +

This document contains the API (Application Programming Interface) +documentation for this project. Documentation for the Python +objects defined by the project is divided into separate pages for each +package, module, and class. The API documentation also includes two +pages containing information about the project as a whole: a trees +page, and an index page.

+ +

Object Documentation

+ +

Each Package Documentation page contains:

+
    +
  • A description of the package.
  • +
  • A list of the modules and sub-packages contained by the + package.
  • +
  • A summary of the classes defined by the package.
  • +
  • A summary of the functions defined by the package.
  • +
  • A summary of the variables defined by the package.
  • +
  • A detailed description of each function defined by the + package.
  • +
  • A detailed description of each variable defined by the + package.
  • +
+ +

Each Module Documentation page contains:

+
    +
  • A description of the module.
  • +
  • A summary of the classes defined by the module.
  • +
  • A summary of the functions defined by the module.
  • +
  • A summary of the variables defined by the module.
  • +
  • A detailed description of each function defined by the + module.
  • +
  • A detailed description of each variable defined by the + module.
  • +
+ +

Each Class Documentation page contains:

+
    +
  • A class inheritance diagram.
  • +
  • A list of known subclasses.
  • +
  • A description of the class.
  • +
  • A summary of the methods defined by the class.
  • +
  • A summary of the instance variables defined by the class.
  • +
  • A summary of the class (static) variables defined by the + class.
  • +
  • A detailed description of each method defined by the + class.
  • +
  • A detailed description of each instance variable defined by the + class.
  • +
  • A detailed description of each class (static) variable defined + by the class.
  • +
+ +

Project Documentation

+ +

The Trees page contains the module and class hierarchies:

+
    +
  • The module hierarchy lists every package and module, with + modules grouped into packages. At the top level, and within each + package, modules and sub-packages are listed alphabetically.
  • +
  • The class hierarchy lists every class, grouped by base + class. If a class has more than one base class, then it will be + listed under each base class. At the top level, and under each base + class, classes are listed alphabetically.
  • +
+ +

The Index page contains indices of terms and + identifiers:

+
    +
  • The term index lists every term indexed by any object's + documentation. For each term, the index provides links to each + place where the term is indexed.
  • +
  • The identifier index lists the (short) name of every package, + module, class, method, function, variable, and parameter. For each + identifier, the index provides a short description, and a link to + its documentation.
  • +
+ +

The Table of Contents

+ +

The table of contents occupies the two frames on the left side of +the window. The upper-left frame displays the project +contents, and the lower-left frame displays the module +contents:

+ + + + + + + + + +
+ Project
Contents
...
+ API
Documentation
Frame


+
+ Module
Contents
 
...
  +

+ +

The project contents frame contains a list of all packages +and modules that are defined by the project. Clicking on an entry +will display its contents in the module contents frame. Clicking on a +special entry, labeled "Everything," will display the contents of +the entire project.

+ +

The module contents frame contains a list of every +submodule, class, type, exception, function, and variable defined by a +module or package. Clicking on an entry will display its +documentation in the API documentation frame. Clicking on the name of +the module, at the top of the frame, will display the documentation +for the module itself.

+ +

The "frames" and "no frames" buttons below the top +navigation bar can be used to control whether the table of contents is +displayed or not.

+ +

The Navigation Bar

+ +

A navigation bar is located at the top and bottom of every page. +It indicates what type of page you are currently viewing, and allows +you to go to related pages. The following table describes the labels +on the navigation bar. Note that not some labels (such as +[Parent]) are not displayed on all pages.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
LabelHighlighted when...Links to...
[Parent](never highlighted) the parent of the current package
[Package]viewing a packagethe package containing the current object +
[Module]viewing a modulethe module containing the current object +
[Class]viewing a class the class containing the current object
[Trees]viewing the trees page the trees page
[Index]viewing the index page the index page
[Help]viewing the help page the help page
+ +

The "show private" and "hide private" buttons below +the top navigation bar can be used to control whether documentation +for private objects is displayed. Private objects are usually defined +as objects whose (short) names begin with a single underscore, but do +not end with an underscore. For example, "_x", +"__pprint", and "epydoc.epytext._tokenize" +are private objects; but "re.sub", +"__init__", and "type_" are not. However, +if a module defines the "__all__" variable, then its +contents are used to decide which objects are private.

+ +

A timestamp below the bottom navigation bar indicates when each +page was last updated.

+ + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/index.html b/psycopg2/doc/api/public/index.html new file mode 100644 index 0000000..ffd6536 --- /dev/null +++ b/psycopg2/doc/api/public/index.html @@ -0,0 +1,15 @@ + + + + + API Documentation + + + + + + + + + diff --git a/psycopg2/doc/api/public/indices.html b/psycopg2/doc/api/public/indices.html new file mode 100644 index 0000000..a6d0fad --- /dev/null +++ b/psycopg2/doc/api/public/indices.html @@ -0,0 +1,418 @@ + + + + + Index + + + + + + + + + + + + + + + + + + + +
+ + + +
[show private | hide private]
[frames | no frames]
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Identifier Index
__add__Method in class __builtin__.list
__base__member_descriptor in class __builtin__.type
__bases__Variable in class __builtin__.type
__basicsize__member_descriptor in class __builtin__.type
__call__Method in class __builtin__.type
typeClass in module __builtin__
__cmp__Method in class __builtin__.type
__contains__Method in class __builtin__.list
__delattr__Method in class __builtin__.object
__delattr__Method in class __builtin__.type
__delitem__Method in class __builtin__.list
__delslice__Method in class __builtin__.list
__dictoffset__member_descriptor in class __builtin__.type
__eq__Method in class __builtin__.list
__flags__member_descriptor in class __builtin__.type
__ge__Method in class __builtin__.list
__getattribute__Method in class __builtin__.list
__getattribute__Method in class __builtin__.object
__getattribute__Method in class __builtin__.type
__getattribute__Method in class datetime.tzinfo
__getitem__Method in class __builtin__.list
__getitem__Method in class exceptions.Exception
__getitem__Method in class psycopg2.extras.DictRow
__getslice__Method in class __builtin__.list
__gt__Method in class __builtin__.list
__hash__Method in class __builtin__.list
__hash__Method in class __builtin__.object
__hash__Method in class __builtin__.type
__iadd__Method in class __builtin__.list
__imul__Method in class __builtin__.list
__init__Method in class __builtin__.list
__init__Method in class __builtin__.object
__init__Method in class exceptions.Exception
__init__Method in class psycopg2.extras.DictRow
__init__Method in class psycopg2.extras.SQL_IN
__init__Method in class psycopg2.pool.AbstractConnectionPool
__init__Method in class psycopg2.pool.PersistentConnectionPool
__init__Method in class psycopg2.pool.ThreadedConnectionPool
__init__Method in class psycopg2.tz.FixedOffsetTimezone
__itemsize__member_descriptor in class __builtin__.type
__iter__Method in class __builtin__.list
__le__Method in class __builtin__.list
__len__Method in class __builtin__.list
__lt__Method in class __builtin__.list
__mro__member_descriptor in class __builtin__.type
__mul__Method in class __builtin__.list
__name__Variable in class __builtin__.type
__ne__Method in class __builtin__.list
__new__Method in class __builtin__.list
__new__Method in class __builtin__.object
__new__Method in class __builtin__.type
__new__Method in class datetime.tzinfo
__reduce__Method in class __builtin__.object
__reduce__Method in class datetime.tzinfo
__reduce_ex__Method in class __builtin__.object
__repr__Method in class __builtin__.list
__repr__Method in class __builtin__.object
__repr__Method in class __builtin__.type
__rmul__Method in class __builtin__.list
__setattr__Method in class __builtin__.object
__setattr__Method in class __builtin__.type
__setitem__Method in class __builtin__.list
__setslice__Method in class __builtin__.list
__str__Method in class __builtin__.object
__str__Method in class exceptions.Exception
__subclasses__Method in class __builtin__.type
__weakrefoffset__member_descriptor in class __builtin__.type
AbstractConnectionPoolClass in module psycopg2.pool
adaptFunction in module psycopg2.extensions
appendMethod in class __builtin__.list
AsIsFunction in module psycopg2.extensions
autocommitMethod in class psycopg2.psycopg1.connection
BinaryFunction in package psycopg2
BooleanFunction in module psycopg2.extensions
callprocMethod in class psycopg2.extras.DictCursor
closeallMethod in class psycopg2.pool.PersistentConnectionPool
closeallMethod in class psycopg2.pool.ThreadedConnectionPool
connectFunction in package psycopg2
connectFunction in module psycopg2.psycopg1
connectionClass in module psycopg2.psycopg1
countMethod in class __builtin__.list
cursorMethod in class psycopg2.extras.DictConnection
cursorMethod in class psycopg2.psycopg1.connection
cursorClass in module psycopg2.psycopg1
DatabaseErrorClass in package psycopg2
DataErrorClass in package psycopg2
DateFunction in package psycopg2
DateFromPyFunction in module psycopg2.extensions
DateFromTicksFunction in package psycopg2
dbgFunction in module psycopg2.pool
DictConnectionClass in module psycopg2.extras
DictCursorClass in module psycopg2.extras
dictfetchallMethod in class psycopg2.psycopg1.cursor
dictfetchmanyMethod in class psycopg2.psycopg1.cursor
dictfetchoneMethod in class psycopg2.psycopg1.cursor
DictRowClass in module psycopg2.extras
dstMethod in class datetime.tzinfo
dstMethod in class psycopg2.tz.FixedOffsetTimezone
dstMethod in class psycopg2.tz.LocalTimezone
DSTDIFFVariable in module psycopg2.tz
ErrorClass in package psycopg2
ExceptionClass in module exceptions
executeMethod in class psycopg2.extras.DictCursor
extendMethod in class __builtin__.list
extensionsModule in package psycopg2
extrasModule in package psycopg2
fetchallMethod in class psycopg2.extras.DictCursor
fetchmanyMethod in class psycopg2.extras.DictCursor
fetchoneMethod in class psycopg2.extras.DictCursor
FixedOffsetTimezoneClass in module psycopg2.tz
fromutcMethod in class datetime.tzinfo
getMethod in class psycopg2.extras.DictRow
getconnMethod in class psycopg2.pool.PersistentConnectionPool
getconnMethod in class psycopg2.pool.ThreadedConnectionPool
getquotedMethod in class psycopg2.extras.SQL_IN
has_keyMethod in class psycopg2.extras.DictRow
indexMethod in class __builtin__.list
insertMethod in class __builtin__.list
IntegrityErrorClass in package psycopg2
InterfaceErrorClass in package psycopg2
InternalErrorClass in package psycopg2
IntervalFromPyFunction in module psycopg2.extensions
ISOLATION_LEVEL_AUTOCOMMITVariable in module psycopg2.extensions
ISOLATION_LEVEL_READ_COMMITTEDVariable in module psycopg2.extensions
ISOLATION_LEVEL_READ_UNCOMMITTEDVariable in module psycopg2.extensions
ISOLATION_LEVEL_REPEATABLE_READVariable in module psycopg2.extensions
ISOLATION_LEVEL_SERIALIZABLEVariable in module psycopg2.extensions
itemsMethod in class psycopg2.extras.DictRow
keysMethod in class psycopg2.extras.DictRow
listClass in module __builtin__
LOCALVariable in module psycopg2.tz
LocalTimezoneClass in module psycopg2.tz
mroMethod in class __builtin__.type
new_typeFunction in module psycopg2.extensions
NotSupportedErrorClass in package psycopg2
objectClass in module __builtin__
OperationalErrorClass in package psycopg2
PersistentConnectionPoolClass in module psycopg2.pool
poolModule in package psycopg2
PoolErrorClass in module psycopg2.pool
popMethod in class __builtin__.list
ProgrammingErrorClass in package psycopg2
psycopg1Module in package psycopg2
psycopg2Package
putconnMethod in class psycopg2.pool.PersistentConnectionPool
putconnMethod in class psycopg2.pool.ThreadedConnectionPool
QuotedStringFunction in module psycopg2.extensions
register_adapterFunction in module psycopg2.extensions
register_typeFunction in module psycopg2.extensions
removeMethod in class __builtin__.list
reverseMethod in class __builtin__.list
SimpleConnectionPoolClass in module psycopg2.pool
sortMethod in class __builtin__.list
SQL_INClass in module psycopg2.extras
StandardErrorClass in module exceptions
STDOFFSETVariable in module psycopg2.tz
ThreadedConnectionPoolClass in module psycopg2.pool
TimeFunction in package psycopg2
TimeFromPyFunction in module psycopg2.extensions
TimeFromTicksFunction in package psycopg2
TimestampFunction in package psycopg2
TimestampFromPyFunction in module psycopg2.extensions
TimestampFromTicksFunction in package psycopg2
typeClass in module __builtin__
tzModule in package psycopg2
tzinfoClass in module datetime
tznameMethod in class datetime.tzinfo
tznameMethod in class psycopg2.tz.FixedOffsetTimezone
tznameMethod in class psycopg2.tz.LocalTimezone
utcoffsetMethod in class datetime.tzinfo
utcoffsetMethod in class psycopg2.tz.FixedOffsetTimezone
utcoffsetMethod in class psycopg2.tz.LocalTimezone
valuesMethod in class psycopg2.extras.DictRow
WarningClass in package psycopg2
ZEROVariable in module psycopg2.tz
+
+ + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2-module.html b/psycopg2/doc/api/public/psycopg2-module.html new file mode 100644 index 0000000..052c338 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2-module.html @@ -0,0 +1,335 @@ + + + + + psycopg2 + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Package psycopg2

+ +

A Python driver for PostgreSQL

+

psycopg is a PostgreSQL database adapter for the Python programming +language. This is version 2, a complete rewrite of the original code to +provide new-style classes for connection and cursor objects and other sweet +candies. Like the original, psycopg 2 was written with the aim of being very +small and fast, and stable as a rock.

+

Homepage: http://initd.org/projects/psycopg2

+
+ + + + + + +
Submodules
    +
  • extensions: psycopg extensions to the DBAPI-2.0
  • +
  • extras: Miscellaneous goodies for psycopg2
  • +
  • pool: Connection pooling for psycopg2
  • +
  • psycopg1: psycopg 1.1.x compatibility module
  • +
  • tz: tzinfo implementations for psycopg2
  • +

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Exceptions
+ DatabaseErrorError related to the database engine.
+ DataErrorError related to problems with the processed data.
+ ErrorBase class for error exceptions.
+ IntegrityErrorError related to database integrity.
+ InterfaceErrorError related to the database interface.
+ InternalErrorThe database encountered an internal error.
+ NotSupportedErrorA not supported datbase API was called.
+ OperationalErrorError related to database operation (disconnect, memory allocation etc).
+ ProgrammingErrorError related to database programming (SQL error, table not found etc).
+ WarningA database warning.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Function Summary
    Connections creation
extensions.connectionconnect(dsn, + ...) +
+Create a new database connection.
    Value objects constructors
new binary objectBinary(buffer) +
+Build an object capable to hold a bynary string value.
new dateDate(year, + month, + day) +
+Build an object holding a date value.
new dateDateFromTicks(ticks) +
+Build an object holding a date value from the given ticks value.
new timeTime(hour, + minutes, + seconds, + tzinfo) +
+Build an object holding a time value.
new timeTimeFromTicks(ticks) +
+Build an object holding a time value from the given ticks value.
new timestampTimestamp(year, + month, + day, + hour, + minutes, + seconds, + tzinfo) +
+Build an object holding a timestamp value.
new timestampTimestampFromTicks(ticks) +
+Build an object holding a timestamp value from the given ticks value.

+ + + + + + +
Function Details
+ + +
+

connect(dsn, + ...) +

+

Create a new database connection.

+

This function supports two different but equivalent sets of arguments. +A single data source name or dsn string can be used to specify the +connection parameters, as follows:

+
+psycopg2.connect("dbname=xxx user=xxx ...")
+
+

If dsn is not provided it is possible to pass the parameters as +keyword arguments; e.g.:

+
+psycopg2.connect(database='xxx', user='xxx', ...)
+
+

The full list of available parameters is:

+
    +
  • dbname -- database name (only in 'dsn')
  • +
  • database -- database name (only as keyword argument)
  • +
  • host -- host address (defaults to UNIX socket if not provided)
  • +
  • port -- port number (defaults to 5432 if not provided)
  • +
  • user -- user name used to authenticate
  • +
  • password -- password used to authenticate
  • +
  • sslmode -- SSL mode (see PostgreSQL documentation)
  • +
+

If the connection_factory keyword argument is not provided this +function always return an instance of the connection class. +Else the given sub-class of extensions.connection will be used to +instantiate the connection object.

+
+
Returns:
+
+New database connection
           + (type=extensions.connection) +
+
+
+
+ + +
+

Binary(buffer) +

+

Build an object capable to hold a bynary string value.

+
+
Returns:
+
+new binary object
+
+
+
+ + +
+

Date(year, + month, + day) +

+

Build an object holding a date value.

+
+
Returns:
+
+new date
+
+
+
+ + +
+

DateFromTicks(ticks) +

+

Build an object holding a date value from the given ticks value.

+

Ticks are the number of seconds since the epoch; see the documentation of the standard Python time module for details).

+
+
Returns:
+
+new date
+
+
+
+ + +
+

Time(hour, + minutes, + seconds, + tzinfo=None) +

+

Build an object holding a time value.

+
+
Returns:
+
+new time
+
+
+
+ + +
+

TimeFromTicks(ticks) +

+

Build an object holding a time value from the given ticks value.

+

Ticks are the number of seconds since the epoch; see the documentation of the standard Python time module for details).

+
+
Returns:
+
+new time
+
+
+
+ + +
+

Timestamp(year, + month, + day, + hour, + minutes, + seconds, + tzinfo=None) +

+

Build an object holding a timestamp value.

+
+
Returns:
+
+new timestamp
+
+
+
+ + +
+

TimestampFromTicks(ticks) +

+

Build an object holding a timestamp value from the given ticks value.

+

Ticks are the number of seconds since the epoch; see the documentation of the standard Python time module for details).

+
+
Returns:
+
+new timestamp
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.DataError-class.html b/psycopg2/doc/api/public/psycopg2.DataError-class.html new file mode 100644 index 0000000..48749b9 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.DataError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.DataError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class DataError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class DataError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       DataError
+

+ +
+ +

Error related to problems with the processed data.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.DatabaseError-class.html b/psycopg2/doc/api/public/psycopg2.DatabaseError-class.html new file mode 100644 index 0000000..154af85 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.DatabaseError-class.html @@ -0,0 +1,110 @@ + + + + + psycopg2.DatabaseError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class DatabaseError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class DatabaseError

+ +
+Exception --+        
+            |        
+StandardError --+    
+                |    
+            Error --+
+                    |
+                   DatabaseError
+

+ +
Known Subclasses:
+
+ DataError, + IntegrityError, + InternalError, + NotSupportedError, + OperationalError, + ProgrammingError
+ +
+ +

Error related to the database engine.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.Error-class.html b/psycopg2/doc/api/public/psycopg2.Error-class.html new file mode 100644 index 0000000..ed0b9fa --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.Error-class.html @@ -0,0 +1,105 @@ + + + + + psycopg2.Error + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class Error +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class Error

+ +
+Exception --+    
+            |    
+StandardError --+
+                |
+               Error
+

+ +
Known Subclasses:
+
+ DatabaseError, + InterfaceError, + PoolError
+ +
+ +

Base class for error exceptions.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.IntegrityError-class.html b/psycopg2/doc/api/public/psycopg2.IntegrityError-class.html new file mode 100644 index 0000000..f2e2752 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.IntegrityError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.IntegrityError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class IntegrityError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class IntegrityError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       IntegrityError
+

+ +
+ +

Error related to database integrity.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.InterfaceError-class.html b/psycopg2/doc/api/public/psycopg2.InterfaceError-class.html new file mode 100644 index 0000000..40667fa --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.InterfaceError-class.html @@ -0,0 +1,101 @@ + + + + + psycopg2.InterfaceError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class InterfaceError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class InterfaceError

+ +
+Exception --+        
+            |        
+StandardError --+    
+                |    
+            Error --+
+                    |
+                   InterfaceError
+

+ +
+ +

Error related to the database interface.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.InternalError-class.html b/psycopg2/doc/api/public/psycopg2.InternalError-class.html new file mode 100644 index 0000000..13290d4 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.InternalError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.InternalError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class InternalError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class InternalError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       InternalError
+

+ +
+ +

The database encountered an internal error.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.NotSupportedError-class.html b/psycopg2/doc/api/public/psycopg2.NotSupportedError-class.html new file mode 100644 index 0000000..842c79f --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.NotSupportedError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.NotSupportedError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class NotSupportedError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class NotSupportedError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       NotSupportedError
+

+ +
+ +

A not supported datbase API was called.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.OperationalError-class.html b/psycopg2/doc/api/public/psycopg2.OperationalError-class.html new file mode 100644 index 0000000..e52e8b1 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.OperationalError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.OperationalError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class OperationalError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class OperationalError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       OperationalError
+

+ +
+ +

Error related to database operation (disconnect, memory allocation etc).

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.ProgrammingError-class.html b/psycopg2/doc/api/public/psycopg2.ProgrammingError-class.html new file mode 100644 index 0000000..ea995a5 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.ProgrammingError-class.html @@ -0,0 +1,103 @@ + + + + + psycopg2.ProgrammingError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class ProgrammingError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class ProgrammingError

+ +
+Exception --+            
+            |            
+StandardError --+        
+                |        
+            Error --+    
+                    |    
+        DatabaseError --+
+                        |
+                       ProgrammingError
+

+ +
+ +

Error related to database programming (SQL error, table not found etc).

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.Warning-class.html b/psycopg2/doc/api/public/psycopg2.Warning-class.html new file mode 100644 index 0000000..86631fe --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.Warning-class.html @@ -0,0 +1,99 @@ + + + + + psycopg2.Warning + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Class Warning +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class Warning

+ +
+Exception --+    
+            |    
+StandardError --+
+                |
+               Warning
+

+ +
+ +

A database warning.

+
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2._psycopg-module.html b/psycopg2/doc/api/public/psycopg2._psycopg-module.html new file mode 100644 index 0000000..034827e --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2._psycopg-module.html @@ -0,0 +1,1001 @@ + + + + + psycopg2._psycopg + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module _psycopg +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2._psycopg

+ +

psycopg PostgreSQL driver

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Variable Summary
str__version__ = '2.0b7 (dt ext pq3)' +
dictadapters = {(<type 'bool'>, <type 'psycopg2._psycopg.ISQ... +
strapilevel = '2.0' +
typeBINARY = <psycopg2._psycopg.type object at 0x009558C0> +
dictbinary_types = {} +
typeBINARYARRAY = <psycopg2._psycopg.type object at 0x00955B... +
typeBOOLEAN = <psycopg2._psycopg.type object at 0x00955760> +
typeBOOLEANARRAY = <psycopg2._psycopg.type object at 0x00955... +
typeDATE = <psycopg2._psycopg.type object at 0x009558A0> +
typeDATEARRAY = <psycopg2._psycopg.type object at 0x00955AA0... +
typeDATETIME = <psycopg2._psycopg.type object at 0x009557C0> +
typeDATETIMEARRAY = <psycopg2._psycopg.type object at 0x0095... +
typeDECIMAL = <psycopg2._psycopg.type object at 0x00955680> +
typeDECIMALARRAY = <psycopg2._psycopg.type object at 0x00955... +
dictencodings = {'UTF8': 'utf_8', 'LATIN-1': 'latin_1', 'SQL... +
typeFLOAT = <psycopg2._psycopg.type object at 0x00955660> +
typeFLOATARRAY = <psycopg2._psycopg.type object at 0x009559E... +
typeINTEGER = <psycopg2._psycopg.type object at 0x00955620> +
typeINTEGERARRAY = <psycopg2._psycopg.type object at 0x00955... +
typeINTERVAL = <psycopg2._psycopg.type object at 0x00955860> +
typeINTERVALARRAY = <psycopg2._psycopg.type object at 0x0095... +
typeLONGINTEGER = <psycopg2._psycopg.type object at 0x009555... +
typeLONGINTEGERARRAY = <psycopg2._psycopg.type object at 0x0... +
typeNUMBER = <psycopg2._psycopg.type object at 0x00955540> +
strparamstyle = 'pyformat' +
typePYDATE = <psycopg2._psycopg.type object at 0x00955D00> +
typePYDATETIME = <psycopg2._psycopg.type object at 0x00955C0... +
typePYINTERVAL = <psycopg2._psycopg.type object at 0x00955CE... +
typePYTIME = <psycopg2._psycopg.type object at 0x00955C40> +
typeROWID = <psycopg2._psycopg.type object at 0x009559A0> +
typeROWIDARRAY = <psycopg2._psycopg.type object at 0x00955BE... +
typeSTRING = <psycopg2._psycopg.type object at 0x00955720> +
dictstring_types = {1028: <psycopg2._psycopg.type object at ... +
typeSTRINGARRAY = <psycopg2._psycopg.type object at 0x00955A... +
intthreadsafety = 2                                                                     
typeTIME = <psycopg2._psycopg.type object at 0x00955840> +
typeTIMEARRAY = <psycopg2._psycopg.type object at 0x00955B00... +
typeUNICODE = <psycopg2._psycopg.type object at 0x009556C0> +
typeUNICODEARRAY = <psycopg2._psycopg.type object at 0x00955... +

+ + + + + + +
Variable Details
+
+ +

__version__

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'2.0b7 (dt ext pq3)'                                                   
+
+
+
+
+
+ +

adapters

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{(<type 'datetime.timedelta'>, <type 'psycopg2._psycopg.ISQLQuote'>): \
+<built-in function IntervalFromPy>,
+ (<type 'datetime.date'>, <type 'psycopg2._psycopg.ISQLQuote'>): <buil\
+t-in function DateFromPy>,
+ (<type 'datetime.time'>, <type 'psycopg2._psycopg.ISQLQuote'>): <buil\
+t-in function TimeFromPy>,
+ (<type 'datetime.datetime'>, <type 'psycopg2._psycopg.ISQLQuote'>): <\
+built-in function TimestampFromPy>,
+...                                                                    
+
+
+
+
+
+ +

apilevel

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'2.0'                                                                  
+
+
+
+
+
+ +

BINARY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009558C0>                          
+
+
+
+
+
+ +

binary_types

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{}                                                                     
+
+
+
+
+
+ +

BINARYARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955B60>                          
+
+
+
+
+
+ +

BOOLEAN

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955760>                          
+
+
+
+
+
+ +

BOOLEANARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955A20>                          
+
+
+
+
+
+ +

DATE

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009558A0>                          
+
+
+
+
+
+ +

DATEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955AA0>                          
+
+
+
+
+
+ +

DATETIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009557C0>                          
+
+
+
+
+
+ +

DATETIMEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955AC0>                          
+
+
+
+
+
+ +

DECIMAL

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955680>                          
+
+
+
+
+
+ +

DECIMALARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955260>                          
+
+
+
+
+
+ +

encodings

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{'LATIN-1': 'latin_1',
+ 'LATIN1': 'latin_1',
+ 'SQL_ASCII': 'ascii',
+ 'UNICODE': 'utf_8',
+ 'UTF8': 'utf_8'}                                                      
+
+
+
+
+
+ +

FLOAT

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955660>                          
+
+
+
+
+
+ +

FLOATARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009559E0>                          
+
+
+
+
+
+ +

INTEGER

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955620>                          
+
+
+
+
+
+ +

INTEGERARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955A00>                          
+
+
+
+
+
+ +

INTERVAL

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955860>                          
+
+
+
+
+
+ +

INTERVALARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955BA0>                          
+
+
+
+
+
+ +

LONGINTEGER

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009555C0>                          
+
+
+
+
+
+ +

LONGINTEGERARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955960>                          
+
+
+
+
+
+ +

NUMBER

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955540>                          
+
+
+
+
+
+ +

paramstyle

+
+
+
+
+
Type:
+
+ str + +
+
Value:
+
+
+'pyformat'                                                             
+
+
+
+
+
+ +

PYDATE

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955D00>                          
+
+
+
+
+
+ +

PYDATETIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955C00>                          
+
+
+
+
+
+ +

PYINTERVAL

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955CE0>                          
+
+
+
+
+
+ +

PYTIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955C40>                          
+
+
+
+
+
+ +

ROWID

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009559A0>                          
+
+
+
+
+
+ +

ROWIDARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955BE0>                          
+
+
+
+
+
+ +

STRING

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955720>                          
+
+
+
+
+
+ +

string_types

+
+
+
+
+
Type:
+
+ dict + +
+
Value:
+
+
+{16: <psycopg2._psycopg.type object at 0x00955760>,
+ 17: <psycopg2._psycopg.type object at 0x009558C0>,
+ 18: <psycopg2._psycopg.type object at 0x00955720>,
+ 19: <psycopg2._psycopg.type object at 0x00955720>,
+ 20: <psycopg2._psycopg.type object at 0x009555C0>,
+ 21: <psycopg2._psycopg.type object at 0x00955620>,
+ 23: <psycopg2._psycopg.type object at 0x00955620>,
+ 25: <psycopg2._psycopg.type object at 0x00955720>,
+...                                                                    
+
+
+
+
+
+ +

STRINGARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955A80>                          
+
+
+
+
+
+ +

threadsafety

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+2                                                                     
+
+
+
+
+
+ +

TIME

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955840>                          
+
+
+
+
+
+ +

TIMEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955B00>                          
+
+
+
+
+
+ +

UNICODE

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x009556C0>                          
+
+
+
+
+
+ +

UNICODEARRAY

+
+
+
+
+
Type:
+
+ type + +
+
Value:
+
+
+<psycopg2._psycopg.type object at 0x00955A40>                          
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.extensions-module.html b/psycopg2/doc/api/public/psycopg2.extensions-module.html new file mode 100644 index 0000000..4e97448 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.extensions-module.html @@ -0,0 +1,418 @@ + + + + + psycopg2.extensions + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extensions +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.extensions

+ +

psycopg extensions to the DBAPI-2.0

+

This module holds all the extensions to the DBAPI-2.0 provided by psycopg.

+
    +
  • connection -- the new-type inheritable connection class
  • +
  • cursor -- the new-type inheritable cursor class
  • +
  • adapt() -- exposes the PEP-246 compatible adapting mechanism used +by psycopg to adapt Python types to PostgreSQL ones
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function Summary
objectadapt(obj, + protocol, + alternate) +
+adapt obj to given protocol
new AsIs wrapper objectAsIs(obj) +
new boolean valueBoolean(obj) +
new wrapperDateFromPy(datetime.date) +
new wrapperIntervalFromPy(datetime.timedelta) +
new type objectnew_type(oids, + name, + adapter) +
+Create a new binding object.
new quoted stringQuotedString(str, + enc) +
 register_adapter(typ, + callable) +
+Register 'callable' as an ISQLQuote adapter for type 'typ'.
Noneregister_type(obj) +
+register obj with psycopg type system
new wrapperTimeFromPy(datetime.time) +
new wrapperTimestampFromPy(datetime.datetime) +

+ + + + + + + + + + + + + + + + +
Variable Summary
intISOLATION_LEVEL_AUTOCOMMIT = 0                                                                     
intISOLATION_LEVEL_READ_COMMITTED = 1                                                                     
intISOLATION_LEVEL_READ_UNCOMMITTED = 1                                                                     
intISOLATION_LEVEL_REPEATABLE_READ = 2                                                                     
intISOLATION_LEVEL_SERIALIZABLE = 2                                                                     

+ + + + + + +
Function Details
+ + +
+

adapt(obj, + protocol, + alternate) +

+

adapt obj to given protocol

+
+
Returns:
+
+object
+
+
+
+ + +
+

AsIs(obj) +

+
+
Returns:
+
+new AsIs wrapper object
+
+
+
+ + +
+

Boolean(obj) +

+
+
Returns:
+
+new boolean value
+
+
+
+ + +
+

DateFromPy(datetime.date) +

+
+
Returns:
+
+new wrapper
+
+
+
+ + +
+

IntervalFromPy(datetime.timedelta) +

+
+
Returns:
+
+new wrapper
+
+
+
+ + +
+

new_type(oids, + name, + adapter) +

+

Create a new binding object. The object can be used with the +register_type() function to bind PostgreSQL objects to python objects.

+
+
Parameters:
+
oids - + Tuple of oid of the PostgreSQL types to convert. +
+
name - + Name for the new type +
+
adapter - + Callable to perform type conversion. +It must have the signature fun(value, cur) where value is +the string representation returned by PostgreSQL (None if NULL) +and cur is the cursor from which data are read. +
+
+
Returns:
+
+new type object
+
+
+
+ + +
+

QuotedString(str, + enc) +

+
+
Returns:
+
+new quoted string
+
+
+
+ + +
+

register_adapter(typ, + callable) +

+

Register 'callable' as an ISQLQuote adapter for type 'typ'.

+
+
+
+ + +
+

register_type(obj) +

+

register obj with psycopg type system

+
+
Parameters:
+
obj - + A type adapter created by new_type() +
+
+
Returns:
+
+None
+
+
+
+ + +
+

TimeFromPy(datetime.time) +

+
+
Returns:
+
+new wrapper
+
+
+
+ + +
+

TimestampFromPy(datetime.datetime) +

+
+
Returns:
+
+new wrapper
+
+
+
+
+ + + + + + +
Variable Details
+
+ +

ISOLATION_LEVEL_AUTOCOMMIT

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+0                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_READ_COMMITTED

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+1                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_READ_UNCOMMITTED

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+1                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_REPEATABLE_READ

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+2                                                                     
+
+
+
+
+
+ +

ISOLATION_LEVEL_SERIALIZABLE

+
+
+
+
+
Type:
+
+ int + +
+
Value:
+
+
+2                                                                     
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.extras-module.html b/psycopg2/doc/api/public/psycopg2.extras-module.html new file mode 100644 index 0000000..c99a0ce --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.extras-module.html @@ -0,0 +1,91 @@ + + + + + psycopg2.extras + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.extras

+ +

Miscellaneous goodies for psycopg2

+

This module is a generic place used to hold little helper functions +and classes untill a better place in the distribution is found.

+
+ + + + + + + + + + + + + +
Classes
+ DictConnectionA connection that uses DictCursor automatically.
+ DictCursorA cursor that keeps a list of column name -> index mappings.
+ DictRowA row object that allow by-colun-name access to data.
+ SQL_INAdapt any iterable to an SQL quotable object.

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.extras.DictConnection-class.html b/psycopg2/doc/api/public/psycopg2.extras.DictConnection-class.html new file mode 100644 index 0000000..988bd79 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.extras.DictConnection-class.html @@ -0,0 +1,137 @@ + + + + + psycopg2.extras.DictConnection + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class DictConnection +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type DictConnection

+ +
+object --+    
+         |    
+connection --+
+             |
+            DictConnection
+

+ +
+ +

A connection that uses DictCursor automatically.

+
+ + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 cursor(self) +
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + +
Method Details
+ + +
+

cursor(self) +

+
+
Overrides:
+
psycopg2._psycopg.connection.cursor
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.extras.DictCursor-class.html b/psycopg2/doc/api/public/psycopg2.extras.DictCursor-class.html new file mode 100644 index 0000000..d546d3a --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.extras.DictCursor-class.html @@ -0,0 +1,205 @@ + + + + + psycopg2.extras.DictCursor + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class DictCursor +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type DictCursor

+ +
+object --+    
+         |    
+    cursor --+
+             |
+            DictCursor
+

+ +
+ +

A cursor that keeps a list of column name -> index mappings.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 callproc(self, + procname, + vars) +
 execute(self, + query, + vars, + async) +
 fetchall(self) +
 fetchmany(self, + size) +
 fetchone(self) +
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + +
Method Details
+ + +
+

callproc(self, + procname, + vars=None) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.callproc
+
+
+
+ + +
+

execute(self, + query, + vars=None, + async=0) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.execute
+
+
+
+ + +
+

fetchall(self) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.fetchall
+
+
+
+ + +
+

fetchmany(self, + size=None) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.fetchmany
+
+
+
+ + +
+

fetchone(self) +

+
+
Overrides:
+
psycopg2._psycopg.cursor.fetchone
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.extras.DictRow-class.html b/psycopg2/doc/api/public/psycopg2.extras.DictRow-class.html new file mode 100644 index 0000000..e278ca3 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.extras.DictRow-class.html @@ -0,0 +1,376 @@ + + + + + psycopg2.extras.DictRow + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class DictRow +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type DictRow

+ +
+object --+    
+         |    
+      list --+
+             |
+            DictRow
+

+ +
+ +

A row object that allow by-colun-name access to data.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + cursor) +
 __getitem__(self, + x) +
 get(self, + x, + default) +
 has_key(self, + x) +
 items(self) +
 keys(self) +
 values(self) +
    Inherited from list
 __add__(x, + y) +
+Return x+y...
 __contains__(x, + y) +
+Return y in x...
 __delitem__(x, + y) +
+Return del x[y]...
 __delslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __eq__(x, + y) +
+Return x==y...
 __ge__(x, + y) +
+Return x>=y...
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __getslice__(x, + i, + j) +
+Use of negative indices is not supported.
 __gt__(x, + y) +
+Return x>y...
 __hash__(x) +
+Return hash(x)...
 __iadd__(x, + y) +
+Return x+=y...
 __imul__(x, + y) +
+Return x*=y...
 __iter__(x) +
+Return iter(x)...
 __le__(x, + y) +
+Return x<=y...
 __len__(x) +
+Return len(x)...
 __lt__(x, + y) +
+Return x<y...
 __mul__(x, + n) +
+Return x*n...
 __ne__(x, + y) +
+Return x!=y...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __repr__(x) +
+Return repr(x)...
 __rmul__(x, + n) +
+Return n*x...
 __setitem__(x, + i, + y) +
+Return x[i]=y...
 __setslice__(x, + i, + j, + y) +
+Use of negative indices is not supported.
 append(L, + object) +
+append object to end
 count(L, + value) +
+return number of occurrences of value
 extend(L, + iterable) +
+extend list by appending elements from the iterable
 index(...) +
+L.index(value, [start, [stop]]) -> integer -- return first index of value
 insert(L, + index, + object) +
+insert object before index
 pop(L, + index) +
+remove and return item at index (default last)
 remove(L, + value) +
+remove first occurrence of value
 reverse(L) +
+reverse IN PLACE
 sort(L, + cmpfunc) +
+stable sort IN PLACE; cmpfunc(x, y) -> -1, 0, 1
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + cursor) +
(Constructor) +

+
+
Overrides:
+
__builtin__.list.__init__
+
+
+
+ + +
+

__getitem__(self, + x) +
(Indexing operator) +

+
+
Overrides:
+
__builtin__.list.__getitem__
+
+
+
+ + +
+

get(self, + x, + default=None) +

+
+
+
+ + +
+

has_key(self, + x) +

+
+
+
+ + +
+

items(self) +

+
+
+
+ + +
+

keys(self) +

+
+
+
+ + +
+

values(self) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.extras.SQL_IN-class.html b/psycopg2/doc/api/public/psycopg2.extras.SQL_IN-class.html new file mode 100644 index 0000000..0b05cd2 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.extras.SQL_IN-class.html @@ -0,0 +1,171 @@ + + + + + psycopg2.extras.SQL_IN + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module extras :: + Class SQL_IN +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type SQL_IN

+ +
+object --+
+         |
+        SQL_IN
+

+ +
+ +

Adapt any iterable to an SQL quotable object.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + seq) +
 __str__(self) +
 getquoted(self) +
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + +
Method Details
+ + +
+

__init__(self, + seq) +
(Constructor) +

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

__str__(self) +
(Informal representation operator) +

+
+
+
+ + +
+

getquoted(self) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.pool-module.html b/psycopg2/doc/api/public/psycopg2.pool-module.html new file mode 100644 index 0000000..34fbebd --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.pool-module.html @@ -0,0 +1,126 @@ + + + + + psycopg2.pool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.pool

+ +

Connection pooling for psycopg2

+

This module implements thread-safe (and not) connection pools.

+
+ + + + + + + + + + + + + +
Classes
+ AbstractConnectionPoolGeneric key-based pooling code.
+ PersistentConnectionPoolA pool that assigns persistent connections to different threads.
+ SimpleConnectionPoolA connection pool that can't be shared across different threads.
+ ThreadedConnectionPoolA connection pool that works with the threading module.

+ + + + + + + + +
Exceptions
+ PoolError 

+ + + + + + + + +
Function Summary
 dbg(*args) +

+ + + + + + +
Function Details
+ + +
+

dbg(*args) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.pool.AbstractConnectionPool-class.html b/psycopg2/doc/api/public/psycopg2.pool.AbstractConnectionPool-class.html new file mode 100644 index 0000000..41d63b9 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.pool.AbstractConnectionPool-class.html @@ -0,0 +1,169 @@ + + + + + psycopg2.pool.AbstractConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class AbstractConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type AbstractConnectionPool

+ +
+object --+
+         |
+        AbstractConnectionPool
+

+ +
Known Subclasses:
+
+ PersistentConnectionPool, + SimpleConnectionPool, + ThreadedConnectionPool
+ +
+ +

Generic key-based pooling code.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the connection pool.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + minconn, + maxconn, + *args, + **kwargs) +
(Constructor) +

+

Initialize the connection pool.

+

New 'minconn' connections are created immediately calling 'connfunc' +with given parameters. The connection pool will support a maximum of +about 'maxconn' connections.

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.pool.PersistentConnectionPool-class.html b/psycopg2/doc/api/public/psycopg2.pool.PersistentConnectionPool-class.html new file mode 100644 index 0000000..954b8b5 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.pool.PersistentConnectionPool-class.html @@ -0,0 +1,210 @@ + + + + + psycopg2.pool.PersistentConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class PersistentConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type PersistentConnectionPool

+ +
+            object --+    
+                     |    
+AbstractConnectionPool --+
+                         |
+                        PersistentConnectionPool
+

+ +
+ +

A pool that assigns persistent connections to different threads.

+

Note that this connection pool generates by itself the required keys +using the current thread id. This means that untill a thread put away +a connection it will always get the same connection object by successive +.getconn() calls. This also means that a thread can't use more than one +single connection from the pool.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the threading lock.
 closeall(self) +
+Close all connections (even the one currently in use.)
 getconn(self) +
+Generate thread id and return a connection.
 putconn(self, + conn, + close) +
+Put away an unused connection.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + minconn, + maxconn, + *args, + **kwargs) +
(Constructor) +

+

Initialize the threading lock.

+
+
Overrides:
+
psycopg2.pool.AbstractConnectionPool.__init__
+
+
+
+ + +
+

closeall(self) +

+

Close all connections (even the one currently in use.)

+
+
+
+ + +
+

getconn(self) +

+

Generate thread id and return a connection.

+
+
+
+ + +
+

putconn(self, + conn=None, + close=False) +

+

Put away an unused connection.

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.pool.PoolError-class.html b/psycopg2/doc/api/public/psycopg2.pool.PoolError-class.html new file mode 100644 index 0000000..89cd4f7 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.pool.PoolError-class.html @@ -0,0 +1,99 @@ + + + + + psycopg2.pool.PoolError + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class PoolError +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Class PoolError

+ +
+Exception --+        
+            |        
+StandardError --+    
+                |    
+            Error --+
+                    |
+                   PoolError
+

+ +
+ + + + + + + + + + + + + + +
Method Summary
    Inherited from Exception
 __init__(...) +
 __getitem__(...) +
 __str__(...) +

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.pool.SimpleConnectionPool-class.html b/psycopg2/doc/api/public/psycopg2.pool.SimpleConnectionPool-class.html new file mode 100644 index 0000000..ea8f605 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.pool.SimpleConnectionPool-class.html @@ -0,0 +1,139 @@ + + + + + psycopg2.pool.SimpleConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class SimpleConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type SimpleConnectionPool

+ +
+            object --+    
+                     |    
+AbstractConnectionPool --+
+                         |
+                        SimpleConnectionPool
+

+ +
+ +

A connection pool that can't be shared across different threads.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
    Inherited from AbstractConnectionPool
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the connection pool.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.pool.ThreadedConnectionPool-class.html b/psycopg2/doc/api/public/psycopg2.pool.ThreadedConnectionPool-class.html new file mode 100644 index 0000000..64c95a9 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.pool.ThreadedConnectionPool-class.html @@ -0,0 +1,209 @@ + + + + + psycopg2.pool.ThreadedConnectionPool + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module pool :: + Class ThreadedConnectionPool +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type ThreadedConnectionPool

+ +
+            object --+    
+                     |    
+AbstractConnectionPool --+
+                         |
+                        ThreadedConnectionPool
+

+ +
+ +

A connection pool that works with the threading module.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + minconn, + maxconn, + *args, + **kwargs) +
+Initialize the threading lock.
 closeall(self) +
+Close all connections (even the one currently in use.)
 getconn(self, + key) +
+Get a free connection and assign it to 'key' if not None.
 putconn(self, + conn, + key, + close) +
+Put away an unused connection.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + minconn, + maxconn, + *args, + **kwargs) +
(Constructor) +

+

Initialize the threading lock.

+
+
Overrides:
+
psycopg2.pool.AbstractConnectionPool.__init__
+
+
+
+ + +
+

closeall(self) +

+

Close all connections (even the one currently in use.)

+
+
+
+ + +
+

getconn(self, + key=None) +

+

Get a free connection and assign it to 'key' if not None.

+
+
+
+ + +
+

putconn(self, + conn=None, + key=None, + close=False) +

+

Put away an unused connection.

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.psycopg1-module.html b/psycopg2/doc/api/public/psycopg2.psycopg1-module.html new file mode 100644 index 0000000..18a9a75 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.psycopg1-module.html @@ -0,0 +1,121 @@ + + + + + psycopg2.psycopg1 + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module psycopg1 +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.psycopg1

+ +

psycopg 1.1.x compatibility module

+

This module uses the new style connection and cursor types to build a psycopg +1.1.1.x compatibility layer. It should be considered a temporary hack to run +old code while porting to psycopg 2. Import it as follows:

+
+from psycopg2 import psycopg1 as psycopg
+
+
+ + + + + + + + + +
Classes
+ connectionpsycopg 1.1.x connection.
+ cursorpsycopg 1.1.x cursor.

+ + + + + + + + +
Function Summary
new psycopg 1.1.x compatible connection objectconnect(dsn, + ...) +

+ + + + + + +
Function Details
+ + +
+

connect(dsn, + ...) +

+
+
Returns:
+
+new psycopg 1.1.x compatible connection object
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.psycopg1.connection-class.html b/psycopg2/doc/api/public/psycopg2.psycopg1.connection-class.html new file mode 100644 index 0000000..9b5b429 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.psycopg1.connection-class.html @@ -0,0 +1,156 @@ + + + + + psycopg2.psycopg1.connection + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module psycopg1 :: + Class connection +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type connection

+ +
+object --+    
+         |    
+connection --+
+             |
+            connection
+

+ +
+ +

psycopg 1.1.x connection.

+
+ + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
switch autocommit on (1) or off (0)autocommit(on_off) +
new psycopg 1.1.x compatible cursor objectcursor() +
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + +
Method Details
+ + +
+

autocommit(on_off=1) +

+
+
Returns:
+
+switch autocommit on (1) or off (0)
+
+
+
+ + +
+

cursor() +

+
+
Returns:
+
+new psycopg 1.1.x compatible cursor object
+
+
Overrides:
+
psycopg2._psycopg.connection.cursor
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.psycopg1.cursor-class.html b/psycopg2/doc/api/public/psycopg2.psycopg1.cursor-class.html new file mode 100644 index 0000000..f80677d --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.psycopg1.cursor-class.html @@ -0,0 +1,161 @@ + + + + + psycopg2.psycopg1.cursor + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module psycopg1 :: + Class cursor +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type cursor

+ +
+object --+    
+         |    
+    cursor --+
+             |
+            cursor
+

+ +
+ +

psycopg 1.1.x cursor.

+

Note that this cursor implements the exact procedure used by psycopg 1 to +build dictionaries out of result rows. The DictCursor in the +psycopg.extras modules implements a much better and faster algorithm.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 dictfetchall(self) +
 dictfetchmany(self, + size) +
 dictfetchone(self) +
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __hash__(x) +
+Return hash(x)...
 __reduce__(...) +
+helper for pickle
 __reduce_ex__(...) +
+helper for pickle
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value

+ + + + + + +
Method Details
+ + +
+

dictfetchall(self) +

+
+
+
+ + +
+

dictfetchmany(self, + size) +

+
+
+
+ + +
+

dictfetchone(self) +

+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.tz-module.html b/psycopg2/doc/api/public/psycopg2.tz-module.html new file mode 100644 index 0000000..192ac5e --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.tz-module.html @@ -0,0 +1,193 @@ + + + + + psycopg2.tz + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module tz +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Module psycopg2.tz

+ +

tzinfo implementations for psycopg2

+

This module holds two different tzinfo implementations that can be used as +the 'tzinfo' argument to datetime constructors, directly passed to psycopg +functions or used to set the .tzinfo_factory attribute in cursors.

+
+ + + + + + + + + +
Classes
+ FixedOffsetTimezoneFixed offset in minutes east from UTC.
+ LocalTimezonePlatform idea of local timezone.

+ + + + + + + + + + + + + + +
Variable Summary
timedeltaDSTDIFF = datetime.timedelta(0, 3600) +
LocalTimezoneLOCAL = <psycopg2.tz.LocalTimezone object at 0x00847090> +
timedeltaSTDOFFSET = datetime.timedelta(0, 3600) +
timedeltaZERO = datetime.timedelta(0) +

+ + + + + + +
Variable Details
+
+ +

DSTDIFF

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0, 3600)                                            
+
+
+
+
+
+ +

LOCAL

+
+
+
+
+
Type:
+
+ LocalTimezone + +
+
Value:
+
+
+<psycopg2.tz.LocalTimezone object at 0x00847090>                       
+
+
+
+
+
+ +

STDOFFSET

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0, 3600)                                            
+
+
+
+
+
+ +

ZERO

+
+
+
+
+
Type:
+
+ timedelta + +
+
Value:
+
+
+datetime.timedelta(0)                                                  
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.tz.FixedOffsetTimezone-class.html b/psycopg2/doc/api/public/psycopg2.tz.FixedOffsetTimezone-class.html new file mode 100644 index 0000000..71145dd --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.tz.FixedOffsetTimezone-class.html @@ -0,0 +1,213 @@ + + + + + psycopg2.tz.FixedOffsetTimezone + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module tz :: + Class FixedOffsetTimezone +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type FixedOffsetTimezone

+ +
+object --+    
+         |    
+    tzinfo --+
+             |
+            FixedOffsetTimezone
+

+ +
+ +

Fixed offset in minutes east from UTC.

+

This is exactly the implementation found in Python 2.3.x documentation, +with a small change to the __init__ method to allow for pickling and a +default name in the form 'sHH:MM' ('s' is the sign.)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 __init__(self, + offset, + name) +
 dst(self, + dt) +
 tzname(self, + dt) +
 utcoffset(self, + dt) +
    Inherited from tzinfo
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+-> (cls, state)
 fromutc(...) +
+datetime in UTC -> datetime in local time.
    Inherited from object
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __hash__(x) +
+Return hash(x)...
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

__init__(self, + offset=None, + name=None) +
(Constructor) +

+
+
Overrides:
+
__builtin__.object.__init__
+
+
+
+ + +
+

dst(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.dst
+
+
+
+ + +
+

tzname(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.tzname
+
+
+
+ + +
+

utcoffset(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.utcoffset
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/psycopg2.tz.LocalTimezone-class.html b/psycopg2/doc/api/public/psycopg2.tz.LocalTimezone-class.html new file mode 100644 index 0000000..7f95294 --- /dev/null +++ b/psycopg2/doc/api/public/psycopg2.tz.LocalTimezone-class.html @@ -0,0 +1,196 @@ + + + + + psycopg2.tz.LocalTimezone + + + + + + + + + + + + + + + + + + + +
+ + Package psycopg2 :: + Module tz :: + Class LocalTimezone +
+
+ + +
[show private | hide private]
[frames | no frames]
+ + +

Type LocalTimezone

+ +
+object --+    
+         |    
+    tzinfo --+
+             |
+            LocalTimezone
+

+ +
+ +

Platform idea of local timezone.

+

This is the exact implementation from the Pyhton 2.3 documentation.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method Summary
 dst(self, + dt) +
 tzname(self, + dt) +
 utcoffset(self, + dt) +
    Inherited from tzinfo
 __getattribute__(...) +
+x.__getattribute__('name') <==> x.name
 __new__(T, + S, + ...) +
+Return a new object with type S, a subtype of T...
 __reduce__(...) +
+-> (cls, state)
 fromutc(...) +
+datetime in UTC -> datetime in local time.
    Inherited from object
 __init__(...) +
+x.__init__(...) initializes x; see x.__class__.__doc__ for signature
 __delattr__(...) +
+x.__delattr__('name') <==> del x.name
 __hash__(x) +
+Return hash(x)...
 __reduce_ex__(...) +
+helper for pickle
 __repr__(x) +
+Return repr(x)...
 __setattr__(...) +
+x.__setattr__('name', value) <==> x.name = value
 __str__(x) +
+Return str(x)...

+ + + + + + +
Method Details
+ + +
+

dst(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.dst
+
+
+
+ + +
+

tzname(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.tzname
+
+
+
+ + +
+

utcoffset(self, + dt) +

+
+
Overrides:
+
datetime.tzinfo.utcoffset
+
+
+
+
+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/api/public/toc-everything.html b/psycopg2/doc/api/public/toc-everything.html new file mode 100644 index 0000000..a13c502 --- /dev/null +++ b/psycopg2/doc/api/public/toc-everything.html @@ -0,0 +1,90 @@ + + + + + Everything + + + + +

Everything

+
+ + +

All Classes

+

psycopg2.extras.DictConnection

+

psycopg2.extras.DictCursor

+

psycopg2.extras.DictRow

+

psycopg2.extras.SQL_IN

+

psycopg2.pool.AbstractConnectionPool

+

psycopg2.pool.PersistentConnectionPool

+

psycopg2.pool.SimpleConnectionPool

+

psycopg2.pool.ThreadedConnectionPool

+

psycopg2.psycopg1.connection

+

psycopg2.psycopg1.cursor

+

psycopg2.tz.FixedOffsetTimezone

+

psycopg2.tz.LocalTimezone

+ + +

All Exceptions

+

psycopg2.DatabaseError

+

psycopg2.DataError

+

psycopg2.Error

+

psycopg2.IntegrityError

+

psycopg2.InterfaceError

+

psycopg2.InternalError

+

psycopg2.NotSupportedError

+

psycopg2.OperationalError

+

psycopg2.pool.PoolError

+

psycopg2.ProgrammingError

+

psycopg2.Warning

+ + +

All Functions

+

adapt

+

AsIs

+

Binary

+

Boolean

+

connect

+

connect

+

Date

+

DateFromPy

+

DateFromTicks

+

dbg

+

IntervalFromPy

+

new_type

+

QuotedString

+

register_adapter

+

register_type

+

Time

+

TimeFromPy

+

TimeFromTicks

+

Timestamp

+

TimestampFromPy

+

TimestampFromTicks

+ + +

All Variables

+

DSTDIFF

+

ISOLATION_LEVEL_AUTOCOMMIT

+

ISOLATION_LEVEL_READ_COMMITTED

+

ISOLATION_LEVEL_READ_UNCOMMITTED

+

ISOLATION_LEVEL_REPEATABLE_READ

+

ISOLATION_LEVEL_SERIALIZABLE

+

LOCAL

+

STDOFFSET

+

ZERO

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2-module.html b/psycopg2/doc/api/public/toc-psycopg2-module.html new file mode 100644 index 0000000..fa15e9b --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2-module.html @@ -0,0 +1,57 @@ + + + + + psycopg2 + + + + +

psycopg2

+
+ + +

Modules

+

extensions

+

extras

+

pool

+

psycopg1

+

tz

+ + +

Exceptions

+

DatabaseError

+

DataError

+

Error

+

IntegrityError

+

InterfaceError

+

InternalError

+

NotSupportedError

+

OperationalError

+

ProgrammingError

+

Warning

+ + +

Functions

+

Binary

+

connect

+

Date

+

DateFromTicks

+

Time

+

TimeFromTicks

+

Timestamp

+

TimestampFromTicks

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2._psycopg-module.html b/psycopg2/doc/api/public/toc-psycopg2._psycopg-module.html new file mode 100644 index 0000000..6e8fa49 --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2._psycopg-module.html @@ -0,0 +1,73 @@ + + + + + psycopg2._psycopg + + + + +

_psycopg

+
+ + +

Classes

+ + +

Functions

+ + +

Variables

+

__version__

+

adapters

+

apilevel

+

BINARY

+

binary_types

+

BINARYARRAY

+

BOOLEAN

+

BOOLEANARRAY

+

DATE

+

DATEARRAY

+

DATETIME

+

DATETIMEARRAY

+

DECIMAL

+

DECIMALARRAY

+

encodings

+

FLOAT

+

FLOATARRAY

+

INTEGER

+

INTEGERARRAY

+

INTERVAL

+

INTERVALARRAY

+

LONGINTEGER

+

LONGINTEGERARRAY

+

NUMBER

+

paramstyle

+

PYDATE

+

PYDATETIME

+

PYINTERVAL

+

PYTIME

+

ROWID

+

ROWIDARRAY

+

STRING

+

string_types

+

STRINGARRAY

+

threadsafety

+

TIME

+

TIMEARRAY

+

UNICODE

+

UNICODEARRAY

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2.extensions-module.html b/psycopg2/doc/api/public/toc-psycopg2.extensions-module.html new file mode 100644 index 0000000..abf93eb --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2.extensions-module.html @@ -0,0 +1,47 @@ + + + + + psycopg2.extensions + + + + +

extensions

+
+ + +

Functions

+

adapt

+

AsIs

+

Boolean

+

DateFromPy

+

IntervalFromPy

+

new_type

+

QuotedString

+

register_adapter

+

register_type

+

TimeFromPy

+

TimestampFromPy

+ + +

Variables

+

ISOLATION_LEVEL_AUTOCOMMIT

+

ISOLATION_LEVEL_READ_COMMITTED

+

ISOLATION_LEVEL_READ_UNCOMMITTED

+

ISOLATION_LEVEL_REPEATABLE_READ

+

ISOLATION_LEVEL_SERIALIZABLE

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2.extras-module.html b/psycopg2/doc/api/public/toc-psycopg2.extras-module.html new file mode 100644 index 0000000..f193b47 --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2.extras-module.html @@ -0,0 +1,32 @@ + + + + + psycopg2.extras + + + + +

extras

+
+ + +

Classes

+

DictConnection

+

DictCursor

+

DictRow

+

SQL_IN

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2.pool-module.html b/psycopg2/doc/api/public/toc-psycopg2.pool-module.html new file mode 100644 index 0000000..0736019 --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2.pool-module.html @@ -0,0 +1,40 @@ + + + + + psycopg2.pool + + + + +

pool

+
+ + +

Classes

+

AbstractConnectionPool

+

PersistentConnectionPool

+

SimpleConnectionPool

+

ThreadedConnectionPool

+ + +

Exceptions

+

PoolError

+ + +

Functions

+

dbg

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2.psycopg1-module.html b/psycopg2/doc/api/public/toc-psycopg2.psycopg1-module.html new file mode 100644 index 0000000..69b1f79 --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2.psycopg1-module.html @@ -0,0 +1,34 @@ + + + + + psycopg2.psycopg1 + + + + +

psycopg1

+
+ + +

Classes

+

connection

+

cursor

+ + +

Functions

+

connect

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc-psycopg2.tz-module.html b/psycopg2/doc/api/public/toc-psycopg2.tz-module.html new file mode 100644 index 0000000..6f617fe --- /dev/null +++ b/psycopg2/doc/api/public/toc-psycopg2.tz-module.html @@ -0,0 +1,37 @@ + + + + + psycopg2.tz + + + + +

tz

+
+ + +

Classes

+

FixedOffsetTimezone

+

LocalTimezone

+ + +

Variables

+

DSTDIFF

+

LOCAL

+

STDOFFSET

+

ZERO

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/toc.html b/psycopg2/doc/api/public/toc.html new file mode 100644 index 0000000..89021cc --- /dev/null +++ b/psycopg2/doc/api/public/toc.html @@ -0,0 +1,38 @@ + + + + + Table of Contents + + + + +

Table of Contents

+
+

Everything

+ + +

Packages

+

psycopg2

+ + +

Modules

+

psycopg2.extensions

+

psycopg2.extras

+

psycopg2.pool

+

psycopg2.psycopg1

+

psycopg2.tz

+ +
+[show private | hide private] + + diff --git a/psycopg2/doc/api/public/trees.html b/psycopg2/doc/api/public/trees.html new file mode 100644 index 0000000..44573d9 --- /dev/null +++ b/psycopg2/doc/api/public/trees.html @@ -0,0 +1,174 @@ + + + + + Module and Class Hierarchies + + + + + + + + + + + + + + + + + + + +
+ + + +
[show private | hide private]
[frames | no frames]
+ + +

Module Hierarchy

+
    +
  • psycopg2: A Python driver for PostgreSQL
      +
    • extensions: psycopg extensions to the DBAPI-2.0
    • +
    • extras: Miscellaneous goodies for psycopg2
    • +
    • pool: Connection pooling for psycopg2
    • +
    • psycopg1: psycopg 1.1.x compatibility module
    • +
    • tz: tzinfo implementations for psycopg2
    • +
    +
  • +
+ + +

Class Hierarchy

+ + + + + + + + + + + + + + + + + + +
+ + diff --git a/psycopg2/doc/async.txt b/psycopg2/doc/async.txt new file mode 100644 index 0000000..518d5fe --- /dev/null +++ b/psycopg2/doc/async.txt @@ -0,0 +1,67 @@ +psycopg asynchronous API +************************ + +** Important: async quaeries are not enabled for 2.0 ** + +Program code can initiate an asynchronous query by passing an 'async=1' flag +to the .execute() method. A very simple example, from the connection to the +query: + + conn = psycopg.connect(database='test') + curs = conn.cursor() + curs.execute("SEECT * from test WHERE fielda > %s", (1971,), async=1) + +From then on any query on other cursors derived from the same connection is +doomed to fail (and raise an exception) until the original cursor (the one +executing the query) complete the asynchronous operation. This can happen in +a number of different ways: + + 1) one of the .fetchXXX() methods is called, effectively blocking untill + data has been sent from the backend to the client, terminating the + query. + + 2) .cancel() is called. This method tries to abort the current query and + will block until the query is aborted or fully executed. The return + value is True if the query was successfully aborted or False if it + was executed. Query result are discarded in both cases. + + 3) .execute() is called again on the same cursor (.execute() on a + different cursor will simply raise an exception.) This waits for the + complete execution of the current query, discard any data and execute + the new one. + +Note that calling .execute() two times in a row will not abort the former +query and will temporarily go to synchronous mode until the first of the two +queries is executed. + +Cursors now have some extra methods that make them usefull during +asynchronous queries: + + .fileno() + Returns the file descriptor associated with the current connection and + make possible to use a cursor in a context where a file object would be + expected (like in a select() call.) + + .isbusy() + Returns True if the backend is still processing the query or false if + data is ready to be fetched (by one of the .fetchXXX() methods.) + +A code snippet that shows how to use the cursor object in a select() call: + + import psycopg + import select + + conn = psycopg.connect(database='test') + curs = conn.cursor() + curs.execute("SEECT * from test WHERE fielda > %s", (1971,), async=1) + + # wait for input with a maximum timeout of 5 seconds + query_ended = False + while not query_ended: + rread, rwrite, rspec = select([cursor, another_file], [], [], 5) + if not cursor.isbusy(): + query_ended = True + # manage input from other sources like other_file, etc. + print "Query Results:" + for row in cursor: + print row diff --git a/psycopg2/doc/extensions.html b/psycopg2/doc/extensions.html new file mode 100644 index 0000000..cb71200 --- /dev/null +++ b/psycopg2/doc/extensions.html @@ -0,0 +1,219 @@ + + + + + + +psycopg 2 extensions to the DBAPI 2.0 + + + +
+

psycopg 2 extensions to the DBAPI 2.0

+

This document is a short summary of the extensions built in psycopg 2.0.x over +the standard Python Database API Specification 2.0, usually called simply +DBAPI-2.0 or even PEP-249. Before reading on this document please make sure +you already know how to program in Python using a DBAPI-2.0 compliant driver: +basic concepts like opening a connection, executing queries and commiting or +rolling back a transaction will not be explained but just used.

+

Many objects and extension functions are defined in the psycopg2.extensions +module.

+
+

Connection and cursor factories

+

psycopg 2 exposes two new-style classes that can be sub-classed and expanded to +adapt them to the needs of the programmer: cursor and connection. The +connection class is usually sub-classed only to provide a . cursor is much +more interesting, because it is the class where query building, execution and +result type-casting into Python variables happens.

+ + +
+
+

Setting transaction isolation levels

+

psycopg2 connection objects hold informations about the PostgreSQL transaction +isolation level. The current transaction level can be read from the +.isolation_level attribute. The default isolation level is READ +COMMITTED. A different isolation level con be set through the +.set_isolation_level() method. The level can be set to one of the following +constants, defined in psycopg2.extensions:

+
+
ISOLATION_LEVEL_AUTOCOMMIT
+
No transaction is started when command are issued and no +.commit()/.rollback() is required. Some PostgreSQL command such as +CREATE DATABASE can't run into a transaction: to run such command use +.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT).
+
`ISOLATION_LEVEL_READ_COMMITTED`
+
+

System Message: ERROR/3 (../doc/extensions.rst, line 54); backlink

+Can't find 'ISOLATION_LEVEL_READ_COMMITTED' in any provided module.
+

This is the default value. A new transaction is started at the first +.execute() command on a cursor and at each new .execute() after a +.commit() or a .rollback(). The transaction runs in the PostgreSQL +READ COMMITTED isolation level.

+
+
ISOLATION_LEVEL_SERIALIZABLE
+
Transactions are run at a SERIALIZABLE isolation level.
+
+
+
+

Adaptation of Python values to SQL types

+

psycopg2 casts Python variables to SQL literals by type. Standard Python types +are already adapted to the proper SQL literal.

+

Example: the Python function:

+
+curs.execute("""INSERT INTO atable (anint, adate, astring)
+                 VALUES (%s, %s, %s)""",
+             (10, datetime.date(2005, 11, 18), "O'Reilly"))
+
+

is converted into the SQL command:

+
+INSERT INTO atable (anint, adate, astring)
+ VALUES (10, '2005-11-18', 'O''Reilly');
+
+

Named arguments are supported too with %(name)s placeholders. Notice that:

+
+
    +
  • The Python string operator % is not used: the .execute() function +accepts the values tuple or dictionary as second parameter.
  • +
  • The variables placeholder must always be a %s, even if a different +placeholder (such as a %d for an integer) may look more appropriate.
  • +
  • For positional variables binding, the second argument must always be a +tuple, even if it contains a single variable.
  • +
  • Only variable values should be bound via this method: it shouldn't be used +to set table or field names. For these elements, ordinary string formatting +should be used before running .execute().
  • +
+
+
+

Adapting new types

+

Any Python class or type can be adapted to an SQL string. Adaptation mechanism +is similar to the Object Adaptation proposed in the PEP-246 and is exposed +by the adapt() function.

+

psycopg2 .execute() method adapts its vars arguments to the ISQLQuote +protocol. Objects that conform to this protocol expose a getquoted() method +returning the SQL representation of the object as a string.

+

The easiest way to adapt an object to an SQL string is to register an adapter +function via the register_adapter() function. The adapter function must take +the value to be adapted as argument and return a conform object. A convenient +object is the AsIs wrapper, whose getquoted() result is simply the +str()ingification of the wrapped object.

+

Example: mapping of a Point class into the point PostgreSQL geometric +type:

+
+from psycopg2.extensions import adapt, register_adapter, AsIs
+
+class Point(object):
+    def __init__(self, x=0.0, y=0.0):
+        self.x = x
+        self.y = y
+
+def adapt_point(point):
+    return AsIs("'(%s,%s)'" % (adapt(point.x), adapt(point.y)))
+    
+register_adapter(Point, adapt_point)
+
+curs.execute("INSERT INTO atable (apoint) VALUES (%s)", 
+             (Point(1.23, 4.56),))
+
+

The above function call results in the SQL command:

+
+INSERT INTO atable (apoint) VALUES ((1.23, 4.56));
+
+
+
+
+

Type casting of SQL types into Python values

+

PostgreSQL objects read from the database can be adapted to Python objects +through an user-defined adapting function. An adapter function takes two +argments: the object string representation as returned by PostgreSQL and the +cursor currently being read, and should return a new Python object. For +example, the following function parses a PostgreSQL point into the +previously defined Point class:

+
+def cast_point(value, curs):
+    if value is not None:
+            # Convert from (f1, f2) syntax using a regular expression.
+        m = re.match("\((.*),(.*)\)", value) 
+        if m:
+            return Point(float(m.group(1)), float(m.group(2)))
+
+

To create a mapping from the PostgreSQL type (either standard or user-defined), +its oid must be known. It can be retrieved either by the second column of +the cursor description:

+
+curs.execute("SELECT NULL::point")
+point_oid = curs.description[0][1]   # usually returns 600
+
+

or by querying the system catalogs for the type name and namespace (the +namespace for system objects is pg_catalog):

+
+curs.execute("""
+    SELECT pg_type.oid
+      FROM pg_type JOIN pg_namespace
+             ON typnamespace = pg_namespace.oid
+     WHERE typname = %(typename)s
+       AND nspname = %(namespace)s""",
+            {'typename': 'point', 'namespace': 'pg_catalog'})
+    
+point_oid = curs.fetchone()[0]
+
+

After you know the object oid, you must can and register the new type:

+
+POINT = psycopg2.extensions.new_type((point_oid,), "POINT", cast_point)
+psycopg2.extensions.register_type(POINT)
+
+

The new_type() function binds the object oids (more than one can be +specified) to the adapter function. register_type() completes the spell. +Conversion is automatically performed when a column whose type is a registered +oid is read:

+
+curs.execute("SELECT '(10.2,20.3)'::point")
+point = curs.fetchone()[0]
+print type(point), point.x, point.y
+# Prints: "<class '__main__.Point'> 10.2 20.3"
+
+
+ + +
+

Using COPY TO and COPY FROM

+

psycopg2 cursor object provides an interface to the efficient PostgreSQL +COPY command to move data from files to tables and back.

+

The .copy_to(file, table) method writes the content of the table +named table to the file-like object file. file must have a +write() method.

+

The .copy_from(file, table) reads data from the file-like object +file appending them to the table named table. file must have both +read() and readline() method.

+

Both methods accept two optional arguments: sep (defaulting to a tab) is +the columns separator and null (defaulting to \N) represents NULL +values in the file.

+
+
+

PostgreSQL status message and executed query

+

cursor objects have two special fields related to the last executed query:

+
+
    +
  • .query is the textual representation (str or unicode, depending on what +was passed to .execute() as first argument) of the query after argument +binding and mogrification has been applied. To put it another way, .query +is the exact query that was sent to the PostgreSQL backend.
  • +
  • .statusmessage is the status message that the backend sent upon query +execution. It usually contains the basic type of the query (SELECT, +INSERT, UPDATE, ...) and some additional information like the number of +rows updated and so on. Refer to the PostgreSQL manual for more +information.
  • +
+
+
+
+ + diff --git a/psycopg2/doc/extensions.rst b/psycopg2/doc/extensions.rst new file mode 100644 index 0000000..3bdc680 --- /dev/null +++ b/psycopg2/doc/extensions.rst @@ -0,0 +1,260 @@ +======================================= + psycopg 2 extensions to the DBAPI 2.0 +======================================= + +This document is a short summary of the extensions built in psycopg 2.0.x over +the standard `Python Database API Specification 2.0`__, usually called simply +DBAPI-2.0 or even PEP-249. Before reading on this document please make sure +you already know how to program in Python using a DBAPI-2.0 compliant driver: +basic concepts like opening a connection, executing queries and commiting or +rolling back a transaction will not be explained but just used. + +.. __: http://www.python.org/peps/pep-0249.html + +Many objects and extension functions are defined in the `psycopg2.extensions` +module. + + +Connection and cursor factories +=============================== + +psycopg 2 exposes two new-style classes that can be sub-classed and expanded to +adapt them to the needs of the programmer: `cursor` and `connection`. The +`connection` class is usually sub-classed only to provide an easy way to create +customized cursors but other uses are possible. `cursor` is much more +interesting, because it is the class where query building, execution and result +type-casting into Python variables happens. + +An example of cursor subclass performing logging is:: + + import psycopg2 + import psycopg2.extensions + import logging + + class LoggingCursor(psycopg2.extensions.cursor): + def execute(self, sql, args=None): + logger = logging.getLogger('sql_debug') + logger.info(self.mogrify(sql, args)) + + try: + psycopg2.extensions.cursor.execute(self, sql, args) + except Exception, exc: + logger.error("%s: %s" % (exc.__class__.__name__, exc)) + raise + + conn = psycopg2.connect(DSN) + curs = conn.cursor(cursor_factory=LoggingCursor) + curs.execute("INSERT INTO mytable VALUES (%s, %s, %s);", + (10, 20, 30)) + + +Row factories +------------- + +tzinfo factories +---------------- + + +Setting transaction isolation levels +==================================== + +psycopg2 connection objects hold informations about the PostgreSQL `transaction +isolation level`_. The current transaction level can be read from the +`.isolation_level` attribute. The default isolation level is ``READ +COMMITTED``. A different isolation level con be set through the +`.set_isolation_level()` method. The level can be set to one of the following +constants, defined in `psycopg2.extensions`: + +`ISOLATION_LEVEL_AUTOCOMMIT` + No transaction is started when command are issued and no + `.commit()`/`.rollback()` is required. Some PostgreSQL command such as + ``CREATE DATABASE`` can't run into a transaction: to run such command use + `.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)`. + +`ISOLATION_LEVEL_READ_COMMITTED` + This is the default value. A new transaction is started at the first + `.execute()` command on a cursor and at each new `.execute()` after a + `.commit()` or a `.rollback()`. The transaction runs in the PostgreSQL + ``READ COMMITTED`` isolation level. + +`ISOLATION_LEVEL_SERIALIZABLE` + Transactions are run at a ``SERIALIZABLE`` isolation level. + + +.. _transaction isolation level: + http://www.postgresql.org/docs/8.1/static/transaction-iso.html + + +Adaptation of Python values to SQL types +======================================== + +psycopg2 casts Python variables to SQL literals by type. Standard Python types +are already adapted to the proper SQL literal. + +Example: the Python function:: + + curs.execute("""INSERT INTO atable (anint, adate, astring) + VALUES (%s, %s, %s)""", + (10, datetime.date(2005, 11, 18), "O'Reilly")) + +is converted into the SQL command:: + + INSERT INTO atable (anint, adate, astring) + VALUES (10, '2005-11-18', 'O''Reilly'); + +Named arguments are supported too with ``%(name)s`` placeholders. Notice that: + + - The Python string operator ``%`` is not used: the `.execute()` function + accepts the values tuple or dictionary as second parameter. + + - The variables placeholder must always be a ``%s``, even if a different + placeholder (such as a ``%d`` for an integer) may look more appropriate. + + - For positional variables binding, the second argument must always be a + tuple, even if it contains a single variable. + + - Only variable values should be bound via this method: it shouldn't be used + to set table or field names. For these elements, ordinary string formatting + should be used before running `.execute()`. + + +Adapting new types +------------------ + +Any Python class or type can be adapted to an SQL string. Adaptation mechanism +is similar to the Object Adaptation proposed in the `PEP-246`_ and is exposed +by the `adapt()` function. + +psycopg2 `.execute()` method adapts its ``vars`` arguments to the `ISQLQuote` +protocol. Objects that conform to this protocol expose a ``getquoted()`` method +returning the SQL representation of the object as a string. + +The easiest way to adapt an object to an SQL string is to register an adapter +function via the `register_adapter()` function. The adapter function must take +the value to be adapted as argument and return a conform object. A convenient +object is the `AsIs` wrapper, whose ``getquoted()`` result is simply the +``str()``\ ingification of the wrapped object. + +Example: mapping of a ``Point`` class into the ``point`` PostgreSQL geometric +type:: + + from psycopg2.extensions import adapt, register_adapter, AsIs + + class Point(object): + def __init__(self, x=0.0, y=0.0): + self.x = x + self.y = y + + def adapt_point(point): + return AsIs("'(%s,%s)'" % (adapt(point.x), adapt(point.y))) + + register_adapter(Point, adapt_point) + + curs.execute("INSERT INTO atable (apoint) VALUES (%s)", + (Point(1.23, 4.56),)) + +The above function call results in the SQL command:: + + INSERT INTO atable (apoint) VALUES ((1.23, 4.56)); + + +.. _PEP-246: http://www.python.org/peps/pep-0246.html + + +Type casting of SQL types into Python values +============================================ + +PostgreSQL objects read from the database can be adapted to Python objects +through an user-defined adapting function. An adapter function takes two +argments: the object string representation as returned by PostgreSQL and the +cursor currently being read, and should return a new Python object. For +example, the following function parses a PostgreSQL ``point`` into the +previously defined ``Point`` class:: + + def cast_point(value, curs): + if value is not None: + # Convert from (f1, f2) syntax using a regular expression. + m = re.match("\((.*),(.*)\)", value) + if m: + return Point(float(m.group(1)), float(m.group(2))) + +To create a mapping from the PostgreSQL type (either standard or user-defined), +its ``oid`` must be known. It can be retrieved either by the second column of +the cursor description:: + + curs.execute("SELECT NULL::point") + point_oid = curs.description[0][1] # usually returns 600 + +or by querying the system catalogs for the type name and namespace (the +namespace for system objects is ``pg_catalog``):: + + curs.execute(""" + SELECT pg_type.oid + FROM pg_type JOIN pg_namespace + ON typnamespace = pg_namespace.oid + WHERE typname = %(typename)s + AND nspname = %(namespace)s""", + {'typename': 'point', 'namespace': 'pg_catalog'}) + + point_oid = curs.fetchone()[0] + +After you know the object ``oid``, you must can and register the new type:: + + POINT = psycopg2.extensions.new_type((point_oid,), "POINT", cast_point) + psycopg2.extensions.register_type(POINT) + +The `new_type()` function binds the object oids (more than one can be +specified) to the adapter function. `register_type()` completes the spell. +Conversion is automatically performed when a column whose type is a registered +``oid`` is read:: + + curs.execute("SELECT '(10.2,20.3)'::point") + point = curs.fetchone()[0] + print type(point), point.x, point.y + # Prints: " 10.2 20.3" + + +Working with times and dates +============================ + + +Receiving NOTIFYs +================= + + +Using COPY TO and COPY FROM +=========================== + +psycopg2 `cursor` object provides an interface to the efficient `PostgreSQL +COPY command`__ to move data from files to tables and back. + +The `.copy_to(file, table)` method writes the content of the table +named ``table`` *to* the file-like object ``file``. ``file`` must have a +``write()`` method. + +The `.copy_from(file, table)` reads data *from* the file-like object +``file`` appending them to the table named ``table``. ``file`` must have both +``read()`` and ``readline()`` method. + +Both methods accept two optional arguments: ``sep`` (defaulting to a tab) is +the columns separator and ``null`` (defaulting to ``\N``) represents ``NULL`` +values in the file. + +.. __: http://www.postgresql.org/docs/8.1/static/sql-copy.html + + +PostgreSQL status message and executed query +============================================ + +`cursor` objects have two special fields related to the last executed query: + + - `.query` is the textual representation (str or unicode, depending on what + was passed to `.execute()` as first argument) of the query *after* argument + binding and mogrification has been applied. To put it another way, `.query` + is the *exact* query that was sent to the PostgreSQL backend. + + - `.statusmessage` is the status message that the backend sent upon query + execution. It usually contains the basic type of the query (SELECT, + INSERT, UPDATE, ...) and some additional information like the number of + rows updated and so on. Refer to the PostgreSQL manual for more + information. diff --git a/psycopg2/examples/binary.py b/psycopg2/examples/binary.py new file mode 100644 index 0000000..eaa8f1e --- /dev/null +++ b/psycopg2/examples/binary.py @@ -0,0 +1,89 @@ +# binary.py - working with binary data +# +# Copyright (C) 2001-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +curs = conn.cursor() +try: + curs.execute("CREATE TABLE test_binary (id int4, name text, img bytea)") +except: + conn.rollback() + curs.execute("DROP TABLE test_binary") + curs.execute("CREATE TABLE test_binary (id int4, name text, img bytea)") +conn.commit() + +# first we try two inserts, one with an explicit Binary call and the other +# using a buffer on a file object. + +data1 = {'id':1, 'name':'somehackers.jpg', + 'img':psycopg2.Binary(open('somehackers.jpg').read())} +data2 = {'id':2, 'name':'whereareyou.jpg', + 'img':buffer(open('whereareyou.jpg').read())} + +curs.execute("""INSERT INTO test_binary + VALUES (%(id)s, %(name)s, %(img)s)""", data1) +curs.execute("""INSERT INTO test_binary + VALUES (%(id)s, %(name)s, %(img)s)""", data2) + +# now we try to extract the images as simple text strings + +print "Extracting the images as strings..." +curs.execute("SELECT * FROM test_binary") + +for row in curs.fetchall(): + name, ext = row[1].split('.') + new_name = name + '_S.' + ext + print " writing %s to %s ..." % (name+'.'+ext, new_name), + open(new_name, 'wb').write(row[2]) + print "done" + print " python type of image data is", type(row[2]) + +# extract exactly the same data but using a binary cursor + +print "Extracting the images using a binary cursor:" + +curs.execute("""DECLARE zot CURSOR FOR + SELECT img, name FROM test_binary FOR READ ONLY""") +curs.execute("""FETCH ALL FROM zot""") + +for row in curs.fetchall(): + name, ext = row[1].split('.') + new_name = name + '_B.' + ext + print " writing %s to %s ..." % (name+'.'+ext, new_name), + open(new_name, 'wb').write(row[0]) + print "done" + print " python type of image data is", type(row[0]) + +# this rollback is requires because we can't drop a table with a binary cusor +# declared and still open +conn.rollback() + +curs.execute("DROP TABLE test_binary") +conn.commit() + +print "\nNow try to load the new images, to check it worked!" diff --git a/psycopg2/examples/copy_from.py b/psycopg2/examples/copy_from.py new file mode 100644 index 0000000..edd3294 --- /dev/null +++ b/psycopg2/examples/copy_from.py @@ -0,0 +1,178 @@ +# copy_from.py -- example about copy_from +# +# Copyright (C) 2002 Tom Jenkins +# Copyright (C) 2005 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import os +import StringIO +import psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +curs = conn.cursor() +try: + curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)") +except: + conn.rollback() + curs.execute("DROP TABLE test_copy") + curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)") +conn.commit() + +# copy_from with default arguments, from open file + +io = open('copy_from.txt', 'wr') +data = ['Tom\tJenkins\t37\n', + 'Madonna\t\N\t45\n', + 'Federico\tDi Gregorio\t\N\n'] +io.writelines(data) +io.close() + +io = open('copy_from.txt', 'r') +curs.copy_from(io, 'test_copy') +print "1) Copy %d records from file object " % len(data) + \ + "using defaults (sep: \\t and null = \\N)" +io.close() + +curs.execute("SELECT * FROM test_copy") +rows = curs.fetchall() +print " Select returned %d rows" % len(rows) + +for r in rows: + print " %s %s\t%s" % (r[0], r[1], r[2]) +curs.execute("delete from test_copy") +conn.commit() + +# copy_from using custom separator, from open file + +io = open('copy_from.txt', 'wr') +data = ['Tom:Jenkins:37\n', + 'Madonna:\N:45\n', + 'Federico:Di Gregorio:\N\n'] +io.writelines(data) +io.close() + +io = open('copy_from.txt', 'r') +curs.copy_from(io, 'test_copy', ':') +print "2) Copy %d records from file object using sep = :" % len(data) +io.close() + +curs.execute("SELECT * FROM test_copy") +rows = curs.fetchall() +print " Select returned %d rows" % len(rows) + +for r in rows: + print " %s %s\t%s" % (r[0], r[1], r[2]) +curs.execute("delete from test_copy") +conn.commit() + +# copy_from using custom null identifier, from open file + +io = open('copy_from.txt', 'wr') +data = ['Tom\tJenkins\t37\n', + 'Madonna\tNULL\t45\n', + 'Federico\tDi Gregorio\tNULL\n'] +io.writelines(data) +io.close() + +io = open('copy_from.txt', 'r') +curs.copy_from(io, 'test_copy', null='NULL') +print "3) Copy %d records from file object using null = NULL" % len(data) +io.close() + +curs.execute("SELECT * FROM test_copy") +rows = curs.fetchall() +print " Select using cursor returned %d rows" % len(rows) + +for r in rows: + print " %s %s\t%s" % (r[0], r[1], r[2]) +curs.execute("delete from test_copy") +conn.commit() + +# copy_from using custom separator and null identifier + +io = open('copy_from.txt', 'wr') +data = ['Tom:Jenkins:37\n', 'Madonna:NULL:45\n', 'Federico:Di Gregorio:NULL\n'] +io.writelines(data) +io.close() + +io = open('copy_from.txt', 'r') +curs.copy_from(io, 'test_copy', ':', 'NULL') +print "4) Copy %d records from file object " % len(data) + \ + "using sep = : and null = NULL" +io.close() + +curs.execute("SELECT * FROM test_copy") +rows = curs.fetchall() +print " Select using cursor returned %d rows" % len(rows) + +for r in rows: + print " %s %s\t%s" % (r[0], r[1], r[2]) +curs.execute("delete from test_copy") +conn.commit() + +# anything can be used as a file if it has .read() and .readline() methods + +data = StringIO.StringIO() +data.write('\n'.join(['Tom\tJenkins\t37', + 'Madonna\t\N\t45', + 'Federico\tDi Gregorio\t\N'])) +data.seek(0) + +curs.copy_from(data, 'test_copy') +print "5) Copy 3 records from StringIO object using defaults" + +curs.execute("SELECT * FROM test_copy") +rows = curs.fetchall() +print " Select using cursor returned %d rows" % len(rows) + +for r in rows: + print " %s %s\t%s" % (r[0], r[1], r[2]) +curs.execute("delete from test_copy") +conn.commit() + +# simple error test + +print "6) About to raise an error" +data = StringIO.StringIO() +data.write('\n'.join(['Tom\tJenkins\t37', + 'Madonna\t\N\t45', + 'Federico\tDi Gregorio\taaa'])) +data.seek(0) + +try: + curs.copy_from(data, 'test_copy') +except StandardError, err: + conn.rollback() + print " Catched error (as expected):\n", err + +conn.rollback() + +curs.execute("DROP TABLE test_copy") +os.unlink('copy_from.txt') +conn.commit() + + + diff --git a/psycopg2/examples/copy_to.py b/psycopg2/examples/copy_to.py new file mode 100644 index 0000000..5570fbc --- /dev/null +++ b/psycopg2/examples/copy_to.py @@ -0,0 +1,104 @@ +# copy_to.py -- example about copy_to +# +# Copyright (C) 2002 Tom Jenkins +# Copyright (C) 2005 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import os +import StringIO +import psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +curs = conn.cursor() +try: + curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)") +except: + conn.rollback() + curs.execute("DROP TABLE test_copy") + curs.execute("CREATE TABLE test_copy (fld1 text, fld2 text, fld3 int4)") +conn.commit() + +# demostrate copy_to functionality +data = [('Tom', 'Jenkins', '37'), + ('Madonna', None, '45'), + ('Federico', 'Di Gregorio', None)] +query = "INSERT INTO test_copy VALUES (%s, %s, %s)" +curs.executemany(query, data) +conn.commit() + +# copy_to using defaults +io = open('copy_to.txt', 'w') +curs.copy_to(io, 'test_copy') +print "1) Copy %d records into file object using defaults: " % len (data) + \ + "sep = \\t and null = \\N" +io.close() + +rows = open('copy_to.txt', 'r').readlines() +print " File has %d rows:" % len(rows) + +for r in rows: + print " ", r, + +# copy_to using custom separator +io = open('copy_to.txt', 'w') +curs.copy_to(io, 'test_copy', ':') +print "2) Copy %d records into file object using sep = :" % len(data) +io.close() + +rows = open('copy_to.txt', 'r').readlines() +print " File has %d rows:" % len(rows) + +for r in rows: + print " ", r, + +# copy_to using custom null identifier +io = open('copy_to.txt', 'w') +curs.copy_to(io, 'test_copy', null='NULL') +print "3) Copy %d records into file object using null = NULL" % len(data) +io.close() + +rows = open('copy_to.txt', 'r').readlines() +print " File has %d rows:" % len(rows) + +for r in rows: + print " ", r, + +# copy_to using custom separator and null identifier +io = open('copy_to.txt', 'w') +curs.copy_to(io, 'test_copy', ':', 'NULL') +print "4) Copy %d records into file object using sep = : and null ) NULL" % \ + len(data) +io.close() + +rows = open('copy_to.txt', 'r').readlines() +print " File has %d rows:" % len(rows) + +for r in rows: + print " ", r, + +curs.execute("DROP TABLE test_copy") +os.unlink('copy_to.txt') +conn.commit() diff --git a/psycopg2/examples/cursor.py b/psycopg2/examples/cursor.py new file mode 100644 index 0000000..54cb5e7 --- /dev/null +++ b/psycopg2/examples/cursor.py @@ -0,0 +1,63 @@ +# cursor.py - how to subclass the cursor type +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below this line (except for experimenting) + +import sys +import psycopg2 +import psycopg2.extensions + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dsn:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + + +class NoDataError(psycopg2.ProgrammingError): + """Exception that will be raised by our cursor.""" + pass + +class Cursor(psycopg2.extensions.cursor): + """A custom cursor.""" + + def fetchone(self): + """Like fetchone but raise an exception if no data is available. + + Note that to have .fetchmany() and .fetchall() to raise the same + exception we'll have to override them too; even if internally psycopg + uses the same function to fetch rows, the code path from Python is + different. + """ + d = psycopg2.extensions.cursor.fetchone(self) + if d is None: + raise NoDataError("no more data") + return d + +curs = conn.cursor(cursor_factory=Cursor) +curs.execute("SELECT 1 AS foo") +print "Result of fetchone():", curs.fetchone() + +# now let's raise the exception +try: + curs.fetchone() +except NoDataError, err: + print "Exception caugth:", err + +conn.rollback() diff --git a/psycopg2/examples/dialtone.py b/psycopg2/examples/dialtone.py new file mode 100644 index 0000000..3a55686 --- /dev/null +++ b/psycopg2/examples/dialtone.py @@ -0,0 +1,144 @@ +""" +This example/recipe has been contributed by Valentino Volonghi (dialtone) + +Mapping arbitrary objects to a PostgreSQL database with psycopg2 + +- Problem + +You need to store arbitrary objects in a PostgreSQL database without being +intrusive for your classes (don't want inheritance from an 'Item' or +'Persistent' object). + +- Solution +""" + +from datetime import datetime + +import psycopg2 +from psycopg2.extensions import adapt, register_adapter + +try: + sorted() +except: + def sorted(seq): + seq.sort() + return seq + +# Here is the adapter for every object that we may ever need to +# insert in the database. It receives the original object and does +# its job on that instance + +class ObjectMapper(object): + def __init__(self, orig, curs=None): + self.orig = orig + self.tmp = {} + self.items, self.fields = self._gatherState() + + def _gatherState(self): + adaptee_name = self.orig.__class__.__name__ + fields = sorted([(field, getattr(self.orig, field)) + for field in persistent_fields[adaptee_name]]) + items = [] + for item, value in fields: + items.append(item) + return items, fields + + def getTableName(self): + return self.orig.__class__.__name__ + + def getMappedValues(self): + tmp = [] + for i in self.items: + tmp.append("%%(%s)s"%i) + return ", ".join(tmp) + + def getValuesDict(self): + return dict(self.fields) + + def getFields(self): + return self.items + + def generateInsert(self): + qry = "INSERT INTO" + qry += " " + self.getTableName() + " (" + qry += ", ".join(self.getFields()) + ") VALUES (" + qry += self.getMappedValues() + ")" + return qry, self.getValuesDict() + +# Here are the objects +class Album(object): + id = 0 + def __init__(self): + self.creation_time = datetime.now() + self.album_id = self.id + Album.id = Album.id + 1 + self.binary_data = buffer('12312312312121') + +class Order(object): + id = 0 + def __init__(self): + self.items = ['rice','chocolate'] + self.price = 34 + self.order_id = self.id + Order.id = Order.id + 1 + +register_adapter(Album, ObjectMapper) +register_adapter(Order, ObjectMapper) + +# Describe what is needed to save on each object +# This is actually just configuration, you can use xml with a parser if you +# like to have plenty of wasted CPU cycles ;P. + +persistent_fields = {'Album': ['album_id', 'creation_time', 'binary_data'], + 'Order': ['order_id', 'items', 'price'] + } + +print adapt(Album()).generateInsert() +print adapt(Album()).generateInsert() +print adapt(Album()).generateInsert() +print adapt(Order()).generateInsert() +print adapt(Order()).generateInsert() +print adapt(Order()).generateInsert() + +""" +- Discussion + +Psycopg 2 has a great new feature: adaptation. The big thing about +adaptation is that it enable the programmer to glue most of the +code out there without many difficulties. + +This recipe tries to focus the attention on a way to generate SQL queries to +insert completely new objects inside a database. As you can see objects do +not know anything about the code that is handling them. We specify all the +fields that we need for each object through the persistent_fields dict. + +The most important lines of this recipe are: + register_adapter(Album, ObjectMapper) + register_adapter(Order, ObjectMapper) + +In these line we notify the system that when we call adapt with an Album instance +as an argument we want it to istantiate ObjectMapper passing the Album instance +as argument (self.orig in the ObjectMapper class). + +The output is something like this (for each call to generateInsert): + +('INSERT INTO Album (album_id, binary_data, creation_time) VALUES + (%(album_id)s, %(binary_data)s, %(creation_time)s)', + + {'binary_data': , + 'creation_time': datetime.datetime(2004, 9, 10, 20, 48, 29, 633728), + 'album_id': 1} +) + +This is a tuple of {SQL_QUERY, FILLING_DICT}, and all the quoting/converting +stuff (from python's datetime to postgres s and from python's buffer to +postgres' blob) is handled with the same adaptation process hunder the hood +by psycopg2. + +At last, just notice that ObjectMapper is working for both Album and Order +instances without any glitches at all, and both classes could have easily been +coming from closed source libraries or C coded ones (which are not easily +modified), whereas a common pattern in todays ORMs or OODBs is to provide +a basic 'Persistent' object that already knows how to store itself in the +database. +""" diff --git a/psycopg2/examples/dict.py b/psycopg2/examples/dict.py new file mode 100644 index 0000000..37dc74a --- /dev/null +++ b/psycopg2/examples/dict.py @@ -0,0 +1,45 @@ +# dict.py - using DictCUrsor/DictRow +# +# Copyright (C) 2005 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below this line (except for experimenting) + +import sys +import psycopg2 +import psycopg2.extras + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dsn:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + + +curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) +curs.execute("SELECT 1 AS foo, 'cip' AS bar, date(now()) as zot") + +data = curs.fetchone() +print "Some data accessed both as tuple and dict:" +print " ", data['foo'], data['bar'], data['zot'] +print " ", data[0], data[1], data[2] + +# execute another query and demostrate we can still access the row +curs.execute("SELECT 2 AS foo") +print "Some more data accessed both as tuple and dict:" +print " ", data['foo'], data['bar'], data['zot'] +print " ", data[0], data[1], data[2] diff --git a/psycopg2/examples/dt.py b/psycopg2/examples/dt.py new file mode 100644 index 0000000..76f0c78 --- /dev/null +++ b/psycopg2/examples/dt.py @@ -0,0 +1,99 @@ +# datetime.py - example of using date and time types +# +# Copyright (C) 2001-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import psycopg2 +import mx.DateTime +import datetime + +from psycopg2.extensions import adapt + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +curs = conn.cursor() + +try: + curs.execute("""CREATE TABLE test_dt ( + k int4, d date, t time, dt timestamp, z interval)""") +except: + conn.rollback() + curs.execute("DROP TABLE test_dt") + curs.execute("""CREATE TABLE test_dt ( + k int4, d date, t time, dt timestamp, z interval)""") +conn.commit() + +# build and insert some data using mx.DateTime +mx1 = ( + 1, + mx.DateTime.Date(2004, 10, 19), + mx.DateTime.Time(0, 11, 17.015), + mx.DateTime.Timestamp(2004, 10, 19, 0, 11, 17.5), + mx.DateTime.DateTimeDelta(13, 15, 17, 59.9)) + +from psycopg2.extensions import adapt +import psycopg2.extras +print adapt(mx1) + +print "Inserting mx.DateTime values..." +curs.execute("INSERT INTO test_dt VALUES (%s, %s, %s, %s, %s)", mx1) + +# build and insert some values using the datetime adapters +dt1 = ( + 2, + datetime.date(2004, 10, 19), + datetime.time(0, 11, 17, 15000), + datetime.datetime(2004, 10, 19, 0, 11, 17, 500000), + datetime.timedelta(13, 15*3600+17*60+59, 900000)) + +print "Inserting Python datetime values..." +curs.execute("INSERT INTO test_dt VALUES (%s, %s, %s, %s, %s)", dt1) + +# now extract the row from database and print them +print "Extracting values inserted with mx.DateTime wrappers:" +curs.execute("SELECT d, t, dt, z FROM test_dt WHERE k = 1") +for n, x in zip(mx1[1:], curs.fetchone()): + try: + # this will work only is psycopg has been compiled with datetime + # as the default typecaster for date/time values + s = repr(n) + "\n -> " + str(adapt(n)) + \ + "\n -> " + repr(x) + "\n -> " + x.isoformat() + except: + s = repr(n) + "\n -> " + str(adapt(n)) + \ + "\n -> " + repr(x) + "\n -> " + str(x) + print s +print + +print "Extracting values inserted with Python datetime wrappers:" +curs.execute("SELECT d, t, dt, z FROM test_dt WHERE k = 2") +for n, x in zip(dt1[1:], curs.fetchone()): + try: + # this will work only is psycopg has been compiled with datetime + # as the default typecaster for date/time values + s = repr(n) + "\n -> " + repr(x) + "\n -> " + x.isoformat() + except: + s = repr(n) + "\n -> " + repr(x) + "\n -> " + str(x) + print s +print + +curs.execute("DROP TABLE test_dt") +conn.commit() diff --git a/psycopg2/examples/encoding.py b/psycopg2/examples/encoding.py new file mode 100644 index 0000000..da57bcf --- /dev/null +++ b/psycopg2/examples/encoding.py @@ -0,0 +1,105 @@ +# enkoding.py - show to change client enkoding (and test it works) +# -*- encoding: utf8 -*- +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below this line (except for experimenting) + +import sys +import psycopg2 +import psycopg2.extensions + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Initial encoding for this connection is", conn.encoding + +print "\n** This example is supposed to be run in a UNICODE terminal! **\n" + +print "Available encodings:" +encs = psycopg2.extensions.encodings.items() +encs.sort() +for a, b in encs: + print " ", a, "<->", b + +print "Using STRING typecaster" +print "Setting backend encoding to LATIN1 and executing queries:" +conn.set_client_encoding('LATIN1') +curs = conn.cursor() +curs.execute("SELECT %s::TEXT AS foo", ('àèìòù',)) +x = curs.fetchone()[0] +print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x) +curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',)) +x = curs.fetchone()[0] +print " ->", unicode(x, 'latin-1').encode('utf-8'), type(x) + +print "Setting backend encoding to UTF8 and executing queries:" +conn.set_client_encoding('UNICODE') +curs = conn.cursor() +curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),)) +x = curs.fetchone()[0] +print " ->", x, type(x) +curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',)) +x = curs.fetchone()[0] +print " ->", x, type(x) + +print "Using UNICODE typecaster" +psycopg2.extensions.register_type(psycopg2.extensions.UNICODE) + +print "Setting backend encoding to LATIN1 and executing queries:" +conn.set_client_encoding('LATIN1') +curs = conn.cursor() +curs.execute("SELECT %s::TEXT AS foo", ('àèìòù',)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) +curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) + +print "Setting backend encoding to UTF8 and executing queries:" +conn.set_client_encoding('UNICODE') +curs = conn.cursor() +curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) +curs.execute("SELECT %s::TEXT AS foo", (u'àèìòù',)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) + +print "Executing full UNICODE queries" + +print "Setting backend encoding to LATIN1 and executing queries:" +conn.set_client_encoding('LATIN1') +curs = conn.cursor() +curs.execute(u"SELECT %s::TEXT AS foo", ('àèìòù',)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) +curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù',)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) + +print "Setting backend encoding to UTF8 and executing queries:" +conn.set_client_encoding('UNICODE') +curs = conn.cursor() +curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù'.encode('utf-8'),)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) +curs.execute(u"SELECT %s::TEXT AS foo", (u'àèìòù',)) +x = curs.fetchone()[0] +print " ->", x.encode('utf-8'), ":", type(x) diff --git a/psycopg2/examples/fetch.py b/psycopg2/examples/fetch.py new file mode 100644 index 0000000..dab0a41 --- /dev/null +++ b/psycopg2/examples/fetch.py @@ -0,0 +1,81 @@ +# fetch.py -- example about declaring cursors +# +# Copyright (C) 2001-2005 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +curs = conn.cursor() +try: + curs.execute("CREATE TABLE test_fetch (val int4)") +except: + conn.rollback() + curs.execute("DROP TABLE test_fetch") + curs.execute("CREATE TABLE test_fetch (val int4)") +conn.commit() + +# we use this function to format the output + +def flatten(l): + """Flattens list of tuples l.""" + return map(lambda x: x[0], l) + +# insert 20 rows in the table + +for i in range(20): + curs.execute("INSERT INTO test_fetch VALUES(%s)", (i,)) +conn.commit() + +# does some nice tricks with the transaction and postgres cursors +# (remember to always commit or rollback before a DECLARE) +# +# we don't need to DECLARE ourselves, psycopg now support named +# cursors (but we leave the code here, comments, as an example of +# what psycopg is doing under the hood) +# +#curs.execute("DECLARE crs CURSOR FOR SELECT * FROM test_fetch") +#curs.execute("FETCH 10 FROM crs") +#print "First 10 rows:", flatten(curs.fetchall()) +#curs.execute("MOVE -5 FROM crs") +#print "Moved back cursor by 5 rows (to row 5.)" +#curs.execute("FETCH 10 FROM crs") +#print "Another 10 rows:", flatten(curs.fetchall()) +#curs.execute("FETCH 10 FROM crs") +#print "The remaining rows:", flatten(curs.fetchall()) + +ncurs = conn.cursor("crs") +ncurs.execute("SELECT * FROM test_fetch") +print "First 10 rows:", flatten(ncurs.fetchmany(10)) +ncurs.scroll(-5) +print "Moved back cursor by 5 rows (to row 5.)" +print "Another 10 rows:", flatten(ncurs.fetchmany(10)) +print "Another one:", list(ncurs.fetchone()) +print "The remaining rows:", flatten(ncurs.fetchall()) +conn.rollback() + +curs.execute("DROP TABLE test_fetch") +conn.commit() diff --git a/psycopg2/examples/lastrowid.py b/psycopg2/examples/lastrowid.py new file mode 100644 index 0000000..205ef6c --- /dev/null +++ b/psycopg2/examples/lastrowid.py @@ -0,0 +1,59 @@ +# lastrowid.py - example of using .lastrowid attribute +# +# Copyright (C) 2001-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys, psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +curs = conn.cursor() + +try: + curs.execute("CREATE TABLE test_oid (name text, surname text)") +except: + conn.rollback() + curs.execute("DROP TABLE test_oid") + curs.execute("CREATE TABLE test_oid (name text, surname text)") +conn.commit() + +data = ({'name':'Federico', 'surname':'Di Gregorio'}, + {'name':'Pierluigi', 'surname':'Di Nunzio'}) + +curs.execute("""INSERT INTO test_oid + VALUES (%(name)s, %(surname)s)""", data[0]) + +foid = curs.lastrowid +print "Oid for %(name)s %(surname)s" % data[0], "is", foid + +curs.execute("""INSERT INTO test_oid + VALUES (%(name)s, %(surname)s)""", data[1]) +moid = curs.lastrowid +print "Oid for %(name)s %(surname)s" % data[1], "is", moid + +curs.execute("SELECT * FROM test_oid WHERE oid = %s", (foid,)) +print "Oid", foid, "selected %s %s" % curs.fetchone() + +curs.execute("SELECT * FROM test_oid WHERE oid = %s", (moid,)) +print "Oid", moid, "selected %s %s" % curs.fetchone() + +curs.execute("DROP TABLE test_oid") +conn.commit() diff --git a/psycopg2/examples/mogrify.py b/psycopg2/examples/mogrify.py new file mode 100644 index 0000000..480c491 --- /dev/null +++ b/psycopg2/examples/mogrify.py @@ -0,0 +1,47 @@ +# mogrify.py - test all possible simple type mogrifications +# -*- encoding: latin1 -*- +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below this line (except for experimenting) + +import sys, psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN + +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +curs = conn.cursor() +curs.execute("SELECT %(foo)s AS foo", {'foo':'bar'}) +curs.execute("SELECT %(foo)s AS foo", {'foo':None}) +curs.execute("SELECT %(foo)s AS foo", {'foo':True}) +curs.execute("SELECT %(foo)s AS foo", {'foo':42}) +curs.execute("SELECT %(foo)s AS foo", {'foo':u'yatt�!'}) +curs.execute("SELECT %(foo)s AS foo", {'foo':u'bar'}) + +print curs.mogrify("SELECT %(foo)s AS foo", {'foo':'bar'}) +print curs.mogrify("SELECT %(foo)s AS foo", {'foo':None}) +print curs.mogrify("SELECT %(foo)s AS foo", {'foo':True}) +print curs.mogrify("SELECT %(foo)s AS foo", {'foo':42}) +print curs.mogrify("SELECT %(foo)s AS foo", {'foo':u'yatt�!'}) +print curs.mogrify("SELECT %(foo)s AS foo", {'foo':u'bar'}) + +conn.rollback() diff --git a/psycopg2/examples/myfirstrecipe.py b/psycopg2/examples/myfirstrecipe.py new file mode 100644 index 0000000..4ddc65e --- /dev/null +++ b/psycopg2/examples/myfirstrecipe.py @@ -0,0 +1,122 @@ +""" +Using a tuple as a bound variable in "SELECT ... IN (...)" clauses +in PostgreSQL using psycopg 2 + +Some time ago someone asked on the psycopg mailing list how to have a +bound variable expand to the right SQL for an SELECT IN clause: + + SELECT * FROM atable WHERE afield IN (value1, value2, value3) + +with the values to be used in the IN clause to be passed to the cursor +.execute() method in a tuple as a bound variable, i.e.: + + in_values = ("value1", "value2", "value3") + curs.execute("SELECT ... IN %s", (in_values,)) + +psycopg 1 does support typecasting from Python to PostgreSQL (and back) +only for simple types and this problem has no elegant solution (short or +writing a wrapper class returning the pre-quoted text in an __str__ +method. + +But psycopg 2 offers a simple and elegant solution by partially +implementing the Object Adaptation from PEP 246. psycopg 2 (still in +beta and currently labeled as 1.99.9) moves the type-casting logic into +external adapters and a somehow broken adapt() function. + +While the original adapt() takes 3 arguments, psycopg's one only takes +1: the bound variable to be adapted. The result is an object supporting +a not-yet well defined protocol that we can call IPsycopgSQLQuote: + + class IPsycopgSQLQuote: + + def getquoted(self): + "Returns a quoted string representing the bound variable." + + def getbinary(self): + "Returns a binary quoted string representing the bound variable." + + def getbuffer(self): + "Returns the wrapped object itself." + + __str__ = getquoted + +Then one of the functions (usually .getquoted()) is called by psycopg at +the right time to obtain the right, sql-quoted representation for the +corresponding bound variable. + +The nice part is that the default, built-in adapters, derived from +psycopg 1 tyecasting code can be overridden by the programmer, simply +replacing them in the psycopg.extensions.adapters dictionary. + +Then the solution to the original problem is now obvious: write an +adapter that adapts tuple objects into the right SQL string, by calling +recursively adapt() on each element. + +Note: psycopg 2 adapter code is still very young and will probably move +to a more 'standard' (3 arguments) implementation for the adapt() +function; as long as that does not slow down too much query execution. + +Psycopg 2 development can be tracked on the psycopg mailing list: + + http://lists.initd.org/mailman/listinfo/psycopg + +and on the psycopg 2 wiki: + + http://wiki.initd.org/Projects/Psycopg2 + +""" + +import psycopg2 +import psycopg2.extensions +from psycopg2.extensions import adapt as psycoadapt +from psycopg2.extensions import register_adapter + +class AsIs(object): + """An adapter that just return the object 'as is'. + + psycopg 1.99.9 has some optimizations that make impossible to call + adapt() without adding some basic adapters externally. This limitation + will be lifted in a future release. + """ + def __init__(self, obj): + self.__obj = obj + def getquoted(self): + return self.__obj + +class SQL_IN(object): + """Adapt a tuple to an SQL quotable object.""" + + def __init__(self, seq): + self._seq = seq + + def prepare(self, conn): + pass + + def getquoted(self): + # this is the important line: note how every object in the + # list is adapted and then how getquoted() is called on it + + qobjs = [str(psycoadapt(o).getquoted()) for o in self._seq] + + return '(' + ', '.join(qobjs) + ')' + + __str__ = getquoted + + +# add our new adapter class to psycopg list of adapters +register_adapter(tuple, SQL_IN) +register_adapter(float, AsIs) +register_adapter(int, AsIs) + +# usually we would call: +# +# conn = psycopg.connect("...") +# curs = conn.cursor() +# curs.execute("SELECT ...", (("this", "is", "the", "tuple"),)) +# +# but we have no connection to a database right now, so we just check +# the SQL_IN class by calling psycopg's adapt() directly: + +if __name__ == '__main__': + print "Note how the string will be SQL-quoted, but the number will not:" + print psycoadapt(("this is an 'sql quoted' str\\ing", 1, 2.0)) diff --git a/psycopg2/examples/notify.py b/psycopg2/examples/notify.py new file mode 100644 index 0000000..83761b9 --- /dev/null +++ b/psycopg2/examples/notify.py @@ -0,0 +1,43 @@ +# notify.py - example of getting notifies +# +# Copyright (C) 2001-2005 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import psycopg2 +import select + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +conn.set_isolation_level(0) +curs = conn.cursor() + +curs.execute("listen test") + +print "Waiting for 'NOTIFY test'" +while 1: + if select.select([curs],[],[],5)==([],[],[]): + print "Timeout" + else: + if curs.isready(): + print "Got NOTIFY: %s" % str(curs.connection.notifies.pop()) diff --git a/psycopg2/examples/simple.py b/psycopg2/examples/simple.py new file mode 100644 index 0000000..2306be1 --- /dev/null +++ b/psycopg2/examples/simple.py @@ -0,0 +1,53 @@ +# simple.py - very simple example of plain DBAPI-2.0 usage +# currently used as test-me-stress-me script for psycopg 2.0 +# +# Copyright (C) 2001-2003 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below this line (except for experimenting) + +class SimpleQuoter(object): + def sqlquote(x=None): + return "'bar'" + +import sys +import psycopg2 + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Encoding for this connection is", conn.encoding + +curs = conn.cursor() +curs.execute("SELECT 1 AS foo") +print curs.fetchone() +curs.execute("SELECT 1 AS foo") +print curs.fetchmany() +curs.execute("SELECT 1 AS foo") +print curs.fetchall() + +conn.rollback() + +sys.exit(0) + +curs.execute("SELECT 1 AS foo", async=1) + +curs.execute("SELECT %(foo)s AS foo", {'foo':'bar'}) +curs.execute("SELECT %(foo)s AS foo", {'foo':None}) +curs.execute("SELECT %(foo)f AS foo", {'foo':42}) +curs.execute("SELECT %(foo)s AS foo", {'foo':SimpleQuoter()}) diff --git a/psycopg2/examples/somehackers.jpg b/psycopg2/examples/somehackers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bb6e013f8859dbeff0e11a88c4c3ff641aa79dc GIT binary patch literal 22565 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 Tvu)H-lCbpplUdhZK0p82LvO}& literal 0 HcmV?d00001 diff --git a/psycopg2/examples/threads.py b/psycopg2/examples/threads.py new file mode 100644 index 0000000..5477aa8 --- /dev/null +++ b/psycopg2/examples/threads.py @@ -0,0 +1,160 @@ +# threads.py -- example of multiple threads using psycopg +# -*- encoding: latin1 -*- +# +# Copyright (C) 2001-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## some others parameters +INSERT_THREADS = ('A', 'B', 'C') +SELECT_THREADS = ('1', '2') + +ROWS = 1000 + +COMMIT_STEP = 20 +SELECT_SIZE = 10000 +SELECT_STEP = 500 +SELECT_DIV = 250 + +# the available modes are: +# 0 - one connection for all insert and one for all select threads +# 1 - connections generated using the connection pool + +MODE = 1 + +## don't modify anything below tis line (except for experimenting) + +import sys, psycopg2, threading +from psycopg2.pool import ThreadedConnectionPool + +if len(sys.argv) > 1: + DSN = sys.argv[1] +if len(sys.argv) > 2: + MODE = int(sys.argv[2]) + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +curs = conn.cursor() + +try: + curs.execute("""CREATE TABLE test_threads ( + name text, value1 int4, value2 float)""") +except: + conn.rollback() + curs.execute("DROP TABLE test_threads") + curs.execute("""CREATE TABLE test_threads ( + name text, value1 int4, value2 float)""") +conn.commit() + + +## this function inserts a big number of rows and creates and destroys +## a large number of cursors + +def insert_func(conn_or_pool, rows): + name = threading.currentThread().getName() + + if MODE == 0: + conn = conn_or_pool + else: + conn = conn_or_pool.getconn() + + for i in range(rows): + if divmod(i, COMMIT_STEP)[1] == 0: + conn.commit() + if MODE == 1: + conn_or_pool.putconn(conn) + s = name + ": COMMIT STEP " + str(i) + print s + if MODE == 1: + conn = conn_or_pool.getconn() + c = conn.cursor() + try: + c.execute("INSERT INTO test_threads VALUES (%s, %s, %s)", + (str(i), i, float(i))) + except psycopg2.ProgrammingError, err: + print name, ": an error occurred; skipping this insert" + print err + conn.commit() + +## a nice select function that prints the current number of rows in the +## database (and transefer them, putting some pressure on the network) + +def select_func(conn_or_pool, z): + name = threading.currentThread().getName() + + if MODE == 0: + conn = conn_or_pool + conn.set_isolation_level(0) + + for i in range(SELECT_SIZE): + if divmod(i, SELECT_STEP)[1] == 0: + try: + if MODE == 1: + conn = conn_or_pool.getconn() + conn.set_isolation_level(0) + c = conn.cursor() + c.execute("SELECT * FROM test_threads WHERE value2 < %s", + (int(i/z),)) + l = c.fetchall() + if MODE == 1: + conn_or_pool.putconn(conn) + s = name + ": number of rows fetched: " + str(len(l)) + print s + except psycopg2.ProgrammingError, err: + print name, ": an error occurred; skipping this select" + print err + +## create the connection pool or the connections +if MODE == 0: + conn_insert = psycopg2.connect(DSN) + conn_select = psycopg2.connect(DSN) +else: + m = len(INSERT_THREADS) + len(SELECT_THREADS) + n = m/2 + conn_insert = conn_select = ThreadedConnectionPool(n, m, DSN) + +## create the threads +threads = [] + +print "Creating INSERT threads:" +for name in INSERT_THREADS: + t = threading.Thread(None, insert_func, 'Thread-'+name, + (conn_insert, ROWS)) + t.setDaemon(0) + threads.append(t) + +print "Creating SELECT threads:" +for name in SELECT_THREADS: + t = threading.Thread(None, select_func, 'Thread-'+name, + (conn_select, SELECT_DIV)) + t.setDaemon(0) + threads.append(t) + +## really start the threads now +for t in threads: + t.start() + +# and wait for them to finish +for t in threads: + t.join() + print t.getName(), "exited OK" + + +conn.commit() +curs.execute("SELECT count(name) FROM test_threads") +print "Inserted", curs.fetchone()[0], "rows." + +curs.execute("DROP TABLE test_threads") +conn.commit() diff --git a/psycopg2/examples/tz.py b/psycopg2/examples/tz.py new file mode 100644 index 0000000..c27bf30 --- /dev/null +++ b/psycopg2/examples/tz.py @@ -0,0 +1,69 @@ +# tz.py - example of datetime objects with time zones +# -*- encoding: utf8 -*- +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below this line (except for experimenting) + +import sys +import psycopg2 +import datetime + +from psycopg2.tz import ZERO, LOCAL, FixedOffsetTimezone + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +curs = conn.cursor() + +try: + curs.execute("CREATE TABLE test_tz (t timestamp with time zone)") +except: + conn.rollback() + curs.execute("DROP TABLE test_tz") + curs.execute("CREATE TABLE test_tz (t timestamp with time zone)") +conn.commit() + +d = datetime.datetime(1971, 10, 19, 22, 30, 0, tzinfo=LOCAL) +curs.execute("INSERT INTO test_tz VALUES (%s)", (d,)) +print "Inserted timestamp with timezone:", d +print "Time zone:", d.tzinfo.tzname(d), "offset:", d.tzinfo.utcoffset(d) + +tz = FixedOffsetTimezone(-5*60, "EST") +d = datetime.datetime(1971, 10, 19, 22, 30, 0, tzinfo=tz) +curs.execute("INSERT INTO test_tz VALUES (%s)", (d,)) +print "Inserted timestamp with timezone:", d +print "Time zone:", d.tzinfo.tzname(d), "offset:", d.tzinfo.utcoffset(d) + +curs.execute("SELECT * FROM test_tz") +d = curs.fetchone()[0] +curs.execute("INSERT INTO test_tz VALUES (%s)", (d,)) +print "Inserted SELECTed timestamp:", d +print "Time zone:", d.tzinfo.tzname(d), "offset:", d.tzinfo.utcoffset(d) + +curs.execute("SELECT * FROM test_tz") +for d in curs: + u = d[0].utcoffset() or ZERO + print "UTC time: ", d[0] - u + print "Local time:", d[0] + print "Time zone:", d[0].tzinfo.tzname(d[0]), d[0].tzinfo.utcoffset(d[0]) + + +curs.execute("DROP TABLE test_tz") +conn.commit() diff --git a/psycopg2/examples/usercast.py b/psycopg2/examples/usercast.py new file mode 100644 index 0000000..5c8031f --- /dev/null +++ b/psycopg2/examples/usercast.py @@ -0,0 +1,126 @@ +# usercast.py -- example of user defined typecasters +# -*- encoding: latin-1 -*- +# +# Copyright (C) 2001-2005 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +## put in DSN your DSN string + +DSN = 'dbname=test' + +## don't modify anything below tis line (except for experimenting) + +import sys +import psycopg2 +import psycopg2.extensions +import whrandom + +# importing psycopg.extras will give us a nice tuple adapter: this is wrong +# because the adapter is meant to be used in SQL IN clauses while we use +# tuples to represent points but it works and the example is about Rect, not +# "Point" +import psycopg2.extras + +if len(sys.argv) > 1: + DSN = sys.argv[1] + +print "Opening connection using dns:", DSN +conn = psycopg2.connect(DSN) +print "Initial encoding for this connection is", conn.encoding + +curs = conn.cursor() +try: + curs.execute("CREATE TABLE test_cast (p1 point, p2 point, b box)") +except: + conn.rollback() + curs.execute("DROP TABLE test_cast") + curs.execute("CREATE TABLE test_cast (p1 point, p2 point, b box)") +conn.commit() + +# this is the callable object we use as a typecast (the typecast is +# usually a function, but we use a class, just to demonstrate the +# flexibility of the psycopg casting system + +class Rect(object): + """Very simple rectangle. + + Note that we use this type as a data holder, as an adapter of itself for + the ISQLQuote protocol used by psycopg's adapt() (see __confrom__ below) + and eventually as a type-caster for the data extracted from the database + (that's why __init__ takes the curs argument.) + """ + + def __init__(self, s=None, curs=None): + """Init the rectangle from the optional string s.""" + self.x = self.y = self.width = self.height = 0.0 + if s: self.from_string(s) + + def __conform__(self, proto): + """This is a terrible hack, just ignore proto and return self.""" + if proto == psycopg2.extensions.ISQLQuote: + return self + + def from_points(self, x0, y0, x1, y1): + """Init the rectangle from points.""" + if x0 > x1: (x0, x1) = (x1, x0) + if y0 > y1: (y0, y1) = (y1, y0) + self.x = x0 + self.y = y0 + self.width = x1 - x0 + self.height = y1 - y0 + + def from_string(self, s): + """Init the rectangle from a string.""" + seq = eval(s) + self.from_points(seq[0][0], seq[0][1], seq[1][0], seq[1][1]) + + def getquoted(self): + """Format self as a string usable by the db to represent a box.""" + s = "'((%d,%d),(%d,%d))'" % ( + self.x, self.y, self.x + self.width, self.y + self.height) + return s + + def show(self): + """Format a description of the box.""" + s = "X: %d\tY: %d\tWidth: %d\tHeight: %d" % ( + self.x, self.y, self.width, self.height) + return s + +# here we select from the empty table, just to grab the description +curs.execute("SELECT b FROM test_cast WHERE 0=1") +boxoid = curs.description[0][1] +print "Oid for the box datatype is", boxoid + +# and build the user cast object +BOX = psycopg2.extensions.new_type((boxoid,), "BOX", Rect) +psycopg2.extensions.register_type(BOX) + +# now insert 100 random data (2 points and a box in each row) +for i in range(100): + p1 = (whrandom.randint(0,100), whrandom.randint(0,100)) + p2 = (whrandom.randint(0,100), whrandom.randint(0,100)) + b = Rect() + b.from_points(whrandom.randint(0,100), whrandom.randint(0,100), + whrandom.randint(0,100), whrandom.randint(0,100)) + curs.execute("INSERT INTO test_cast VALUES ('%(p1)s', '%(p2)s', %(box)s)", + {'box':b, 'p1':p1, 'p2':p2}) +print "Added 100 boxed to the database" + +# select and print all boxes with at least one point inside +curs.execute("SELECT b FROM test_cast WHERE p1 @ b OR p2 @ b") +boxes = curs.fetchall() +print "Found %d boxes with at least a point inside:" % len(boxes) +for box in boxes: + print " ", box[0].show() + +curs.execute("DROP TABLE test_cast") +conn.commit() diff --git a/psycopg2/examples/whereareyou.jpg b/psycopg2/examples/whereareyou.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f508c0ba11e52031d7ce839da4f149a3f86a4b47 GIT binary patch literal 34980 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 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +# Import modules needed by _psycopg to allow tools like py2exe to do +# their work without bothering about the module dependencies. +# +# TODO: we should probably use the Warnings framework to signal a missing +# module instead of raising an exception (in case we're running a thin +# embedded Python or something even more devious.) + +import sys, warnings +if sys.version_info[0] >= 2 and sys.version_info[1] >= 3: + try: + import datetime as _psycopg_needs_datetime + except: + warnings.warn( + "can't import datetime module probably needed by _psycopg", + RuntimeWarning) +if sys.version_info[0] >= 2 and sys.version_info[1] >= 4: + try: + import decimal as _psycopg_needs_decimal + except: + warnings.warn( + "can't import decimal module probably needed by _psycopg", + RuntimeWarning) +from psycopg2 import tz +del sys, warnings + +# Import the DBAPI-2.0 stuff into top-level module. + +from _psycopg import BINARY, NUMBER, STRING, DATETIME, ROWID + +from _psycopg import Binary, Date, Time, Timestamp +from _psycopg import DateFromTicks, TimeFromTicks, TimestampFromTicks + +from _psycopg import Error, Warning, DataError, DatabaseError, ProgrammingError +from _psycopg import IntegrityError, InterfaceError, InternalError +from _psycopg import NotSupportedError, OperationalError + +from _psycopg import connect, apilevel, threadsafety, paramstyle +from _psycopg import __version__ + +__all__ = [ k for k in locals().keys() if not k.startswith('_') ] diff --git a/psycopg2/lib/extensions.py b/psycopg2/lib/extensions.py new file mode 100644 index 0000000..9233d1d --- /dev/null +++ b/psycopg2/lib/extensions.py @@ -0,0 +1,69 @@ +"""psycopg extensions to the DBAPI-2.0 + +This module holds all the extensions to the DBAPI-2.0 provided by psycopg. + +- `connection` -- the new-type inheritable connection class +- `cursor` -- the new-type inheritable cursor class +- `adapt()` -- exposes the PEP-246_ compatible adapting mechanism used + by psycopg to adapt Python types to PostgreSQL ones + +.. _PEP-246: http://www.python.org/peps/pep-0246.html +""" +# psycopg/extensions.py - DBAPI-2.0 extensions specific to psycopg +# +# Copyright (C) 2003-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +from _psycopg import UNICODE, INTEGER, LONGINTEGER, BOOLEAN, FLOAT +from _psycopg import TIME, DATE, INTERVAL + +from _psycopg import Boolean, QuotedString, AsIs +try: + from _psycopg import DateFromMx, TimeFromMx, TimestampFromMx + from _psycopg import IntervalFromMx +except: + pass +try: + from _psycopg import DateFromPy, TimeFromPy, TimestampFromPy + from _psycopg import IntervalFromPy +except: + pass + +from _psycopg import adapt, adapters, encodings, connection, cursor +from _psycopg import string_types, binary_types, new_type, register_type +from _psycopg import ISQLQuote + +"""Isolation level values.""" +ISOLATION_LEVEL_AUTOCOMMIT = 0 +ISOLATION_LEVEL_READ_COMMITTED = 1 +ISOLATION_LEVEL_SERIALIZABLE = 2 + +# PostgreSQL maps the the other standard values to already defined levels +ISOLATION_LEVEL_REPEATABLE_READ = ISOLATION_LEVEL_SERIALIZABLE +ISOLATION_LEVEL_READ_UNCOMMITTED = ISOLATION_LEVEL_READ_COMMITTED + +"""Transaction status values.""" +STATUS_SETUP = 0 +STATUS_READY = 1 +STATUS_BEGIN = 2 +STATUS_SYNC = 3 +STATUS_ASYNC = 4 + +# This is a usefull mnemonic to check if the connection is in a transaction +STATUS_IN_TRANSACTION = STATUS_BEGIN + + +def register_adapter(typ, callable): + """Register 'callable' as an ISQLQuote adapter for type 'typ'.""" + adapters[(typ, ISQLQuote)] = callable + +__all__ = [ k for k in locals().keys() if not k.startswith('_') ] diff --git a/psycopg2/lib/extras.py b/psycopg2/lib/extras.py new file mode 100644 index 0000000..847bdb7 --- /dev/null +++ b/psycopg2/lib/extras.py @@ -0,0 +1,235 @@ +"""Miscellaneous goodies for psycopg2 + +This module is a generic place used to hold little helper functions +and classes untill a better place in the distribution is found. +""" +# psycopg/extras.py - miscellaneous extra goodies for psycopg +# +# Copyright (C) 2003-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +import os +import time + +try: + import logging +except: + logging = None + +from psycopg2.extensions import cursor as _cursor +from psycopg2.extensions import connection as _connection +from psycopg2.extensions import register_adapter as _RA +from psycopg2.extensions import adapt as _A + + +class DictConnection(_connection): + """A connection that uses DictCursor automatically.""" + def cursor(self): + return _connection.cursor(self, cursor_factory=DictCursor) + +class DictCursor(_cursor): + """A cursor that keeps a list of column name -> index mappings.""" + + __query_executed = 0 + + def execute(self, query, vars=None, async=0): + self.row_factory = DictRow + self.index = {} + self.__query_executed = 1 + return _cursor.execute(self, query, vars, async) + + def callproc(self, procname, vars=None): + self.row_factory = DictRow + self.index = {} + self.__query_executed = 1 + return _cursor.callproc(self, procname, vars) + + def _build_index(self): + if self.__query_executed == 1 and self.description: + for i in range(len(self.description)): + self.index[self.description[i][0]] = i + self.__query_executed = 0 + + def fetchone(self): + res = _cursor.fetchone(self) + if self.__query_executed: + self._build_index() + return res + + def fetchmany(self, size=None): + res = _cursor.fetchmany(self, size) + if self.__query_executed: + self._build_index() + return res + + def fetchall(self): + res = _cursor.fetchall(self) + if self.__query_executed: + self._build_index() + return res + + def next(self): + res = _cursor.fetchone(self) + if res is None: + raise StopIteration() + if self.__query_executed: + self._build_index() + return res + +class DictRow(list): + """A row object that allow by-colun-name access to data.""" + + def __init__(self, cursor): + self._index = cursor.index + self[:] = [None] * len(cursor.description) + + def __getitem__(self, x): + if type(x) != int: + x = self._index[x] + return list.__getitem__(self, x) + + def items(self): + res = [] + for n, v in self._index.items(): + res.append((n, list.__getitem__(self, v))) + return res + + def keys(self): + return self._index.keys() + + def values(self): + return tuple(self[:]) + + def has_key(self, x): + return self._index.has_key(x) + + def get(self, x, default=None): + try: + return self[x] + except: + return default + + +class SQL_IN(object): + """Adapt any iterable to an SQL quotable object.""" + + def __init__(self, seq): + self._seq = seq + + def prepare(self, conn): + self._conn = conn + + def getquoted(self): + # this is the important line: note how every object in the + # list is adapted and then how getquoted() is called on it + pobjs = [_A(o) for o in self._seq] + for obj in pobjs: + if hasattr(obj, 'prepare'): + obj.prepare(self._conn) + qobjs = [str(o.getquoted()) for o in pobjs] + return '(' + ', '.join(qobjs) + ')' + + __str__ = getquoted + +_RA(tuple, SQL_IN) + + +class LoggingConnection(_connection): + """A connection that logs all queries to a file or logger object.""" + + def initialize(self, logobj): + """Initialize the connection to log to `logobj`. + + The `logobj` parameter can be an open file object or a Logger instance + from the standard logging module. + """ + self._logobj = logobj + if logging and isinstance(logobj, logging.Logger): + self.log = self._logtologger + else: + self.log = self._logtofile + + def filter(self, msg, curs): + """Filter the query before logging it. + + This is the method to overwrite to filter unwanted queries out of the + log or to add some extra data to the output. The default implementation + just does nothing. + """ + return msg + + def _logtofile(self, msg, curs): + msg = self.filter(msg, curs) + if msg: self._logobj.write(msg + os.linesep) + + def _logtologger(self, msg, curs): + msg = self.filter(msg, curs) + if msg: self._logobj.debug(msg) + + def _check(self): + if not hasattr(self, '_logobj'): + raise self.ProgrammingError( + "LoggingConnection object has not been initialize()d") + + def cursor(self): + self._check() + return _connection.cursor(self, cursor_factory=LoggingCursor) + +class LoggingCursor(_cursor): + """A cursor that logs queries using its connection logging facilities.""" + + def execute(self, query, vars=None, async=0): + try: + return _cursor.execute(self, query, vars, async) + finally: + self.connection.log(self.query, self) + + def callproc(self, procname, vars=None): + try: + return _cursor.callproc(self, procname, vars) + finally: + self.connection.log(self.query, self) + + +class MinTimeLoggingConnection(LoggingConnection): + """A connection that logs queries based on execution time. + + This is just an example of how to sub-class LoggingConnection to provide + some extra filtering for the logged queries. Both the `.inizialize()` and + `.filter()` methods are overwritten to make sure that only queries + executing for more than `mintime` ms are logged. + + Note that this connection uses the specialized cursor MinTimeLoggingCursor. + """ + def initialize(self, logobj, mintime=0): + LoggingConnection.initialize(self, logobj) + self._mintime = mintime + + def filter(self, msg, curs): + t = (time.time() - curs.timestamp) * 1000 + if t > self._mintime: + return msg + os.linesep + " (execution time: %d ms)" % t + + def cursor(self): + self._check() + return _connection.cursor(self, cursor_factory=MinTimeLoggingCursor) + +class MinTimeLoggingCursor(LoggingCursor): + """The cursor sub-class companion to MinTimeLoggingConnection.""" + + def execute(self, query, vars=None, async=0): + self.timestamp = time.time() + return LoggingCursor.execute(self, query, vars, async) + + def callproc(self, procname, vars=None): + self.timestamp = time.time() + return LoggingCursor.execute(self, procname, var) diff --git a/psycopg2/lib/pool.py b/psycopg2/lib/pool.py new file mode 100644 index 0000000..0468db6 --- /dev/null +++ b/psycopg2/lib/pool.py @@ -0,0 +1,236 @@ +"""Connection pooling for psycopg2 + +This module implements thread-safe (and not) connection pools. +""" +# psycopg/pool.py - pooling code for psycopg +# +# Copyright (C) 2003-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +import psycopg2 + +try: + import logging + # do basic initialization if the module is not already initialized + logging.basicConfig(level=logging.INFO, + format='%(asctime)s %(levelname)s %(message)s') + # create logger object for psycopg2 module and sub-modules + _logger = logging.getLogger("psycopg2") + def dbg(*args): + _logger.debug("psycopg2", ' '.join([str(x) for x in args])) + try: + import App # does this make sure that we're running in Zope? + _logger.info("installed. Logging using Python logging module") + except: + _logger.debug("installed. Logging using Python logging module") + +except ImportError: + from zLOG import LOG, DEBUG, INFO + def dbg(*args): + LOG('ZPsycopgDA', DEBUG, "", + ' '.join([str(x) for x in args])+'\n') + LOG('ZPsycopgDA', INFO, "Installed", "Logging using Zope's zLOG\n") + +except: + import sys + def dbg(*args): + sys.stderr.write(' '.join(args)+'\n') + + +class PoolError(psycopg2.Error): + pass + + +class AbstractConnectionPool(object): + """Generic key-based pooling code.""" + + def __init__(self, minconn, maxconn, *args, **kwargs): + """Initialize the connection pool. + + New 'minconn' connections are created immediately calling 'connfunc' + with given parameters. The connection pool will support a maximum of + about 'maxconn' connections. + """ + self.minconn = minconn + self.maxconn = maxconn + self.closed = False + + self._args = args + self._kwargs = kwargs + + self._pool = [] + self._used = {} + self._rused = {} # id(conn) -> key map + self._keys = 0 + + for i in range(self.minconn): + self._connect() + + def _connect(self, key=None): + """Create a new connection and assign it to 'key' if not None.""" + conn = psycopg2.connect(*self._args, **self._kwargs) + if key is not None: + self._used[key] = conn + self._rused[id(conn)] = key + else: + self._pool.append(conn) + return conn + + def _getkey(self): + """Return a new unique key.""" + self._keys += 1 + return self._keys + + def _getconn(self, key=None): + """Get a free connection and assign it to 'key' if not None.""" + if self.closed: raise PoolError("connection pool is closed") + if key is None: key = self._getkey() + + if self._used.has_key(key): + return self._used[key] + + if self._pool: + self._used[key] = conn = self._pool.pop() + self._rused[id(conn)] = key + return conn + else: + if len(self._used) == self.maxconn: + raise PoolError("connection pool exausted") + return self._connect(key) + + def _putconn(self, conn, key=None, close=False): + """Put away a connection.""" + if self.closed: raise PoolError("connection pool is closed") + if key is None: key = self._rused[id(conn)] + + if not key: + raise PoolError("trying to put unkeyed connection") + + if len(self._pool) < self.minconn and not close: + self._pool.append(conn) + else: + conn.close() + + # here we check for the presence of key because it can happen that a + # thread tries to put back a connection after a call to close + if not self.closed or key in self._used: + del self._used[key] + del self._rused[id(conn)] + + def _closeall(self): + """Close all connections. + + Note that this can lead to some code fail badly when trying to use + an already closed connection. If you call .closeall() make sure + your code can deal with it. + """ + if self.closed: raise PoolError("connection pool is closed") + for conn in self._pool + list(self._used.values()): + try: + print "Closing connection", conn + conn.close() + except: + pass + self.closed = True + + +class SimpleConnectionPool(AbstractConnectionPool): + """A connection pool that can't be shared across different threads.""" + + getconn = AbstractConnectionPool._getconn + putconn = AbstractConnectionPool._putconn + closeall = AbstractConnectionPool._closeall + + +class ThreadedConnectionPool(AbstractConnectionPool): + """A connection pool that works with the threading module.""" + + def __init__(self, minconn, maxconn, *args, **kwargs): + """Initialize the threading lock.""" + import threading + AbstractConnectionPool.__init__( + self, minconn, maxconn, *args, **kwargs) + self._lock = threading.Lock() + + def getconn(self, key=None): + """Get a free connection and assign it to 'key' if not None.""" + self._lock.acquire() + try: + return self._getconn(key) + finally: + self._lock.release() + + def putconn(self, conn=None, key=None, close=False): + """Put away an unused connection.""" + self._lock.acquire() + try: + self._putconn(conn, key, close) + finally: + self._lock.release() + + def closeall(self): + """Close all connections (even the one currently in use.)""" + self._lock.acquire() + try: + self._closeall() + finally: + self._lock.release() + + +class PersistentConnectionPool(AbstractConnectionPool): + """A pool that assigns persistent connections to different threads. + + Note that this connection pool generates by itself the required keys + using the current thread id. This means that untill a thread put away + a connection it will always get the same connection object by successive + .getconn() calls. This also means that a thread can't use more than one + single connection from the pool. + """ + + def __init__(self, minconn, maxconn, *args, **kwargs): + """Initialize the threading lock.""" + import threading + AbstractConnectionPool.__init__( + self, minconn, maxconn, *args, **kwargs) + self._lock = threading.Lock() + + # we we'll need the thread module, to determine thread ids, so we + # import it here and copy it in an instance variable + import thread + self.__thread = thread + + def getconn(self): + """Generate thread id and return a connection.""" + key = self.__thread.get_ident() + self._lock.acquire() + try: + return self._getconn(key) + finally: + self._lock.release() + + def putconn(self, conn=None, close=False): + """Put away an unused connection.""" + key = self.__thread.get_ident() + self._lock.acquire() + try: + if not conn: conn = self._used[key] + self._putconn(conn, key, close) + finally: + self._lock.release() + + def closeall(self): + """Close all connections (even the one currently in use.)""" + self._lock.acquire() + try: + self._closeall() + finally: + self._lock.release() diff --git a/psycopg2/lib/psycopg1.py b/psycopg2/lib/psycopg1.py new file mode 100644 index 0000000..d539888 --- /dev/null +++ b/psycopg2/lib/psycopg1.py @@ -0,0 +1,87 @@ +"""psycopg 1.1.x compatibility module + +This module uses the new style connection and cursor types to build a psycopg +1.1.1.x compatibility layer. It should be considered a temporary hack to run +old code while porting to psycopg 2. Import it as follows:: + + from psycopg2 import psycopg1 as psycopg +""" +# psycopg/psycopg1.py - psycopg 1.1.x compatibility module +# +# Copyright (C) 2003-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +import _psycopg as _2psycopg +from psycopg2.extensions import cursor as _2cursor +from psycopg2.extensions import connection as _2connection + +from psycopg2 import * +del connect + + +def connect(*args, **kwargs): + """connect(dsn, ...) -> new psycopg 1.1.x compatible connection object""" + kwargs['connection_factory'] = connection + conn = _2psycopg.connect(*args, **kwargs) + conn.set_isolation_level(2) + return conn + +class connection(_2connection): + """psycopg 1.1.x connection.""" + + def cursor(self): + """cursor() -> new psycopg 1.1.x compatible cursor object""" + return _2connection.cursor(self, cursor_factory=cursor) + + def autocommit(self, on_off=1): + """autocommit(on_off=1) -> switch autocommit on (1) or off (0)""" + if on_off > 0: + self.set_isolation_level(0) + else: + self.set_isolation_level(2) + + +class cursor(_2cursor): + """psycopg 1.1.x cursor. + + Note that this cursor implements the exact procedure used by psycopg 1 to + build dictionaries out of result rows. The DictCursor in the + psycopg.extras modules implements a much better and faster algorithm. + """ + + def __build_dict(self, row): + res = {} + for i in range(len(self.description)): + res[self.description[i][0]] = row[i] + return res + + def dictfetchone(self): + row = _2cursor.fetchone(self) + if row: + return self.__build_dict(row) + else: + return row + + def dictfetchmany(self, size): + res = [] + rows = _2cursor.fetchmany(self, size) + for row in rows: + res.append(self.__build_dict(row)) + return res + + def dictfetchall(self): + res = [] + rows = _2cursor.fetchall(self) + for row in rows: + res.append(self.__build_dict(row)) + return res + diff --git a/psycopg2/lib/tz.py b/psycopg2/lib/tz.py new file mode 100644 index 0000000..e521b6d --- /dev/null +++ b/psycopg2/lib/tz.py @@ -0,0 +1,100 @@ +"""tzinfo implementations for psycopg2 + +This module holds two different tzinfo implementations that can be used as +the 'tzinfo' argument to datetime constructors, directly passed to psycopg +functions or used to set the .tzinfo_factory attribute in cursors. +""" +# psycopg/tz.py - tzinfo implementation +# +# Copyright (C) 2003-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +import datetime +import time + + +ZERO = datetime.timedelta(0) + +class FixedOffsetTimezone(datetime.tzinfo): + """Fixed offset in minutes east from UTC. + + This is exactly the implementation found in Python 2.3.x documentation, + with a small change to the __init__ method to allow for pickling and a + default name in the form 'sHH:MM' ('s' is the sign.) + """ + _name = None + _offset = ZERO + + def __init__(self, offset=None, name=None): + if offset is not None: + self._offset = datetime.timedelta(minutes = offset) + if name is not None: + self._name = name + + def utcoffset(self, dt): + return self._offset + + def tzname(self, dt): + if self._name is not None: + return self._name + else: + seconds = self._offset.seconds + self._offset.days * 86400 + hours, seconds = divmod(seconds, 3600) + minutes = seconds/60 + if minutes: + return "%+03d:%d" % (hours, minutes) + else: + return "%+03d" % hours + + def dst(self, dt): + return ZERO + + +STDOFFSET = datetime.timedelta(seconds = -time.timezone) +if time.daylight: + DSTOFFSET = datetime.timedelta(seconds = -time.altzone) +else: + DSTOFFSET = STDOFFSET +DSTDIFF = DSTOFFSET - STDOFFSET + +class LocalTimezone(datetime.tzinfo): + """Platform idea of local timezone. + + This is the exact implementation from the Pyhton 2.3 documentation. + """ + + def utcoffset(self, dt): + if self._isdst(dt): + return DSTOFFSET + else: + return STDOFFSET + + def dst(self, dt): + if self._isdst(dt): + return DSTDIFF + else: + return ZERO + + def tzname(self, dt): + return time.tzname[self._isdst(dt)] + + def _isdst(self, dt): + tt = (dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + stamp = time.mktime(tt) + tt = time.localtime(stamp) + return tt.tm_isdst > 0 + +LOCAL = LocalTimezone() + +# TODO: pre-generate some interesting time zones? diff --git a/psycopg2/psycopg/adapter_asis.c b/psycopg2/psycopg/adapter_asis.c new file mode 100644 index 0000000..75ee0e4 --- /dev/null +++ b/psycopg2/psycopg/adapter_asis.c @@ -0,0 +1,227 @@ +/* adapter_asis.c - adapt types as they are + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/adapter_asis.h" +#include "psycopg/microprotocols_proto.h" + +/** the AsIs object **/ + +static PyObject * +asis_str(asisObject *self) +{ + if (self->wrapped == Py_None) { + return PyString_FromString("NULL"); + } + else { + return PyObject_Str(self->wrapped); + } +} + +PyObject * +asis_getquoted(asisObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return asis_str(self); +} + +PyObject * +asis_conform(asisObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the AsIs object */ + +/* object member list */ + +static struct PyMemberDef asisObject_members[] = { + {"adapted", T_OBJECT, offsetof(asisObject, wrapped), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef asisObject_methods[] = { + {"getquoted", (PyCFunction)asis_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL-quoted string"}, + {"__conform__", (PyCFunction)asis_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +asis_setup(asisObject *self, PyObject *obj) +{ + Dprintf("asis_setup: init asis object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->wrapped = obj; + Py_INCREF(self->wrapped); + + Dprintf("asis_setup: good asis object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +asis_dealloc(PyObject* obj) +{ + asisObject *self = (asisObject *)obj; + + Py_XDECREF(self->wrapped); + + Dprintf("asis_dealloc: deleted asis object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +asis_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *o; + + if (!PyArg_ParseTuple(args, "O", &o)) + return -1; + + return asis_setup((asisObject *)obj, o); +} + +static PyObject * +asis_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +asis_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +asis_repr(asisObject *self) +{ + return PyString_FromFormat("", self); +} + + +/* object type */ + +#define asisType_doc \ +"AsIs(str) -> new AsIs adapter object" + +PyTypeObject asisType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.AsIs", + sizeof(asisObject), + 0, + asis_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + + (reprfunc)asis_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)asis_str, /*tp_str*/ + + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + asisType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + asisObject_methods, /*tp_methods*/ + asisObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + asis_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + asis_new, /*tp_new*/ + (freefunc)asis_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +PyObject * +psyco_AsIs(PyObject *module, PyObject *args) +{ + PyObject *obj; + + if (!PyArg_ParseTuple(args, "O", &obj)) + return NULL; + + return PyObject_CallFunction((PyObject *)&asisType, "O", obj); +} diff --git a/psycopg2/psycopg/adapter_asis.h b/psycopg2/psycopg/adapter_asis.h new file mode 100644 index 0000000..9495c58 --- /dev/null +++ b/psycopg2/psycopg/adapter_asis.h @@ -0,0 +1,51 @@ +/* adapter_asis.h - definition for the psycopg AsIs type wrapper + * + * Copyright (C) 2003-2005 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_ASIS_H +#define PSYCOPG_ASIS_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject asisType; + +typedef struct { + PyObject HEAD; + + /* this is the real object we wrap */ + PyObject *wrapped; + +} asisObject; + +/* functions exported to psycopgmodule.c */ + +extern PyObject *psyco_AsIs(PyObject *module, PyObject *args); +#define psyco_AsIs_doc \ + "AsIs(obj) -> new AsIs wrapper object" + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_ASIS_H) */ diff --git a/psycopg2/psycopg/adapter_binary.c b/psycopg2/psycopg/adapter_binary.c new file mode 100644 index 0000000..0fc8101 --- /dev/null +++ b/psycopg2/psycopg/adapter_binary.c @@ -0,0 +1,382 @@ +/* adapter_binary.c - Binary objects + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/connection.h" +#include "psycopg/adapter_binary.h" +#include "psycopg/microprotocols_proto.h" + +/** the quoting code */ + +#ifndef PSYCOPG_OWN_QUOTING +static unsigned char * +binary_escape(unsigned char *from, unsigned int from_length, + unsigned int *to_length, PGconn *conn) +{ +#if PG_MAJOR_VERSION > 8 || \ + (PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION > 1) || \ + (PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION == 1 && PG_PATCH_VERSION >= 4) + if (conn) + return PQescapeByteaConn(conn, from, from_length, to_length); + else +#endif + return PQescapeBytea(from, from_length, to_length); +} +#else +static unsigned char * +binary_escape(unsigned char *from, unsigned int from_length, + unsigned int *to_length, PGconn *conn) +{ + unsigneed char *quoted, *chptr, *newptr; + int i, space, new_space; + + space = from_length + 2; + + Py_BEGIN_ALLOW_THREADS; + + quoted = (unsigned char*)calloc(space, sizeof(char)); + if (quoted == NULL) return NULL; + + chptr = quoted; + + for (i=0; i < len; i++) { + if (chptr - quoted > space - 6) { + new_space = space * ((space) / (i + 1)) + 2 + 6; + if (new_space - space < 1024) space += 1024; + else space = new_space; + newptr = (unsigned char *)realloc(quoted, space); + if (newptr == NULL) { + free(quoted); + return NULL; + } + /* chptr has to be moved to the new location*/ + chptr = newptr + (chptr - quoted); + quoted = newptr; + Dprintf("binary_escape: reallocated %i bytes at %p", space,quoted); + } + if (from[i]) { + if (from[i] >= ' ' && from[i] <= '~') { + if (from[i] == '\'') { + *chptr = '\''; + chptr++; + *chptr = '\''; + chptr++; + } + else if (from[i] == '\\') { + memcpy(chptr, "\\\\\\\\", 4); + chptr += 4; + } + else { + /* leave it as it is if ascii printable */ + *chptr = from[i]; + chptr++; + } + } + else { + unsigned char c; + + /* escape to octal notation \nnn */ + *chptr++ = '\\'; + *chptr++ = '\\'; + c = from[i]; + *chptr = ((c >> 6) & 0x07) + 0x30; chptr++; + *chptr = ((c >> 3) & 0x07) + 0x30; chptr++; + *chptr = ( c & 0x07) + 0x30; chptr++; + } + } + else { + /* escape null as \\000 */ + memcpy(chptr, "\\\\000", 5); + chptr += 5; + } + } + *chptr = '\0'; + + Py_END_ALLOW_THREADS; + + *to_size = chptr - quoted + 1; + return quoted; +} +#endif + +/* binary_quote - do the quote process on plain and unicode strings */ + +static PyObject * +binary_quote(binaryObject *self) +{ + char *to; + const char *buffer; + int buffer_len; + size_t len = 0; + + /* if we got a plain string or a buffer we escape it and save the buffer */ + if (PyString_Check(self->wrapped) || PyBuffer_Check(self->wrapped)) { + /* escape and build quoted buffer */ + PyObject_AsCharBuffer(self->wrapped, &buffer, &buffer_len); + + to = (char *)binary_escape((unsigned char*)buffer, buffer_len, &len, + self->conn ? ((connectionObject*)self->conn)->pgconn : NULL); + if (to == NULL) { + PyErr_NoMemory(); + return NULL; + } + + if (len > 0) + self->buffer = PyString_FromFormat("'%s'", to); + else + self->buffer = PyString_FromString("''"); + PQfreemem(to); + } + + /* if the wrapped object is not a string or a buffer, this is an error */ + else { + PyErr_SetString(PyExc_TypeError, "can't escape non-string object"); + return NULL; + } + + return self->buffer; +} + +/* binary_str, binary_getquoted - return result of quoting */ + +static PyObject * +binary_str(binaryObject *self) +{ + if (self->buffer == NULL) { + binary_quote(self); + } + Py_XINCREF(self->buffer); + return self->buffer; +} + +PyObject * +binary_getquoted(binaryObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return binary_str(self); +} + +PyObject * +binary_prepare(binaryObject *self, PyObject *args) +{ + connectionObject *conn; + + if (!PyArg_ParseTuple(args, "O", &conn)) + return NULL; + + Py_XDECREF(self->conn); + if (conn) { + self->conn = (PyObject*)conn; + Py_INCREF(self->conn); + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * +binary_conform(binaryObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the Binary object **/ + +/* object member list */ + +static struct PyMemberDef binaryObject_members[] = { + {"adapted", T_OBJECT, offsetof(binaryObject, wrapped), RO}, + {"buffer", T_OBJECT, offsetof(binaryObject, buffer), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef binaryObject_methods[] = { + {"getquoted", (PyCFunction)binary_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL-quoted binary string"}, + {"prepare", (PyCFunction)binary_prepare, METH_VARARGS, + "prepare(conn) -> prepare for binary encoding using conn"}, + {"__conform__", (PyCFunction)binary_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +binary_setup(binaryObject *self, PyObject *str) +{ + Dprintf("binary_setup: init binary object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->buffer = NULL; + self->conn = NULL; + self->wrapped = str; + Py_INCREF(self->wrapped); + + Dprintf("binary_setup: good binary object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +binary_dealloc(PyObject* obj) +{ + binaryObject *self = (binaryObject *)obj; + + Py_XDECREF(self->wrapped); + Py_XDECREF(self->buffer); + Py_XDECREF(self->conn); + + Dprintf("binary_dealloc: deleted binary object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +binary_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *str; + + if (!PyArg_ParseTuple(args, "O", &str)) + return -1; + + return binary_setup((binaryObject *)obj, str); +} + +static PyObject * +binary_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +binary_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +binary_repr(binaryObject *self) +{ + return PyString_FromFormat("", self); +} + +/* object type */ + +#define binaryType_doc \ +"Binary(buffer) -> new binary object" + +PyTypeObject binaryType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.Binary", + sizeof(binaryObject), + 0, + binary_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + (reprfunc)binary_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)binary_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + + binaryType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + binaryObject_methods, /*tp_methods*/ + binaryObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + binary_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + binary_new, /*tp_new*/ + (freefunc)binary_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +PyObject * +psyco_Binary(PyObject *module, PyObject *args) +{ + PyObject *str; + + if (!PyArg_ParseTuple(args, "O", &str)) + return NULL; + + return PyObject_CallFunction((PyObject *)&binaryType, "O", str); +} diff --git a/psycopg2/psycopg/adapter_binary.h b/psycopg2/psycopg/adapter_binary.h new file mode 100644 index 0000000..262a72d --- /dev/null +++ b/psycopg2/psycopg/adapter_binary.h @@ -0,0 +1,53 @@ +/* adapter_binary.h - definition for the Binary type + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_BINARY_H +#define PSYCOPG_BINARY_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject binaryType; + +typedef struct { + PyObject HEAD; + + PyObject *wrapped; + PyObject *buffer; + PyObject *conn; +} binaryObject; + +/* functions exported to psycopgmodule.c */ + +extern PyObject *psyco_Binary(PyObject *module, PyObject *args); +#define psyco_Binary_doc \ + "Binary(buffer) -> new binary object\n\n" \ + "Build an object capable to hold a bynary string value." + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_BINARY_H) */ diff --git a/psycopg2/psycopg/adapter_datetime.c b/psycopg2/psycopg/adapter_datetime.c new file mode 100644 index 0000000..6409cef --- /dev/null +++ b/psycopg2/psycopg/adapter_datetime.c @@ -0,0 +1,461 @@ +/* adapter_datetime.c - python date/time objects + * + * Copyright (C) 2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/adapter_datetime.h" +#include "psycopg/microprotocols_proto.h" + + +/* the pointer to the datetime module API is initialized by the module init + code, we just need to grab it */ +extern PyObject* pyDateTimeModuleP; +extern PyObject *pyDateTypeP; +extern PyObject *pyTimeTypeP; +extern PyObject *pyDateTimeTypeP; +extern PyObject *pyDeltaTypeP; + +extern PyObject *pyPsycopgTzModule; +extern PyObject *pyPsycopgTzLOCAL; + +/* datetime_str, datetime_getquoted - return result of quoting */ + +static PyObject * +pydatetime_str(pydatetimeObject *self) +{ + if (self->type <= PSYCO_DATETIME_TIMESTAMP) { + PyObject *res = NULL; + PyObject *iso = PyObject_CallMethod(self->wrapped, "isoformat", NULL); + if (iso) { + res = PyString_FromFormat("'%s'", PyString_AsString(iso)); + Py_DECREF(iso); + } + return res; + } + else { + PyDateTime_Delta *obj = (PyDateTime_Delta*)self->wrapped; + + char buffer[8]; + int i; + int a = obj->microseconds; + + for (i=0; i < 6 ; i++) { + buffer[5-i] = '0' + (a % 10); + a /= 10; + } + buffer[6] = '\0'; + + return PyString_FromFormat("'%d days %d.%s seconds'", + obj->days, obj->seconds, buffer); + } +} + +PyObject * +pydatetime_getquoted(pydatetimeObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return pydatetime_str(self); +} + +PyObject * +pydatetime_conform(pydatetimeObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the DateTime wrapper object **/ + +/* object member list */ + +static struct PyMemberDef pydatetimeObject_members[] = { + {"adapted", T_OBJECT, offsetof(pydatetimeObject, wrapped), RO}, + {"type", T_INT, offsetof(pydatetimeObject, type), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef pydatetimeObject_methods[] = { + {"getquoted", (PyCFunction)pydatetime_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL date/time"}, + {"__conform__", (PyCFunction)pydatetime_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +pydatetime_setup(pydatetimeObject *self, PyObject *obj, int type) +{ + Dprintf("pydatetime_setup: init datetime object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->type = type; + self->wrapped = obj; + Py_INCREF(self->wrapped); + + Dprintf("pydatetime_setup: good pydatetime object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +pydatetime_dealloc(PyObject* obj) +{ + pydatetimeObject *self = (pydatetimeObject *)obj; + + Py_XDECREF(self->wrapped); + + Dprintf("mpydatetime_dealloc: deleted pydatetime object at %p, " + "refcnt = %d", obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +pydatetime_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *dt; + int type = -1; /* raise an error if type was not passed! */ + + if (!PyArg_ParseTuple(args, "O|i", &dt, &type)) + return -1; + + return pydatetime_setup((pydatetimeObject *)obj, dt, type); +} + +static PyObject * +pydatetime_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +pydatetime_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +pydatetime_repr(pydatetimeObject *self) +{ + return PyString_FromFormat("", + self); +} + +/* object type */ + +#define pydatetimeType_doc \ +"datetime(datetime, type) -> new datetime wrapper object" + +PyTypeObject pydatetimeType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.datetime", + sizeof(pydatetimeObject), + 0, + pydatetime_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + (reprfunc)pydatetime_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)pydatetime_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + + pydatetimeType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + pydatetimeObject_methods, /*tp_methods*/ + pydatetimeObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + pydatetime_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + pydatetime_new, /*tp_new*/ + (freefunc)pydatetime_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +#ifdef PSYCOPG_DEFAULT_PYDATETIME + +PyObject * +psyco_Date(PyObject *self, PyObject *args) +{ + PyObject *res = NULL; + int year, month, day; + + PyObject* obj = NULL; + + if (!PyArg_ParseTuple(args, "iii", &year, &month, &day)) + return NULL; + + obj = PyObject_CallFunction(pyDateTypeP, "iii", year, month, day); + + if (obj) { + res = PyObject_CallFunction((PyObject *)&pydatetimeType, + "Oi", obj, PSYCO_DATETIME_DATE); + Py_DECREF(obj); + } + + return res; +} + +PyObject * +psyco_Time(PyObject *self, PyObject *args) +{ + PyObject *res = NULL; + PyObject *tzinfo = NULL; + int hours, minutes=0; + double micro, seconds=0.0; + + PyObject* obj = NULL; + + if (!PyArg_ParseTuple(args, "iid|O", &hours, &minutes, &seconds, + &tzinfo)) + return NULL; + + micro = (seconds - floor(seconds)) * 1000000.0; + + if (tzinfo == NULL) + obj = PyObject_CallFunction(pyTimeTypeP, "iiii", + hours, minutes, (int)round(seconds), (int)round(micro)); + else + obj = PyObject_CallFunction(pyTimeTypeP, "iiiiO", + hours, minutes, (int)round(seconds), (int)round(micro), tzinfo); + + if (obj) { + res = PyObject_CallFunction((PyObject *)&pydatetimeType, + "Oi", obj, PSYCO_DATETIME_TIME); + Py_DECREF(obj); + } + + return res; +} + +PyObject * +psyco_Timestamp(PyObject *self, PyObject *args) +{ + PyObject *res = NULL; + PyObject *tzinfo = NULL; + int year, month, day; + int hour=0, minute=0; /* default to midnight */ + double micro, second=0.0; + + PyObject* obj = NULL; + + if (!PyArg_ParseTuple(args, "lii|iidO", &year, &month, &day, + &hour, &minute, &second, &tzinfo)) + return NULL; + + micro = (second - floor(second)) * 1000000.0; + + if (tzinfo == NULL) + obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiii", + year, month, day, hour, minute, (int)round(second), + (int)round(micro)); + else + obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO", + year, month, day, hour, minute, (int)round(second), + (int)round(micro), tzinfo); + + if (obj) { + res = PyObject_CallFunction((PyObject *)&pydatetimeType, + "Oi", obj, PSYCO_DATETIME_TIMESTAMP); + Py_DECREF(obj); + } + + return res; +} + +PyObject * +psyco_DateFromTicks(PyObject *self, PyObject *args) +{ + PyObject *res = NULL; + struct tm tm; + time_t t; + double ticks; + + if (!PyArg_ParseTuple(args, "d", &ticks)) + return NULL; + + t = (time_t)round(ticks); + if (localtime_r(&t, &tm)) { + args = Py_BuildValue("iii", tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday); + if (args) { + res = psyco_Date(self, args); + Py_DECREF(args); + } + } + return res; +} + +PyObject * +psyco_TimeFromTicks(PyObject *self, PyObject *args) +{ + PyObject *res = NULL; + struct tm tm; + time_t t; + double ticks; + + if (!PyArg_ParseTuple(args,"d", &ticks)) + return NULL; + + t = (time_t)round(ticks); + if (localtime_r(&t, &tm)) { + args = Py_BuildValue("iid", tm.tm_hour, tm.tm_min, (double)tm.tm_sec); + if (args) { + res = psyco_Time(self, args); + Py_DECREF(args); + } + } + return res; +} + +PyObject * +psyco_TimestampFromTicks(PyObject *self, PyObject *args) +{ + PyObject *res = NULL; + struct tm tm; + time_t t; + double ticks; + + if (!PyArg_ParseTuple(args,"d", &ticks)) + return NULL; + + t = (time_t)round(ticks); + if (localtime_r(&t, &tm)) { + args = Py_BuildValue("iiiiidO", + tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, (double)tm.tm_sec, + pyPsycopgTzLOCAL); + if (args) { + res = psyco_Timestamp(self, args); + Py_DECREF(args); + } + } + return res; +} + +#endif + +PyObject * +psyco_DateFromPy(PyObject *self, PyObject *args) +{ + PyObject *obj; + + if (!PyArg_ParseTuple(args, "O!", pyDateTypeP, &obj)) + return NULL; + + return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, + PSYCO_DATETIME_DATE); +} + +PyObject * +psyco_TimeFromPy(PyObject *self, PyObject *args) +{ + PyObject *obj; + + if (!PyArg_ParseTuple(args, "O!", pyTimeTypeP, &obj)) + return NULL; + + return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, + PSYCO_DATETIME_TIME); +} + +PyObject * +psyco_TimestampFromPy(PyObject *self, PyObject *args) +{ + PyObject *obj; + + if (!PyArg_ParseTuple(args, "O!", pyDateTimeTypeP, &obj)) + return NULL; + + return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, + PSYCO_DATETIME_TIMESTAMP); +} + +PyObject * +psyco_IntervalFromPy(PyObject *self, PyObject *args) +{ + PyObject *obj; + + if (!PyArg_ParseTuple(args, "O!", pyDeltaTypeP, &obj)) + return NULL; + + return PyObject_CallFunction((PyObject *)&pydatetimeType, "Oi", obj, + PSYCO_DATETIME_INTERVAL); +} diff --git a/psycopg2/psycopg/adapter_datetime.h b/psycopg2/psycopg/adapter_datetime.h new file mode 100644 index 0000000..a32bb8d --- /dev/null +++ b/psycopg2/psycopg/adapter_datetime.h @@ -0,0 +1,107 @@ +/* adapter_datetime.h - definition for the python date/time types + * + * Copyright (C) 2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_DATETIME_H +#define PSYCOPG_DATETIME_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject pydatetimeType; + +typedef struct { + PyObject HEAD; + + PyObject *wrapped; + int type; +#define PSYCO_DATETIME_TIME 0 +#define PSYCO_DATETIME_DATE 1 +#define PSYCO_DATETIME_TIMESTAMP 2 +#define PSYCO_DATETIME_INTERVAL 3 + +} pydatetimeObject; + + +/* functions exported to psycopgmodule.c */ +#ifdef PSYCOPG_DEFAULT_PYDATETIME + +extern PyObject *psyco_Date(PyObject *module, PyObject *args); +#define psyco_Date_doc \ + "Date(year, month, day) -> new date\n\n" \ + "Build an object holding a date value." + +extern PyObject *psyco_Time(PyObject *module, PyObject *args); +#define psyco_Time_doc \ + "Time(hour, minutes, seconds, tzinfo=None) -> new time\n\n" \ + "Build an object holding a time value." + +extern PyObject *psyco_Timestamp(PyObject *module, PyObject *args); +#define psyco_Timestamp_doc \ + "Timestamp(year, month, day, hour, minutes, seconds, tzinfo=None) -> new timestamp\n\n" \ + "Build an object holding a timestamp value." + +extern PyObject *psyco_DateFromTicks(PyObject *module, PyObject *args); +#define psyco_DateFromTicks_doc \ + "DateFromTicks(ticks) -> new date\n\n" \ + "Build an object holding a date value from the given ticks value.\n\n" \ + "Ticks are the number of seconds since the epoch; see the documentation " \ + "of the standard Python time module for details)." + +extern PyObject *psyco_TimeFromTicks(PyObject *module, PyObject *args); +#define psyco_TimeFromTicks_doc \ + "TimeFromTicks(ticks) -> new time\n\n" \ + "Build an object holding a time value from the given ticks value.\n\n" \ + "Ticks are the number of seconds since the epoch; see the documentation " \ + "of the standard Python time module for details)." + +extern PyObject *psyco_TimestampFromTicks(PyObject *module, PyObject *args); +#define psyco_TimestampFromTicks_doc \ + "TimestampFromTicks(ticks) -> new timestamp\n\n" \ + "Build an object holding a timestamp value from the given ticks value.\n\n" \ + "Ticks are the number of seconds since the epoch; see the documentation " \ + "of the standard Python time module for details)." + +#endif /* PSYCOPG_DEFAULT_PYDATETIME */ + +extern PyObject *psyco_DateFromPy(PyObject *module, PyObject *args); +#define psyco_DateFromPy_doc \ + "DateFromPy(datetime.date) -> new wrapper" + +extern PyObject *psyco_TimeFromPy(PyObject *module, PyObject *args); +#define psyco_TimeFromPy_doc \ + "TimeFromPy(datetime.time) -> new wrapper" + +extern PyObject *psyco_TimestampFromPy(PyObject *module, PyObject *args); +#define psyco_TimestampFromPy_doc \ + "TimestampFromPy(datetime.datetime) -> new wrapper" + +extern PyObject *psyco_IntervalFromPy(PyObject *module, PyObject *args); +#define psyco_IntervalFromPy_doc \ + "IntervalFromPy(datetime.timedelta) -> new wrapper" + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_DATETIME_H) */ diff --git a/psycopg2/psycopg/adapter_list.c b/psycopg2/psycopg/adapter_list.c new file mode 100644 index 0000000..29ef116 --- /dev/null +++ b/psycopg2/psycopg/adapter_list.c @@ -0,0 +1,297 @@ +/* adapter_list.c - python list objects + * + * Copyright (C) 2004-2005 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/adapter_list.h" +#include "psycopg/microprotocols.h" +#include "psycopg/microprotocols_proto.h" + + +/* list_str, list_getquoted - return result of quoting */ + +static PyObject * +list_quote(listObject *self) +{ + /* adapt the list by calling adapt() recursively and then wrapping + everything into "ARRAY[]" */ + PyObject *tmp = NULL, *str = NULL, *joined = NULL, *res = NULL; + int i, len; + + len = PyList_GET_SIZE(self->wrapped); + + /* empty arrays are converted to NULLs (still searching for a way to + insert an empty array in postgresql */ + if (len == 0) return PyString_FromString("'{}'"); + + tmp = PyTuple_New(len); + + for (i=0; iwrapped, i), + (connectionObject*)self->connection); + if (quoted == NULL) goto error; + + /* here we don't loose a refcnt: SET_ITEM does not change the + reference count and we are just transferring ownership of the tmp + object to the tuple */ + PyTuple_SET_ITEM(tmp, i, quoted); + } + + /* now that we have a tuple of adapted objects we just need to join them + and put "ARRAY[] around the result */ + str = PyString_FromString(", "); + joined = PyObject_CallMethod(str, "join", "(O)", tmp); + if (joined == NULL) goto error; + + res = PyString_FromFormat("ARRAY[%s]", PyString_AsString(joined)); + + error: + Py_XDECREF(tmp); + Py_XDECREF(str); + Py_XDECREF(joined); + return res; +} + +PyObject * +list_str(listObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return list_quote(self); +} + +PyObject * +list_getquoted(listObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return list_quote(self); +} + +PyObject * +list_prepare(listObject *self, PyObject *args) +{ + connectionObject *conn; + + if (!PyArg_ParseTuple(args, "O", &conn)) + return NULL; + + /* note that we don't copy the encoding from the connection, but take a + reference to it; we'll need it during the recursive adapt() call (the + encoding is here for a future expansion that will make .getquoted() + work even without a connection to the backend. */ + Py_XDECREF(self->connection); + self->connection = (PyObject*)conn; + Py_INCREF(self->connection); + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * +list_conform(listObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the DateTime wrapper object **/ + +/* object member list */ + +static struct PyMemberDef listObject_members[] = { + {"adapted", T_OBJECT, offsetof(listObject, wrapped), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef listObject_methods[] = { + {"getquoted", (PyCFunction)list_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL date/time"}, + {"prepare", (PyCFunction)list_prepare, METH_VARARGS, + "prepare(conn) -> set encoding to conn->encoding"}, + {"__conform__", (PyCFunction)list_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +list_setup(listObject *self, PyObject *obj, char *enc) +{ + Dprintf("list_setup: init list object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + if (!PyList_Check(obj)) + return -1; + + /* FIXME: remove this orrible strdup */ + if (enc) self->encoding = strdup(enc); + + self->connection = NULL; + self->wrapped = obj; + Py_INCREF(self->wrapped); + + Dprintf("list_setup: good list object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +list_dealloc(PyObject* obj) +{ + listObject *self = (listObject *)obj; + + Py_XDECREF(self->wrapped); + Py_XDECREF(self->connection); + if (self->encoding) free(self->encoding); + + Dprintf("list_dealloc: deleted list object at %p, " + "refcnt = %d", obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +list_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *l; + char *enc = "latin-1"; /* default encoding as in Python */ + + if (!PyArg_ParseTuple(args, "O|s", &l, &enc)) + return -1; + + return list_setup((listObject *)obj, l, enc); +} + +static PyObject * +list_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +list_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +list_repr(listObject *self) +{ + return PyString_FromFormat("", self); +} + +/* object type */ + +#define listType_doc \ +"List(list) -> new list wrapper object" + +PyTypeObject listType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.List", + sizeof(listObject), + 0, + list_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + (reprfunc)list_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)list_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + + listType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + listObject_methods, /*tp_methods*/ + listObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + list_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + list_new, /*tp_new*/ + (freefunc)list_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +PyObject * +psyco_List(PyObject *module, PyObject *args) +{ + PyObject *str; + char *enc = "latin-1"; /* default encoding as in Python */ + + if (!PyArg_ParseTuple(args, "O|s", &str, &enc)) + return NULL; + + return PyObject_CallFunction((PyObject *)&listType, "Os", str, enc); +} diff --git a/psycopg2/psycopg/adapter_list.h b/psycopg2/psycopg/adapter_list.h new file mode 100644 index 0000000..71b4286 --- /dev/null +++ b/psycopg2/psycopg/adapter_list.h @@ -0,0 +1,49 @@ +/* adapter_list.h - definition for the python list types + * + * Copyright (C) 2004-2005 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_LIST_H +#define PSYCOPG_LIST_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject listType; + +typedef struct { + PyObject HEAD; + + PyObject *wrapped; + PyObject *connection; + char *encoding; +} listObject; + +extern PyObject *psyco_List(PyObject *module, PyObject *args); +#define psyco_List_doc \ + "List(list, enc) -> new quoted list" + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_LIST_H) */ diff --git a/psycopg2/psycopg/adapter_mxdatetime.c b/psycopg2/psycopg/adapter_mxdatetime.c new file mode 100644 index 0000000..3b23148 --- /dev/null +++ b/psycopg2/psycopg/adapter_mxdatetime.c @@ -0,0 +1,446 @@ +/* adapter_mxdatetime.c - mx date/time objects + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/adapter_mxdatetime.h" +#include "psycopg/microprotocols_proto.h" + +/* the pointer to the mxDateTime API is initialized by the module init code, + we just need to grab it */ +extern mxDateTimeModule_APIObject *mxDateTimeP; + + +/* mxdatetime_str, mxdatetime_getquoted - return result of quoting */ + +static PyObject * +mxdatetime_str(mxdatetimeObject *self) +{ + PyObject *str = NULL, *res = NULL; + + switch (self->type) { + + case PSYCO_MXDATETIME_DATE: + case PSYCO_MXDATETIME_TIMESTAMP: + str = PyObject_Str(self->wrapped); + + /* given the limitation of the mx.DateTime module that uses the same + type for both date and timestamp values we need to do some black + magic and make sure we're not using an adapt()ed timestamp as a + simple date */ + if (strncmp(&(PyString_AsString(str)[11]), "00:00:00.000", 12) == 0) { + PyObject *tmp = + PyString_FromStringAndSize(PyString_AsString(str), 10); + Py_DECREF(str); + str = tmp; + } + break; + + case PSYCO_MXDATETIME_TIME: + case PSYCO_MXDATETIME_INTERVAL: + str = PyObject_Str(self->wrapped); + + /* given the limitation of the mx.DateTime module that uses the same + type for both time and delta values we need to do some black magic + and make sure we're not using an adapt()ed interval as a simple + time */ + if (PyString_Size(str) > 8 && PyString_AsString(str)[8] == ':') { + mxDateTimeDeltaObject *obj = (mxDateTimeDeltaObject*)self->wrapped; + + char buffer[8]; + int i, j, x; + + double ss = obj->hour*3600.0 + obj->minute*60.0 + obj->second; + int us = (int)((ss - floor(ss))*1000000); + + for (i=1000000, j=0; i > 0 ; i /= 10) { + x = us/i; + us -= x*i; + buffer[j++] = '0'+x; + } + buffer[j] = '\0'; + + res = PyString_FromFormat("'%ld days %d.%s seconds'", + obj->day, (int)round(ss), buffer); + } + break; + } + + if (str != NULL && res == NULL) { + res = PyString_FromFormat("'%s'", PyString_AsString(str)); + } + Py_XDECREF(str); + + return res; +} + +PyObject * +mxdatetime_getquoted(mxdatetimeObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return mxdatetime_str(self); +} + +PyObject * +mxdatetime_conform(mxdatetimeObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the MxDateTime object **/ + +/* object member list */ + +static struct PyMemberDef mxdatetimeObject_members[] = { + {"adapted", T_OBJECT, offsetof(mxdatetimeObject, wrapped), RO}, + {"type", T_INT, offsetof(mxdatetimeObject, type), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef mxdatetimeObject_methods[] = { + {"getquoted", (PyCFunction)mxdatetime_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL date/time"}, + {"__conform__", (PyCFunction)mxdatetime_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +mxdatetime_setup(mxdatetimeObject *self, PyObject *obj, int type) +{ + Dprintf("mxdatetime_setup: init mxdatetime object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->type = type; + self->wrapped = obj; + Py_INCREF(self->wrapped); + + Dprintf("mxdatetime_setup: good mxdatetime object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +mxdatetime_dealloc(PyObject* obj) +{ + mxdatetimeObject *self = (mxdatetimeObject *)obj; + + Py_XDECREF(self->wrapped); + + Dprintf("mxdatetime_dealloc: deleted mxdatetime object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +mxdatetime_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *mx; + int type = -1; /* raise an error if type was not passed! */ + + if (!PyArg_ParseTuple(args, "O|i", &mx, &type)) + return -1; + + return mxdatetime_setup((mxdatetimeObject *)obj, mx, type); +} + +static PyObject * +mxdatetime_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +mxdatetime_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +mxdatetime_repr(mxdatetimeObject *self) +{ + return PyString_FromFormat("", + self); +} + +/* object type */ + +#define mxdatetimeType_doc \ +"MxDateTime(mx, type) -> new mx.DateTime wrapper object" + +PyTypeObject mxdatetimeType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.MxDateTime", + sizeof(mxdatetimeObject), + 0, + mxdatetime_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + (reprfunc)mxdatetime_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)mxdatetime_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + + mxdatetimeType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + mxdatetimeObject_methods, /*tp_methods*/ + mxdatetimeObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + mxdatetime_init, /*tp_init*/ + PyType_GenericAlloc, /*tp_alloc*/ + mxdatetime_new, /*tp_new*/ + (freefunc)mxdatetime_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +#ifdef PSYCOPG_DEFAULT_MXDATETIME + +PyObject * +psyco_Date(PyObject *self, PyObject *args) +{ + PyObject *res, *mx; + int year, month, day; + + if (!PyArg_ParseTuple(args, "iii", &year, &month, &day)) + return NULL; + + mx = mxDateTimeP->DateTime_FromDateAndTime(year, month, day, 0, 0, 0.0); + if (mx == NULL) return NULL; + + res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_DATE); + Py_DECREF(mx); + return res; +} + +PyObject * +psyco_Time(PyObject *self, PyObject *args) +{ + PyObject *res, *mx; + int hours, minutes=0; + double seconds=0.0; + + if (!PyArg_ParseTuple(args, "iid", &hours, &minutes, &seconds)) + return NULL; + + mx = mxDateTimeP->DateTimeDelta_FromTime(hours, minutes, seconds); + if (mx == NULL) return NULL; + + res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_TIME); + Py_DECREF(mx); + return res; +} + +PyObject * +psyco_Timestamp(PyObject *self, PyObject *args) +{ + PyObject *res, *mx; + int year, month, day; + int hour=0, minute=0; /* default to midnight */ + double second=0.0; + + if (!PyArg_ParseTuple(args, "lii|iid", &year, &month, &day, + &hour, &minute, &second)) + return NULL; + + mx = mxDateTimeP->DateTime_FromDateAndTime(year, month, day, + hour, minute, second); + if (mx == NULL) return NULL; + + res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_TIMESTAMP); + Py_DECREF(mx); + return res; +} + +PyObject * +psyco_DateFromTicks(PyObject *self, PyObject *args) +{ + PyObject *res, *mx; + double ticks; + + if (!PyArg_ParseTuple(args,"d", &ticks)) + return NULL; + + if (!(mx = mxDateTimeP->DateTime_FromTicks(ticks))) + return NULL; + + res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_DATE); + Py_DECREF(mx); + return res; +} + +PyObject * +psyco_TimeFromTicks(PyObject *self, PyObject *args) +{ + PyObject *res, *mx, *dt; + double ticks; + + if (!PyArg_ParseTuple(args,"d", &ticks)) + return NULL; + + if (!(dt = mxDateTimeP->DateTime_FromTicks(ticks))) + return NULL; + + if (!(mx = mxDateTimeP->DateTimeDelta_FromDaysAndSeconds( + 0, ((mxDateTimeObject*)dt)->abstime))) + { + Py_DECREF(dt); + return NULL; + } + + Py_DECREF(dt); + res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_TIME); + Py_DECREF(mx); + return res; +} + +PyObject * +psyco_TimestampFromTicks(PyObject *self, PyObject *args) +{ + PyObject *mx, *res; + double ticks; + + if (!PyArg_ParseTuple(args, "d", &ticks)) + return NULL; + + if (!(mx = mxDateTimeP->DateTime_FromTicks(ticks))) + return NULL; + + res = PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_TIMESTAMP); + Py_DECREF(mx); + return res; +} + +#endif + +PyObject * +psyco_DateFromMx(PyObject *self, PyObject *args) +{ + PyObject *mx; + + if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTime_Type, &mx)) + return NULL; + + return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_DATE); +} + +PyObject * +psyco_TimeFromMx(PyObject *self, PyObject *args) +{ + PyObject *mx; + + if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTimeDelta_Type, &mx)) + return NULL; + + return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_TIME); +} + +PyObject * +psyco_TimestampFromMx(PyObject *self, PyObject *args) +{ + PyObject *mx; + + if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTime_Type, &mx)) + return NULL; + + return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_TIMESTAMP); +} + +PyObject * +psyco_IntervalFromMx(PyObject *self, PyObject *args) +{ + PyObject *mx; + + if (!PyArg_ParseTuple(args, "O!", mxDateTimeP->DateTime_Type, &mx)) + return NULL; + + return PyObject_CallFunction((PyObject *)&mxdatetimeType, "Oi", mx, + PSYCO_MXDATETIME_INTERVAL); +} diff --git a/psycopg2/psycopg/adapter_mxdatetime.h b/psycopg2/psycopg/adapter_mxdatetime.h new file mode 100644 index 0000000..c485707 --- /dev/null +++ b/psycopg2/psycopg/adapter_mxdatetime.h @@ -0,0 +1,94 @@ +/* adapter_mxdatetime.h - definition for the mx date/time types + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_MXDATETIME_H +#define PSYCOPG_MXDATETIME_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject mxdatetimeType; + +typedef struct { + PyObject HEAD; + + PyObject *wrapped; + int type; +#define PSYCO_MXDATETIME_TIME 0 +#define PSYCO_MXDATETIME_DATE 1 +#define PSYCO_MXDATETIME_TIMESTAMP 2 +#define PSYCO_MXDATETIME_INTERVAL 3 + +} mxdatetimeObject; + +/* functions exported to psycopgmodule.c */ +#ifdef PSYCOPG_DEFAULT_MXDATETIME + +extern PyObject *psyco_Date(PyObject *module, PyObject *args); +#define psyco_Date_doc \ + "Date(year, month, day) -> new date" + +extern PyObject *psyco_Time(PyObject *module, PyObject *args); +#define psyco_Time_doc \ + "Time(hour, minutes, seconds) -> new time" + +extern PyObject *psyco_Timestamp(PyObject *module, PyObject *args); +#define psyco_Timestamp_doc \ + "Time(year, month, day, hour, minutes, seconds) -> new timestamp" + +extern PyObject *psyco_DateFromTicks(PyObject *module, PyObject *args); +#define psyco_DateFromTicks_doc \ + "DateFromTicks(ticks) -> new date" + +extern PyObject *psyco_TimeFromTicks(PyObject *module, PyObject *args); +#define psyco_TimeFromTicks_doc \ + "TimeFromTicks(ticks) -> new time" + +extern PyObject *psyco_TimestampFromTicks(PyObject *module, PyObject *args); +#define psyco_TimestampFromTicks_doc \ + "TimestampFromTicks(ticks) -> new timestamp" + +#endif /* PSYCOPG_DEFAULT_MXDATETIME */ + +extern PyObject *psyco_DateFromMx(PyObject *module, PyObject *args); +#define psyco_DateFromMx_doc \ + "DateFromMx(mx) -> new date" + +extern PyObject *psyco_TimeFromMx(PyObject *module, PyObject *args); +#define psyco_TimeFromMx_doc \ + "TimeFromMx(mx) -> new time" + +extern PyObject *psyco_TimestampFromMx(PyObject *module, PyObject *args); +#define psyco_TimestampFromMx_doc \ + "TimestampFromMx(mx) -> new timestamp" + +extern PyObject *psyco_IntervalFromMx(PyObject *module, PyObject *args); +#define psyco_IntervalFromMx_doc \ + "IntervalFromMx(mx) -> new interval" + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_MXDATETIME_H) */ diff --git a/psycopg2/psycopg/adapter_pboolean.c b/psycopg2/psycopg/adapter_pboolean.c new file mode 100644 index 0000000..fa70ad0 --- /dev/null +++ b/psycopg2/psycopg/adapter_pboolean.c @@ -0,0 +1,238 @@ +/* adapter_pboolean.c - psycopg boolean type wrapper implementation + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/adapter_pboolean.h" +#include "psycopg/microprotocols_proto.h" + + +/** the Boolean object **/ + +static PyObject * +pboolean_str(pbooleanObject *self) +{ +#ifdef PSYCOPG_NEW_BOOLEAN + if (PyObject_IsTrue(self->wrapped)) { + return PyString_FromString("true"); + } + else { + return PyString_FromString("false"); + } +#else + if (PyObject_IsTrue(self->wrapped)) { + return PyString_FromString("'t'"); + } + else { + return PyString_FromString("'f'"); + } +#endif +} + +PyObject * +pboolean_getquoted(pbooleanObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return pboolean_str(self); +} + +PyObject * +pboolean_conform(pbooleanObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the Boolean object */ + +/* object member list */ + +static struct PyMemberDef pbooleanObject_members[] = { + {"adapted", T_OBJECT, offsetof(pbooleanObject, wrapped), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef pbooleanObject_methods[] = { + {"getquoted", (PyCFunction)pboolean_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL-quoted string"}, + {"__conform__", (PyCFunction)pboolean_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +pboolean_setup(pbooleanObject *self, PyObject *obj) +{ + Dprintf("pboolean_setup: init pboolean object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->wrapped = obj; + Py_INCREF(self->wrapped); + + Dprintf("pboolean_setup: good pboolean object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +pboolean_dealloc(PyObject* obj) +{ + pbooleanObject *self = (pbooleanObject *)obj; + + Py_XDECREF(self->wrapped); + + Dprintf("pboolean_dealloc: deleted pboolean object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +pboolean_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *o; + + if (!PyArg_ParseTuple(args, "O", &o)) + return -1; + + return pboolean_setup((pbooleanObject *)obj, o); +} + +static PyObject * +pboolean_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +pboolean_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +pboolean_repr(pbooleanObject *self) +{ + return PyString_FromFormat("", + self); +} + + +/* object type */ + +#define pbooleanType_doc \ +"Boolean(str) -> new Boolean adapter object" + +PyTypeObject pbooleanType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.Boolean", + sizeof(pbooleanObject), + 0, + pboolean_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + + (reprfunc)pboolean_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)pboolean_str, /*tp_str*/ + + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + pbooleanType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + pbooleanObject_methods, /*tp_methods*/ + pbooleanObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + pboolean_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + pboolean_new, /*tp_new*/ + (freefunc)pboolean_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +PyObject * +psyco_Boolean(PyObject *module, PyObject *args) +{ + PyObject *obj; + + if (!PyArg_ParseTuple(args, "O", &obj)) + return NULL; + + return PyObject_CallFunction((PyObject *)&pbooleanType, "O", obj); +} diff --git a/psycopg2/psycopg/adapter_pboolean.h b/psycopg2/psycopg/adapter_pboolean.h new file mode 100644 index 0000000..efdfe56 --- /dev/null +++ b/psycopg2/psycopg/adapter_pboolean.h @@ -0,0 +1,51 @@ +/* adapter_pboolean.h - definition for the psycopg boolean type wrapper + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_PBOOLEAN_H +#define PSYCOPG_PBOOLEAN_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject pbooleanType; + +typedef struct { + PyObject HEAD; + + /* this is the real object we wrap */ + PyObject *wrapped; + +} pbooleanObject; + +/* functions exported to psycopgmodule.c */ + +extern PyObject *psyco_Boolean(PyObject *module, PyObject *args); +#define psyco_Boolean_doc \ + "Boolean(obj) -> new boolean value" + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_PBOOLEAN_H) */ diff --git a/psycopg2/psycopg/adapter_qstring.c b/psycopg2/psycopg/adapter_qstring.c new file mode 100644 index 0000000..2eaf7f3 --- /dev/null +++ b/psycopg2/psycopg/adapter_qstring.c @@ -0,0 +1,393 @@ +/* adapter_qstring.c - QuotedString objects + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/connection.h" +#include "psycopg/adapter_qstring.h" +#include "psycopg/microprotocols_proto.h" + + +/** the quoting code */ + +#ifndef PSYCOPG_OWN_QUOTING +static size_t +qstring_escape(char *to, char *from, size_t len, PGconn *conn) +{ +#if PG_MAJOR_VERSION > 8 || \ + (PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION > 1) || \ + (PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION == 1 && PG_PATCH_VERSION >= 4) + int err; + if (conn) + return PQescapeStringConn(conn, to, from, len, &err); + else +#endif + return PQescapeString(to, from, len); +} +#else +static size_t +qstring_escape(char *to, char *from, size_t len, PGconn *conn) +{ + int i, j; + + for (i=0, j=0; iencoding but if the encoding is not specified we don't know what + to do and we raise an exception */ + + /* TODO: we need a real translation table from postgres encoding names to + python ones here */ + + if (PyUnicode_Check(self->wrapped) && self->encoding) { + PyObject *enc = PyDict_GetItemString(psycoEncodings, self->encoding); + /* note that pgenc is a borrowed reference */ + + if (enc) { + char *s = PyString_AsString(enc); + Dprintf("qstring_quote: encoding unicode object to %s", s); + str = PyUnicode_AsEncodedString(self->wrapped, s, NULL); + Dprintf("qstring_quote: got encoded object at %p", str); + if (str == NULL) return NULL; + } + else { + /* can't find the right encoder, raise exception */ + PyErr_Format(InterfaceError, + "can't encode unicode string to %s", self->encoding); + return NULL; + } + } + + /* if the wrapped object is a simple string, we don't know how to + (re)encode it, so we pass it as-is */ + else if (PyString_Check(self->wrapped)) { + str = self->wrapped; + /* INCREF to make it ref-wise identical to unicode one */ + Py_INCREF(str); + } + + /* if the wrapped object is not a string, this is an error */ + else { + PyErr_SetString(PyExc_TypeError, + "can't quote non-string object (or missing encoding)"); + return NULL; + } + + /* encode the string into buffer */ + PyString_AsStringAndSize(str, &s, &len); + + buffer = (char *)PyMem_Malloc((len*2+3) * sizeof(char)); + if (buffer == NULL) { + Py_DECREF(str); + PyErr_NoMemory(); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS; + len = qstring_escape(buffer+1, s, len, + self->conn ? ((connectionObject*)self->conn)->pgconn : NULL); + buffer[0] = '\'' ; buffer[len+1] = '\''; + Py_END_ALLOW_THREADS; + + self->buffer = PyString_FromStringAndSize(buffer, len+2); + PyMem_Free(buffer); + Py_DECREF(str); + + return self->buffer; +} + +/* qstring_str, qstring_getquoted - return result of quoting */ + +static PyObject * +qstring_str(qstringObject *self) +{ + if (self->buffer == NULL) { + qstring_quote(self); + } + Py_XINCREF(self->buffer); + return self->buffer; +} + +PyObject * +qstring_getquoted(qstringObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + return qstring_str(self); +} + +PyObject * +qstring_prepare(qstringObject *self, PyObject *args) +{ + connectionObject *conn; + + if (!PyArg_ParseTuple(args, "O", &conn)) + return NULL; + + /* we bother copying the encoding only if the wrapped string is unicode, + we don't need the encoding if that's not the case */ + if (PyUnicode_Check(self->wrapped)) { + if (self->encoding) free(self->encoding); + self->encoding = strdup(conn->encoding); + Dprintf("qstring_prepare: set encoding to %s", conn->encoding); + } + + Py_XDECREF(self->conn); + if (conn) { + self->conn = (PyObject*)conn; + Py_INCREF(self->conn); + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject * +qstring_conform(qstringObject *self, PyObject *args) +{ + PyObject *res, *proto; + + if (!PyArg_ParseTuple(args, "O", &proto)) return NULL; + + if (proto == (PyObject*)&isqlquoteType) + res = (PyObject*)self; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +/** the QuotedString object **/ + +/* object member list */ + +static struct PyMemberDef qstringObject_members[] = { + {"adapted", T_OBJECT, offsetof(qstringObject, wrapped), RO}, + {"buffer", T_OBJECT, offsetof(qstringObject, buffer), RO}, + {"encoding", T_STRING, offsetof(qstringObject, encoding), RO}, + {NULL} +}; + +/* object method table */ + +static PyMethodDef qstringObject_methods[] = { + {"getquoted", (PyCFunction)qstring_getquoted, METH_VARARGS, + "getquoted() -> wrapped object value as SQL-quoted string"}, + {"prepare", (PyCFunction)qstring_prepare, METH_VARARGS, + "prepare(conn) -> set encoding to conn->encoding and store conn"}, + {"__conform__", (PyCFunction)qstring_conform, METH_VARARGS, NULL}, + {NULL} /* Sentinel */ +}; + +/* initialization and finalization methods */ + +static int +qstring_setup(qstringObject *self, PyObject *str, char *enc) +{ + Dprintf("qstring_setup: init qstring object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->buffer = NULL; + self->conn = NULL; + + /* FIXME: remove this orrible strdup */ + if (enc) self->encoding = strdup(enc); + + self->wrapped = str; + Py_INCREF(self->wrapped); + + Dprintf("qstring_setup: good qstring object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +qstring_dealloc(PyObject* obj) +{ + qstringObject *self = (qstringObject *)obj; + + Py_XDECREF(self->wrapped); + Py_XDECREF(self->buffer); + Py_XDECREF(self->conn); + + if (self->encoding) free(self->encoding); + + Dprintf("qstring_dealloc: deleted qstring object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +qstring_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *str; + char *enc = "latin-1"; /* default encoding as in Python */ + + if (!PyArg_ParseTuple(args, "O|s", &str, &enc)) + return -1; + + return qstring_setup((qstringObject *)obj, str, enc); +} + +static PyObject * +qstring_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +qstring_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +qstring_repr(qstringObject *self) +{ + return PyString_FromFormat("", + self); +} + +/* object type */ + +#define qstringType_doc \ +"QuotedString(str, enc) -> new quoted object with 'enc' encoding" + +PyTypeObject qstringType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.QuotedString", + sizeof(qstringObject), + 0, + qstring_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + + 0, /*tp_compare*/ + (reprfunc)qstring_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)qstring_str, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + + qstringType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + qstringObject_methods, /*tp_methods*/ + qstringObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + qstring_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + qstring_new, /*tp_new*/ + (freefunc)qstring_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + + +/** module-level functions **/ + +PyObject * +psyco_QuotedString(PyObject *module, PyObject *args) +{ + PyObject *str; + char *enc = "latin-1"; /* default encoding as in Python */ + + if (!PyArg_ParseTuple(args, "O|s", &str, &enc)) + return NULL; + + return PyObject_CallFunction((PyObject *)&qstringType, "Os", str, enc); +} diff --git a/psycopg2/psycopg/adapter_qstring.h b/psycopg2/psycopg/adapter_qstring.h new file mode 100644 index 0000000..544b32b --- /dev/null +++ b/psycopg2/psycopg/adapter_qstring.h @@ -0,0 +1,53 @@ +/* adapter_qstring.h - definition for the QuotedString type + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_QSTRING_H +#define PSYCOPG_QSTRING_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject qstringType; + +typedef struct { + PyObject HEAD; + + PyObject *wrapped; + PyObject *buffer; + char *encoding; + + PyObject *conn; +} qstringObject; + +/* functions exported to psycopgmodule.c */ + +extern PyObject *psyco_QuotedString(PyObject *module, PyObject *args); +#define psyco_QuotedString_doc \ + "QuotedString(str, enc) -> new quoted string" + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_QSTRING_H) */ diff --git a/psycopg2/psycopg/config.h b/psycopg2/psycopg/config.h new file mode 100644 index 0000000..649fee8 --- /dev/null +++ b/psycopg2/psycopg/config.h @@ -0,0 +1,118 @@ +/* config.h - general config and Dprintf macro + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_CONFIG_H +#define PSYCOPG_CONFIG_H 1 + +/* debug printf-like function */ +#if defined( __GNUC__) && !defined(__APPLE__) +#ifdef PSYCOPG_DEBUG +#include +#include +#define Dprintf(fmt, args...) \ + fprintf(stderr, "[%d] " fmt "\n", getpid() , ## args) +#else +#define Dprintf(fmt, args...) +#endif +#else /* !__GNUC__ or __APPLE__ */ +#ifdef PSYCOPG_DEBUG +#include +static void Dprintf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); +} +#else +static void Dprintf(const char *fmt, ...) {} +#endif +#endif + +/* pthreads work-arounds for mutilated operating systems */ +#if defined(_WIN32) || defined(__BEOS__) + +#ifdef _WIN32 +#include +#define pthread_mutex_t HANDLE +#define pthread_condvar_t HANDLE +#define pthread_mutex_lock(object) WaitForSingleObject(object, INFINITE) +#define pthread_mutex_unlock(object) ReleaseMutex(object) +#define pthread_mutex_destroy(ref) (CloseHandle(*(ref))) +/* convert pthread mutex to native mutex */ +static int pthread_mutex_init(pthread_mutex_t *mutex, void* fake) +{ + *mutex = CreateMutex(NULL, FALSE, NULL); + return 0; +} +#endif /* _WIN32 */ + +#ifdef __BEOS__ +#include +#define pthread_mutex_t sem_id +#define pthread_mutex_lock(object) acquire_sem(object) +#define pthread_mutex_unlock(object) release_sem(object) +#define pthread_mutex_destroy(ref) delete_sem(*ref) +static int pthread_mutex_init(pthread_mutex_t *mutex, void* fake) +{ + *mutex = create_sem(1, "psycopg_mutex"); + if (*mutex < B_OK) + return *mutex; + return 0; +} +#endif /* __BEOS__ */ + +#else /* pthread is available */ +#include +#endif + +/* to work around the fact that Windows does not have a gmtime_r function, or + a proper gmtime function */ +#ifdef _WIN32 +static struct tm *gmtime_r(time_t *t, struct tm *tm) +{ + tm = gmtime(t); + return tm; +} +static struct tm *localtime_r(time_t *t, struct tm *tm) +{ + tm = localtime(t); + return tm; +} +/* remove the inline keyword, since it doesn't work unless C++ file */ +#define inline +#endif + +#if defined(__FreeBSD__) || defined(_WIN32) || defined(__sun__) +/* what's this, we have no round function either? */ +static double round(double num) +{ + return (num >= 0) ? floor(num + 0.5) : ceil(num - 0.5); +} +#endif + +/* postgresql < 7.4 does not have PQfreemem */ +#ifndef HAVE_PQFREEMEM +#define PQfreemem free +#endif + +#endif /* !defined(PSYCOPG_CONFIG_H) */ diff --git a/psycopg2/psycopg/connection.h b/psycopg2/psycopg/connection.h new file mode 100644 index 0000000..7010120 --- /dev/null +++ b/psycopg2/psycopg/connection.h @@ -0,0 +1,97 @@ +/* connection.h - definition for the psycopg connection type + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_CONNECTION_H +#define PSYCOPG_CONNECTION_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* connection status */ +#define CONN_STATUS_READY 1 +#define CONN_STATUS_BEGIN 2 +#define CONN_STATUS_SYNC 3 +#define CONN_STATUS_ASYNC 4 + +extern PyTypeObject connectionType; + +typedef struct { + PyObject HEAD; + + pthread_mutex_t lock; /* the global connection lock */ + + char *dsn; /* data source name */ + char *critical; /* critical error on this connection */ + char *encoding; /* current backend encoding */ + + long int closed; /* 2 means connection has been closed */ + long int isolation_level; /* isolation level for this connection */ + long int mark; /* number of commits/rollbacks done so far */ + int status; /* status of the connection */ + int protocol; /* protocol version */ + + PGconn *pgconn; /* the postgresql connection */ + + PyObject *async_cursor; + + /* notice processing */ + PyObject *notice_list; + PyObject *notice_filter; + + /* notifies */ + PyObject *notifies; + + /* errors (DBAPI-2.0 extension) */ + PyObject *exc_Error; + PyObject *exc_Warning; + PyObject *exc_InterfaceError; + PyObject *exc_DatabaseError; + PyObject *exc_InternalError; + PyObject *exc_OperationalError; + PyObject *exc_ProgrammingError; + PyObject *exc_IntegrityError; + PyObject *exc_DataError; + PyObject *exc_NotSupportedError; + +} connectionObject; + +/* C-callable functions in connection_int.c and connection_ext.c */ +extern int conn_connect(connectionObject *self); +extern void conn_close(connectionObject *self); +extern int conn_commit(connectionObject *self); +extern int conn_rollback(connectionObject *self); +extern int conn_switch_isolation_level(connectionObject *self, int level); +extern int conn_set_client_encoding(connectionObject *self, char *enc); + +/* exception-raising macros */ +#define EXC_IF_CONN_CLOSED(self) if ((self)->closed > 0) { \ + PyErr_SetString(InterfaceError, "connection already closed"); \ + return NULL; } + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_CONNECTION_H) */ diff --git a/psycopg2/psycopg/connection_int.c b/psycopg2/psycopg/connection_int.c new file mode 100644 index 0000000..3e61ddf --- /dev/null +++ b/psycopg2/psycopg/connection_int.c @@ -0,0 +1,303 @@ +/* connection_int.c - code used by the connection object + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/psycopg.h" +#include "psycopg/connection.h" +#include "psycopg/cursor.h" +#include "psycopg/pqpath.h" + +/* conn_notice_callback - process notices */ + +void +conn_notice_callback(void *args, const char *message) +{ + connectionObject *self = (connectionObject *)args; + + Dprintf("conn_notice_callback: %s", message); + + /* unfortunately the old protocl return COPY FROM errors only as notices, + so we need to filter them looking for such errors */ + if (strncmp(message, "ERROR", 5) == 0) + pq_set_critical(self, message); + else + PyList_Append(self->notice_list, PyString_FromString(message)); +} + +/* conn_connect - execute a connection to the dataabase */ + +int +conn_connect(connectionObject *self) +{ + PGconn *pgconn; + PGresult *pgres; + char *data, *tmp; + int i; + + /* we need the initial date style to be ISO, for typecasters; if the user + later change it, she must know what she's doing... */ + const char *datestyle = "SET DATESTYLE TO 'ISO'"; + const char *encoding = "SHOW client_encoding"; + const char *isolevel = "SHOW default_transaction_isolation"; + + const char *lvl1a = "read uncommitted"; + const char *lvl1b = "read committed"; + const char *lvl2a = "repeatable read"; + const char *lvl2b = "serializable"; + + Py_BEGIN_ALLOW_THREADS; + pgconn = PQconnectdb(self->dsn); + Py_END_ALLOW_THREADS; + + Dprintf("conn_connect: new postgresql connection at %p", pgconn); + + if (pgconn == NULL) + { + Dprintf("conn_connect: PQconnectdb(%s) FAILED", self->dsn); + PyErr_SetString(OperationalError, "PQconnectdb() failed"); + return -1; + } + else if (PQstatus(pgconn) == CONNECTION_BAD) + { + Dprintf("conn_connect: PQconnectdb(%s) returned BAD", self->dsn); + PyErr_SetString(OperationalError, PQerrorMessage(pgconn)); + PQfinish(pgconn); + return -1; + } + + PQsetNoticeProcessor(pgconn, conn_notice_callback, (void*)self); + + Py_BEGIN_ALLOW_THREADS; + pgres = PQexec(pgconn, datestyle); + Py_END_ALLOW_THREADS; + + if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) { + PyErr_SetString(OperationalError, "can't set datestyle to ISO"); + PQfinish(pgconn); + IFCLEARPGRES(pgres); + return -1; + } + CLEARPGRES(pgres); + + Py_BEGIN_ALLOW_THREADS; + pgres = PQexec(pgconn, encoding); + Py_END_ALLOW_THREADS; + + if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) { + PyErr_SetString(OperationalError, "can't fetch client_encoding"); + PQfinish(pgconn); + IFCLEARPGRES(pgres); + return -1; + } + tmp = PQgetvalue(pgres, 0, 0); + self->encoding = PyMem_Malloc(strlen(tmp)+1); + if (self->encoding == NULL) { + /* exception already set by PyMem_Malloc() */ + PQfinish(pgconn); + IFCLEARPGRES(pgres); + return -1; + } + for (i=0 ; i < strlen(tmp) ; i++) + self->encoding[i] = toupper(tmp[i]); + self->encoding[i] = '\0'; + CLEARPGRES(pgres); + + Py_BEGIN_ALLOW_THREADS; + pgres = PQexec(pgconn, isolevel); + Py_END_ALLOW_THREADS; + + if (pgres == NULL || PQresultStatus(pgres) != PGRES_TUPLES_OK) { + PyErr_SetString(OperationalError, + "can't fetch default_isolation_level"); + PQfinish(pgconn); + IFCLEARPGRES(pgres); + return -1; + } + data = PQgetvalue(pgres, 0, 0); + if ((strncmp(lvl1a, data, strlen(lvl1a)) == 0) + || (strncmp(lvl1b, data, strlen(lvl1b)) == 0)) + self->isolation_level = 1; + else if ((strncmp(lvl2a, data, strlen(lvl2a)) == 0) + || (strncmp(lvl2b, data, strlen(lvl2b)) == 0)) + self->isolation_level = 2; + else + self->isolation_level = 2; + CLEARPGRES(pgres); + + if (PQsetnonblocking(pgconn, 1) != 0) { + Dprintf("conn_connect: PQsetnonblocking() FAILED"); + PyErr_SetString(OperationalError, "PQsetnonblocking() failed"); + PQfinish(pgconn); + return -1; + } + +#ifdef HAVE_PQPROTOCOL3 + self->protocol = PQprotocolVersion(pgconn); +#else + self->protocol = 2; +#endif + Dprintf("conn_connect: using protocol %d", self->protocol); + + self->pgconn = pgconn; + return 0; +} + +/* conn_close - do anything needed to shut down the connection */ + +void +conn_close(connectionObject *self) +{ + /* sets this connection as closed even for other threads; also note that + we need to check the value of pgconn, because we get called even when + the connection fails! */ + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&self->lock); + + self->closed = 1; + + /* execute a forced rollback on the connection (but don't check the + result, we're going to close the pq connection anyway */ + if (self->pgconn) { + pq_abort(self); + PQfinish(self->pgconn); + Dprintf("conn_close: PQfinish called"); + self->pgconn = NULL; + } + + pthread_mutex_unlock(&self->lock); + Py_END_ALLOW_THREADS; + +} + +/* conn_commit - commit on a connection */ + +int +conn_commit(connectionObject *self) +{ + int res; + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&self->lock); + + res = pq_commit(self); + self->mark++; + + pthread_mutex_unlock(&self->lock); + Py_END_ALLOW_THREADS; + + return res; +} + +/* conn_rollback - rollback a connection */ + +int +conn_rollback(connectionObject *self) +{ + int res; + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&self->lock); + + res = pq_abort(self); + self->mark++; + + pthread_mutex_unlock(&self->lock); + Py_END_ALLOW_THREADS; + + return res; +} + +/* conn_switch_isolation_level - switch isolation level on the connection */ + +int +conn_switch_isolation_level(connectionObject *self, int level) +{ + int res = 0; + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&self->lock); + + /* if the current isolation level is > 0 we need to abort the current + transaction before changing; that all folks! */ + if (self->isolation_level != level && self->isolation_level > 0) { + res = pq_abort(self); + } + self->isolation_level = level; + self->mark++; + + Dprintf("conn_switch_isolation_level: switched to level %d", level); + + pthread_mutex_unlock(&self->lock); + Py_END_ALLOW_THREADS; + + return res; +} + +/* conn_set_client_encoding - switch client encoding on connection */ + +int +conn_set_client_encoding(connectionObject *self, char *enc) +{ + PGresult *pgres; + char query[48]; + int res = 0; + + /* TODO: check for async query here and raise error if necessary */ + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&self->lock); + + /* set encoding, no encoding string is longer than 24 bytes */ + PyOS_snprintf(query, 47, "SET client_encoding = '%s'", enc); + + /* abort the current transaction, to set the encoding ouside of + transactions */ + res = pq_abort(self); + + if (res == 0) { + pgres = PQexec(self->pgconn, query); + + if (pgres == NULL || PQresultStatus(pgres) != PGRES_COMMAND_OK ) { + res = -1; + } + else { + /* no error, we can proceeed and store the new encoding */ + if (self->encoding) free(self->encoding); + self->encoding = strdup(enc); + } + + IFCLEARPGRES(pgres); + } + + Dprintf("conn_set_client_encoding: set encoding to %s", self->encoding); + + pthread_mutex_unlock(&self->lock); + Py_END_ALLOW_THREADS; + + if (res == -1) + PyErr_Format(OperationalError, "can't set encoding to %s", enc); + + return res; +} diff --git a/psycopg2/psycopg/connection_type.c b/psycopg2/psycopg/connection_type.c new file mode 100644 index 0000000..f8cbd80 --- /dev/null +++ b/psycopg2/psycopg/connection_type.c @@ -0,0 +1,422 @@ +/* connection_type.c - python interface to connection objects + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/connection.h" +#include "psycopg/cursor.h" + +/** DBAPI methods **/ + +/* cursor method - allocate a new cursor */ + +#define psyco_conn_cursor_doc \ +"cursor(cursor_factory=extensions.cursor) -- new cursor\n\n" \ +"Return a new cursor.\n\nThe ``cursor_factory`` argument can be used to\n" \ +"create non-standard cursors by passing a class different from the\n" \ +"default. Note that the new class *should* be a sub-class of\n" \ +"`extensions.cursor`.\n\n" \ +":rtype: `extensions.cursor`" + +static PyObject * +psyco_conn_cursor(connectionObject *self, PyObject *args, PyObject *keywds) +{ + char *name = NULL; + PyObject *obj, *factory = NULL; + + static char *kwlist[] = {"name", "cursor_factory", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sO", kwlist, + &name, &factory)) { + return NULL; + } + + EXC_IF_CONN_CLOSED(self); + + Dprintf("psyco_conn_cursor: new cursor for connection at %p", self); + Dprintf("psyco_conn_cursor: parameters: name = %s", name); + + if (factory == NULL) factory = (PyObject *)&cursorType; + if (name) + obj = PyObject_CallFunction(factory, "Os", self, name); + else + obj = PyObject_CallFunction(factory, "O", self); + + if (obj == NULL) return NULL; + if (PyObject_IsInstance(obj, (PyObject *)&cursorType) == 0) { + PyErr_SetString(PyExc_TypeError, + "cursor factory must be subclass of psycopg2._psycopg.cursor"); + Py_DECREF(obj); + return NULL; + } + + Dprintf("psyco_conn_cursor: new cursor at %p: refcnt = %d", + obj, obj->ob_refcnt); + return obj; +} + + +/* close method - close the connection and all related cursors */ + +#define psyco_conn_close_doc "close() -- Close the connection." + +static PyObject * +psyco_conn_close(connectionObject *self, PyObject *args) +{ + EXC_IF_CONN_CLOSED(self); + + if (!PyArg_ParseTuple(args, "")) return NULL; + + Dprintf("psyco_conn_close: closing connection at %p", self); + conn_close(self); + Dprintf("psyco_conn_close: connection at %p closed", self); + + Py_INCREF(Py_None); + return Py_None; +} + + +/* commit method - commit all changes to the database */ + +#define psyco_conn_commit_doc "commit() -- Commit all changes to database." + +static PyObject * +psyco_conn_commit(connectionObject *self, PyObject *args) +{ + EXC_IF_CONN_CLOSED(self); + + if (!PyArg_ParseTuple(args, "")) return NULL; + + /* FIXME: check return status? */ + conn_commit(self); + + Py_INCREF(Py_None); + return Py_None; +} + + +/* rollback method - roll back all changes done to the database */ + +#define psyco_conn_rollback_doc \ +"rollback() -- Roll back all changes done to database." + +static PyObject * +psyco_conn_rollback(connectionObject *self, PyObject *args) +{ + EXC_IF_CONN_CLOSED(self); + + if (!PyArg_ParseTuple(args, "")) return NULL; + + /* FIXME: check return status? */ + conn_rollback(self); + + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef PSYCOPG_EXTENSIONS +/* set_isolation_level method - switch connection isolation level */ + +#define psyco_conn_set_isolation_level_doc \ +"set_isolation_level(level) -- Switch isolation level to ``level``." + +static PyObject * +psyco_conn_set_isolation_level(connectionObject *self, PyObject *args) +{ + int level = 1; + + EXC_IF_CONN_CLOSED(self); + + if (!PyArg_ParseTuple(args, "i", &level)) return NULL; + + if (level < 0 || level > 2) { + PyErr_SetString(PyExc_ValueError, + "isolation level out of bounds (0,3)"); + return NULL; + } + + /* FIXME: check return status? */ + conn_switch_isolation_level(self, level); + + Py_INCREF(Py_None); + return Py_None; +} + + + +/* set_isolation_level method - switch connection isolation level */ + +#define psyco_conn_set_client_encoding_doc \ +"set_client_encoding(encoding) -- Set client encoding to ``encoding``." + +static PyObject * +psyco_conn_set_client_encoding(connectionObject *self, PyObject *args) +{ + char *enc = NULL; + + EXC_IF_CONN_CLOSED(self); + + if (!PyArg_ParseTuple(args, "s", &enc)) return NULL; + + if (conn_set_client_encoding(self, enc) == 0) { + Py_INCREF(Py_None); + return Py_None; + } + else { + return NULL; + } +} +#endif + + +/** the connection object **/ + + +/* object method list */ + +static struct PyMethodDef connectionObject_methods[] = { + {"cursor", (PyCFunction)psyco_conn_cursor, + METH_VARARGS|METH_KEYWORDS, psyco_conn_cursor_doc}, + {"close", (PyCFunction)psyco_conn_close, + METH_VARARGS, psyco_conn_close_doc}, + {"commit", (PyCFunction)psyco_conn_commit, + METH_VARARGS, psyco_conn_commit_doc}, + {"rollback", (PyCFunction)psyco_conn_rollback, + METH_VARARGS, psyco_conn_rollback_doc}, +#ifdef PSYCOPG_EXTENSIONS + {"set_isolation_level", (PyCFunction)psyco_conn_set_isolation_level, + METH_VARARGS, psyco_conn_set_isolation_level_doc}, + {"set_client_encoding", (PyCFunction)psyco_conn_set_client_encoding, + METH_VARARGS, psyco_conn_set_client_encoding_doc}, +#endif + {NULL} +}; + +/* object member list */ + +static struct PyMemberDef connectionObject_members[] = { + /* DBAPI-2.0 extensions (exception objects) */ + {"Error", T_OBJECT, + offsetof(connectionObject, exc_Error), RO, Error_doc}, + {"Warning", + T_OBJECT, offsetof(connectionObject, exc_Warning), RO, Warning_doc}, + {"InterfaceError", T_OBJECT, + offsetof(connectionObject, exc_InterfaceError), RO, + InterfaceError_doc}, + {"DatabaseError", T_OBJECT, + offsetof(connectionObject, exc_DatabaseError), RO, DatabaseError_doc}, + {"InternalError", T_OBJECT, + offsetof(connectionObject, exc_InternalError), RO, InternalError_doc}, + {"OperationalError", T_OBJECT, + offsetof(connectionObject, exc_OperationalError), RO, + OperationalError_doc}, + {"ProgrammingError", T_OBJECT, + offsetof(connectionObject, exc_ProgrammingError), RO, + ProgrammingError_doc}, + {"IntegrityError", T_OBJECT, + offsetof(connectionObject, exc_IntegrityError), RO, + IntegrityError_doc}, + {"DataError", T_OBJECT, + offsetof(connectionObject, exc_DataError), RO, DataError_doc}, + {"NotSupportedError", T_OBJECT, + offsetof(connectionObject, exc_NotSupportedError), RO, + NotSupportedError_doc}, +#ifdef PSYCOPG_EXTENSIONS + {"closed", T_LONG, offsetof(connectionObject, closed), RO, + "True if the connection is closed."}, + {"isolation_level", T_LONG, + offsetof(connectionObject, isolation_level), RO, + "The current isolation level."}, + {"encoding", T_STRING, offsetof(connectionObject, encoding), RO, + "The current client encoding."}, + {"notices", T_OBJECT, offsetof(connectionObject, notice_list), RO}, + {"notifies", T_OBJECT, offsetof(connectionObject, notifies), RO}, + {"dsn", T_STRING, offsetof(connectionObject, dsn), RO, + "The current connection string."}, + {"status", T_LONG, + offsetof(connectionObject, status), RO, + "The current transaction status."}, +#endif + {NULL} +}; + +/* initialization and finalization methods */ + +static int +connection_setup(connectionObject *self, char *dsn) +{ + Dprintf("connection_setup: init connection object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + + self->dsn = strdup(dsn); + self->notice_list = PyList_New(0); + self->notifies = PyList_New(0); + self->closed = 0; + self->status = CONN_STATUS_READY; + self->critical = NULL; + self->async_cursor = NULL; + self->pgconn = NULL; + self->mark = 0; + + pthread_mutex_init(&(self->lock), NULL); + + if (conn_connect(self) != 0) { + pthread_mutex_destroy(&(self->lock)); + Dprintf("connection_init: FAILED"); + return -1; + } + + Dprintf("connection_setup: good connection object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +connection_dealloc(PyObject* obj) +{ + connectionObject *self = (connectionObject *)obj; + + if (self->closed == 0) conn_close(self); + + if (self->dsn) free(self->dsn); + if (self->encoding) PyMem_Free(self->encoding); + if (self->critical) free(self->critical); + + Py_XDECREF(self->notice_list); + Py_XDECREF(self->notifies); + Py_XDECREF(self->async_cursor); + + pthread_mutex_destroy(&(self->lock)); + + Dprintf("connection_dealloc: deleted connection object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +connection_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + char *dsn; + + if (!PyArg_ParseTuple(args, "s", &dsn)) + return -1; + + return connection_setup((connectionObject *)obj, dsn); +} + +static PyObject * +connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +connection_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +connection_repr(connectionObject *self) +{ + return PyString_FromFormat( + "", + self, self->dsn, self->closed); +} + + +/* object type */ + +#define connectionType_doc \ +"connection(dsn, ...) -> new connection object\n\n" \ +":Groups:\n" \ +" * `DBAPI-2.0 errors`: Error, Warning, InterfaceError,\n" \ +" DatabaseError, InternalError, OperationalError,\n" \ +" ProgrammingError, IntegrityError, DataError, NotSupportedError" + +PyTypeObject connectionType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.connection", + sizeof(connectionObject), + 0, + connection_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)connection_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)connection_repr, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + connectionType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + connectionObject_methods, /*tp_methods*/ + connectionObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + connection_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + connection_new, /*tp_new*/ + (freefunc)connection_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; diff --git a/psycopg2/psycopg/cursor.h b/psycopg2/psycopg/cursor.h new file mode 100644 index 0000000..5aab172 --- /dev/null +++ b/psycopg2/psycopg/cursor.h @@ -0,0 +1,103 @@ +/* cursor.h - definition for the psycopg cursor type + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_CURSOR_H +#define PSYCOPG_CURSOR_H 1 + +#include +#include + +#include "psycopg/connection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject cursorType; + +typedef struct { + PyObject HEAD; + + connectionObject *conn; /* connection owning the cursor */ + + int closed:1; /* 1 if the cursor is closed */ + int notuples:1; /* 1 if the command was not a SELECT query */ + int needsfetch:1; /* 1 if a call to pq_fetch is pending */ + + long int rowcount; /* number of rows affected by last execute */ + long int columns; /* number of columns fetched from the db */ + long int arraysize; /* how many rows should fetchmany() return */ + long int row; /* the row counter for fetch*() operations */ + long int mark; /* transaction marker, copied from conn */ + + PyObject *description; /* read-only attribute: sequence of 7-item + sequences.*/ + + /* postgres connection stuff */ + PGresult *pgres; /* result of last query */ + PyObject *pgstatus; /* last message from the server after an execute */ + Oid lastoid; /* last oid from an insert or InvalidOid */ + + PyObject *casts; /* an array (tuple) of typecast functions */ + PyObject *caster; /* the current typecaster object */ + + PyObject *copyfile; /* file-like used during COPY TO/FROM ops */ + long int copysize; /* size of the copy buffer during COPY TO/FROM ops */ +#define DEFAULT_COPYSIZE 16384 + + PyObject *tuple_factory; /* factory for result tuples */ + PyObject *tzinfo_factory; /* factory for tzinfo objects */ + + PyObject *query; /* last query executed */ + + char *qattr; /* quoting attr, used when quoting strings */ + char *notice; /* a notice from the backend */ + char *name; /* this cursor name */ + + PyObject *string_types; /* a set of typecasters for string types */ + PyObject *binary_types; /* a set of typecasters for binary types */ + +} cursorObject; + +/* C-callable functions in cursor_int.c and cursor_ext.c */ +extern void curs_reset(cursorObject *self); + +/* exception-raising macros */ +#define EXC_IF_CURS_CLOSED(self) \ +if ((self)->closed || ((self)->conn && (self)->conn->closed)) { \ + PyErr_SetString(InterfaceError, "cursor already closed"); \ + return NULL; } + +#define EXC_IF_NO_TUPLES(self) \ +if ((self)->notuples && (self)->name == NULL) { \ + PyErr_SetString(ProgrammingError, "no results to fetch"); \ + return NULL; } + +#define EXC_IF_NO_MARK(self) \ +if ((self)->mark != (self)->conn->mark) { \ + PyErr_SetString(ProgrammingError, "named cursor isn't valid anymore"); \ + return NULL; } + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_CURSOR_H) */ diff --git a/psycopg2/psycopg/cursor_int.c b/psycopg2/psycopg/cursor_int.c new file mode 100644 index 0000000..8036268 --- /dev/null +++ b/psycopg2/psycopg/cursor_int.c @@ -0,0 +1,47 @@ +/* cursor_int.c - code used by the cursor object + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/psycopg.h" +#include "psycopg/cursor.h" +#include "psycopg/pqpath.h" + +/* curs_reset - reset the cursor to a clean state */ + +void +curs_reset(cursorObject *self) +{ + /* initialize some variables to default values */ + self->notuples = 1; + self->rowcount = -1; + self->row = 0; + + Py_XDECREF(self->description); + Py_INCREF(Py_None); + self->description = Py_None; + + Py_XDECREF(self->casts); + self->casts = NULL; +} diff --git a/psycopg2/psycopg/cursor_type.c b/psycopg2/psycopg/cursor_type.c new file mode 100644 index 0000000..73e4de6 --- /dev/null +++ b/psycopg2/psycopg/cursor_type.c @@ -0,0 +1,1553 @@ +/* cursor_type.c - python interface to cursor objects + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public Likcense + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/cursor.h" +#include "psycopg/connection.h" +#include "psycopg/pqpath.h" +#include "psycopg/typecast.h" +#include "psycopg/microprotocols.h" +#include "psycopg/microprotocols_proto.h" +#include "pgversion.h" + +extern PyObject *pyPsycopgTzFixedOffsetTimezone; + + +/** DBAPI methods **/ + +/* close method - close the cursor */ + +#define psyco_curs_close_doc \ +"close() -- Close the cursor." + +static PyObject * +psyco_curs_close(cursorObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + + EXC_IF_CURS_CLOSED(self); + + if (self->name != NULL) { + char buffer[128]; + + EXC_IF_NO_MARK(self); + PyOS_snprintf(buffer, 127, "CLOSE %s", self->name); + if (pq_execute(self, buffer, 0) == -1) return NULL; + } + + self->closed = 1; + Dprintf("psyco_curs_close: cursor at %p closed", self); + + Py_INCREF(Py_None); + return Py_None; +} + + +/* execute method - executes a query */ + +/* mogrify a query string and build argument array or dict */ + +static int +_mogrify(PyObject *var, PyObject *fmt, connectionObject *conn, PyObject **new) +{ + PyObject *key, *value, *n, *item; + char *d, *c; + int index = 0, force = 0; + + /* from now on we'll use n and replace its value in *new only at the end, + just before returning. we also init *new to NULL to exit with an error + if we can't complete the mogrification */ + n = *new = NULL; + c = PyString_AsString(fmt); + + while(*c) { + /* handle plain percent symbol in format string */ + if (c[0] == '%' && c[1] == '%') { + c+=2; force = 1; + } + + /* if we find '%(' then this is a dictionary, we: + 1/ find the matching ')' and extract the key name + 2/ locate the value in the dictionary (or return an error) + 3/ mogrify the value into something usefull (quoting)... + 4/ ...and add it to the new dictionary to be used as argument + */ + else if (c[0] == '%' && c[1] == '(') { + + /* let's have d point the end of the argument */ + for (d = c + 2; *d && *d != ')'; d++); + + if (*d == ')') { + key = PyString_FromStringAndSize(c+2, d-c-2); + value = PyObject_GetItem(var, key); + /* key has refcnt 1, value the original value + 1 */ + + /* if value is NULL we did not find the key (or this is not a + dictionary): let python raise a KeyError */ + if (value == NULL) { + Py_DECREF(key); /* destroy key */ + Py_XDECREF(n); /* destroy n */ + return -1; + } + + Dprintf("_mogrify: value refcnt: %d (+1)", value->ob_refcnt); + + if (n == NULL) { + n = PyDict_New(); + } + + if ((item = PyObject_GetItem(n, key)) == NULL) { + PyObject *t = NULL; + + PyErr_Clear(); + + /* None is always converted to NULL; this is an + optimization over the adapting code and can go away in + the future if somebody finds a None adapter usefull. */ + if (value == Py_None) { + t = PyString_FromString("NULL"); + PyDict_SetItem(n, key, t); + /* t is a new object, refcnt = 1, key is at 2 */ + + /* if the value is None we need to substitute the + formatting char with 's' (FIXME: this should not be + necessary if we drop support for formats other than + %s!) */ + while (*d && !isalpha(*d)) d++; + if (*d) *d = 's'; + } + else { + t = microprotocol_getquoted(value, conn); + + if (t != NULL) { + PyDict_SetItem(n, key, t); + /* both key and t refcnt +1, key is at 2 now */ + } + else { + /* no adapter found, raise a BIG exception */ + Py_XDECREF(value); + Py_DECREF(n); + return -1; + } + } + + Py_XDECREF(t); /* t dies here */ + /* after the DECREF value has the original refcnt plus 1 + if it was added to the dictionary directly; good */ + Py_XDECREF(value); + } + else { + /* we have an item with one extra refcnt here, zap! */ + Py_DECREF(item); + } + Py_DECREF(key); /* key has the original refcnt now */ + Dprintf("_mogrify: after value refcnt: %d",value->ob_refcnt); + } + c = d; + } + + else if (c[0] == '%' && c[1] != '(') { + /* this is a format that expects a tuple; it is much easier, + because we don't need to check the old/new dictionary for + keys */ + + value = PySequence_GetItem(var, index); + /* value has refcnt inc'ed by 1 here */ + + /* if value is NULL this is not a sequence or the index is wrong; + anyway we let python set its own exception */ + if (value == NULL) { + Py_XDECREF(n); + return -1; + } + + if (n == NULL) { + n = PyTuple_New(PyObject_Length(var)); + } + + /* let's have d point just after the '%' */ + d = c+1; + + if (value == Py_None) { + PyTuple_SET_ITEM(n, index, PyString_FromString("NULL")); + while (*d && !isalpha(*d)) d++; + if (*d) *d = 's'; + Py_DECREF(value); + } + else { + PyObject *t = microprotocol_getquoted(value, conn); + + if (t != NULL) { + PyTuple_SET_ITEM(n, index, t); + Py_DECREF(value); + } + else { + Py_DECREF(n); + Py_DECREF(value); + return -1; + } + } + c = d; + index += 1; + } + else { + c++; + } + } + + if (force && n == NULL) + n = PyTuple_New(0); + *new = n; + + return 0; +} + +#define psyco_curs_execute_doc \ +"execute(query, vars=None, async=0) -- Execute query with bound vars." + +static int +_psyco_curs_execute(cursorObject *self, + PyObject *operation, PyObject *vars, long int async) +{ + int res; + PyObject *fquery, *cvt = NULL, *uoperation = NULL; + + pthread_mutex_lock(&(self->conn->lock)); + if (self->conn->async_cursor != NULL + && self->conn->async_cursor != (PyObject*)self) { + pthread_mutex_unlock(&(self->conn->lock)); + psyco_set_error(ProgrammingError, (PyObject*)self, + "asynchronous query already in execution", NULL, NULL); + return 0; + } + pthread_mutex_unlock(&(self->conn->lock)); + + if (!PyObject_IsTrue(operation)) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't execute an empty query", NULL, NULL); + return 0; + } + + if (PyUnicode_Check(operation)) { + PyObject *enc = PyDict_GetItemString(psycoEncodings, + self->conn->encoding); + /* enc is a borrowed reference, we won't decref it */ + + if (enc) { + operation = PyUnicode_AsEncodedString( + operation, PyString_AsString(enc), NULL); + + /* if there was an error during the encoding from unicode to the + target encoding we just let the exception propagate */ + if (operation == NULL) return 0; + + /* we clone operation in uoperation to be sure to free it later */ + uoperation = operation; + } + else { + PyErr_Format(InterfaceError, "can't encode unicode query to %s", + self->conn->encoding); + return 0; + } + } + else if (!PyString_Check(operation)) { + /* the operation is not unicode or string, raise an error */ + PyErr_SetString(PyExc_TypeError, + "argument 1 must be a string or unicode object"); + return 0; + } + + IFCLEARPGRES(self->pgres); + + if (self->query) { + Py_DECREF(self->query); + self->query = NULL; + } + + Dprintf("psyco_curs_execute: starting execution of new query"); + + /* here we are, and we have a sequence or a dictionary filled with + objects to be substituted (bound variables). we try to be smart and do + the right thing (i.e., what the user expects) */ + + if (vars && vars != Py_None) + { + if(_mogrify(vars, operation, self->conn, &cvt) == -1) { + Py_XDECREF(uoperation); + return 0; + } + } + + if (vars && cvt) { + /* if PyString_Format() return NULL an error occured: if the error is + a TypeError we need to check the exception.args[0] string for the + values: + + "not enough arguments for format string" + "not all arguments converted" + + and return the appropriate ProgrammingError. we do that by grabbing + the curren exception (we will later restore it if the type or the + strings do not match.) */ + + if (!(fquery = PyString_Format(operation, cvt))) { + PyObject *err, *arg, *trace; + int pe = 0; + + PyErr_Fetch(&err, &arg, &trace); + + if (err && PyErr_GivenExceptionMatches(err, PyExc_TypeError)) { + Dprintf("psyco_curs_execute: TypeError exception catched"); + PyErr_NormalizeException(&err, &arg, &trace); + + if (PyObject_HasAttrString(arg, "args")) { + PyObject *args = PyObject_GetAttrString(arg, "args"); + PyObject *str = PySequence_GetItem(args, 0); + char *s = PyString_AS_STRING(str); + + Dprintf("psyco_curs_execute: -> %s", s); + + if (!strcmp(s, "not enough arguments for format string") + || !strcmp(s, "not all arguments converted")) { + Dprintf("psyco_curs_execute: -> got a match"); + psyco_set_error(ProgrammingError, (PyObject*)self, + s, NULL, NULL); + pe = 1; + } + + Py_DECREF(args); + Py_DECREF(str); + } + } + + /* if we did not manage our own exception, restore old one */ + if (pe == 1) { + Py_XDECREF(err); Py_XDECREF(arg); Py_XDECREF(trace); + } + else { + PyErr_Restore(err, arg, trace); + } + Py_XDECREF(uoperation); + return 0; + } + + if (self->name != NULL) { + self->query = PyString_FromFormat( + "DECLARE %s CURSOR WITHOUT HOLD FOR %s", + self->name, PyString_AS_STRING(fquery)); + Py_DECREF(fquery); + } + else { + self->query = fquery; + } + + Dprintf("psyco_curs_execute: cvt->refcnt = %d", cvt->ob_refcnt); + Py_DECREF(cvt); + } + else { + if (self->name != NULL) { + self->query = PyString_FromFormat( + "DECLARE %s CURSOR WITHOUT HOLD FOR %s", + self->name, PyString_AS_STRING(operation)); + } + else { + Py_INCREF(operation); + self->query = operation; + } + } + + res = pq_execute(self, PyString_AS_STRING(self->query), async); + + Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres); + + Py_XDECREF(uoperation); + + return res == -1 ? 0 : 1; +} + +static PyObject * +psyco_curs_execute(cursorObject *self, PyObject *args, PyObject *kwargs) +{ + long int async = 0; + PyObject *vars = NULL, *operation = NULL; + + static char *kwlist[] = {"query", "vars", "async", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi", kwlist, + &operation, &vars, &async)) { + return NULL; + } + + if (self->name != NULL) { + if (self->query != Py_None) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't call .execute() on named cursors more than once", + NULL, NULL); + return NULL; + } + if (self->conn->isolation_level == 0) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't use a named cursor outside of transactions", NULL, NULL); + return NULL; + } + if (self->conn->mark != self->mark) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "named cursor isn't valid anymore", NULL, NULL); + return NULL; + } + } + + EXC_IF_CURS_CLOSED(self); + + if (_psyco_curs_execute(self, operation, vars, async)) { + Py_INCREF(Py_None); + return Py_None; + } + else { + return NULL; + } +} + +#define psyco_curs_executemany_doc \ +"executemany(query, vars_list) -- Execute many queries with bound vars." + +static PyObject * +psyco_curs_executemany(cursorObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *operation = NULL, *vars = NULL; + PyObject *v, *iter = NULL; + + static char *kwlist[] = {"query", "vars_list", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", kwlist, + &operation, &vars)) { + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + + if (self->name != NULL) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't call .executemany() on named cursors", NULL, NULL); + return NULL; + } + + if (!PyIter_Check(vars)) { + vars = iter = PyObject_GetIter(vars); + if (iter == NULL) return NULL; + } + + while ((v = PyIter_Next(vars)) != NULL) { + if (_psyco_curs_execute(self, operation, v, 0) == 0) { + Py_DECREF(v); + return NULL; + } + else { + Py_DECREF(v); + } + } + Py_XDECREF(iter); + + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef PSYCOPG_EXTENSIONS +#define psyco_curs_mogrify_doc \ +"mogrify(query, vars=None) -> str -- Return query after vars binding." + +static PyObject * +psyco_curs_mogrify(cursorObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *vars = NULL, *cvt = NULL, *operation = NULL; + PyObject *fquery; + + static char *kwlist[] = {"query", "vars", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, + &operation, &vars)) { + return NULL; + } + + if (PyUnicode_Check(operation)) { + PyErr_SetString(NotSupportedError, + "unicode queries not yet supported"); + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + IFCLEARPGRES(self->pgres); + + /* note that we don't overwrite the last query executed on the cursor, we + just *return* the new query with bound variables + + TODO: refactor the common mogrification code (see psycopg_curs_execute + for comments, the code is amost identical) */ + + if (vars) + { + if(_mogrify(vars, operation, self->conn, &cvt) == -1) return NULL; + } + + if (vars && cvt) { + if (!(fquery = PyString_Format(operation, cvt))) { + PyObject *err, *arg, *trace; + int pe = 0; + + PyErr_Fetch(&err, &arg, &trace); + + if (err && PyErr_GivenExceptionMatches(err, PyExc_TypeError)) { + Dprintf("psyco_curs_execute: TypeError exception catched"); + PyErr_NormalizeException(&err, &arg, &trace); + + if (PyObject_HasAttrString(arg, "args")) { + PyObject *args = PyObject_GetAttrString(arg, "args"); + PyObject *str = PySequence_GetItem(args, 0); + char *s = PyString_AS_STRING(str); + + Dprintf("psyco_curs_execute: -> %s", s); + + if (!strcmp(s, "not enough arguments for format string") + || !strcmp(s, "not all arguments converted")) { + Dprintf("psyco_curs_execute: -> got a match"); + psyco_set_error(ProgrammingError, (PyObject*)self, + s, NULL, NULL); + pe = 1; + } + + Py_DECREF(args); + Py_DECREF(str); + } + } + + /* if we did not manage our own exception, restore old one */ + if (pe == 1) { + Py_XDECREF(err); Py_XDECREF(arg); Py_XDECREF(trace); + } + else { + PyErr_Restore(err, arg, trace); + } + return NULL; + } + + Dprintf("psyco_curs_execute: cvt->refcnt = %d, fquery->refcnt = %d", + cvt->ob_refcnt, fquery->ob_refcnt); + Py_DECREF(cvt); + } + else { + fquery = operation; + Py_INCREF(operation); + } + + return fquery; +} +#endif + + +/* fetchone method - fetch one row of results */ + +#define psyco_curs_fetchone_doc \ +"fetchone() -> tuple or None\n\n" \ +"Return the next row of a query result set in the form of a tuple (by\n" \ +"default) or using the sequence factory previously set in the\n" \ +"`row_factory` attribute. Return `None` when no more data is available.\n" + +static int +_psyco_curs_prefetch(cursorObject *self) +{ + int i = 0; + + /* check if the fetching cursor is the one that did the asynchronous query + and raise an exception if not */ + pthread_mutex_lock(&(self->conn->lock)); + if (self->conn->async_cursor != NULL + && self->conn->async_cursor != (PyObject*)self) { + pthread_mutex_unlock(&(self->conn->lock)); + psyco_set_error(ProgrammingError, (PyObject*)self, + "asynchronous fetch by wrong cursor", NULL, NULL); + return -2; + } + pthread_mutex_unlock(&(self->conn->lock)); + + if (self->pgres == NULL || self->needsfetch) { + self->needsfetch = 0; + Dprintf("_psyco_curs_prefetch: trying to fetch data"); + do { + i = pq_fetch(self); + Dprintf("_psycopg_curs_prefetch: result = %d", i); + } while(i == 1); + } + + Dprintf("_psyco_curs_prefetch: result = %d", i); + return i; +} + +static PyObject * +_psyco_curs_buildrow_fill(cursorObject *self, PyObject *res, + int row, int n, int istuple) +{ + int i, len; + unsigned char *str; + PyObject *val; + + for (i=0; i < n; i++) { + if (PQgetisnull(self->pgres, row, i)) { + str = NULL; + len = 0; + } + else { + str = (unsigned char*)PQgetvalue(self->pgres, row, i); + len = PQgetlength(self->pgres, row, i); + } + + Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %i", + self->row, i, len); + + val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), (char*)str, len, + (PyObject*)self); + + if (val) { + Dprintf("_psyco_curs_buildrow: val->refcnt = %d", val->ob_refcnt); + if (istuple) { + PyTuple_SET_ITEM(res, i, val); + } + else { + PySequence_SetItem(res, i, val); + Py_DECREF(val); + } + } + else { + /* an error occurred in the type system, we return NULL to raise + an exception. the typecast code should already have set the + exception type and text */ + Py_DECREF(res); + res = NULL; + break; + } + } + return res; +} + +static PyObject * +_psyco_curs_buildrow(cursorObject *self, int row) +{ + int n; + + n = PQnfields(self->pgres); + return _psyco_curs_buildrow_fill(self, PyTuple_New(n), row, n, 1); +} + +static PyObject * +_psyco_curs_buildrow_with_factory(cursorObject *self, int row) +{ + int n; + PyObject *res; + + n = PQnfields(self->pgres); + if ((res = PyObject_CallFunction(self->tuple_factory, "O", self))== NULL) + return NULL; + + return _psyco_curs_buildrow_fill(self, res, row, n, 0); +} + +PyObject * +psyco_curs_fetchone(cursorObject *self, PyObject *args) +{ + PyObject *res; + + if (args && !PyArg_ParseTuple(args, "")) return NULL; + + EXC_IF_CURS_CLOSED(self) + if (_psyco_curs_prefetch(self) < 0) return NULL; + EXC_IF_NO_TUPLES(self); + + if (self->name != NULL) { + char buffer[128]; + + EXC_IF_NO_MARK(self); + PyOS_snprintf(buffer, 127, "FETCH FORWARD 1 FROM %s", self->name); + if (pq_execute(self, buffer, 0) == -1) return NULL; + if (_psyco_curs_prefetch(self) < 0) return NULL; + } + + Dprintf("psyco_curs_fetchone: fetching row %ld", self->row); + Dprintf("psyco_curs_fetchone: rowcount = %ld", self->rowcount); + + if (self->row >= self->rowcount) { + /* we exausted available data: return None */ + Py_INCREF(Py_None); + return Py_None; + } + + if (self->tuple_factory == Py_None) + res = _psyco_curs_buildrow(self, self->row); + else + res = _psyco_curs_buildrow_with_factory(self, self->row); + + self->row++; /* move the counter to next line */ + + /* if the query was async aggresively free pgres, to allow + successive requests to reallocate it */ + if (self->row >= self->rowcount + && self->conn->async_cursor == (PyObject*)self) + IFCLEARPGRES(self->pgres); + + return res; +} + + +/* fetch many - fetch some results */ + +#define psyco_curs_fetchmany_doc \ +"fetchmany(size=self.arraysize) -> list of tuple\n\n" \ +"Return the next `size` rows of a query result set in the form of a list\n" \ +"of tuples (by default) or using the sequence factory previously set in\n" \ +"the `row_factory` attribute. Return `None` when no more data is available.\n" + +PyObject * +psyco_curs_fetchmany(cursorObject *self, PyObject *args, PyObject *kwords) +{ + int i; + PyObject *list, *res; + + long int size = self->arraysize; + static char *kwlist[] = {"size", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwords, "|l", kwlist, &size)) { + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + if (_psyco_curs_prefetch(self) < 0) return NULL; + EXC_IF_NO_TUPLES(self); + + if (self->name != NULL) { + char buffer[128]; + + EXC_IF_NO_MARK(self); + PyOS_snprintf(buffer, 127, "FETCH FORWARD %d FROM %s", + (int)size, self->name); + if (pq_execute(self, buffer, 0) == -1) return NULL; + if (_psyco_curs_prefetch(self) < 0) return NULL; + } + + /* make sure size is not > than the available number of rows */ + if (size > self->rowcount - self->row || size < 0) { + size = self->rowcount - self->row; + } + + Dprintf("psyco_curs_fetchmany: size = %ld", size); + + if (size <= 0) { + return PyList_New(0); + } + + list = PyList_New(size); + + for (i = 0; i < size; i++) { + if (self->tuple_factory == Py_None) + res = _psyco_curs_buildrow(self, self->row); + else + res = _psyco_curs_buildrow_with_factory(self, self->row); + + self->row++; + + if (res == NULL) { + Py_DECREF(list); + return NULL; + } + + PyList_SET_ITEM(list, i, res); + } + + /* if the query was async aggresively free pgres, to allow + successive requests to reallocate it */ + if (self->row >= self->rowcount + && self->conn->async_cursor == (PyObject*)self) + IFCLEARPGRES(self->pgres); + + return list; +} + + +/* fetch all - fetch all results */ + +#define psyco_curs_fetchall_doc \ +"fetchall() -> list of tuple\n\n" \ +"Return all the remaining rows of a query result set.\n\n" \ +"Rows are returned in the form of a list of tuples (by default) or using\n" \ +"the sequence factory previously set in the `row_factory` attribute.\n" \ +"Return `None` when no more data is available.\n" + +PyObject * +psyco_curs_fetchall(cursorObject *self, PyObject *args) +{ + int i, size; + PyObject *list, *res; + + if (!PyArg_ParseTuple(args, "")) { + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + if (_psyco_curs_prefetch(self) < 0) return NULL; + EXC_IF_NO_TUPLES(self); + + if (self->name != NULL) { + char buffer[128]; + + EXC_IF_NO_MARK(self); + PyOS_snprintf(buffer, 127, "FETCH FORWARD ALL FROM %s", self->name); + if (pq_execute(self, buffer, 0) == -1) return NULL; + if (_psyco_curs_prefetch(self) < 0) return NULL; + } + + size = self->rowcount - self->row; + + if (size <= 0) { + return PyList_New(0); + } + + list = PyList_New(size); + + for (i = 0; i < size; i++) { + if (self->tuple_factory == Py_None) + res = _psyco_curs_buildrow(self, self->row); + else + res = _psyco_curs_buildrow_with_factory(self, self->row); + + self->row++; + + if (res == NULL) { + Py_DECREF(list); + return NULL; + } + + PyList_SET_ITEM(list, i, res); + } + + /* if the query was async aggresively free pgres, to allow + successive requests to reallocate it */ + if (self->row >= self->rowcount + && self->conn->async_cursor == (PyObject*)self) + IFCLEARPGRES(self->pgres); + + return list; +} + + +/* callproc method - execute a stored procedure */ + +#define psyco_curs_callproc_doc \ +"callproc(procname, parameters=None, async=0) -- Execute stored procedure." + +static PyObject * +psyco_curs_callproc(cursorObject *self, PyObject *args, PyObject *kwargs) +{ + char *procname = NULL, *sql = NULL; + long int async = 0; + int i, nparameters = 0, sl = 0; + PyObject *parameters = NULL; + PyObject *operation = NULL; + PyObject *res = NULL; + + if (!PyArg_ParseTuple(args, "s|Oi", &procname, ¶meters, &async)) { + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + + if (self->name != NULL) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "can't call .callproc() on named cursors", NULL, NULL); + return NULL; + } + + if(parameters && parameters != Py_None) { + nparameters = PyObject_Length(parameters); + if (nparameters < 0) nparameters = 0; + } + + /* allocate some memory, build the SQL and create a PyString from it */ + sl = strlen(procname) + 10 + nparameters*3 - (nparameters ? 1 : 0); + sql = (char*)PyMem_Malloc(sl); + if (sql == NULL) return NULL; + + sprintf(sql, "SELECT %s(", procname); + for(i=0; iname == NULL) { + if (strcmp(mode, "relative") == 0) { + newpos = self->row + value; + } else if (strcmp( mode, "absolute") == 0) { + newpos = value; + } else { + psyco_set_error(ProgrammingError, (PyObject*)self, + "scroll mode must be 'relative' or 'absolute'", NULL, NULL); + return NULL; + } + + if (newpos < 0 || newpos >= self->rowcount ) { + psyco_set_error(ProgrammingError, (PyObject*)self, + "scroll destination out of bounds", NULL, NULL); + return NULL; + } + + self->row = newpos; + } + + else { + char buffer[128]; + + EXC_IF_NO_MARK(self); + + if (strcmp(mode, "absolute") == 0) { + PyOS_snprintf(buffer, 127, "MOVE ABSOLUTE %d FROM %s", + value, self->name); + } + else { + PyOS_snprintf(buffer, 127, "MOVE %d FROM %s", value, self->name); + } + if (pq_execute(self, buffer, 0) == -1) return NULL; + if (_psyco_curs_prefetch(self) < 0) return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef PSYCOPG_EXTENSIONS + +/* extension: copy_from - implements COPY FROM */ + +#define psyco_curs_copy_from_doc \ +"copy_from(file, table, sep='\\t', null='\\N', columns=None) -- Copy table from file." + +static int +_psyco_curs_has_read_check(PyObject* o, void* var) +{ + if (PyObject_HasAttrString(o, "readline") + && PyObject_HasAttrString(o, "read")) { + Py_INCREF(o); + *((PyObject**)var) = o; + return 1; + } + else { + PyErr_SetString(PyExc_TypeError, + "argument 1 must have both .read() and .readline() methods"); + return 0; + } +} + +static PyObject * +psyco_curs_copy_from(cursorObject *self, PyObject *args, PyObject *kwargs) +{ + char query[1024]; + char *table_name; + char *sep = "\t", *null = NULL; + long int bufsize = DEFAULT_COPYSIZE; + PyObject *file, *columns = NULL, *res = NULL; + char columnlist[1024] = ""; + + static char *kwlist[] = {"file", "table", "sep", "null", "size", + "columns", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ssiO", kwlist, + _psyco_curs_has_read_check, &file, + &table_name, &sep, &null, &bufsize, + &columns)) { + return NULL; + } + + if (columns != NULL && columns != Py_None) { + PyObject* collistiter = PyObject_GetIter(columns); + PyObject* col; + int collistlen = 2; + int colitemlen; + char* colname; + if (collistiter == NULL) { + return NULL; + } + strcpy(columnlist, " ("); + while ((col = PyIter_Next(collistiter)) != NULL) { + if (!PyString_Check(col)) { + Py_DECREF(col); + Py_DECREF(collistiter); + PyErr_SetString(PyExc_ValueError, + "Elements in column list must be strings"); + return NULL; + } + PyString_AsStringAndSize(col, &colname, &colitemlen); + if (collistlen + colitemlen > 1022) { + Py_DECREF(col); + Py_DECREF(collistiter); + PyErr_SetString(PyExc_ValueError, "Column list too long"); + return NULL; + } + strncpy(&columnlist[collistlen], colname, colitemlen); + collistlen += colitemlen; + columnlist[collistlen++] = ','; + Py_DECREF(col); + } + Py_DECREF(collistiter); + + if (collistlen == 2) { /* empty list; we printed no comma */ + collistlen++; + } + + columnlist[collistlen - 1] = ')'; + columnlist[collistlen] = '\0'; + } + + if (PyErr_Occurred()) { + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + + if (null) { + PyOS_snprintf(query, 1023, "COPY %s%s FROM stdin USING DELIMITERS '%s'" + " WITH NULL AS '%s'", table_name, columnlist, sep, null); + } + else { + PyOS_snprintf(query, 1023, "COPY %s%s FROM stdin USING DELIMITERS '%s'", + table_name, columnlist, sep); + } + Dprintf("psyco_curs_copy_from: query = %s", query); + + self->copysize = bufsize; + self->copyfile = file; + + if (pq_execute(self, query, 0) == 1) { + res = Py_None; + Py_INCREF(Py_None); + } + + self->copyfile =NULL; + + return res; +} + +#define psyco_curs_copy_to_doc \ +"copy_to(file, table, sep='\\t', null='\\N') -- Copy table to file." + +static int +_psyco_curs_has_write_check(PyObject* o, void* var) +{ + if (PyObject_HasAttrString(o, "write")) { + Py_INCREF(o); + *((PyObject**)var) = o; + return 1; + } + else { + PyErr_SetString(PyExc_TypeError, + "argument 1 must have a .write() method"); + return 0; + } +} + +static PyObject * +psyco_curs_copy_to(cursorObject *self, PyObject *args, PyObject *kwargs) +{ + char query[256]; + char *table_name; + char *sep = "\t", *null = NULL; + PyObject *file, *res = NULL; + + static char *kwlist[] = {"file", "table", "sep", "null", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|ss", kwlist, + _psyco_curs_has_write_check, &file, + &table_name, &sep, &null)) { + return NULL; + } + + EXC_IF_CURS_CLOSED(self); + + if (null) { + PyOS_snprintf(query, 255, "COPY %s TO stdout USING DELIMITERS '%s'" + " WITH NULL AS '%s'", table_name, sep, null); + } + else { + PyOS_snprintf(query, 255, "COPY %s TO stdout USING DELIMITERS '%s'", + table_name, sep); + } + + self->copysize = 0; + self->copyfile = file; + + if (pq_execute(self, query, 0) == 1) { + res = Py_None; + Py_INCREF(Py_None); + } + + self->copyfile = NULL; + + return res; +} +/* extension: fileno - return the file descripor of the connection */ + +#define psyco_curs_fileno_doc \ +"fileno() -> int -- Return file descriptor associated to database connection." + +static PyObject * +psyco_curs_fileno(cursorObject *self, PyObject *args) +{ + long int socket; + + if (!PyArg_ParseTuple(args, "")) return NULL; + EXC_IF_CURS_CLOSED(self); + + /* note how we call PQflush() to make sure the user will use + select() in the safe way! */ + pthread_mutex_lock(&(self->conn->lock)); + Py_BEGIN_ALLOW_THREADS; + PQflush(self->conn->pgconn); + socket = (long int)PQsocket(self->conn->pgconn); + Py_END_ALLOW_THREADS; + pthread_mutex_unlock(&(self->conn->lock)); + + return PyInt_FromLong(socket); +} + +/* extension: isready - return true if data from async execute is ready */ + +#define psyco_curs_isready_doc \ +"isready() -> bool -- Return True if data is ready after an async query." + +static PyObject * +psyco_curs_isready(cursorObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + EXC_IF_CURS_CLOSED(self); + + /* pq_is_busy does its own locking, we don't need anything special but if + the cursor is ready we need to fetch the result and free the connection + for the next query. */ + + if (pq_is_busy(self->conn)) { + Py_INCREF(Py_False); + return Py_False; + } + else { + IFCLEARPGRES(self->pgres); + pthread_mutex_lock(&(self->conn->lock)); + self->pgres = PQgetResult(self->conn->pgconn); + self->conn->async_cursor = NULL; + pthread_mutex_unlock(&(self->conn->lock)); + self->needsfetch = 1; + Py_INCREF(Py_True); + return Py_True; + } +} + +#endif + + +/** the cursor object **/ + +/* iterator protocol */ + +static PyObject * +cursor_iter(PyObject *self) +{ + EXC_IF_CURS_CLOSED((cursorObject*)self); + Py_INCREF(self); + return self; +} + +static PyObject * +cursor_next(PyObject *self) +{ + PyObject *res; + + /* we don't parse arguments: psyco_curs_fetchone will do that for us */ + res = psyco_curs_fetchone((cursorObject*)self, NULL); + + /* convert a None to NULL to signal the end of iteration */ + if (res && res == Py_None) { + Py_DECREF(res); + res = NULL; + } + return res; +} + +/* object method list */ + +static struct PyMethodDef cursorObject_methods[] = { + /* DBAPI-2.0 core */ + {"close", (PyCFunction)psyco_curs_close, + METH_VARARGS, psyco_curs_close_doc}, + {"execute", (PyCFunction)psyco_curs_execute, + METH_VARARGS|METH_KEYWORDS, psyco_curs_execute_doc}, + {"executemany", (PyCFunction)psyco_curs_executemany, + METH_VARARGS|METH_KEYWORDS, psyco_curs_executemany_doc}, + {"fetchone", (PyCFunction)psyco_curs_fetchone, + METH_VARARGS, psyco_curs_fetchone_doc}, + {"fetchmany", (PyCFunction)psyco_curs_fetchmany, + METH_VARARGS|METH_KEYWORDS, psyco_curs_fetchmany_doc}, + {"fetchall", (PyCFunction)psyco_curs_fetchall, + METH_VARARGS, psyco_curs_fetchall_doc}, + {"callproc", (PyCFunction)psyco_curs_callproc, + METH_VARARGS, psyco_curs_callproc_doc}, + {"nextset", (PyCFunction)psyco_curs_nextset, + METH_VARARGS, psyco_curs_nextset_doc}, + {"setinputsizes", (PyCFunction)psyco_curs_setinputsizes, + METH_VARARGS, psyco_curs_setinputsizes_doc}, + {"setoutputsize", (PyCFunction)psyco_curs_setoutputsize, + METH_VARARGS, psyco_curs_setoutputsize_doc}, + /* DBAPI-2.0 extensions */ + {"scroll", (PyCFunction)psyco_curs_scroll, + METH_VARARGS|METH_KEYWORDS, psyco_curs_scroll_doc}, + /* psycopg extensions */ +#ifdef PSYCOPG_EXTENSIONS + {"mogrify", (PyCFunction)psyco_curs_mogrify, + METH_VARARGS|METH_KEYWORDS, psyco_curs_mogrify_doc}, + {"fileno", (PyCFunction)psyco_curs_fileno, + METH_VARARGS, psyco_curs_fileno_doc}, + {"isready", (PyCFunction)psyco_curs_isready, + METH_VARARGS, psyco_curs_isready_doc}, + {"copy_from", (PyCFunction)psyco_curs_copy_from, + METH_VARARGS|METH_KEYWORDS, psyco_curs_copy_from_doc}, + {"copy_to", (PyCFunction)psyco_curs_copy_to, + METH_VARARGS|METH_KEYWORDS, psyco_curs_copy_to_doc}, +#endif + {NULL} +}; + +/* object member list */ + +#define OFFSETOF(x) offsetof(cursorObject, x) + +static struct PyMemberDef cursorObject_members[] = { + /* DBAPI-2.0 basics */ + {"rowcount", T_LONG, OFFSETOF(rowcount), RO, + "Number of rows read from the backend in the last command."}, + {"arraysize", T_LONG, OFFSETOF(arraysize), 0, + "Number of records `fetchmany()` must fetch if not explicitely " \ + "specified."}, + {"description", T_OBJECT, OFFSETOF(description), RO, + "Cursor description as defined in DBAPI-2.0."}, + {"lastrowid", T_LONG, OFFSETOF(lastoid), RO, + "The ``oid`` of the last row inserted by the cursor."}, + /* DBAPI-2.0 extensions */ + {"rownumber", T_LONG, OFFSETOF(row), RO, + "The current row position."}, + {"connection", T_OBJECT, OFFSETOF(conn), RO, + "The connection where the cursor comes from."}, +#ifdef PSYCOPG_EXTENSIONS + {"name", T_STRING, OFFSETOF(name), RO}, + {"statusmessage", T_OBJECT, OFFSETOF(pgstatus), RO, + "The return message of the last command."}, + {"query", T_OBJECT, OFFSETOF(query), RO, + "The last query text sent to the backend."}, + {"row_factory", T_OBJECT, OFFSETOF(tuple_factory), 0}, + {"tzinfo_factory", T_OBJECT, OFFSETOF(tzinfo_factory), 0}, + {"typecaster", T_OBJECT, OFFSETOF(caster), RO}, + {"string_types", T_OBJECT, OFFSETOF(string_types), 0}, + {"binary_types", T_OBJECT, OFFSETOF(binary_types), 0}, +#endif + {NULL} +}; + +/* initialization and finalization methods */ + +static int +cursor_setup(cursorObject *self, connectionObject *conn, char *name) +{ + Dprintf("cursor_setup: init cursor object at %p", self); + Dprintf("cursor_setup: parameters: name = %s, conn = %p", name, conn); + + if (name) { + self->name = PyMem_Malloc(strlen(name)+1); + if (self->name == NULL) return 1; + strncpy(self->name, name, strlen(name)+1); + } + + /* FIXME: why does this raise an excpetion on the _next_ line of code? + if (PyObject_IsInstance((PyObject*)conn, + (PyObject *)&connectionType) == 0) { + PyErr_SetString(PyExc_TypeError, + "argument 1 must be subclass of psycopg2._psycopg.connection"); + return 1; + } */ + self->conn = conn; + Py_INCREF((PyObject*)self->conn); + + self->closed = 0; + self->mark = conn->mark; + self->pgres = NULL; + self->notuples = 1; + self->arraysize = 1; + self->rowcount = -1; + self->lastoid = InvalidOid; + + self->casts = NULL; + self->notice = NULL; + + self->string_types = NULL; + self->binary_types = NULL; + + self->description = Py_None; + Py_INCREF(Py_None); + self->pgstatus = Py_None; + Py_INCREF(Py_None); + self->tuple_factory = Py_None; + Py_INCREF(Py_None); + self->query = Py_None; + Py_INCREF(Py_None); + + /* default tzinfo factory */ + self->tzinfo_factory = pyPsycopgTzFixedOffsetTimezone; + Py_INCREF(self->tzinfo_factory); + + Dprintf("cursor_setup: good cursor object at %p, refcnt = %d", + self, ((PyObject *)self)->ob_refcnt); + return 0; +} + +static void +cursor_dealloc(PyObject* obj) +{ + cursorObject *self = (cursorObject *)obj; + + if (self->name) PyMem_Free(self->name); + + Py_XDECREF((PyObject*)self->conn); + Py_XDECREF(self->casts); + Py_XDECREF(self->description); + Py_XDECREF(self->pgstatus); + Py_XDECREF(self->tuple_factory); + Py_XDECREF(self->tzinfo_factory); + Py_XDECREF(self->query); + + IFCLEARPGRES(self->pgres); + + Dprintf("cursor_dealloc: deleted cursor object at %p, refcnt = %d", + obj, obj->ob_refcnt); + + obj->ob_type->tp_free(obj); +} + +static int +cursor_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + char *name = NULL; + PyObject *conn; + + if (!PyArg_ParseTuple(args, "O|s", &conn, &name)) + return -1; + + return cursor_setup((cursorObject *)obj, (connectionObject *)conn, name); +} + +static PyObject * +cursor_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +cursor_del(PyObject* self) +{ + PyObject_Del(self); +} + +static PyObject * +cursor_repr(cursorObject *self) +{ + return PyString_FromFormat( + "", self, self->closed); +} + + +/* object type */ + +#define cursorType_doc \ +"A database cursor." + +PyTypeObject cursorType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.cursor", + sizeof(cursorObject), + 0, + cursor_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)cursor_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + (reprfunc)cursor_repr, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ + cursorType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + cursor_iter, /*tp_iter*/ + cursor_next, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + cursorObject_methods, /*tp_methods*/ + cursorObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + cursor_init, /*tp_init*/ + 0, /*tp_alloc Will be set to PyType_GenericAlloc in module init*/ + cursor_new, /*tp_new*/ + (freefunc)cursor_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; diff --git a/psycopg2/psycopg/microprotocols.c b/psycopg2/psycopg/microprotocols.c new file mode 100644 index 0000000..73abbfc --- /dev/null +++ b/psycopg2/psycopg/microprotocols.c @@ -0,0 +1,161 @@ +/* microprotocols.c - minimalist and non-validating protocols implementation + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/cursor.h" +#include "psycopg/connection.h" +#include "psycopg/microprotocols.h" +#include "psycopg/microprotocols_proto.h" + + +/** the adapters registry **/ + +PyObject *psyco_adapters; + +/* microprotocols_init - initialize the adapters dictionary */ + +int +microprotocols_init(PyObject *dict) +{ + /* create adapters dictionary and put it in module namespace */ + if ((psyco_adapters = PyDict_New()) == NULL) { + return -1; + } + + PyDict_SetItemString(dict, "adapters", psyco_adapters); + + return 0; +} + + +/* microprotocols_add - add a reverse type-caster to the dictionary */ + +int +microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) +{ + if (proto == NULL) proto = (PyObject*)&isqlquoteType; + + Dprintf("microprotocols_add: cast %p for (%s, ?)", cast, type->tp_name); + + PyDict_SetItem(psyco_adapters, + Py_BuildValue("(OO)", (PyObject*)type, proto), + cast); + return 0; +} + +/* microprotocols_adapt - adapt an object to the built-in protocol */ + +PyObject * +microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) +{ + PyObject *adapter, *key; + + /* we don't check for exact type conformance as specified in PEP 246 + because the ISQLQuote type is abstract and there is no way to get a + quotable object to be its instance */ + + Dprintf("microprotocols_adapt: trying to adapt %s", obj->ob_type->tp_name); + + /* look for an adapter in the registry */ + key = Py_BuildValue("(OO)", (PyObject*)obj->ob_type, proto); + adapter = PyDict_GetItem(psyco_adapters, key); + Py_DECREF(key); + if (adapter) { + PyObject *adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL); + return adapted; + } + + /* try to have the protocol adapt this object*/ + if (PyObject_HasAttrString(proto, "__adapt__")) { + PyObject *adapted = PyObject_CallMethod(proto, "__adapt__", "O", obj); + if (adapted && adapted != Py_None) return adapted; + Py_XDECREF(adapted); + if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + } + + /* and finally try to have the object adapt itself */ + if (PyObject_HasAttrString(obj, "__conform__")) { + PyObject *adapted = PyObject_CallMethod(obj, "__conform__","O", proto); + if (adapted && adapted != Py_None) return adapted; + Py_XDECREF(adapted); + if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + } + + /* else set the right exception and return NULL */ + psyco_set_error(ProgrammingError, NULL, "can't adapt", NULL, NULL); + return NULL; +} + +/* microprotocol_getquoted - utility function that adapt and call getquoted */ + +PyObject * +microprotocol_getquoted(PyObject *obj, connectionObject *conn) +{ + PyObject *res = NULL; + PyObject *tmp = microprotocols_adapt( + obj, (PyObject*)&isqlquoteType, NULL); + + if (tmp != NULL) { + Dprintf("microprotocol_getquoted: adapted to %s", + tmp->ob_type->tp_name); + + /* if requested prepare the object passing it the connection */ + if (PyObject_HasAttrString(tmp, "prepare") && conn) { + res = PyObject_CallMethod(tmp, "prepare", "O", (PyObject*)conn); + if (res == NULL) { + Py_DECREF(tmp); + return NULL; + } + else { + Py_DECREF(res); + } + } + + /* call the getquoted method on tmp (that should exist because we + adapted to the right protocol) */ + res = PyObject_CallMethod(tmp, "getquoted", NULL); + Py_DECREF(tmp); + } + + /* we return res with one extra reference, the caller shall free it */ + return res; +} + + +/** module-level functions **/ + +PyObject * +psyco_microprotocols_adapt(cursorObject *self, PyObject *args) +{ + PyObject *obj, *alt = NULL; + PyObject *proto = (PyObject*)&isqlquoteType; + + if (!PyArg_ParseTuple(args, "O|OO", &obj, &proto, &alt)) return NULL; + return microprotocols_adapt(obj, proto, alt); +} diff --git a/psycopg2/psycopg/microprotocols.h b/psycopg2/psycopg/microprotocols.h new file mode 100644 index 0000000..5501a7c --- /dev/null +++ b/psycopg2/psycopg/microprotocols.h @@ -0,0 +1,60 @@ +/* microprotocols.c - definitions for minimalist and non-validating protocols + * + * Copyright (C) 2003-2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_MICROPROTOCOLS_H +#define PSYCOPG_MICROPROTOCOLS_H 1 + +#include +#include "psycopg/connection.h" +#include "psycopg/cursor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** adapters registry **/ + +extern PyObject *psyco_adapters; + +/** the names of the three mandatory methods **/ + +#define MICROPROTOCOLS_GETQUOTED_NAME "getquoted" +#define MICROPROTOCOLS_GETSTRING_NAME "getstring" +#define MICROPROTOCOLS_GETBINARY_NAME "getbinary" + +/** exported functions **/ + +/* used by module.c to init the microprotocols system */ +extern int microprotocols_init(PyObject *dict); +extern int microprotocols_add( + PyTypeObject *type, PyObject *proto, PyObject *cast); + +extern PyObject *microprotocols_adapt( + PyObject *obj, PyObject *proto, PyObject *alt); +extern PyObject *microprotocol_getquoted( + PyObject *obj, connectionObject *conn); + +extern PyObject * + psyco_microprotocols_adapt(cursorObject *self, PyObject *args); +#define psyco_microprotocols_adapt_doc \ + "adapt(obj, protocol, alternate) -> object -- adapt obj to given protocol" + +#endif /* !defined(PSYCOPG_MICROPROTOCOLS_H) */ diff --git a/psycopg2/psycopg/microprotocols_proto.c b/psycopg2/psycopg/microprotocols_proto.c new file mode 100644 index 0000000..72c3a7e --- /dev/null +++ b/psycopg2/psycopg/microprotocols_proto.c @@ -0,0 +1,216 @@ +/* microprotocol_proto.c - psycopg protocols + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/microprotocols_proto.h" + + +/** void protocol implementation **/ + + +/* getquoted - return quoted representation for object */ + +#define psyco_isqlquote_getquoted_doc \ +"getquoted() -- return SQL-quoted representation of this object" + +static PyObject * +psyco_isqlquote_getquoted(isqlquoteObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +/* getbinary - return quoted representation for object */ + +#define psyco_isqlquote_getbinary_doc \ +"getbinary() -- return SQL-quoted binary representation of this object" + +static PyObject * +psyco_isqlquote_getbinary(isqlquoteObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +/* getbuffer - return quoted representation for object */ + +#define psyco_isqlquote_getbuffer_doc \ +"getbuffer() -- return this object" + +static PyObject * +psyco_isqlquote_getbuffer(isqlquoteObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + + + +/** the ISQLQuote object **/ + + +/* object method list */ + +static struct PyMethodDef isqlquoteObject_methods[] = { + {"getquoted", (PyCFunction)psyco_isqlquote_getquoted, + METH_VARARGS, psyco_isqlquote_getquoted_doc}, + {"getbinary", (PyCFunction)psyco_isqlquote_getbinary, + METH_VARARGS, psyco_isqlquote_getbinary_doc}, + {"getbuffer", (PyCFunction)psyco_isqlquote_getbuffer, + METH_VARARGS, psyco_isqlquote_getbuffer_doc}, + /* {"prepare", (PyCFunction)psyco_isqlquote_prepare, + METH_VARARGS, psyco_isqlquote_prepare_doc}, */ + {NULL} +}; + +/* object member list */ + +static struct PyMemberDef isqlquoteObject_members[] = { + /* DBAPI-2.0 extensions (exception objects) */ + {"_wrapped", T_OBJECT, offsetof(isqlquoteObject, wrapped), RO}, + {NULL} +}; + +/* initialization and finalization methods */ + +static int +isqlquote_setup(isqlquoteObject *self, PyObject *wrapped) +{ + self->wrapped = wrapped; + Py_INCREF(wrapped); + + return 0; +} + +static void +isqlquote_dealloc(PyObject* obj) +{ + isqlquoteObject *self = (isqlquoteObject *)obj; + + Py_XDECREF(self->wrapped); + + obj->ob_type->tp_free(obj); +} + +static int +isqlquote_init(PyObject *obj, PyObject *args, PyObject *kwds) +{ + PyObject *wrapped = NULL; + + if (!PyArg_ParseTuple(args, "O", &wrapped)) + return -1; + + return isqlquote_setup((isqlquoteObject *)obj, wrapped); +} + +static PyObject * +isqlquote_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static void +isqlquote_del(PyObject* self) +{ + PyObject_Del(self); +} + + +/* object type */ + +#define isqlquoteType_doc \ +"Abstract ISQLQuote protocol\n\n" \ +"An object conform to this protocol should expose a ``getquoted()`` method\n" \ +"returning the SQL representation of the object.\n\n" + +PyTypeObject isqlquoteType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.ISQLQuote", + sizeof(isqlquoteObject), + 0, + isqlquote_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + isqlquoteType_doc, /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + isqlquoteObject_methods, /*tp_methods*/ + isqlquoteObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + isqlquote_init, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + isqlquote_new, /*tp_new*/ + (freefunc)isqlquote_del, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; diff --git a/psycopg2/psycopg/microprotocols_proto.h b/psycopg2/psycopg/microprotocols_proto.h new file mode 100644 index 0000000..c671264 --- /dev/null +++ b/psycopg2/psycopg/microprotocols_proto.h @@ -0,0 +1,45 @@ +/* microporotocols_proto.h - definiton for psycopg's protocols + * + * Copyright (C) 2004 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_ISQLQUOTE_H +#define PSYCOPG_ISQLQUOTE_H 1 + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern PyTypeObject isqlquoteType; + +typedef struct { + PyObject HEAD; + + PyObject *wrapped; + +} isqlquoteObject; + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_ISQLQUOTE_H) */ diff --git a/psycopg2/psycopg/pgtypes.h b/psycopg2/psycopg/pgtypes.h new file mode 100644 index 0000000..1fdbda9 --- /dev/null +++ b/psycopg2/psycopg/pgtypes.h @@ -0,0 +1,65 @@ +#define BOOLOID 16 +#define BYTEAOID 17 +#define CHAROID 18 +#define NAMEOID 19 +#define INT8OID 20 +#define INT2OID 21 +#define INT2VECTOROID 22 +#define INT4OID 23 +#define REGPROCOID 24 +#define TEXTOID 25 +#define OIDOID 26 +#define TIDOID 27 +#define XIDOID 28 +#define CIDOID 29 +#define OIDVECTOROID 30 +#define PG_TYPE_RELTYPE_OID 71 +#define PG_ATTRIBUTE_RELTYPE_OID 75 +#define PG_PROC_RELTYPE_OID 81 +#define PG_CLASS_RELTYPE_OID 83 +#define POINTOID 600 +#define LSEGOID 601 +#define PATHOID 602 +#define BOXOID 603 +#define POLYGONOID 604 +#define LINEOID 628 +#define FLOAT4OID 700 +#define FLOAT8OID 701 +#define ABSTIMEOID 702 +#define RELTIMEOID 703 +#define TINTERVALOID 704 +#define UNKNOWNOID 705 +#define CIRCLEOID 718 +#define CASHOID 790 +#define MACADDROID 829 +#define INETOID 869 +#define CIDROID 650 +#define INT4ARRAYOID 1007 +#define ACLITEMOID 1033 +#define BPCHAROID 1042 +#define VARCHAROID 1043 +#define DATEOID 1082 +#define TIMEOID 1083 +#define TIMESTAMPOID 1114 +#define TIMESTAMPTZOID 1184 +#define INTERVALOID 1186 +#define TIMETZOID 1266 +#define BITOID 1560 +#define VARBITOID 1562 +#define NUMERICOID 1700 +#define REFCURSOROID 1790 +#define REGPROCEDUREOID 2202 +#define REGOPEROID 2203 +#define REGOPERATOROID 2204 +#define REGCLASSOID 2205 +#define REGTYPEOID 2206 +#define RECORDOID 2249 +#define CSTRINGOID 2275 +#define ANYOID 2276 +#define ANYARRAYOID 2277 +#define VOIDOID 2278 +#define TRIGGEROID 2279 +#define LANGUAGE_HANDLEROID 2280 +#define INTERNALOID 2281 +#define OPAQUEOID 2282 +#define ANYELEMENTOID 2283 diff --git a/psycopg2/psycopg/pgversion.h b/psycopg2/psycopg/pgversion.h new file mode 100644 index 0000000..f874a9a --- /dev/null +++ b/psycopg2/psycopg/pgversion.h @@ -0,0 +1,2 @@ +#define PG_VERSION_MAJOR 7 +#define PG_VERSION_MINOR 4 diff --git a/psycopg2/psycopg/pqpath.c b/psycopg2/psycopg/pqpath.c new file mode 100644 index 0000000..1ebb569 --- /dev/null +++ b/psycopg2/psycopg/pqpath.c @@ -0,0 +1,883 @@ +/* pqpath.c - single path into libpq + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* IMPORTANT NOTE: no function in this file do its own connection locking + except for pg_execute and pq_fetch (that are somehow high-level. This means + that all the othe functions should be called while holding a lock to the + connection. +*/ + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/pqpath.h" +#include "psycopg/connection.h" +#include "psycopg/cursor.h" +#include "psycopg/typecast.h" +#include "psycopg/pgtypes.h" +#include "psycopg/pgversion.h" + +/* pq_raise - raise a python exception of the right kind + + This function should be called while holding the GIL. */ + +void +pq_raise(connectionObject *conn, cursorObject *curs, PyObject *exc, char *msg) +{ + PyObject *pgc = (PyObject*)curs; + + char *err = NULL; + char *err2 = NULL; + char *code = NULL; + char *buf = NULL; + + if ((conn == NULL && curs == NULL) || (curs != NULL && conn == NULL)) { + PyErr_SetString(Error, "psycopg went psycotic and raised a null error"); + return; + } + + if (curs && curs->pgres) { + err = PQresultErrorMessage(curs->pgres); +#ifdef HAVE_PQPROTOCOL3 + if (err != NULL && conn->protocol == 3) { + code = PQresultErrorField(curs->pgres, PG_DIAG_SQLSTATE); + } +#endif + } + if (err == NULL) + err = PQerrorMessage(conn->pgconn); + + /* if the is no error message we probably called pq_raise without reason: + we need to set an exception anyway because the caller will probably + raise and a meaningful message is better than an empty one */ + if (err == NULL) { + PyErr_SetString(Error, "psycopg went psycotic without error set"); + return; + } + + /* if exc is NULL, analyze the message and try to deduce the right + exception kind (only if we have a pgres, obviously) */ + if (exc == NULL) { + if (curs && curs->pgres) { + if (conn->protocol == 3) { +#ifdef HAVE_PQPROTOCOL3 + char *pgstate = + PQresultErrorField(curs->pgres, PG_DIAG_SQLSTATE); + if (pgstate != NULL && !strncmp(pgstate, "23", 2)) + exc = IntegrityError; + else + exc = ProgrammingError; +#endif + } + } + } + + /* if exc is still NULL psycopg was not built with HAVE_PQPROTOCOL3 or the + connection is using protocol 2: in both cases we default to comparing + error messages */ + if (exc == NULL) { + if (!strncmp(err, "ERROR: Cannot insert a duplicate key", 37) + || !strncmp(err, "ERROR: ExecAppend: Fail to add null", 36) + || strstr(err, "referential integrity violation")) + exc = IntegrityError; + else + exc = ProgrammingError; + } + + /* try to remove the initial "ERROR: " part from the postgresql error */ + if (err && strlen(err) > 8) err2 = &(err[8]); + else err2 = err; + + /* if msg is not NULL, add it to the error message, after a '\n' */ + if (msg && code) { + int len = strlen(code) + strlen(err) + strlen(msg) + 5; + if ((buf = PyMem_Malloc(len))) { + snprintf(buf, len, "[%s] %s\n%s", code, err2, msg); + psyco_set_error(exc, pgc, buf, err, code); + } + } + else if (msg) { + int len = strlen(err) + strlen(msg) + 2; + if ((buf = PyMem_Malloc(len))) { + snprintf(buf, len, "%s\n%s", err2, msg); + psyco_set_error(exc, pgc, buf, err, code); + } + } + else { + psyco_set_error(exc, pgc, err2, err, code); + } + + if (buf != NULL) PyMem_Free(buf); +} + +/* pq_set_critical, pq_resolve_critical - manage critical errors + + this function is invoked when a PQexec() call returns NULL, meaning a + critical condition like out of memory or lost connection. it save the error + message and mark the connection as 'wanting cleanup'. + + both functions do not call any Py_*_ALLOW_THREADS macros. + pq_resolve_critical should be called while holding the GIL. */ + +void +pq_set_critical(connectionObject *conn, const char *msg) +{ + if (msg == NULL) + msg = PQerrorMessage(conn->pgconn); + if (conn->critical) free(conn->critical); + if (msg && msg[0] != '\0') conn->critical = strdup(msg); + else conn->critical = NULL; +} + +PyObject * +pq_resolve_critical(connectionObject *conn, int close) +{ + Dprintf("pq_resolve_critical: resolving %s", conn->critical); + + if (conn->critical) { + char *msg = &(conn->critical[6]); + Dprintf("pq_resolve_critical: error = %s", msg); + /* we can't use pq_raise because the error has already been cleared + from the connection, so we just raise an OperationalError with the + critical message */ + PyErr_SetString(OperationalError, msg); + + /* we don't want to destroy this connection but just close it */ + if (close == 1) conn_close(conn); + } + return NULL; +} + +/* pq_clear_async - clear the effects of a previous async query + + note that this function does block because it needs to wait for the full + result sets of the previous query to clear them. + + + this function does not call any Py_*_ALLOW_THREADS macros */ + +void +pq_clear_async(connectionObject *conn) +{ + PGresult *pgres; + + do { + pgres = PQgetResult(conn->pgconn); + Dprintf("pq_clear_async: clearing PGresult at %p", pgres); + IFCLEARPGRES(pgres); + } while (pgres != NULL); +} + +/* pq_begin - send a BEGIN WORK, if necessary + + this function does not call any Py_*_ALLOW_THREADS macros */ + +int +pq_begin(connectionObject *conn) +{ + const char *query[] = { + NULL, + "BEGIN; SET TRANSACTION ISOLATION LEVEL READ COMMITTED", + "BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE"}; + + int pgstatus, retvalue = -1; + PGresult *pgres = NULL; + + Dprintf("pq_begin: pgconn = %p, isolevel = %ld, status = %d", + conn->pgconn, conn->isolation_level, conn->status); + + if (conn->isolation_level == 0 || conn->status != CONN_STATUS_READY) { + Dprintf("pq_begin: transaction in progress"); + return 0; + } + + pq_clear_async(conn); + pgres = PQexec(conn->pgconn, query[conn->isolation_level]); + if (pgres == NULL) { + Dprintf("pq_begin: PQexec() failed"); + pq_set_critical(conn, NULL); + goto cleanup; + } + + pgstatus = PQresultStatus(pgres); + if (pgstatus != PGRES_COMMAND_OK ) { + Dprintf("pq_begin: result is NOT OK"); + pq_set_critical(conn, NULL); + goto cleanup; + } + Dprintf("pq_begin: issued '%s' command", query[conn->isolation_level]); + + retvalue = 0; + conn->status = CONN_STATUS_BEGIN; + + cleanup: + IFCLEARPGRES(pgres); + return retvalue; +} + +/* pq_commit - send an END, if necessary + + this function does not call any Py_*_ALLOW_THREADS macros */ + +int +pq_commit(connectionObject *conn) +{ + const char *query = "END"; + int pgstatus, retvalue = -1; + PGresult *pgres = NULL; + + Dprintf("pq_commit: pgconn = %p, isolevel = %ld, status = %d", + conn->pgconn, conn->isolation_level, conn->status); + + if (conn->isolation_level == 0 || conn->status != CONN_STATUS_BEGIN) { + Dprintf("pq_commit: no transaction to commit"); + return 0; + } + + pq_clear_async(conn); + pgres = PQexec(conn->pgconn, query); + if (pgres == NULL) { + Dprintf("pq_commit: PQexec() failed"); + pq_set_critical(conn, NULL); + goto cleanup; + } + + pgstatus = PQresultStatus(pgres); + if (pgstatus != PGRES_COMMAND_OK ) { + Dprintf("pq_commit: result is NOT OK"); + pq_set_critical(conn, NULL); + goto cleanup; + } + Dprintf("pq_commit: issued '%s' command", query); + + retvalue = 0; + conn->status = CONN_STATUS_READY; + + cleanup: + IFCLEARPGRES(pgres); + return retvalue; +} + +/* pq_abort - send an ABORT, if necessary + + this function does not call any Py_*_ALLOW_THREADS macros */ + +int +pq_abort(connectionObject *conn) +{ + const char *query = "ABORT"; + int pgstatus, retvalue = -1; + PGresult *pgres = NULL; + + Dprintf("pq_abort: pgconn = %p, isolevel = %ld, status = %d", + conn->pgconn, conn->isolation_level, conn->status); + + if (conn->isolation_level == 0 || conn->status != CONN_STATUS_BEGIN) { + Dprintf("pq_abort: no transaction to abort"); + return 0; + } + + pq_clear_async(conn); + pgres = PQexec(conn->pgconn, query); + if (pgres == NULL) { + Dprintf("pq_abort: PQexec() failed"); + pq_set_critical(conn, NULL); + goto cleanup; + } + + pgstatus = PQresultStatus(pgres); + if (pgstatus != PGRES_COMMAND_OK ) { + Dprintf("pq_abort: result is NOT OK"); + pq_set_critical(conn, NULL); + goto cleanup; + } + Dprintf("pq_abort: issued '%s' command", query); + + retvalue = 0; + conn->status = CONN_STATUS_READY; + + cleanup: + IFCLEARPGRES(pgres); + return retvalue; +} + +/* pq_is_busy - consume input and return connection status + + a status of 1 means that a call to pq_fetch will block, while a status of 0 + means that there is data available to be collected. -1 means an error, the + exception will be set accordingly. + + this fucntion locks the connection object + this function call Py_*_ALLOW_THREADS macros */ + +int +pq_is_busy(connectionObject *conn) +{ + PGnotify *pgn; + + Dprintf("pq_is_busy: consuming input"); + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&(conn->lock)); + + if (PQconsumeInput(conn->pgconn) == 0) { + Dprintf("pq_is_busy: PQconsumeInput() failed"); + pthread_mutex_unlock(&(conn->lock)); + Py_BLOCK_THREADS; + PyErr_SetString(OperationalError, PQerrorMessage(conn->pgconn)); + return -1; + } + + pthread_mutex_unlock(&(conn->lock)); + Py_END_ALLOW_THREADS; + + /* now check for notifies */ + while ((pgn = PQnotifies(conn->pgconn)) != NULL) { + PyObject *notify; + + Dprintf("curs_is_busy: got NOTIFY from pid %d, msg = %s", + pgn->be_pid, pgn->relname); + + notify = PyTuple_New(2); + PyTuple_SET_ITEM(notify, 0, PyInt_FromLong((long)pgn->be_pid)); + PyTuple_SET_ITEM(notify, 1, PyString_FromString(pgn->relname)); + PyList_Append(conn->notifies, notify); + free(pgn); + } + + return PQisBusy(conn->pgconn); +} + +/* pq_execute - execute a query, possibly asyncronously + + this fucntion locks the connection object + this function call Py_*_ALLOW_THREADS macros */ + +int +pq_execute(cursorObject *curs, const char *query, int async) +{ + /* if the status of the connection is critical raise an exception and + definitely close the connection */ + if (curs->conn->critical) { + pq_resolve_critical(curs->conn, 1); + return -1; + } + + /* check status of connection, raise error if not OK */ + if (PQstatus(curs->conn->pgconn) != CONNECTION_OK) { + Dprintf("pq_execute: connection NOT OK"); + PyErr_SetString(OperationalError, PQerrorMessage(curs->conn->pgconn)); + return -1; + } + Dprintf("curs_execute: pg connection at %p OK", curs->conn->pgconn); + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&(curs->conn->lock)); + + pq_begin(curs->conn); + + if (async == 0) { + IFCLEARPGRES(curs->pgres); + Dprintf("pq_execute: executing SYNC query:"); + Dprintf(" %-.200s", query); + curs->pgres = PQexec(curs->conn->pgconn, query); + } + + else if (async == 1) { + /* first of all, let see if the previous query has already ended, if + not what should we do? just block and discard data or execute + another query? */ + pq_clear_async(curs->conn); + + Dprintf("pq_execute: executing ASYNC query:"); + Dprintf(" %-.200s", query); + + /* then we can go on and send a new query without fear */ + IFCLEARPGRES(curs->pgres); + if (PQsendQuery(curs->conn->pgconn, query) == 0) { + pthread_mutex_unlock(&(curs->conn->lock)); + Py_BLOCK_THREADS; + PyErr_SetString(OperationalError, + PQerrorMessage(curs->conn->pgconn)); + return -1; + } + Dprintf("pq_execute: async query sent to backend"); + } + + pthread_mutex_unlock(&(curs->conn->lock)); + Py_END_ALLOW_THREADS; + + /* if the execute was sync, we call pq_fetch() immediately, + to respect the old DBAPI-2.0 compatible behaviour */ + if (async == 0) { + Dprintf("pq_execute: entering syncronous DBAPI compatibility mode"); + if (pq_fetch(curs) == -1) return -1; + } + else { + curs->conn->async_cursor = (PyObject*)curs; + } + + return 1-async; +} + + +/* pq_fetch - fetch data after a query + + this fucntion locks the connection object + this function call Py_*_ALLOW_THREADS macros + + return value: + -1 - some error occurred while calling libpq + 0 - no result from the backend but no libpq errors + 1 - result from backend (possibly data is ready) +*/ + +static void +_pq_fetch_tuples(cursorObject *curs) +{ + int i, *dsize = NULL; + + int pgnfields = PQnfields(curs->pgres); + int pgbintuples = PQbinaryTuples(curs->pgres); + + curs->notuples = 0; + + /* create the tuple for description and typecasting */ + Py_XDECREF(curs->description); + Py_XDECREF(curs->casts); + curs->description = PyTuple_New(pgnfields); + curs->casts = PyTuple_New(pgnfields); + curs->columns = pgnfields; + + /* calculate the display size for each column (cpu intensive, can be + switched off at configuration time) */ +#ifdef PSYCOPG_DISPLAY_SIZE + dsize = (int *)PyMem_Malloc(pgnfields * sizeof(int)); + if (dsize != NULL) { + int j, len; + for (i=0; i < pgnfields; i++) { + dsize[i] = -1; + } + for (j = 0; j < curs->rowcount; j++) { + for (i = 0; i < pgnfields; i++) { + len = PQgetlength(curs->pgres, j, i); + if (len > dsize[i]) dsize[i] = len; + } + } + } +#endif + + /* calculate various parameters and typecasters */ + for (i = 0; i < pgnfields; i++) { + Oid ftype = PQftype(curs->pgres, i); + int fsize = PQfsize(curs->pgres, i); + int fmod = PQfmod(curs->pgres, i); + + PyObject *dtitem = PyTuple_New(7); + PyObject *type = PyInt_FromLong(ftype); + PyObject *cast = NULL; + + PyTuple_SET_ITEM(curs->description, i, dtitem); + + /* fill the right cast function by accessing the global dictionary of + casting objects. if we got no defined cast use the default + one */ + if (!(cast = PyDict_GetItem(curs->casts, type))) { + Dprintf("_pq_fetch_tuples: cast %d not in per-cursor dict", ftype); + if (!(cast = PyDict_GetItem(psyco_types, type))) { + Dprintf("_pq_fetch_tuples: cast %d not found, using default", + PQftype(curs->pgres,i)); + cast = psyco_default_cast; + } + } + /* else if we got binary tuples and if we got a field that + is binary use the default cast + FIXME: what the hell am I trying to do here? This just can't work.. + */ + else if (pgbintuples && cast == psyco_default_binary_cast) { + Dprintf("_pq_fetch_tuples: Binary cursor and " + "binary field: %i using default cast", + PQftype(curs->pgres,i)); + cast = psyco_default_cast; + } + Dprintf("_pq_fetch_tuples: using cast at %p (%s) for type %d", + cast, PyString_AS_STRING(((typecastObject*)cast)->name), + PQftype(curs->pgres,i)); + Py_INCREF(cast); + PyTuple_SET_ITEM(curs->casts, i, cast); + + + /* 1/ fill the other fields */ + PyTuple_SET_ITEM(dtitem, 0, + PyString_FromString(PQfname(curs->pgres, i))); + PyTuple_SET_ITEM(dtitem, 1, type); + + /* 2/ display size is the maximum size of this field result tuples. */ + if (dsize && dsize[i] >= 0) { + PyTuple_SET_ITEM(dtitem, 2, PyInt_FromLong(dsize[i])); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(dtitem, 2, Py_None); + } + + /* 3/ size on the backend */ + if (fmod > 0) fmod = fmod - sizeof(int); + if (fsize == -1) { + if (ftype == NUMERICOID) { + PyTuple_SET_ITEM(dtitem, 3, + PyInt_FromLong((fmod >> 16) & 0xFFFF)); + } + else { /* If variable length record, return maximum size */ + PyTuple_SET_ITEM(dtitem, 3, PyInt_FromLong(fmod)); + } + } + else { + PyTuple_SET_ITEM(dtitem, 3, PyInt_FromLong(fsize)); + } + + /* 4,5/ scale and precision */ + if (ftype == NUMERICOID) { + PyTuple_SET_ITEM(dtitem, 4, PyInt_FromLong((fmod >> 16) & 0xFFFF)); + PyTuple_SET_ITEM(dtitem, 5, PyInt_FromLong((fmod & 0xFFFF) - 4)); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(dtitem, 4, Py_None); + Py_INCREF(Py_None); + PyTuple_SET_ITEM(dtitem, 5, Py_None); + } + + /* 6/ FIXME: null_ok??? */ + Py_INCREF(Py_None); + PyTuple_SET_ITEM(dtitem, 6, Py_None); + } + + if (dsize) PyMem_Free(dsize); +} + +#ifdef HAVE_PQPROTOCOL3 +static int +_pq_copy_in_v3(cursorObject *curs) +{ + /* COPY FROM implementation when protocol 3 is available: this function + uses the new PQputCopyData() and can detect errors and set the correct + exception */ + PyObject *o; + int length = 0, error = 0; + + while (1) { + o = PyObject_CallMethod(curs->copyfile, "read", "i", curs->copysize); + if (!o || !PyString_Check(o) || (length = PyString_Size(o)) == -1) { + error = 1; + } + if (length == 0 || error == 1) break; + + Py_BEGIN_ALLOW_THREADS; + if (PQputCopyData(curs->conn->pgconn, + PyString_AS_STRING(o), length) == -1) { + error = 2; + } + Py_END_ALLOW_THREADS; + + if (error == 2) break; + + Py_DECREF(o); + } + + Py_XDECREF(o); + + if (error == 0 || error == 2) + /* 0 means that the copy went well, 2 that there was an error on the + backend: in both cases we'll get the error message from the + PQresult */ + PQputCopyEnd(curs->conn->pgconn, NULL); + else + PQputCopyEnd(curs->conn->pgconn, "error during .read() call"); + + /* and finally we grab the operation result from the backend */ + IFCLEARPGRES(curs->pgres); + while ((curs->pgres = PQgetResult(curs->conn->pgconn)) != NULL) { + if (PQresultStatus(curs->pgres) == PGRES_FATAL_ERROR) + pq_raise(curs->conn, curs, NULL, NULL); + IFCLEARPGRES(curs->pgres); + } + + return 1; +} +#endif +static int +_pq_copy_in(cursorObject *curs) +{ + /* COPY FROM implementation when protocol 3 is not available: this + function can't fail but the backend will send an ERROR notice that will + be catched by our notice collector */ + PyObject *o; + + while (1) { + o = PyObject_CallMethod(curs->copyfile, "readline", NULL); + if (!o || o == Py_None || PyString_GET_SIZE(o) == 0) break; + if (PQputline(curs->conn->pgconn, PyString_AS_STRING(o)) != 0) { + Py_DECREF(o); + return -1; + } + Py_DECREF(o); + } + Py_XDECREF(o); + PQputline(curs->conn->pgconn, "\\.\n"); + PQendcopy(curs->conn->pgconn); + + /* if for some reason we're using a protocol 3 libpq to connect to a + protocol 2 backend we still need to cycle on the result set */ + IFCLEARPGRES(curs->pgres); + while ((curs->pgres = PQgetResult(curs->conn->pgconn)) != NULL) { + if (PQresultStatus(curs->pgres) == PGRES_FATAL_ERROR) + pq_raise(curs->conn, curs, NULL, NULL); + IFCLEARPGRES(curs->pgres); + } + + return 1; +} + +#ifdef HAVE_PQPROTOCOL3 +static int +_pq_copy_out_v3(cursorObject *curs) +{ + char *buffer; + int len; + + while (1) { + Py_BEGIN_ALLOW_THREADS; + len = PQgetCopyData(curs->conn->pgconn, &buffer, 0); + Py_END_ALLOW_THREADS; + + if (len > 0 && buffer) { + PyObject_CallMethod(curs->copyfile, "write", "s#", buffer, len); + PQfreemem(buffer); + } + /* we break on len == 0 but note that that should *not* happen, + because we are not doing an async call (if it happens blame + postgresql authors :/) */ + else if (len <= 0) break; + } + + if (len == -2) { + pq_raise(curs->conn, NULL, NULL, NULL); + return -1; + } + + /* and finally we grab the operation result from the backend */ + IFCLEARPGRES(curs->pgres); + while ((curs->pgres = PQgetResult(curs->conn->pgconn)) != NULL) { + if (PQresultStatus(curs->pgres) == PGRES_FATAL_ERROR) + pq_raise(curs->conn, curs, NULL, NULL); + IFCLEARPGRES(curs->pgres); + } + return 1; +} +#endif + +static int +_pq_copy_out(cursorObject *curs) +{ + char buffer[4096]; + int status, len; + + while (1) { + Py_BEGIN_ALLOW_THREADS; + status = PQgetline(curs->conn->pgconn, buffer, 4096); + Py_END_ALLOW_THREADS; + if (status == 0) { + if (buffer[0] == '\\' && buffer[1] == '.') break; + + len = strlen(buffer); + buffer[len++] = '\n'; + } + else if (status == 1) { + len = 4096-1; + } + else { + return -1; + } + + PyObject_CallMethod(curs->copyfile, "write", "s#", buffer, len); + } + + status = 1; + if (PQendcopy(curs->conn->pgconn) != 0) + status = -1; + + /* if for some reason we're using a protocol 3 libpq to connect to a + protocol 2 backend we still need to cycle on the result set */ + IFCLEARPGRES(curs->pgres); + while ((curs->pgres = PQgetResult(curs->conn->pgconn)) != NULL) { + if (PQresultStatus(curs->pgres) == PGRES_FATAL_ERROR) + pq_raise(curs->conn, curs, NULL, NULL); + IFCLEARPGRES(curs->pgres); + } + + return status; +} + +int +pq_fetch(cursorObject *curs) +{ + int pgstatus, ex = -1; + + /* even if we fail, we remove any information about the previous query */ + curs_reset(curs); + + /* we check the result from the previous execute; if the result is not + already there, we need to consume some input and go to sleep until we + get something edible to eat */ + if (!curs->pgres) { + + Dprintf("pq_fetch: no data: entering polling loop"); + + while (pq_is_busy(curs->conn) > 0) { + fd_set rfds; + struct timeval tv; + int sval, sock; + + Py_BEGIN_ALLOW_THREADS; + pthread_mutex_lock(&(curs->conn->lock)); + + sock = PQsocket(curs->conn->pgconn); + FD_ZERO(&rfds); + FD_SET(sock, &rfds); + + /* set a default timeout of 5 seconds + TODO: make use of the timeout, maybe allowing the user to + make a non-blocking (timeouted) call to fetchXXX */ + tv.tv_sec = 5; + tv.tv_usec = 0; + + Dprintf("pq_fetch: entering PDflush() loop"); + while (PQflush(curs->conn->pgconn) != 0); + sval = select(sock+1, &rfds, NULL, NULL, &tv); + + pthread_mutex_unlock(&(curs->conn->lock)); + Py_END_ALLOW_THREADS; + } + + Dprintf("pq_fetch: data is probably ready"); + IFCLEARPGRES(curs->pgres); + curs->pgres = PQgetResult(curs->conn->pgconn); + } + + /* check for PGRES_FATAL_ERROR result */ + /* FIXME: I am not sure we need to check for critical error here. + if (curs->pgres == NULL) { + Dprintf("pq_fetch: got a NULL pgres, checking for critical"); + pq_set_critical(curs->conn); + if (curs->conn->critical) { + pq_resolve_critical(curs->conn); + return -1; + } + else { + return 0; + } + } + */ + + if (curs->pgres == NULL) return 0; + + pgstatus = PQresultStatus(curs->pgres); + Dprintf("pq_fetch: pgstatus = %s", PQresStatus(pgstatus)); + + /* backend status message */ + Py_XDECREF(curs->pgstatus); + curs->pgstatus = PyString_FromString(PQcmdStatus(curs->pgres)); + + switch(pgstatus) { + + case PGRES_COMMAND_OK: + Dprintf("pq_fetch: command returned OK (no tuples)"); + curs->rowcount = atoi(PQcmdTuples(curs->pgres)); + curs->lastoid = PQoidValue(curs->pgres); + CLEARPGRES(curs->pgres); + ex = 1; + break; + + case PGRES_COPY_OUT: + Dprintf("pq_fetch: data from a COPY TO (no tuples)"); +#ifdef HAVE_PQPROTOCOL3 + if (curs->conn->protocol == 3) + ex = _pq_copy_out_v3(curs); + else +#endif + ex = _pq_copy_out(curs); + curs->rowcount = -1; + /* error caught by out glorious notice handler */ + if (PyErr_Occurred()) ex = -1; + IFCLEARPGRES(curs->pgres); + break; + + case PGRES_COPY_IN: + Dprintf("pq_fetch: data from a COPY FROM (no tuples)"); +#ifdef HAVE_PQPROTOCOL3 + if (curs->conn->protocol == 3) + ex = _pq_copy_in_v3(curs); + else +#endif + ex = _pq_copy_in(curs); + curs->rowcount = -1; + /* error caught by out glorious notice handler */ + if (PyErr_Occurred()) ex = -1; + IFCLEARPGRES(curs->pgres); + break; + + case PGRES_TUPLES_OK: + Dprintf("pq_fetch: data from a SELECT (got tuples)"); + curs->rowcount = PQntuples(curs->pgres); + _pq_fetch_tuples(curs); ex = 0; + /* don't clear curs->pgres, because it contains the results! */ + break; + + default: + Dprintf("pq_fetch: uh-oh, something FAILED"); + pq_raise(curs->conn, curs, NULL, NULL); + IFCLEARPGRES(curs->pgres); + ex = -1; + break; + } + + Dprintf("pq_fetch: fetching done; check for critical errors"); + + /* error checking, close the connection if necessary (some critical errors + are not really critical, like a COPY FROM error: if that's the case we + raise the exception but we avoid to close the connection) */ + if (curs->conn->critical) { + if (ex == -1) { + pq_resolve_critical(curs->conn, 1); + } + else { + pq_resolve_critical(curs->conn, 0); + } + return -1; + } + + return ex; +} diff --git a/psycopg2/psycopg/pqpath.h b/psycopg2/psycopg/pqpath.h new file mode 100644 index 0000000..64d113e --- /dev/null +++ b/psycopg2/psycopg/pqpath.h @@ -0,0 +1,41 @@ +/* pqpath.h - definitions for pqpath.c + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_PQPATH_H +#define PSYCOPG_PQPATH_H 1 + +#include "psycopg/cursor.h" +#include "psycopg/connection.h" + +/* macros to clean the pg result */ +#define IFCLEARPGRES(pgres) if (pgres) {PQclear(pgres); pgres = NULL;} +#define CLEARPGRES(pgres) PQclear(pgres); pgres = NULL + +/* exported functions */ +extern int pq_fetch(cursorObject *curs); +extern int pq_execute(cursorObject *curs, const char *query, int async); +extern int pq_begin(connectionObject *conn); +extern int pq_commit(connectionObject *conn); +extern int pq_abort(connectionObject *conn); +extern int pq_is_busy(connectionObject *conn); +extern void pq_set_critical(connectionObject *conn, const char *msg); + +#endif /* !defined(PSYCOPG_PQPATH_H) */ diff --git a/psycopg2/psycopg/psycopg.h b/psycopg2/psycopg/psycopg.h new file mode 100644 index 0000000..a689ea4 --- /dev/null +++ b/psycopg2/psycopg/psycopg.h @@ -0,0 +1,142 @@ +/* psycopg.h - definitions for the psycopg python module + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_H +#define PSYCOPG_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* DBAPI compliance parameters */ +#define APILEVEL "2.0" +#define THREADSAFETY 2 +#define PARAMSTYLE "pyformat" + +/* C API functions */ +#define psyco_errors_fill_NUM 0 +#define psyco_errors_fill_RETURN void +#define psyco_errors_fill_PROTO (PyObject *dict) +#define psyco_errors_set_NUM 1 +#define psyco_errors_set_RETURN void +#define psyco_errors_set_PROTO (PyObject *type) + +/* Total number of C API pointers */ +#define PSYCOPG_API_pointers 2 + +#ifdef PSYCOPG_MODULE + /** This section is used when compiling psycopgmodule.c & co. **/ +extern psyco_errors_fill_RETURN psyco_errors_fill psyco_errors_fill_PROTO; +extern psyco_errors_set_RETURN psyco_errors_set psyco_errors_set_PROTO; + +/* global excpetions */ +extern PyObject *Error, *Warning, *InterfaceError, *DatabaseError, + *InternalError, *OperationalError, *ProgrammingError, + *IntegrityError, *DataError, *NotSupportedError; + +/* python versions and compatibility stuff */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC void +#endif + +#else + /** This section is used in modules that use psycopg's C API **/ + +static void **PSYCOPG_API; + +#define psyco_errors_fill \ + (*(psyco_errors_fill_RETURN (*)psyco_errors_fill_PROTO) \ + PSYCOPG_API[psyco_errors_fill_NUM]) +#define psyco_errors_set \ + (*(psyco_errors_set_RETURN (*)psyco_errors_set_PROTO) \ + PSYCOPG_API[psyco_errors_set_NUM]) + +/* Return -1 and set exception on error, 0 on success. */ +static int +import_psycopg(void) +{ + PyObject *module = PyImport_ImportModule("psycopg"); + + if (module != NULL) { + PyObject *c_api_object = PyObject_GetAttrString(module, "_C_API"); + if (c_api_object == NULL) return -1; + if (PyCObject_Check(c_api_object)) + PSYCOPG_API = (void **)PyCObject_AsVoidPtr(c_api_object); + Py_DECREF(c_api_object); + } + return 0; +} + +#endif + +/* postgresql<->python encoding map */ +extern PyObject *psycoEncodings; + +typedef struct { + char *pgenc; + char *pyenc; +} encodingPair; + +/* the Decimal type, used by the DECIMAL typecaster */ +extern PyObject *decimalType; + +/* some utility functions */ +extern void psyco_set_error(PyObject *exc, PyObject *curs, char *msg, + char *pgerror, char *pgcode); + +/* Exceptions docstrings */ +#define Error_doc \ +"Base class for error exceptions." + +#define Warning_doc \ +"A database warning." + +#define InterfaceError_doc \ +"Error related to the database interface." + +#define DatabaseError_doc \ +"Error related to the database engine." + +#define InternalError_doc \ +"The database encountered an internal error." + +#define OperationalError_doc \ +"Error related to database operation (disconnect, memory allocation etc)." + +#define ProgrammingError_doc \ +"Error related to database programming (SQL error, table not found etc)." + +#define IntegrityError_doc \ +"Error related to database integrity." + +#define DataError_doc \ +"Error related to problems with the processed data." + +#define NotSupportedError_doc \ +"A not supported datbase API was called." + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_H) */ diff --git a/psycopg2/psycopg/psycopgmodule.c b/psycopg2/psycopg/psycopgmodule.c new file mode 100644 index 0000000..426fb27 --- /dev/null +++ b/psycopg2/psycopg/psycopgmodule.c @@ -0,0 +1,672 @@ +/* psycopgmodule.c - psycopg module (will import other C classes) + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/python.h" +#include "psycopg/psycopg.h" +#include "psycopg/connection.h" +#include "psycopg/cursor.h" +#include "psycopg/typecast.h" +#include "psycopg/microprotocols.h" +#include "psycopg/microprotocols_proto.h" + +#include "psycopg/adapter_qstring.h" +#include "psycopg/adapter_binary.h" +#include "psycopg/adapter_pboolean.h" +#include "psycopg/adapter_asis.h" +#include "psycopg/adapter_list.h" +#include "psycopg/typecast_binary.h" + +#ifdef HAVE_MXDATETIME +#include +#include "psycopg/adapter_mxdatetime.h" +mxDateTimeModule_APIObject *mxDateTimeP = NULL; +#endif + +/* some module-level variables, like the datetime module */ +#ifdef HAVE_PYDATETIME +#include +#include "psycopg/adapter_datetime.h" +PyObject *pyDateTimeModuleP = NULL; +PyObject *pyDateTypeP = NULL; +PyObject *pyTimeTypeP = NULL; +PyObject *pyDateTimeTypeP = NULL; +PyObject *pyDeltaTypeP = NULL; +#endif + +/* pointers to the psycopg.tz classes */ +PyObject *pyPsycopgTzModule = NULL; +PyObject *pyPsycopgTzLOCAL = NULL; +PyObject *pyPsycopgTzFixedOffsetTimezone = NULL; + +PyObject *psycoEncodings = NULL; +PyObject *decimalType = NULL; + +/** connect module-level function **/ +#define psyco_connect_doc \ +"connect(dsn, ...) -- Create a new database connection.\n\n" \ +"This function supports two different but equivalent sets of arguments.\n" \ +"A single data source name or ``dsn`` string can be used to specify the\n" \ +"connection parameters, as follows::\n\n" \ +" psycopg2.connect(\"dbname=xxx user=xxx ...\")\n\n" \ +"If ``dsn`` is not provided it is possible to pass the parameters as\n" \ +"keyword arguments; e.g.::\n\n" \ +" psycopg2.connect(database='xxx', user='xxx', ...)\n\n" \ +"The full list of available parameters is:\n\n" \ +"- ``dbname`` -- database name (only in 'dsn')\n" \ +"- ``database`` -- database name (only as keyword argument)\n" \ +"- ``host`` -- host address (defaults to UNIX socket if not provided)\n" \ +"- ``port`` -- port number (defaults to 5432 if not provided)\n" \ +"- ``user`` -- user name used to authenticate\n" \ +"- ``password`` -- password used to authenticate\n" \ +"- ``sslmode`` -- SSL mode (see PostgreSQL documentation)\n\n" \ +"If the ``connection_factory`` keyword argument is not provided this\n" \ +"function always return an instance of the `connection` class.\n" \ +"Else the given sub-class of `extensions.connection` will be used to\n" \ +"instantiate the connection object.\n\n" \ +":return: New database connection\n" \ +":rtype: `extensions.connection`" + +static int +_psyco_connect_fill_dsn(char *dsn, char *kw, char *v, int i) +{ + strcpy(&dsn[i], kw); i += strlen(kw); + strcpy(&dsn[i], v); i += strlen(v); + return i; +} + +static void +_psyco_connect_fill_exc(connectionObject *conn) +{ + /* fill the connection object with the exceptions */ + conn->exc_Error = Error; + Py_INCREF(Error); + conn->exc_Warning = Warning; + Py_INCREF(Warning); + conn->exc_InterfaceError = InterfaceError; + Py_INCREF(InterfaceError); + conn->exc_DatabaseError = DatabaseError; + Py_INCREF(DatabaseError); + conn->exc_InternalError = InternalError; + Py_INCREF(InternalError); + conn->exc_ProgrammingError = ProgrammingError; + Py_INCREF(ProgrammingError); + conn->exc_IntegrityError = IntegrityError; + Py_INCREF(IntegrityError); + conn->exc_DataError = DataError; + Py_INCREF(DataError); + conn->exc_NotSupportedError = NotSupportedError; + Py_INCREF(NotSupportedError); + conn->exc_OperationalError = OperationalError; + Py_INCREF(OperationalError); +} + +static PyObject * +psyco_connect(PyObject *self, PyObject *args, PyObject *keywds) +{ + PyObject *conn, *factory = NULL; + PyObject *pyport = NULL; + + int idsn=-1, iport=-1; + char *dsn=NULL, *database=NULL, *user=NULL, *password=NULL; + char *host=NULL, *sslmode=NULL; + char port[16]; + + static char *kwlist[] = {"dsn", "database", "host", "port", + "user", "password", "sslmode", + "connection_factory", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sssOsssO", kwlist, + &dsn, &database, &host, &pyport, + &user, &password, &sslmode, &factory)) { + return NULL; + } + + if (pyport && PyString_Check(pyport)) { + PyObject *pyint = PyInt_FromString(PyString_AsString(pyport), NULL, 10); + if (!pyint) return NULL; + iport = PyInt_AsLong(pyint); + } + else if (pyport && PyInt_Check(pyport)) { + iport = PyInt_AsLong(pyport); + } + else if (pyport != NULL) { + PyErr_SetString(PyExc_TypeError, "port must be a string or int"); + return NULL; + } + + if (iport > 0) + PyOS_snprintf(port, 16, "%d", iport); + + if (dsn == NULL) { + int l = 45; /* len("dbname= user= password= host= port= sslmode=\0") */ + + if (database) l += strlen(database); + if (host) l += strlen(host); + if (iport > 0) l += strlen(port); + if (user) l += strlen(user); + if (password) l += strlen(password); + if (sslmode) l += strlen(sslmode); + + dsn = malloc(l*sizeof(char)); + if (dsn == NULL) { + PyErr_SetString(InterfaceError, "dynamic dsn allocation failed"); + return NULL; + } + + idsn = 0; + if (database) + idsn = _psyco_connect_fill_dsn(dsn, " dbname=", database, idsn); + if (host) + idsn = _psyco_connect_fill_dsn(dsn, " host=", host, idsn); + if (iport > 0) + idsn = _psyco_connect_fill_dsn(dsn, " port=", port, idsn); + if (user) + idsn = _psyco_connect_fill_dsn(dsn, " user=", user, idsn); + if (password) + idsn = _psyco_connect_fill_dsn(dsn, " password=", password, idsn); + if (sslmode) + idsn = _psyco_connect_fill_dsn(dsn, " sslmode=", sslmode, idsn); + + if (idsn > 0) { + dsn[idsn] = '\0'; + memmove(dsn, &dsn[1], idsn); + } + else { + free(dsn); + PyErr_SetString(InterfaceError, "missing dsn and no parameters"); + return NULL; + } + } + + Dprintf("psyco_connect: dsn = '%s'", dsn); + + /* allocate connection, fill with errors and return it */ + if (factory == NULL) factory = (PyObject *)&connectionType; + conn = PyObject_CallFunction(factory, "s", dsn); + if (conn) _psyco_connect_fill_exc((connectionObject*)conn); + + return conn; +} + +/** type registration **/ +#define psyco_register_type_doc \ +"register_type(obj) -> None -- register obj with psycopg type system\n\n" \ +":Parameters:\n" \ +" * `obj`: A type adapter created by `new_type()`" + +#define typecast_from_python_doc \ +"new_type(oids, name, adapter) -> new type object\n\n" \ +"Create a new binding object. The object can be used with the\n" \ +"`register_type()` function to bind PostgreSQL objects to python objects.\n\n" \ +":Parameters:\n" \ +" * `oids`: Tuple of ``oid`` of the PostgreSQL types to convert.\n" \ +" * `name`: Name for the new type\n" \ +" * `adapter`: Callable to perform type conversion.\n" \ +" It must have the signature ``fun(value, cur)`` where ``value`` is\n" \ +" the string representation returned by PostgreSQL (`None` if ``NULL``)\n" \ +" and ``cur`` is the cursor from which data are read." + +static PyObject * +psyco_register_type(PyObject *self, PyObject *args) +{ + PyObject *type; + + if (!PyArg_ParseTuple(args, "O!", &typecastType, &type)) { + return NULL; + } + + typecast_add(type, 0); + + Py_INCREF(Py_None); + return Py_None; +} + + +/* default adapters */ + +static void +psyco_adapters_init(PyObject *mod) +{ + PyObject *call; + + microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&asisType); + microprotocols_add(&PyInt_Type, NULL, (PyObject*)&asisType); + microprotocols_add(&PyLong_Type, NULL, (PyObject*)&asisType); + + microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType); + microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType); + microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType); + microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType); + +#ifdef HAVE_MXDATETIME + /* the module has already been initialized, so we can obtain the callable + objects directly from its dictionary :) */ + call = PyMapping_GetItemString(mod, "TimestampFromMx"); + microprotocols_add(mxDateTimeP->DateTime_Type, NULL, call); + call = PyMapping_GetItemString(mod, "TimeFromMx"); + microprotocols_add(mxDateTimeP->DateTimeDelta_Type, NULL, call); +#endif + +#ifdef HAVE_PYDATETIME + /* as above, we use the callable objects from the psycopg module */ + call = PyMapping_GetItemString(mod, "DateFromPy"); + microprotocols_add((PyTypeObject*)pyDateTypeP, NULL, call); + call = PyMapping_GetItemString(mod, "TimeFromPy"); + microprotocols_add((PyTypeObject*)pyTimeTypeP, NULL, call); + call = PyMapping_GetItemString(mod, "TimestampFromPy"); + microprotocols_add((PyTypeObject*)pyDateTimeTypeP, NULL, call); + call = PyMapping_GetItemString(mod, "IntervalFromPy"); + microprotocols_add((PyTypeObject*)pyDeltaTypeP, NULL, call); +#endif + +#ifdef HAVE_PYBOOL + microprotocols_add(&PyBool_Type, NULL, (PyObject*)&pbooleanType); +#endif + +#ifdef HAVE_DECIMAL + microprotocols_add((PyTypeObject*)decimalType, NULL, (PyObject*)&asisType); +#endif +} + +/* psyco_encodings_fill + + Fill the module's postgresql<->python encoding table */ + +static encodingPair encodings[] = { + {"SQL_ASCII", "ascii"}, + {"LATIN1", "latin_1"}, + {"UNICODE", "utf_8"}, + {"UTF8", "utf_8"}, + + /* some compatibility stuff */ + {"LATIN-1", "latin_1"}, + + {NULL, NULL} +}; +static void psyco_encodings_fill(PyObject *dict) +{ + encodingPair *enc; + + for (enc = encodings; enc->pgenc != NULL; enc++) { + PyObject *value = PyString_FromString(enc->pyenc); + PyDict_SetItemString(dict, enc->pgenc, value); + Py_DECREF(value); + } +} + +/* psyco_errors_init, psyco_errors_fill (callable from C) + + Initialize the module's exceptions and after that a dictionary with a full + set of exceptions. */ + +PyObject *Error, *Warning, *InterfaceError, *DatabaseError, + *InternalError, *OperationalError, *ProgrammingError, + *IntegrityError, *DataError, *NotSupportedError; + +/* mapping between exception names and their PyObject */ +static struct { + char *name; + PyObject **exc; + PyObject **base; + char *docstr; +} exctable[] = { + { "psycopg2.Error", &Error, 0, Error_doc }, + { "psycopg2.Warning", &Warning, 0, Warning_doc }, + { "psycopg2.InterfaceError", &InterfaceError, &Error, InterfaceError_doc }, + { "psycopg2.DatabaseError", &DatabaseError, &Error, DatabaseError_doc }, + { "psycopg2.InternalError", &InternalError, &DatabaseError, InternalError_doc }, + { "psycopg2.OperationalError", &OperationalError, &DatabaseError, + OperationalError_doc }, + { "psycopg2.ProgrammingError", &ProgrammingError, &DatabaseError, + ProgrammingError_doc }, + { "psycopg2.IntegrityError", &IntegrityError, &DatabaseError, + IntegrityError_doc }, + { "psycopg2.DataError", &DataError, &DatabaseError, DataError_doc }, + { "psycopg2.NotSupportedError", &NotSupportedError, &DatabaseError, + NotSupportedError_doc }, + {NULL} /* Sentinel */ +}; + +static void +psyco_errors_init(void) +{ + /* the names of the exceptions here reflect the oranization of the + psycopg2 module and not the fact the the original error objects + live in _psycopg */ + + int i; + PyObject *dict; + PyObject *base; + PyObject *str; + + for (i=0; exctable[i].name; i++) { + dict = PyDict_New(); + + if (exctable[i].docstr) { + str = PyString_FromString(exctable[i].docstr); + PyDict_SetItemString(dict, "__doc__", str); + } + + if (exctable[i].base == 0) + base = PyExc_StandardError; + else + base = *exctable[i].base; + + *exctable[i].exc = PyErr_NewException(exctable[i].name, base, dict); + } +} + +void +psyco_errors_fill(PyObject *dict) +{ + PyDict_SetItemString(dict, "Error", Error); + PyDict_SetItemString(dict, "Warning", Warning); + PyDict_SetItemString(dict, "InterfaceError", InterfaceError); + PyDict_SetItemString(dict, "DatabaseError", DatabaseError); + PyDict_SetItemString(dict, "InternalError", InternalError); + PyDict_SetItemString(dict, "OperationalError", OperationalError); + PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError); + PyDict_SetItemString(dict, "IntegrityError", IntegrityError); + PyDict_SetItemString(dict, "DataError", DataError); + PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError); +} + +void +psyco_errors_set(PyObject *type) +{ + PyObject_SetAttrString(type, "Error", Error); + PyObject_SetAttrString(type, "Warning", Warning); + PyObject_SetAttrString(type, "InterfaceError", InterfaceError); + PyObject_SetAttrString(type, "DatabaseError", DatabaseError); + PyObject_SetAttrString(type, "InternalError", InternalError); + PyObject_SetAttrString(type, "OperationalError", OperationalError); + PyObject_SetAttrString(type, "ProgrammingError", ProgrammingError); + PyObject_SetAttrString(type, "IntegrityError", IntegrityError); + PyObject_SetAttrString(type, "DataError", DataError); + PyObject_SetAttrString(type, "NotSupportedError", NotSupportedError); +} + +/* psyco_error_new + + Create a new error of the given type with extra attributes. */ + +void +psyco_set_error(PyObject *exc, PyObject *curs, char *msg, + char *pgerror, char *pgcode) +{ + PyObject *t; + + PyObject *err = PyObject_CallFunction(exc, "s", msg); + + if (err) { + if (pgerror) { + t = PyString_FromString(pgerror); + } + else { + t = Py_None ; Py_INCREF(t); + } + PyObject_SetAttrString(err, "pgerror", t); + Py_DECREF(t); + + if (pgcode) { + t = PyString_FromString(pgcode); + } + else { + t = Py_None ; Py_INCREF(t); + } + PyObject_SetAttrString(err, "pgcode", t); + Py_DECREF(t); + + if (curs) + PyObject_SetAttrString(err, "cursor", curs); + else + PyObject_SetAttrString(err, "cursor", Py_None); + + PyErr_SetObject(exc, err); + Py_DECREF(err); + } +} + +/* psyco_decimal_init + + Initialize the module's pointer to the decimal type. */ + +void +psyco_decimal_init(void) +{ +#ifdef HAVE_DECIMAL + PyObject *decimal = PyImport_ImportModule("decimal"); + if (decimal) { + decimalType = PyObject_GetAttrString(decimal, "Decimal"); + } + else { + PyErr_Clear(); + decimalType = (PyObject *)&PyFloat_Type; + Py_INCREF(decimalType); + } +#endif +} + + +/** method table and module initialization **/ + +static PyMethodDef psycopgMethods[] = { + {"connect", (PyCFunction)psyco_connect, + METH_VARARGS|METH_KEYWORDS, psyco_connect_doc}, + {"adapt", (PyCFunction)psyco_microprotocols_adapt, + METH_VARARGS, psyco_microprotocols_adapt_doc}, + + {"register_type", (PyCFunction)psyco_register_type, + METH_VARARGS, psyco_register_type_doc}, + {"new_type", (PyCFunction)typecast_from_python, + METH_VARARGS|METH_KEYWORDS, typecast_from_python_doc}, + + {"AsIs", (PyCFunction)psyco_AsIs, + METH_VARARGS, psyco_AsIs_doc}, + {"QuotedString", (PyCFunction)psyco_QuotedString, + METH_VARARGS, psyco_QuotedString_doc}, + {"Boolean", (PyCFunction)psyco_Boolean, + METH_VARARGS, psyco_Boolean_doc}, + {"Binary", (PyCFunction)psyco_Binary, + METH_VARARGS, psyco_Binary_doc}, + {"Date", (PyCFunction)psyco_Date, + METH_VARARGS, psyco_Date_doc}, + {"Time", (PyCFunction)psyco_Time, + METH_VARARGS, psyco_Time_doc}, + {"Timestamp", (PyCFunction)psyco_Timestamp, + METH_VARARGS, psyco_Timestamp_doc}, + {"DateFromTicks", (PyCFunction)psyco_DateFromTicks, + METH_VARARGS, psyco_DateFromTicks_doc}, + {"TimeFromTicks", (PyCFunction)psyco_TimeFromTicks, + METH_VARARGS, psyco_TimeFromTicks_doc}, + {"TimestampFromTicks", (PyCFunction)psyco_TimestampFromTicks, + METH_VARARGS, psyco_TimestampFromTicks_doc}, + {"List", (PyCFunction)psyco_List, + METH_VARARGS, psyco_List_doc}, + +#ifdef HAVE_MXDATETIME + {"DateFromMx", (PyCFunction)psyco_DateFromMx, + METH_VARARGS, psyco_DateFromMx_doc}, + {"TimeFromMx", (PyCFunction)psyco_TimeFromMx, + METH_VARARGS, psyco_TimeFromMx_doc}, + {"TimestampFromMx", (PyCFunction)psyco_TimestampFromMx, + METH_VARARGS, psyco_TimestampFromMx_doc}, + {"IntervalFromMx", (PyCFunction)psyco_IntervalFromMx, + METH_VARARGS, psyco_IntervalFromMx_doc}, +#endif + +#ifdef HAVE_PYDATETIME + {"DateFromPy", (PyCFunction)psyco_DateFromPy, + METH_VARARGS, psyco_DateFromPy_doc}, + {"TimeFromPy", (PyCFunction)psyco_TimeFromPy, + METH_VARARGS, psyco_TimeFromPy_doc}, + {"TimestampFromPy", (PyCFunction)psyco_TimestampFromPy, + METH_VARARGS, psyco_TimestampFromPy_doc}, + {"IntervalFromPy", (PyCFunction)psyco_IntervalFromPy, + METH_VARARGS, psyco_IntervalFromPy_doc}, +#endif + + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +init_psycopg(void) +{ + static void *PSYCOPG_API[PSYCOPG_API_pointers]; + + PyObject *module, *dict; + PyObject *c_api_object; + + Dprintf("initpsycopg: initializing psycopg %s", PSYCOPG_VERSION); + + /* initialize all the new types and then the module */ + connectionType.ob_type = &PyType_Type; + cursorType.ob_type = &PyType_Type; + typecastType.ob_type = &PyType_Type; + qstringType.ob_type = &PyType_Type; + binaryType.ob_type = &PyType_Type; + isqlquoteType.ob_type = &PyType_Type; + asisType.ob_type = &PyType_Type; + listType.ob_type = &PyType_Type; + chunkType.ob_type = &PyType_Type; + + if (PyType_Ready(&connectionType) == -1) return; + if (PyType_Ready(&cursorType) == -1) return; + if (PyType_Ready(&typecastType) == -1) return; + if (PyType_Ready(&qstringType) == -1) return; + if (PyType_Ready(&binaryType) == -1) return; + if (PyType_Ready(&isqlquoteType) == -1) return; + if (PyType_Ready(&asisType) == -1) return; + if (PyType_Ready(&listType) == -1) return; + if (PyType_Ready(&chunkType) == -1) return; + +#ifdef HAVE_PYBOOL + pbooleanType.ob_type = &PyType_Type; + if (PyType_Ready(&pbooleanType) == -1) return; +#endif + + /* import mx.DateTime module, if necessary */ +#ifdef HAVE_MXDATETIME + mxdatetimeType.ob_type = &PyType_Type; + if (PyType_Ready(&mxdatetimeType) == -1) return; + if (mxDateTime_ImportModuleAndAPI() != 0) { + Dprintf("initpsycopg: why marc hide mx.DateTime again?!"); + PyErr_SetString(PyExc_ImportError, "can't import mx.DateTime module"); + return; + } + mxDateTimeP = &mxDateTime; +#endif + + /* import python builtin datetime module, if available */ +#ifdef HAVE_PYDATETIME + pyDateTimeModuleP = PyImport_ImportModule("datetime"); + if (pyDateTimeModuleP == NULL) { + Dprintf("initpsycopg: can't import datetime module"); + PyErr_SetString(PyExc_ImportError, "can't import datetime module"); + return; + } + pydatetimeType.ob_type = &PyType_Type; + if (PyType_Ready(&pydatetimeType) == -1) return; + + /* now we define the datetime types, this is crazy because python should + be doing that, not us! */ + pyDateTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "date"); + pyTimeTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "time"); + pyDateTimeTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "datetime"); + pyDeltaTypeP = PyObject_GetAttrString(pyDateTimeModuleP, "timedelta"); +#endif + + /* import psycopg2.tz anyway (TODO: replace with C-level module?) */ + pyPsycopgTzModule = PyImport_ImportModule("psycopg2.tz"); + if (pyPsycopgTzModule == NULL) { + Dprintf("initpsycopg: can't import psycopg2.tz module"); + PyErr_SetString(PyExc_ImportError, "can't import psycopg2.tz module"); + return; + } + pyPsycopgTzLOCAL = + PyObject_GetAttrString(pyPsycopgTzModule, "LOCAL"); + pyPsycopgTzFixedOffsetTimezone = + PyObject_GetAttrString(pyPsycopgTzModule, "FixedOffsetTimezone"); + + /* initialize the module and grab module's dictionary */ + module = Py_InitModule("_psycopg", psycopgMethods); + dict = PyModule_GetDict(module); + + /* initialize all the module's exported functions */ + /* PyBoxer_API[PyBoxer_Fake_NUM] = (void *)PyBoxer_Fake; */ + + /* Create a CObject containing the API pointer array's address */ + c_api_object = PyCObject_FromVoidPtr((void *)PSYCOPG_API, NULL); + if (c_api_object != NULL) + PyModule_AddObject(module, "_C_API", c_api_object); + + /* other mixed initializations of module-level variables */ + psycoEncodings = PyDict_New(); + psyco_encodings_fill(psycoEncodings); + psyco_decimal_init(); + + /* set some module's parameters */ + PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION); + PyModule_AddStringConstant(module, "__doc__", "psycopg PostgreSQL driver"); + PyModule_AddObject(module, "apilevel", PyString_FromString(APILEVEL)); + PyModule_AddObject(module, "threadsafety", PyInt_FromLong(THREADSAFETY)); + PyModule_AddObject(module, "paramstyle", PyString_FromString(PARAMSTYLE)); + + /* put new types in module dictionary */ + PyModule_AddObject(module, "connection", (PyObject*)&connectionType); + PyModule_AddObject(module, "cursor", (PyObject*)&cursorType); + PyModule_AddObject(module, "ISQLQuote", (PyObject*)&isqlquoteType); + + /* encodings dictionary in module dictionary */ + PyModule_AddObject(module, "encodings", psycoEncodings); + + /* initialize default set of typecasters */ + typecast_init(dict); + + /* initialize microprotocols layer */ + microprotocols_init(dict); + psyco_adapters_init(dict); + + /* create a standard set of exceptions and add them to the module's dict */ + psyco_errors_init(); + psyco_errors_fill(dict); + + /* Solve win32 build issue about non-constant initializer element */ + cursorType.tp_alloc = PyType_GenericAlloc; + binaryType.tp_alloc = PyType_GenericAlloc; + isqlquoteType.tp_alloc = PyType_GenericAlloc; + pbooleanType.tp_alloc = PyType_GenericAlloc; + connectionType.tp_alloc = PyType_GenericAlloc; + asisType.tp_alloc = PyType_GenericAlloc; + qstringType.tp_alloc = PyType_GenericAlloc; + listType.tp_alloc = PyType_GenericAlloc; + chunkType.tp_alloc = PyType_GenericAlloc; + +#ifdef HAVE_PYDATETIME + pydatetimeType.tp_alloc = PyType_GenericAlloc; +#endif + + Dprintf("initpsycopg: module initialization complete"); +} diff --git a/psycopg2/psycopg/python.h b/psycopg2/psycopg/python.h new file mode 100644 index 0000000..1c2b96d --- /dev/null +++ b/psycopg2/psycopg/python.h @@ -0,0 +1,43 @@ +/* python.h - python version compatibility stuff + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_PYTHON_H +#define PSYCOPG_PYTHON_H 1 + +#include +#include + +/* python < 2.2 does not have PyMemeberDef */ +#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 2 +#define PyMemberDef memberlist +#endif + +/* PyObject_TypeCheck introduced in 2.2 */ +#ifndef PyObject_TypeCheck +#define PyObject_TypeCheck(o, t) ((o)->ob_type == (t)) +#endif + +/* python 2.2 does not have freefunc (it has destructor instead) */ +#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 3 +#define freefunc destructor +#endif + +#endif /* !defined(PSYCOPG_PYTHON_H) */ diff --git a/psycopg2/psycopg/typecast.c b/psycopg2/psycopg/typecast.c new file mode 100644 index 0000000..ef91bfd --- /dev/null +++ b/psycopg2/psycopg/typecast.c @@ -0,0 +1,563 @@ +/* typecast.c - basic utility functions related to typecasting + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include + +#define PSYCOPG_MODULE +#include "psycopg/config.h" +#include "psycopg/psycopg.h" +#include "psycopg/python.h" +#include "psycopg/typecast.h" +#include "psycopg/cursor.h" + +/* usefull function used by some typecasters */ + +static char * +skip_until_space(char *s) +{ + while (*s && *s != ' ') s++; + return s; +} + +static char * +skip_until_space2(char *s, int *len) +{ + while (*len > 0 && *s && *s != ' ') { + s++; (*len)--; + } + return s; +} + +static int +typecast_parse_date(char* s, char** t, int* len, + int* year, int* month, int* day) +{ + int acc = -1, cz = 0; + + Dprintf("typecast_parse_date: len = %d, s = %s", *len, s); + + while (cz < 3 && *len > 0 && *s) { + switch (*s) { + case '-': + case ' ': + case 'T': + if (cz == 0) *year = acc; + else if (cz == 1) *month = acc; + else if (cz == 2) *day = acc; + acc = -1; cz++; + break; + default: + acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0'); + break; + } + + s++; (*len)--; + } + + if (acc != -1) { + *day = acc; + cz += 1; + } + if (t != NULL) *t = s; + + return cz; +} + +static int +typecast_parse_time(char* s, char** t, int* len, + int* hh, int* mm, int* ss, int* us, int* tz) +{ + int acc = -1, cz = 0; + int tzs = 1, tzhh = 0, tzmm = 0; + int usd = 0; + + /* sets microseconds and timezone to 0 because they may be missing */ + *us = *tz = 0; + + Dprintf("typecast_parse_time: len = %d, s = %s", *len, s); + + while (cz < 6 && *len > 0 && *s) { + switch (*s) { + case ':': + if (cz == 0) *hh = acc; + else if (cz == 1) *mm = acc; + else if (cz == 2) *ss = acc; + else if (cz == 3) *us = acc; + else if (cz == 4) tzhh = acc; + acc = -1; cz++; + break; + case '.': + /* we expect seconds and if we don't get them we return an error */ + if (cz != 2) return -1; + *ss = acc; + acc = -1; cz++; + break; + case '+': + case '-': + /* seconds or microseconds here, anything else is an error */ + if (cz < 2 || cz > 3) return -1; + if (*s == '-') tzs = -1; + if (cz == 2) *ss = acc; + else if (cz == 3) *us = acc; + acc = -1; cz = 4; + break; + default: + acc = (acc == -1 ? 0 : acc*10) + ((int)*s - (int)'0'); + if (cz == 3) usd += 1; + break; + } + + s++; (*len)--; + } + + if (acc != -1) { + if (cz == 2) { *ss = acc; cz += 1; } + else if (cz == 3) { *us = acc; cz += 1; } + else if (cz == 4) { tzhh = acc; cz += 1; } + else if (cz == 5) tzmm = acc; + } + if (t != NULL) *t = s; + + *tz = tzs * tzhh*60 + tzmm; + + if (*us != 0.0) { + while (usd++ < 6) *us *= 10.0; + } + + return cz; +} + +/** include casting objects **/ +#include "psycopg/typecast_basic.c" +#include "psycopg/typecast_binary.c" + +#ifdef HAVE_MXDATETIME +#include "psycopg/typecast_mxdatetime.c" +#endif + +#ifdef HAVE_PYDATETIME +#include "psycopg/typecast_datetime.c" +#endif + +#include "psycopg/typecast_array.c" +#include "psycopg/typecast_builtins.c" + + +/* a list of initializers, used to make the typecasters accessible anyway */ +#ifdef HAVE_PYDATETIME +typecastObject_initlist typecast_pydatetime[] = { + {"PYDATETIME", typecast_DATETIME_types, typecast_PYDATETIME_cast}, + {"PYTIME", typecast_TIME_types, typecast_PYTIME_cast}, + {"PYDATE", typecast_DATE_types, typecast_PYDATE_cast}, + {"PYINTERVAL", typecast_INTERVAL_types, typecast_PYINTERVAL_cast}, + {NULL, NULL, NULL} +}; +#endif + +/* a list of initializers, used to make the typecasters accessible anyway */ +#ifdef HAVE_MXDATETIME +typecastObject_initlist typecast_mxdatetime[] = { + {"MXDATETIME", typecast_DATETIME_types, typecast_MXDATE_cast}, + {"MXTIME", typecast_TIME_types, typecast_MXTIME_cast}, + {"MXDATE", typecast_DATE_types, typecast_MXDATE_cast}, + {"MXINTERVAL", typecast_INTERVAL_types, typecast_MXINTERVAL_cast}, + {NULL, NULL, NULL} +}; +#endif + + +/** the type dictionary and associated functions **/ + +PyObject *psyco_types; +PyObject *psyco_default_cast; +PyObject *psyco_binary_types; +PyObject *psyco_default_binary_cast; + +static long int typecast_default_DEFAULT[] = {0}; +static typecastObject_initlist typecast_default = { + "DEFAULT", typecast_default_DEFAULT, typecast_STRING_cast}; + + +/* typecast_init - initialize the dictionary and create default types */ + +int +typecast_init(PyObject *dict) +{ + int i; + + /* create type dictionary and put it in module namespace */ + psyco_types = PyDict_New(); + psyco_binary_types = PyDict_New(); + + if (!psyco_types || !psyco_binary_types) { + Py_XDECREF(psyco_types); + Py_XDECREF(psyco_binary_types); + return -1; + } + + PyDict_SetItemString(dict, "string_types", psyco_types); + PyDict_SetItemString(dict, "binary_types", psyco_binary_types); + + /* insert the cast types into the 'types' dictionary and register them in + the module dictionary */ + for (i = 0; typecast_builtins[i].name != NULL; i++) { + typecastObject *t; + + Dprintf("typecast_init: initializing %s", typecast_builtins[i].name); + + t = (typecastObject *)typecast_from_c(&(typecast_builtins[i]), dict); + if (t == NULL) return -1; + if (typecast_add((PyObject *)t, 0) != 0) return -1; + + PyDict_SetItem(dict, t->name, (PyObject *)t); + + /* export binary object */ + if (typecast_builtins[i].values == typecast_BINARY_types) { + psyco_default_binary_cast = (PyObject *)t; + } + } + + /* create and save a default cast object (but does not register it) */ + psyco_default_cast = typecast_from_c(&typecast_default, dict); + + /* register the date/time typecasters with their original names */ +#ifdef HAVE_MXDATETIME + for (i = 0; typecast_mxdatetime[i].name != NULL; i++) { + typecastObject *t; + Dprintf("typecast_init: initializing %s", typecast_mxdatetime[i].name); + t = (typecastObject *)typecast_from_c(&(typecast_mxdatetime[i]), dict); + if (t == NULL) return -1; + PyDict_SetItem(dict, t->name, (PyObject *)t); + } +#endif +#ifdef HAVE_PYDATETIME + for (i = 0; typecast_pydatetime[i].name != NULL; i++) { + typecastObject *t; + Dprintf("typecast_init: initializing %s", typecast_pydatetime[i].name); + t = (typecastObject *)typecast_from_c(&(typecast_pydatetime[i]), dict); + if (t == NULL) return -1; + PyDict_SetItem(dict, t->name, (PyObject *)t); + } +#endif + + return 0; +} + +/* typecast_add - add a type object to the dictionary */ +int +typecast_add(PyObject *obj, int binary) +{ + PyObject *val; + int len, i; + + typecastObject *type = (typecastObject *)obj; + + Dprintf("typecast_add: object at %p, values refcnt = %d", + obj, type->values->ob_refcnt); + + len = PyTuple_Size(type->values); + for (i = 0; i < len; i++) { + val = PyTuple_GetItem(type->values, i); + Dprintf("typecast_add: adding val: %ld", PyInt_AsLong(val)); + if (binary) { + PyDict_SetItem(psyco_binary_types, val, obj); + } + else { + PyDict_SetItem(psyco_types, val, obj); + } + } + + Dprintf("typecast_add: base caster: %p", type->bcast); + + return 0; +} + + +/** typecast type **/ + +#define OFFSETOF(x) offsetof(typecastObject, x) + +static int +typecast_cmp(PyObject *obj1, PyObject* obj2) +{ + typecastObject *self = (typecastObject*)obj1; + typecastObject *other = NULL; + PyObject *number = NULL; + int i, j, res = -1; + + if (PyObject_TypeCheck(obj2, &typecastType)) { + other = (typecastObject*)obj2; + } + else { + number = PyNumber_Int(obj2); + } + + Dprintf("typecast_cmp: other = %p, number = %p", other, number); + + for (i=0; i < PyObject_Length(self->values) && res == -1; i++) { + long int val = PyInt_AsLong(PyTuple_GET_ITEM(self->values, i)); + + if (other != NULL) { + for (j=0; j < PyObject_Length(other->values); j++) { + if (PyInt_AsLong(PyTuple_GET_ITEM(other->values, j)) == val) { + res = 0; break; + } + } + } + + else if (number != NULL) { + if (PyInt_AsLong(number) == val) { + res = 0; break; + } + } + } + + Py_XDECREF(number); + return res; +} + +static PyObject* +typecast_richcompare(PyObject *obj1, PyObject* obj2, int opid) +{ + PyObject *result = NULL; + int res = typecast_cmp(obj1, obj2); + + if (PyErr_Occurred()) return NULL; + + if ((opid == Py_EQ && res == 0) || (opid != Py_EQ && res != 0)) + result = Py_True; + else + result = Py_False; + + Py_INCREF(result); + return result; +} + +static struct PyMemberDef typecastObject_members[] = { + {"name", T_OBJECT, OFFSETOF(name), RO}, + {"values", T_OBJECT, OFFSETOF(values), RO}, + {NULL} +}; + +static void +typecast_dealloc(PyObject *obj) +{ + typecastObject *self = (typecastObject*)obj; + + Py_XDECREF(self->values); + Py_XDECREF(self->name); + Py_XDECREF(self->pcast); + + PyObject_Del(self); +} + +static PyObject * +typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs) +{ + PyObject *string, *cursor; + + if (!PyArg_ParseTuple(args, "OO", &string, &cursor)) { + return NULL; + } + + return typecast_cast(obj, + PyString_AsString(string), PyString_Size(string), + cursor); +} + +PyTypeObject typecastType = { + PyObject_HEAD_INIT(NULL) + 0, + "psycopg2._psycopg.type", + sizeof(typecastObject), + 0, + + typecast_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + typecast_cmp, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + + typecast_call, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + + Py_TPFLAGS_HAVE_RICHCOMPARE, /*tp_flags*/ + "psycopg type-casting object", /*tp_doc*/ + + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + + typecast_richcompare, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + + /* Attribute descriptor and subclassing stuff */ + + 0, /*tp_methods*/ + typecastObject_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + + 0, /*tp_init*/ + 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/ + 0, /*tp_new*/ + 0, /*tp_free Low-level free-memory routine */ + 0, /*tp_is_gc For PyObject_IS_GC */ + 0, /*tp_bases*/ + 0, /*tp_mro method resolution order */ + 0, /*tp_cache*/ + 0, /*tp_subclasses*/ + 0 /*tp_weaklist*/ +}; + +static PyObject * +typecast_new(PyObject *name, PyObject *values, PyObject *cast, PyObject *base) +{ + typecastObject *obj; + + obj = PyObject_NEW(typecastObject, &typecastType); + if (obj == NULL) return NULL; + + Dprintf("typecast_new: new type at = %p, refcnt = %d", obj, obj->ob_refcnt); + + Py_INCREF(values); + obj->values = values; + + if (name) { + Py_INCREF(name); + obj->name = name; + } + else { + Py_INCREF(Py_None); + obj->name = Py_None; + } + + obj->pcast = NULL; + obj->ccast = NULL; + obj->bcast = base; + + if (obj->bcast) Py_INCREF(obj->bcast); + + /* FIXME: raise an exception when None is passed as Python caster */ + if (cast && cast != Py_None) { + Py_INCREF(cast); + obj->pcast = cast; + } + + Dprintf("typecast_new: typecast object created at %p", obj); + + return (PyObject *)obj; +} + +PyObject * +typecast_from_python(PyObject *self, PyObject *args, PyObject *keywds) +{ + PyObject *v, *name, *cast = NULL, *base = NULL; + + static char *kwlist[] = {"values", "name", "castobj", "baseobj", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!OO", kwlist, + &PyTuple_Type, &v, + &PyString_Type, &name, + &cast, &base)) { + return NULL; + } + + return typecast_new(name, v, cast, base); +} + +PyObject * +typecast_from_c(typecastObject_initlist *type, PyObject *dict) +{ + PyObject *tuple, *base = NULL; + typecastObject *obj; + int i, len = 0; + + /* before doing anything else we look for the base */ + if (type->base) { + /* NOTE: base is a borrowed reference! */ + base = PyDict_GetItemString(dict, type->base); + if (!base) { + PyErr_Format(Error, "typecast base not found: %s", type->base); + return NULL; + } + } + + while (type->values[len] != 0) len++; + + tuple = PyTuple_New(len); + if (!tuple) return NULL; + + for (i = 0; i < len ; i++) { + PyTuple_SET_ITEM(tuple, i, PyInt_FromLong(type->values[i])); + } + + + obj = (typecastObject *) + typecast_new(PyString_FromString(type->name), tuple, NULL, base); + + if (obj) { + obj->ccast = type->cast; + obj->pcast = NULL; + } + return (PyObject *)obj; +} + +PyObject * +typecast_cast(PyObject *obj, char *str, int len, PyObject *curs) +{ + PyObject *old, *res = NULL; + typecastObject *self = (typecastObject *)obj; + + /* we don't incref, the caster *can't* die at this point */ + old = ((cursorObject*)curs)->caster; + ((cursorObject*)curs)->caster = obj; + + if (self->ccast) { + res = self->ccast(str, len, curs); + } + else if (self->pcast) { + res = PyObject_CallFunction(self->pcast, "s#O", str, len, curs); + } + else { + PyErr_SetString(Error, "internal error: no casting function found"); + } + + ((cursorObject*)curs)->caster = old; + + return res; +} diff --git a/psycopg2/psycopg/typecast.h b/psycopg2/psycopg/typecast.h new file mode 100644 index 0000000..ec77e5c --- /dev/null +++ b/psycopg2/psycopg/typecast.h @@ -0,0 +1,85 @@ +/* typecast.h - definitions for typecasters + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_TYPECAST_H +#define PSYCOPG_TYPECAST_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* type of type-casting functions (both C and Python) */ +typedef PyObject *(*typecast_function)(char *, int len, PyObject *); + +/** typecast type **/ + +extern PyTypeObject typecastType; + +typedef struct { + PyObject_HEAD + + PyObject *name; /* the name of this type */ + PyObject *values; /* the different types this instance can match */ + + typecast_function ccast; /* the C casting function */ + PyObject *pcast; /* the python casting function */ + PyObject *bcast; /* base cast, used by array typecasters */ +} typecastObject; + +/* the initialization values are stored here */ + +typedef struct { + char *name; + long int *values; + typecast_function cast; + + /* base is the base typecaster for arrays */ + char *base; +} typecastObject_initlist; + +/* the type dictionary, much faster to access it globally */ +extern PyObject *psyco_types; +extern PyObject *psyco_binary_types; + +/* the default casting objects, used when no other objects are available */ +extern PyObject *psyco_default_cast; +extern PyObject *psyco_default_binary_cast; + +/** exported functions **/ + +/* used by module.c to init the type system and register types */ +extern int typecast_init(PyObject *dict); +extern int typecast_add(PyObject *obj, int binary); + +/* the C callable typecastObject creator function */ +extern PyObject *typecast_from_c(typecastObject_initlist *type, PyObject *d); + +/* the python callable typecast creator function */ +extern PyObject *typecast_from_python( + PyObject *self, PyObject *args, PyObject *keywds); + +/* the function used to dispatch typecasting calls */ +extern PyObject *typecast_cast( + PyObject *self, char *str, int len, PyObject *curs); + +#endif /* !defined(PSYCOPG_TYPECAST_H) */ diff --git a/psycopg2/psycopg/typecast_array.c b/psycopg2/psycopg/typecast_array.c new file mode 100644 index 0000000..7dcb3a3 --- /dev/null +++ b/psycopg2/psycopg/typecast_array.c @@ -0,0 +1,258 @@ +/* typecast_array.c - array typecasters + * + * Copyright (C) 2005 Federico Di Gregorio + * + * This file is part of the psycopg module. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define MAX_DIMENSIONS 16 + +/** typecast_array_cleanup - remove the horrible [...]= stuff **/ + +static int +typecast_array_cleanup(char **str, int *len) +{ + int i, depth = 1; + + if ((*str)[0] != '[') return -1; + + for (i=1 ; depth > 0 && i < *len ; i++) { + if ((*str)[i] == '[') + depth += 1; + else if ((*str)[i] == ']') + depth -= 1; + } + if ((*str)[i] != '=') return -1; + + *str = &((*str)[i+1]); + *len = *len - i - 1; + return 0; +} + +/** typecast_array_scan - scan a string looking for array items **/ + +#define ASCAN_ERROR -1 +#define ASCAN_EOF 0 +#define ASCAN_BEGIN 1 +#define ASCAN_END 2 +#define ASCAN_TOKEN 3 +#define ASCAN_QUOTED 4 + +static int +typecast_array_tokenize(char *str, int strlength, + int *pos, char** token, int *length) +{ + /* FORTRAN glory */ + int i, j, q, b, l, res; + + Dprintf("typecast_array_tokenize: '%s', %d/%d", + &str[*pos], *pos, strlength); + + /* we always get called with pos pointing at the start of a token, so a + fast check is enough for ASCAN_EOF, ASCAN_BEGIN and ASCAN_END */ + if (*pos == strlength) { + return ASCAN_EOF; + } + else if (str[*pos] == '{') { + *pos += 1; + return ASCAN_BEGIN; + } + else if (str[*pos] == '}') { + *pos += 1; + if (str[*pos] == ',') + *pos += 1; + return ASCAN_END; + } + + /* now we start looking for the first unquoted ',' or '}', the only two + tokens that can limit an array element */ + q = 0; /* if q is odd we're inside quotes */ + b = 0; /* if b is 1 we just encountered a backslash */ + res = ASCAN_TOKEN; + + for (i = *pos ; i < strlength ; i++) { + switch (str[i]) { + case '"': + if (b == 0) + q += 1; + else + b = 0; + break; + + case '\\': + res = ASCAN_QUOTED; + if (b == 0) + b = 1; + else + /* we're backslashing a backslash */ + b = 0; + break; + + case '}': + case ',': + if (b == 0 && ((q&1) == 0)) + goto tokenize; + break; + + default: + /* reset the backslash counter */ + b = 0; + break; + } + } + + tokenize: + /* remove initial quoting character and calculate raw length */ + l = i - *pos; + if (str[*pos] == '"') { + *pos += 1; + l -= 2; + } + + if (res == ASCAN_QUOTED) { + char *buffer = PyMem_Malloc(l+1); + if (buffer == NULL) return ASCAN_ERROR; + + *token = buffer; + + for (j = *pos; j < *pos+l; j++) { + if (str[j] != '\\' + || (j > *pos && str[j-1] == '\\')) + *(buffer++) = str[j]; + } + + *buffer = '\0'; + *length = buffer - *token; + } + else { + *token = &str[*pos]; + *length = l; + } + + *pos = i; + + /* skip the comma and set position to the start of next token */ + if (str[i] == ',') *pos += 1; + + return res; +} + +static int +typecast_array_scan(char *str, int strlength, + PyObject *curs, PyObject *base, PyObject *array) +{ + int state, length = 0, pos = 0; + char *token; + + PyObject *stack[MAX_DIMENSIONS]; + int stack_index = 0; + + while (1) { + token = NULL; + state = typecast_array_tokenize(str, strlength, &pos, &token, &length); + Dprintf("typecast_array_scan: state = %d, length = %d, token = '%s'", + state, length, token); + if (state == ASCAN_TOKEN || state == ASCAN_QUOTED) { + PyObject *obj = typecast_cast(base, token, length, curs); + + /* before anything else we free the memory */ + if (state == ASCAN_QUOTED) PyMem_Free(token); + if (obj == NULL) return 0; + + PyList_Append(array, obj); + Py_DECREF(obj); + } + + else if (state == ASCAN_BEGIN) { + PyObject *sub = PyList_New(0); + if (sub == NULL) return 0; + + PyList_Append(array, sub); + Py_DECREF(sub); + + if (stack_index == MAX_DIMENSIONS) + return 0; + + stack[stack_index++] = array; + array = sub; + } + + else if (state == ASCAN_ERROR) { + return 0; + } + + else if (state == ASCAN_END) { + if (--stack_index < 0) + return 0; + array = stack[stack_index]; + } + + else if (state == ASCAN_EOF) + break; + } + + return 1; +} + + +/** GENERIC - a generic typecaster that can be used when no special actions + have to be taken on the single items **/ + +static PyObject * +typecast_GENERIC_ARRAY_cast(char *str, int len, PyObject *curs) +{ + PyObject *obj = NULL; + PyObject *base = ((typecastObject*)((cursorObject*)curs)->caster)->bcast; + + Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s', len = %d", str, len); + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + if (str[0] == '[') + typecast_array_cleanup(&str, &len); + if (str[0] != '{') { + PyErr_SetString(Error, "array does not start with '{'"); + return NULL; + } + + Dprintf("typecast_GENERIC_ARRAY_cast: str = '%s', len = %d", str, len); + + obj = PyList_New(0); + + /* scan the array skipping the first level of {} */ + if (typecast_array_scan(&str[1], len-2, curs, base, obj) == 0) { + Py_DECREF(obj); + obj = NULL; + } + + return obj; +} + +/** almost all the basic array typecasters are derived from GENERIC **/ + +#define typecast_LONGINTEGERARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_INTEGERARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_FLOATARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_DECIMALARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_STRINGARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_UNICODEARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_BOOLEANARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_DATETIMEARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_DATEARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_TIMEARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_INTERVALARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_BINARYARRAY_cast typecast_GENERIC_ARRAY_cast +#define typecast_ROWIDARRAY_cast typecast_GENERIC_ARRAY_cast diff --git a/psycopg2/psycopg/typecast_basic.c b/psycopg2/psycopg/typecast_basic.c new file mode 100644 index 0000000..e9ac7f4 --- /dev/null +++ b/psycopg2/psycopg/typecast_basic.c @@ -0,0 +1,141 @@ +/* pgcasts_basic.c - basic typecasting functions to python types + * + * Copyright (C) 2001-2003 Federico Di Gregorio + * + * This file is part of the psycopg module. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/** INTEGER - cast normal integers (4 bytes) to python int **/ + +static PyObject * +typecast_INTEGER_cast(char *s, int len, PyObject *curs) +{ + char buffer[12]; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + if (s[len] != '\0') { + strncpy(buffer, s, len); buffer[len] = '\0'; + s = buffer; + } + return PyInt_FromString(s, NULL, 0); +} + +/** LONGINTEGER - cast long integers (8 bytes) to python long **/ + +static PyObject * +typecast_LONGINTEGER_cast(char *s, int len, PyObject *curs) +{ + char buffer[24]; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + if (s[len] != '\0') { + strncpy(buffer, s, len); buffer[len] = '\0'; + s = buffer; + } + return PyLong_FromString(s, NULL, 0); +} + +/** FLOAT - cast floating point numbers to python float **/ + +static PyObject * +typecast_FLOAT_cast(char *s, int len, PyObject *curs) +{ + PyObject *str = NULL, *flo = NULL; + char *pend; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + str = PyString_FromStringAndSize(s, len); + flo = PyFloat_FromString(str, &pend); + Py_DECREF(str); + return flo; +} + +/** STRING - cast strings of any type to python string **/ + +static PyObject * +typecast_STRING_cast(char *s, int len, PyObject *curs) +{ + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + return PyString_FromStringAndSize(s, len); +} + +/** UNICODE - cast strings of any type to a python unicode object **/ + +static PyObject * +typecast_UNICODE_cast(char *s, int len, PyObject *curs) +{ + PyObject *enc; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + + enc = PyDict_GetItemString(psycoEncodings, + ((cursorObject*)curs)->conn->encoding); + if (enc) { + return PyUnicode_Decode(s, len, PyString_AsString(enc), NULL); + } + else { + PyErr_Format(InterfaceError, + "can't decode into unicode string from %s", + ((cursorObject*)curs)->conn->encoding); + return NULL; + } +} + +/** BOOLEAN - cast boolean value into right python object **/ + +static PyObject * +typecast_BOOLEAN_cast(char *s, int len, PyObject *curs) +{ + PyObject *res; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + + if (s[0] == 't') + res = Py_True; + else + res = Py_False; + + Py_INCREF(res); + return res; +} + +/** DECIMAL - cast any kind of number into a Python Decimal object **/ + +#ifdef HAVE_DECIMAL +static PyObject * +typecast_DECIMAL_cast(char *s, int len, PyObject *curs) +{ + PyObject *res = NULL; + char *buffer; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + + if ((buffer = PyMem_Malloc(len+1)) == NULL) + PyErr_NoMemory(); + strncpy(buffer, s, len); buffer[len] = '\0'; + res = PyObject_CallFunction(decimalType, "s", buffer); + PyMem_Free(buffer); + + return res; +} +#else +#define typecast_DECIMAL_cast typecast_FLOAT_cast +#endif + +/* some needed aliases */ +#define typecast_NUMBER_cast typecast_FLOAT_cast +#define typecast_ROWID_cast typecast_INTEGER_cast diff --git a/psycopg2/psycopg/typecast_binary.c b/psycopg2/psycopg/typecast_binary.c new file mode 100644 index 0000000..d490bc7 --- /dev/null +++ b/psycopg2/psycopg/typecast_binary.c @@ -0,0 +1,191 @@ +/* typecast_binary.c - binary typecasting functions to python types + * + * Copyright (C) 2001-2003 Federico Di Gregorio + * + * This file is part of the psycopg module. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "typecast_binary.h" + +#include +#include + + +/* Python object holding a memory chunk. The memory is deallocated when + the object is destroyed. This type is used to let users directly access + memory chunks holding unescaped binary data through the buffer interface. + */ + +static void +chunk_dealloc(chunkObject *self) +{ + Dprintf("chunk_dealloc: deallocating memory at %p, size %d", + self->base, self->len); + free(self->base); + self->ob_type->tp_free((PyObject *) self); +} + +static PyObject * +chunk_repr(chunkObject *self) +{ + return PyString_FromFormat("", + self->base, self->len); +} + +static int +chunk_getreadbuffer(chunkObject *self, int segment, void **ptr) +{ + if (segment != 0) + { + PyErr_SetString(PyExc_SystemError, + "acessing non-existant buffer segment"); + return -1; + } + *ptr = self->base; + return self->len; +} + +static int +chunk_getsegcount(chunkObject *self, int *lenp) +{ + if (lenp != NULL) + *lenp = self->len; + return 1; +} + +static PyBufferProcs chunk_as_buffer = +{ + (getreadbufferproc) chunk_getreadbuffer, + (getwritebufferproc) NULL, + (getsegcountproc) chunk_getsegcount, + (getcharbufferproc) NULL +}; + +#define chunk_doc "memory chunk" + +PyTypeObject chunkType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "psycopg2._psycopg.chunk", /* tp_name */ + sizeof(chunkObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor) chunk_dealloc, /* tp_dealloc*/ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) chunk_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &chunk_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + chunk_doc /* tp_doc */ +}; + +/* the function typecast_BINARY_cast_unescape is used when libpq does not + provide PQunescapeBytea: it convert all the \xxx octal sequences to the + proper byte value */ + +#ifdef PSYCOPG_OWN_QUOTING +static unsigned char * +typecast_BINARY_cast_unescape(unsigned char *str, size_t *to_length) +{ + char *dstptr, *dststr; + int len, i; + + len = strlen(str); + dststr = (char*)calloc(len, sizeof(char)); + dstptr = dststr; + + if (dststr == NULL) return NULL; + + Py_BEGIN_ALLOW_THREADS; + + for (i = 0; i < len; i++) { + if (str[i] == '\\') { + if ( ++i < len) { + if (str[i] == '\\') { + *dstptr = '\\'; + } + else { + *dstptr = 0; + *dstptr |= (str[i++] & 7) << 6; + *dstptr |= (str[i++] & 7) << 3; + *dstptr |= (str[i] & 7); + } + } + } + else { + *dstptr = str[i]; + } + dstptr++; + } + + Py_END_ALLOW_THREADS; + + *to_length = (size_t)(dstptr-dststr); + + return dststr; +} + +#define PQunescapeBytea typecast_BINARY_cast_unescape +#endif + +static PyObject * +typecast_BINARY_cast(char *s, int l, PyObject *curs) +{ + chunkObject *chunk; + PyObject *res; + char *str, *buffer = NULL; + size_t len; + + if (s == NULL) {Py_INCREF(Py_None); return Py_None;} + + /* PQunescapeBytea absolutely wants a 0-terminated string and we don't + want to copy the whole buffer, right? Wrong, but there isn't any other + way */ + if (s[l] != '\0') { + if ((buffer = PyMem_Malloc(l+1)) == NULL) + PyErr_NoMemory(); + strncpy(buffer, s, l); + buffer[l] = '\0'; + s = buffer; + } + str = (char*)PQunescapeBytea((unsigned char*)s, &len); + Dprintf("typecast_BINARY_cast: unescaped %d bytes", len); + if (buffer) PyMem_Free(buffer); + + chunk = (chunkObject *) PyObject_New(chunkObject, &chunkType); + if (chunk == NULL) return NULL; + + chunk->base = str; + chunk->len = len; + if ((res = PyBuffer_FromObject((PyObject *)chunk, 0, len)) == NULL) + return NULL; + + /* PyBuffer_FromObject() created a new reference. Release our reference so + that the memory can be freed once the buffer is garbage collected. */ + Py_DECREF(chunk); + + return res; +} diff --git a/psycopg2/psycopg/typecast_binary.h b/psycopg2/psycopg/typecast_binary.h new file mode 100644 index 0000000..cf985bb --- /dev/null +++ b/psycopg2/psycopg/typecast_binary.h @@ -0,0 +1,47 @@ +/* typecast_binary.h - definitions for binary typecaster + * + * Copyright (C) 2003 Federico Di Gregorio + * + * This file is part of psycopg. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef PSYCOPG_TYPECAST_BINARY_H +#define PSYCOPG_TYPECAST_BINARY_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** chunk type **/ + +extern PyTypeObject chunkType; + +typedef struct { + PyObject_HEAD + + void *base; /* Pointer to the memory chunk. */ + int len; /* Size in bytes of the memory chunk. */ + +} chunkObject; + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(PSYCOPG_TYPECAST_BINARY_H) */ diff --git a/psycopg2/psycopg/typecast_builtins.c b/psycopg2/psycopg/typecast_builtins.c new file mode 100644 index 0000000..0fc109d --- /dev/null +++ b/psycopg2/psycopg/typecast_builtins.c @@ -0,0 +1,60 @@ +static long int typecast_NUMBER_types[] = {20, 23, 21, 701, 700, 1700, 0}; +static long int typecast_LONGINTEGER_types[] = {20, 0}; +static long int typecast_INTEGER_types[] = {23, 21, 0}; +static long int typecast_FLOAT_types[] = {701, 700, 0}; +static long int typecast_DECIMAL_types[] = {1700, 0}; +static long int typecast_UNICODE_types[] = {19, 18, 25, 1042, 1043, 0}; +static long int typecast_STRING_types[] = {19, 18, 25, 1042, 1043, 0}; +static long int typecast_BOOLEAN_types[] = {16, 0}; +static long int typecast_DATETIME_types[] = {1114, 1184, 704, 1186, 0}; +static long int typecast_TIME_types[] = {1083, 1266, 0}; +static long int typecast_DATE_types[] = {1082, 0}; +static long int typecast_INTERVAL_types[] = {704, 1186, 0}; +static long int typecast_BINARY_types[] = {17, 0}; +static long int typecast_ROWID_types[] = {26, 0}; +static long int typecast_LONGINTEGERARRAY_types[] = {1016, 0}; +static long int typecast_INTEGERARRAY_types[] = {1005, 1006, 1007, 0}; +static long int typecast_FLOATARRAY_types[] = {1017, 1021, 1022, 0}; +static long int typecast_DECIMALARRAY_types[] = {1231, 0}; +static long int typecast_UNICODEARRAY_types[] = {1002, 1003, 1009, 1014, 1015, 0}; +static long int typecast_STRINGARRAY_types[] = {1002, 1003, 1009, 1014, 1015, 0}; +static long int typecast_BOOLEANARRAY_types[] = {1000, 0}; +static long int typecast_DATETIMEARRAY_types[] = {1115, 1185, 0}; +static long int typecast_TIMEARRAY_types[] = {1183, 1270, 0}; +static long int typecast_DATEARRAY_types[] = {1182, 0}; +static long int typecast_INTERVALARRAY_types[] = {1187, 0}; +static long int typecast_BINARYARRAY_types[] = {1001, 0}; +static long int typecast_ROWIDARRAY_types[] = {1028, 1013, 0}; + + +typecastObject_initlist typecast_builtins[] = { + {"NUMBER", typecast_NUMBER_types, typecast_NUMBER_cast, NULL}, + {"LONGINTEGER", typecast_LONGINTEGER_types, typecast_LONGINTEGER_cast, NULL}, + {"INTEGER", typecast_INTEGER_types, typecast_INTEGER_cast, NULL}, + {"FLOAT", typecast_FLOAT_types, typecast_FLOAT_cast, NULL}, + {"DECIMAL", typecast_DECIMAL_types, typecast_DECIMAL_cast, NULL}, + {"UNICODE", typecast_UNICODE_types, typecast_UNICODE_cast, NULL}, + {"STRING", typecast_STRING_types, typecast_STRING_cast, NULL}, + {"BOOLEAN", typecast_BOOLEAN_types, typecast_BOOLEAN_cast, NULL}, + {"DATETIME", typecast_DATETIME_types, typecast_DATETIME_cast, NULL}, + {"TIME", typecast_TIME_types, typecast_TIME_cast, NULL}, + {"DATE", typecast_DATE_types, typecast_DATE_cast, NULL}, + {"INTERVAL", typecast_INTERVAL_types, typecast_INTERVAL_cast, NULL}, + {"BINARY", typecast_BINARY_types, typecast_BINARY_cast, NULL}, + {"ROWID", typecast_ROWID_types, typecast_ROWID_cast, NULL}, + {"LONGINTEGERARRAY", typecast_LONGINTEGERARRAY_types, typecast_LONGINTEGERARRAY_cast, "LONGINTEGER"}, + {"INTEGERARRAY", typecast_INTEGERARRAY_types, typecast_INTEGERARRAY_cast, "INTEGER"}, + {"FLOATARRAY", typecast_FLOATARRAY_types, typecast_FLOATARRAY_cast, "FLOAT"}, + {"DECIMALARRAY", typecast_DECIMALARRAY_types, typecast_DECIMALARRAY_cast, "DECIMAL"}, + {"UNICODEARRAY", typecast_UNICODEARRAY_types, typecast_UNICODEARRAY_cast, "UNICODE"}, + {"STRINGARRAY", typecast_STRINGARRAY_types, typecast_STRINGARRAY_cast, "STRING"}, + {"BOOLEANARRAY", typecast_BOOLEANARRAY_types, typecast_BOOLEANARRAY_cast, "BOOLEAN"}, + {"DATETIMEARRAY", typecast_DATETIMEARRAY_types, typecast_DATETIMEARRAY_cast, "DATETIME"}, + {"TIMEARRAY", typecast_TIMEARRAY_types, typecast_TIMEARRAY_cast, "TIME"}, + {"DATEARRAY", typecast_DATEARRAY_types, typecast_DATEARRAY_cast, "DATE"}, + {"INTERVALARRAY", typecast_INTERVALARRAY_types, typecast_INTERVALARRAY_cast, "INTERVAL"}, + {"BINARYARRAY", typecast_BINARYARRAY_types, typecast_BINARYARRAY_cast, "BINARY"}, + {"ROWIDARRAY", typecast_ROWIDARRAY_types, typecast_ROWIDARRAY_cast, "ROWID"}, + {NULL, NULL, NULL, NULL} +}; + diff --git a/psycopg2/psycopg/typecast_datetime.c b/psycopg2/psycopg/typecast_datetime.c new file mode 100644 index 0000000..3a09f07 --- /dev/null +++ b/psycopg2/psycopg/typecast_datetime.c @@ -0,0 +1,279 @@ +/* typecast_datetime.c - date and time typecasting functions to python types + * + * Copyright (C) 2001-2003 Federico Di Gregorio + * + * This file is part of the psycopg module. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include "datetime.h" + + +/* the pointer to the datetime module API is initialized by the module init + code, we just need to grab it */ +extern PyObject* pyDateTimeModuleP; +extern PyObject *pyDateTypeP; +extern PyObject *pyTimeTypeP; +extern PyObject *pyDateTimeTypeP; +extern PyObject *pyDeltaTypeP; + +/** DATE - cast a date into a date python object **/ + +static PyObject * +typecast_PYDATE_cast(char *str, int len, PyObject *curs) +{ + PyObject* obj = NULL; + int n, y=0, m=0, d=0; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { + if (str[0] == '-') { + obj = PyObject_GetAttrString(pyDateTypeP, "min"); + } + else { + obj = PyObject_GetAttrString(pyDateTypeP, "max"); + } + } + + else { + n = typecast_parse_date(str, NULL, &len, &y, &m, &d); + Dprintf("typecast_PYDATE_cast: " + "n = %d, len = %d, y = %d, m = %d, d = %d", + n, len, y, m, d); + if (n != 3) { + PyErr_SetString(DataError, "unable to parse date"); + } + else { + obj = PyObject_CallFunction(pyDateTypeP, "iii", y, m, d); + } + } + return obj; +} + +/** DATETIME - cast a timestamp into a datetime python object **/ + +static PyObject * +typecast_PYDATETIME_cast(char *str, int len, PyObject *curs) +{ + PyObject* obj = NULL; + int n, y=0, m=0, d=0; + int hh=0, mm=0, ss=0, us=0, tz=0; + char *tp = NULL; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + /* check for infinity */ + if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { + if (str[0] == '-') { + obj = PyObject_GetAttrString(pyDateTimeTypeP, "min"); + } + else { + obj = PyObject_GetAttrString(pyDateTimeTypeP, "max"); + } + } + + else { + Dprintf("typecast_PYDATETIME_cast: s = %s", str); + n = typecast_parse_date(str, &tp, &len, &y, &m, &d); + Dprintf("typecast_PYDATE_cast: tp = %p " + "n = %d, len = %d, y = %d, m = %d, d = %d", + tp, n, len, y, m, d); + if (n != 3) { + PyErr_SetString(DataError, "unable to parse date"); + } + + if (len > 0) { + n = typecast_parse_time(tp, NULL, &len, &hh, &mm, &ss, &us, &tz); + Dprintf("typecast_PYDATETIME_cast: n = %d, len = %d, " + "hh = %d, mm = %d, ss = %d, us = %d, tz = %d", + n, len, hh, mm, ss, us, tz); + if (n < 3 || n > 5) { + PyErr_SetString(DataError, "unable to parse time"); + } + } + + if (ss > 59) { + mm += 1; + ss -= 60; + } + + if (n == 5 && ((cursorObject*)curs)->tzinfo_factory != Py_None) { + /* we have a time zone, calculate minutes and create + appropriate tzinfo object calling the factory */ + PyObject *tzinfo; + Dprintf("typecast_PYDATETIME_cast: UTC offset = %dm", tz); + tzinfo = PyObject_CallFunction( + ((cursorObject*)curs)->tzinfo_factory, "i", tz); + obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiiiO", + y, m, d, hh, mm, ss, us, tzinfo); + Dprintf("typecast_PYDATETIME_cast: tzinfo: %p, refcnt = %d", + tzinfo, tzinfo->ob_refcnt); + Py_XDECREF(tzinfo); + } + else { + obj = PyObject_CallFunction(pyDateTimeTypeP, "iiiiiii", + y, m, d, hh, mm, ss, us); + } + } + return obj; +} + +/** TIME - parse time into a time object **/ + +static PyObject * +typecast_PYTIME_cast(char *str, int len, PyObject *curs) +{ + PyObject* obj = NULL; + int n, hh=0, mm=0, ss=0, us=0, tz=0; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + n = typecast_parse_time(str, NULL, &len, &hh, &mm, &ss, &us, &tz); + Dprintf("typecast_PYTIME_cast: n = %d, len = %d, " + "hh = %d, mm = %d, ss = %d, us = %d, tz = %d", + n, len, hh, mm, ss, us, tz); + + if (n < 3 || n > 5) { + PyErr_SetString(DataError, "unable to parse time"); + } + else { + if (ss > 59) { + mm += 1; + ss -= 60; + } + obj = PyObject_CallFunction(pyTimeTypeP, "iiii", hh, mm, ss, us); + } + return obj; +} + +/** INTERVAL - parse an interval into a timedelta object **/ + +static PyObject * +typecast_PYINTERVAL_cast(char *str, int len, PyObject *curs) +{ + long years = 0, months = 0, days = 0; + double hours = 0.0, minutes = 0.0, seconds = 0.0, hundredths = 0.0; + double v = 0.0, sign = 1.0, denominator = 1.0; + int part = 0, sec; + double micro; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + Dprintf("typecast_PYINTERVAL_cast: s = %s", str); + + while (len-- > 0 && *str) { + switch (*str) { + + case '-': + sign = -1.0; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + v = v*10 + (double)*str - (double)'0'; + if (part == 6){ + denominator *= 10; + } + break; + + case 'y': + if (part == 0) { + years = (long)(v*sign); + str = skip_until_space2(str, &len); + v = 0.0; sign = 1.0; part = 1; + } + break; + + case 'm': + if (part <= 1) { + months = (long)(v*sign); + str = skip_until_space2(str, &len); + v = 0.0; sign = 1.0; part = 2; + } + break; + + case 'd': + if (part <= 2) { + days = (long)(v*sign); + str = skip_until_space2(str, &len); + v = 0.0; sign = 1.0; part = 3; + } + break; + + case ':': + if (part <= 3) { + hours = v; + v = 0.0; part = 4; + } + else if (part == 4) { + minutes = v; + v = 0.0; part = 5; + } + break; + + case '.': + if (part == 5) { + seconds = v; + v = 0.0; part = 6; + } + break; + + default: + break; + } + + str++; + } + + /* manage last value, be it minutes or seconds or hundredths of a second */ + if (part == 4) { + minutes = v; + } + else if (part == 5) { + seconds = v; + } + else if (part == 6) { + hundredths = v; + hundredths = hundredths/denominator; + } + + /* calculates seconds */ + if (sign < 0.0) { + seconds = - (hundredths + seconds + minutes*60 + hours*3600); + } + else { + seconds += hundredths + minutes*60 + hours*3600; + } + + /* calculates days */ + days += years*365 + months*30; + + micro = (seconds - floor(seconds)) * 1000000.0; + sec = (int)floor(seconds); + return PyObject_CallFunction(pyDeltaTypeP, "iii", + days, sec, (int)round(micro)); +} + +/* psycopg defaults to using python datetime types */ + +#ifdef PSYCOPG_DEFAULT_PYDATETIME +#define typecast_DATE_cast typecast_PYDATE_cast +#define typecast_TIME_cast typecast_PYTIME_cast +#define typecast_INTERVAL_cast typecast_PYINTERVAL_cast +#define typecast_DATETIME_cast typecast_PYDATETIME_cast +#endif diff --git a/psycopg2/psycopg/typecast_mxdatetime.c b/psycopg2/psycopg/typecast_mxdatetime.c new file mode 100644 index 0000000..52b1ce7 --- /dev/null +++ b/psycopg2/psycopg/typecast_mxdatetime.c @@ -0,0 +1,231 @@ +/* typecast_mxdatetime.c - date and time typecasting functions to mx types + * + * Copyright (C) 2001-2003 Federico Di Gregorio + * + * This file is part of the psycopg module. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "mxDateTime.h" + +/* the pointer to the mxDateTime API is initialized by the module init code, + we just need to grab it */ +extern mxDateTimeModule_APIObject *mxDateTimeP; + +/** DATE - cast a date into mx.DateTime python object **/ + +static PyObject * +typecast_MXDATE_cast(char *str, int len, PyObject *curs) +{ + int n, y=0, m=0, d=0; + int hh=0, mm=0, ss=0, us=0, tz=0; + char *tp = NULL; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + Dprintf("typecast_MXDATE_cast: s = %s", str); + + /* check for infinity */ + if (!strcmp(str, "infinity") || !strcmp(str, "-infinity")) { + if (str[0] == '-') { + return mxDateTimeP->DateTime_FromDateAndTime(-999998,1,1, 0,0,0); + } + else { + return mxDateTimeP->DateTime_FromDateAndTime(999999,12,31, 0,0,0); + } + } + + n = typecast_parse_date(str, &tp, &len, &y, &m, &d); + Dprintf("typecast_MXDATE_cast: tp = %p n = %d, len = %d, " + "y = %d, m = %d, d = %d", tp, n, len, y, m, d); + if (n != 3) { + PyErr_SetString(DataError, "unable to parse date"); + } + + if (len > 0) { + n = typecast_parse_time(tp, NULL, &len, &hh, &mm, &ss, &us, &tz); + Dprintf("typecast_MXDATE_cast: n = %d, len = %d, " + "hh = %d, mm = %d, ss = %d, us = %d, tz = %d", + n, len, hh, mm, ss, us, tz); + if (n < 3 || n > 5) { + PyErr_SetString(DataError, "unable to parse time"); + } + } + + Dprintf("typecast_MXDATE_cast: fractionary seconds: %lf", + (double)ss + (double)us/(double)1000000.0); + return mxDateTimeP->DateTime_FromDateAndTime(y, m, d, hh, mm, + (double)ss + (double)us/(double)1000000.0); +} + +/** TIME - parse time into an mx.DateTime object **/ + +static PyObject * +typecast_MXTIME_cast(char *str, int len, PyObject *curs) +{ + int n, hh=0, mm=0, ss=0, us=0, tz=0; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + Dprintf("typecast_MXTIME_cast: s = %s", str); + + n = typecast_parse_time(str, NULL, &len, &hh, &mm, &ss, &us, &tz); + Dprintf("typecast_MXTIME_cast: time parsed, %d components", n); + Dprintf("typecast_MXTIME_cast: hh = %d, mm = %d, ss = %d, us = %d", + hh, mm, ss, us); + + if (n < 3 || n > 5) { + PyErr_SetString(DataError, "unable to parse time"); + return NULL; + } + + Dprintf("typecast_MXTIME_cast: fractionary seconds: %lf", + (double)ss + (double)us/(double)1000000.0); + return mxDateTimeP->DateTimeDelta_FromTime(hh, mm, + (double)ss + (double)us/(double)1000000.0); +} + +/** INTERVAL - parse an interval into an mx.DateTimeDelta **/ + +static PyObject * +typecast_MXINTERVAL_cast(char *str, int len, PyObject *curs) +{ + long years = 0, months = 0, days = 0, denominator = 1; + double hours = 0.0, minutes = 0.0, seconds = 0.0, hundredths = 0.0; + double v = 0.0, sign = 1.0; + int part = 0; + + if (str == NULL) {Py_INCREF(Py_None); return Py_None;} + + Dprintf("typecast_MXINTERVAL_cast: s = %s", str); + + while (*str) { + switch (*str) { + + case '-': + sign = -1.0; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + v = v*10 + (double)*str - (double)'0'; + Dprintf("typecast_MXINTERVAL_cast: v = %f", v); + if (part == 6){ + denominator *= 10; + Dprintf("typecast_MXINTERVAL_cast: denominator = %ld", + denominator); + } + break; + + case 'y': + if (part == 0) { + years = (long)(v*sign); + str = skip_until_space(str); + Dprintf("typecast_MXINTERVAL_cast: years = %ld, rest = %s", + years, str); + v = 0.0; sign = 1.0; part = 1; + } + break; + + case 'm': + if (part <= 1) { + months = (long)(v*sign); + str = skip_until_space(str); + Dprintf("typecast_MXINTERVAL_cast: months = %ld, rest = %s", + months, str); + v = 0.0; sign = 1.0; part = 2; + } + break; + + case 'd': + if (part <= 2) { + days = (long)(v*sign); + str = skip_until_space(str); + Dprintf("typecast_MXINTERVAL_cast: days = %ld, rest = %s", + days, str); + v = 0.0; sign = 1.0; part = 3; + } + break; + + case ':': + if (part <= 3) { + hours = v; + Dprintf("typecast_MXINTERVAL_cast: hours = %f", hours); + v = 0.0; part = 4; + } + else if (part == 4) { + minutes = v; + Dprintf("typecast_MXINTERVAL_cast: minutes = %f", minutes); + v = 0.0; part = 5; + } + break; + + case '.': + if (part == 5) { + seconds = v; + Dprintf("typecast_MXINTERVAL_cast: seconds = %f", seconds); + v = 0.0; part = 6; + } + break; + + default: + break; + } + + str++; + } + + /* manage last value, be it minutes or seconds or hundredths of a second */ + if (part == 4) { + minutes = v; + Dprintf("typecast_MXINTERVAL_cast: minutes = %f", minutes); + } + else if (part == 5) { + seconds = v; + Dprintf("typecast_MXINTERVAL_cast: seconds = %f", seconds); + } + else if (part == 6) { + hundredths = v; + Dprintf("typecast_MXINTERVAL_cast: hundredths = %f", hundredths); + hundredths = hundredths/denominator; + Dprintf("typecast_MXINTERVAL_cast: fractions = %.20f", hundredths); + } + + /* calculates seconds */ + if (sign < 0.0) { + seconds = - (hundredths + seconds + minutes*60 + hours*3600); + } + else { + seconds += hundredths + minutes*60 + hours*3600; + } + + /* calculates days */ + days += years*365 + months*30; + + Dprintf("typecast_MXINTERVAL_cast: days = %ld, seconds = %f", + days, seconds); + return mxDateTimeP->DateTimeDelta_FromDaysAndSeconds(days, seconds); +} + +/* psycopg defaults to using mx types */ + +#ifdef PSYCOPG_DEFAULT_MXDATETIME +#define typecast_DATE_cast typecast_MXDATE_cast +#define typecast_TIME_cast typecast_MXTIME_cast +#define typecast_INTERVAL_cast typecast_MXINTERVAL_cast +#define typecast_DATETIME_cast typecast_MXDATE_cast +#endif + diff --git a/psycopg2/scripts/buildtypes.py b/psycopg2/scripts/buildtypes.py new file mode 100644 index 0000000..197272f --- /dev/null +++ b/psycopg2/scripts/buildtypes.py @@ -0,0 +1,124 @@ +# -*- python -*- +# +# Copyright (C) 2001-2003 Federico Di Gregorio +# +# This file is part of the psycopg module. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2, +# or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# this a little script that analyze a file with (TYPE, NUMBER) tuples +# and write out C code ready for inclusion in psycopg. the generated +# code defines the DBAPITypeObject fundamental types and warns for +# undefined types. + +import sys, os, string, copy +from string import split, join, strip + + +# here is the list of the foundamental types we want to import from +# postgresql header files + +basic_types = (['NUMBER', ['INT8', 'INT4', 'INT2', 'FLOAT8', 'FLOAT4', + 'NUMERIC']], + ['LONGINTEGER', ['INT8']], + ['INTEGER', ['INT4', 'INT2']], + ['FLOAT', ['FLOAT8', 'FLOAT4']], + ['DECIMAL', ['NUMERIC']], + ['UNICODE', ['NAME', 'CHAR', 'TEXT', 'BPCHAR', + 'VARCHAR']], + ['STRING', ['NAME', 'CHAR', 'TEXT', 'BPCHAR', + 'VARCHAR']], + ['BOOLEAN', ['BOOL']], + ['DATETIME', ['TIMESTAMP', 'TIMESTAMPTZ', + 'TINTERVAL', 'INTERVAL']], + ['TIME', ['TIME', 'TIMETZ']], + ['DATE', ['DATE']], + ['INTERVAL', ['TINTERVAL', 'INTERVAL']], + ['BINARY', ['BYTEA']], + ['ROWID', ['OID']]) + +# unfortunately we don't have a nice way to extract array information +# from postgresql headers; we'll have to do it hard-coding :/ +array_types = (['LONGINTEGER', [1016]], + ['INTEGER', [1005, 1006, 1007]], + ['FLOAT', [1017, 1021, 1022]], + ['DECIMAL', [1231]], + ['UNICODE', [1002, 1003, 1009, 1014, 1015]], + ['STRING', [1002, 1003, 1009, 1014, 1015]], + ['BOOLEAN', [1000]], + ['DATETIME', [1115, 1185]], + ['TIME', [1183, 1270]], + ['DATE', [1182]], + ['INTERVAL', [1187]], + ['BINARY', [1001]], + ['ROWID', [1028, 1013]]) + +# this is the header used to compile the data in the C module +HEADER = """ +typecastObject_initlist typecast_builtins[] = { +""" + +# then comes the footer +FOOTER = """ {NULL, NULL, NULL, NULL}\n};\n""" + + +# usefull error reporting function +def error(msg): + """Report an error on stderr.""" + sys.stderr.write(msg+'\n') + + +# read couples from stdin and build list +read_types = [] +for l in sys.stdin.readlines(): + oid, val = split(l) + read_types.append((strip(oid)[:-3], strip(val))) + +# look for the wanted types in the read touples +found_types = {} + +for t in basic_types: + k = t[0] + found_types[k] = [] + for v in t[1]: + found = filter(lambda x, y=v: x[0] == y, read_types) + if len(found) == 0: + error(v+': value not found') + elif len(found) > 1: + error(v+': too many values') + else: + found_types[k].append(int(found[0][1])) + +# now outputs to stdout the right C-style definitions +stypes = "" ; sstruct = "" +for t in basic_types: + k = t[0] + s = str(found_types[k]) + s = '{' + s[1:-1] + ', 0}' + stypes = stypes + ('static long int typecast_%s_types[] = %s;\n' % (k, s)) + sstruct += (' {"%s", typecast_%s_types, typecast_%s_cast, NULL},\n' + % (k, k, k)) +for t in array_types: + kt = t[0] + ka = t[0]+'ARRAY' + s = str(t[1]) + s = '{' + s[1:-1] + ', 0}' + stypes = stypes + ('static long int typecast_%s_types[] = %s;\n' % (ka, s)) + sstruct += (' {"%s", typecast_%s_types, typecast_%s_cast, "%s"},\n' + % (ka, ka, ka, kt)) +sstruct = HEADER + sstruct + FOOTER + +print stypes +print sstruct diff --git a/psycopg2/scripts/ext2html.py b/psycopg2/scripts/ext2html.py new file mode 100755 index 0000000..f7c95d8 --- /dev/null +++ b/psycopg2/scripts/ext2html.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python + +# Author: Daniele Varrazzo +# Contact: daniele dot varrazzo at gmail dot com +# Revision: $Revision: 711 $ +# Date: $Date$ +# Copyright: This module has been placed in the public domain. + +""" +A minimal front end to the Docutils Publisher, producing HTML. + +Output can refer to Epydoc-generated APIs through the iterpreted text role +"api". +""" + +import types +import sys + +# The url fragment where the api "index.html" resides w.r.t. the generated docs +api_root = "api/" + +try: + import locale + locale.setlocale(locale.LC_ALL, '') +except: + pass + +from docutils.core import publish_cmdline, default_description +from docutils.parsers.rst.roles import register_canonical_role +from docutils import nodes, utils + +# api references are searched for in these modules +api_modules = [ + 'psycopg2', + 'psycopg2._psycopg', + 'psycopg2.extensions', +] + +# name starting with a dot are looking as those objects attributes. +searched_objects = [ + # module_name, object_name + ('psycopg2.extensions', 'connection'), + ('psycopg2.extensions', 'cursor'), +] + +# import all the referenced modules +for modname in api_modules: + __import__(modname) + +class EpydocTarget: + """Representation of an element language.""" + def __init__(self, name, element): + self.name = name + + # The python object described + self.element = element + + # The base name of the page + self.page = None + + # The url fragment + self.fragment = None + + def get_url(self): + # is it a private element? + components = self.page.split('.') + if self.fragment: components.append(self.fragment) + + for component in components: + if component.startswith('_'): + private = True + break + else: + private = False + + ref = api_root + (private and "private/" or "public/") \ + + self.page + "-" + self.get_type() + ".html" + if self.fragment: + ref = ref + "#" + self.fragment + + return ref + + def get_type(self): + # detect the element type + if isinstance(self.element, types.TypeType): + return 'class' + elif isinstance(self.element, types.ModuleType): + return 'module' + else: + raise ValueError("Can't choose a type for '%s'." % self.name) + +def filter_par(name): + """Filter parenthesis away from a name.""" + if name.endswith(")"): + return name.split("(")[0] + else: + return name + +def get_element_target(name): + """Return the life, the death, the miracles about a package element.""" + + name = filter_par(name) + + if name.startswith('.'): + for modname, objname in searched_objects: + if hasattr(getattr(sys.modules[modname], objname), name[1:]): + name = objname + name + break + + # is the element a module? + if name in api_modules: + out = EpydocTarget(name, sys.modules[name]) + out.page = name + return out + + # look for the element in some module + for modname in api_modules: + element = getattr(sys.modules[modname], name, None) + if element is not None: + + # Check if it is a function defined in a module + if isinstance(element, + (int, types.FunctionType, types.BuiltinFunctionType)): + out = EpydocTarget(name, sys.modules[modname]) + out.page = modname + out.fragment = name + else: + out = EpydocTarget(name, element) + out.page = modname + '.' + name + + return out + + # maybe a qualified name? + if '.' in name: + out = get_element_target('.'.join(name.split('.')[:-1])) + if out is not None: + out.fragment = filter_par(name.split('.')[-1]) + return out + + raise ValueError("Can't find '%s' in any provided module." % name) + +def api_role(role, rawtext, text, lineno, inliner, + options={}, content=[]): + try: + target = get_element_target(text) + except Exception, exc: + msg = inliner.reporter.error(str(exc), line=lineno) + prb = inliner.problematic(rawtext, rawtext, msg) + return [prb], [msg] + + ref = target.get_url() + node2 = nodes.literal(rawtext, utils.unescape(text)) + node = nodes.reference(rawtext, '', node2, refuri=ref, + **options) + return [node], [] + + +register_canonical_role('api', api_role) + +# Register the 'api' role as canonical role +from docutils.parsers.rst import roles +roles.DEFAULT_INTERPRETED_ROLE = 'api' + + +description = ('Generates (X)HTML documents from standalone reStructuredText ' + 'sources with links to Epydoc API. ' + default_description) + + +publish_cmdline(writer_name='html', description=description) diff --git a/psycopg2/scripts/makedocs.py b/psycopg2/scripts/makedocs.py new file mode 100755 index 0000000..dcaa940 --- /dev/null +++ b/psycopg2/scripts/makedocs.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +"""Build documentation and api.""" + +import os + +EPYDOC = "python c:/programmi/python23/scripts/epydoc.py" +PSYCOPG = "c:/programmi/python23/lib/site-packages/psycopg2" + +os.system("python ext2html.py ../doc/extensions.rst > ../doc/extensions.html") +os.system("%s " + "-o ../doc/api " + "--css ../doc/api-screen.css " + "--docformat restructuredtext " + "%s" + % (EPYDOC,PSYCOPG,)) diff --git a/psycopg2/scripts/maketypes.sh b/psycopg2/scripts/maketypes.sh new file mode 100755 index 0000000..ab133c1 --- /dev/null +++ b/psycopg2/scripts/maketypes.sh @@ -0,0 +1,41 @@ +#!/bin/sh + +SCRIPTSDIR="`dirname $0`" +SRCDIR="`dirname $SCRIPTSDIR`/psycopg" + +if [ -z "$1" ] ; then + echo Usage: $0 '' + exit 1 +fi + +echo -n checking for pg_type.h ... +if [ -f "$1/catalog/pg_type.h" ] ; then + PGTYPE="$1/catalog/pg_type.h" +else + if [ -f "$1/server/catalog/pg_type.h" ] ; then + PGTYPE="$1/server/catalog/pg_type.h" + else + echo + echo "error: can't find pg_type.h under $1" + exit 2 + fi +fi +echo " found" + +PGVERSION="`sed -n -e 's/.*PG_VERSION \"\([0-9]\.[0-9]\).*\"/\1/p' $1/pg_config.h`" +PGMAJOR="`echo $PGVERSION | cut -d. -f1`" +PGMINOR="`echo $PGVERSION | cut -d. -f2`" + +echo checking for postgresql major: $PGMAJOR +echo checking for postgresql minor: $PGMINOR + +echo -n generating pgtypes.h ... +awk '/#define .+OID/ {print "#define " $2 " " $3}' "$PGTYPE" \ + > $SRCDIR/pgtypes.h +echo " done" +echo -n generating typecast_builtins.c ... +awk '/#define .+OID/ {print $2 " " $3}' "$PGTYPE" | \ + python $SCRIPTSDIR/buildtypes.py >$SRCDIR/typecast_builtins.c +echo " done" + + diff --git a/psycopg2/setup.cfg b/psycopg2/setup.cfg new file mode 100644 index 0000000..9c32951 --- /dev/null +++ b/psycopg2/setup.cfg @@ -0,0 +1,46 @@ +[build_ext] +define=PSYCOPG_EXTENSIONS,PSYCOPG_DISPLAY_SIZE,PSYCOPG_NEW_BOOLEAN,HAVE_PQFREEMEM,HAVE_PQPROTOCOL3 +# PSYCOPG_EXTENSIONS enables extensions to PEP-249 (you really want this) +# PSYCOPG_DISPLAY_SIZE enable display size calculation (a little slower) +# HAVE_PQFREEMEM should be defined on PostgreSQL >= 7.3 +# HAVE_PQPROTOCOL3 should be defined on PostgreSQL >= 7.4 +# PSYCOPG_DEBUG can be added to enable verbose debug information +# PSYCOPG_OWN_QUOTING can be added, but it is deprecated (will go away in 2.1) +# PSYCOPG_NEW_BOOLEAN to format booleans as true/false vs 't'/'f' + +# Set to 1 to use Python datatime objects for default date/time representation +use_pydatetime=1 + +# Set to 1 if you want to enable "Decimal" type on python 2.3. +# If the "decimal" module is found in the PYTHONPATH it will be used, else +# fall back on the float type (this is disabled by default to be compatible +# with old versions of psycopg 1 and pre-beta versions of psycopg 2.) +use_decimal=0 + +# If the build system does not find the mx.DateTime headers, try +# uncommenting the following line and setting its value to the right path. +#mx_include_dir= + +# "pg_config" is the preferred method to locate PostgreSQL headers and +# libraries needed to build psycopg2. If pg_config is not in the path or +# is installed under a different name uncomment the following option and +# set it to the pg_config full path. +#pg_config= + +# If "pg_config" is not available, "include_dirs" can be used to locate +# postgresql headers and libraries. Some extra checks on sys.platform will +# still be done in setup.py. +# The next line is the default as used on psycopg author Debian laptop: +#include_dirs=/usr/include/postgresql:/usr/include/postgresql/server + +# Uncomment next line on Mandrake 10.x (and comment previous ones): +#include_dirs=/usr/include/pgsql/8.0:/usr/include/pgsql/8.0/server + +# Uncomment next line on SUSE 9.3 (and comment previous ones): +#include_dirs=/usr/include/pgsql:/usr/include/pgsql/server + +# If postgresql is installed somewhere weird (i.e., not in your runtime library +# path like /usr/lib), just add the right path in "library_dirs" and any extra +# libraries required to link in "libraries". +#library_dirs= +#libraries= diff --git a/psycopg2/setup.py b/psycopg2/setup.py new file mode 100644 index 0000000..45daed7 --- /dev/null +++ b/psycopg2/setup.py @@ -0,0 +1,293 @@ +# setup.py - distutils packaging +# +# Copyright (C) 2003-2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +"""Python-PostgreSQL Database Adapter + +psycopg is a PostgreSQL database adapter for the Python programming +language. This is version 2, a complete rewrite of the original code to +provide new-style classes for connection and cursor objects and other sweet +candies. Like the original, psycopg 2 was written with the aim of being +very small and fast, and stable as a rock. + +psycopg is different from the other database adapter because it was +designed for heavily multi-threaded applications that create and destroy +lots of cursors and make a conspicuous number of concurrent INSERTs or +UPDATEs. psycopg 2 also provide full asycronous operations for the really +brave programmer. +""" + +classifiers = """\ +Development Status :: 4 - Beta +Intended Audience :: Developers +License :: OSI Approved :: GNU General Public License (GPL) +License :: OSI Approved :: Zope Public License +Programming Language :: Python +Programming Language :: C +Programming Language :: SQL +Topic :: Database +Topic :: Database :: Front-Ends +Topic :: Software Development +Topic :: Software Development :: Libraries :: Python Modules +Operating System :: Microsoft :: Windows +Operating System :: Unix +""" + +import os +import sys +import popen2 +from distutils.core import setup, Extension +from distutils.errors import DistutilsFileError +from distutils.command.build_ext import build_ext +from distutils.sysconfig import get_python_inc +from distutils.ccompiler import get_default_compiler + +PSYCOPG_VERSION = '2.0.5.1' +version_flags = [] + +# to work around older distutil limitations +if sys.version < '2.2.3': + from distutils.dist import DistributionMetadata + DistributionMetadata.classifiers = None + DistributionMetadata.download_url = None + +def get_pg_config(kind, pg_config="pg_config"): + p = popen2.popen3(pg_config + " --" + kind) + r = p[0].readline().strip() + if not r: + raise Warning(p[2].readline()) + return r + +class psycopg_build_ext(build_ext): + """Conditionally complement the setup.cfg options file. + + This class configures the include_dirs, libray_dirs, libraries + options as required by the system. Most of the configuration happens + in finalize_options() method. + + If you want to set up the build step for a peculiar platform, add a + method finalize_PLAT(), where PLAT matches your sys.platform. + """ + user_options = build_ext.user_options[:] + user_options.extend([ + ('use-pydatetime', None, + "Use Python datatime objects for date and time representation."), + ('pg-config=', None, + "The name of the pg_config binary and/or full path to find it"), + ('use-decimal', None, + "Use Decimal type even on Python 2.3 if the module is provided."), + ]) + + boolean_options = build_ext.boolean_options[:] + boolean_options.extend(('use-pydatetime', 'use-decimal')) + + DEFAULT_PG_CONFIG = "pg_config" + + def initialize_options(self): + build_ext.initialize_options(self) + self.use_pg_dll = 1 + self.pgdir = None + self.pg_config = self.DEFAULT_PG_CONFIG + self.mx_include_dir = None + + def get_compiler(self): + """Return the c compiler to compile extensions. + + If a compiler was not explicitely set (on the command line, for + example), fall back on the default compiler. + """ + return self.compiler or get_default_compiler() + + def get_pg_config(self, kind): + return get_pg_config(kind, self.pg_config) + + def build_extensions(self): + # Linking against this library causes psycopg2 to crash + # on Python >= 2.4. Maybe related to strdup calls, cfr. + # http://mail.python.org/pipermail/distutils-sig/2005-April/004433.html + if self.get_compiler().compiler_type == "mingw32" \ + and 'msvcr71' in self.compiler.dll_libraries: + self.compiler.dll_libraries.remove('msvcr71') + + build_ext.build_extensions(self) + + def finalize_win32(self): + """Finalize build system configuration on win32 platform.""" + self.libraries.append("ws2_32") + self.libraries.append("advapi32") + if self.get_compiler() == "msvc": + # MSVC requires an explicit "libpq" + self.libraries.remove("pq") + self.libraries.append("libpq") + self.libraries.append("shfolder") + for path in self.library_dirs: + if os.path.isfile(os.path.join(path, "ms", "libpq.lib")): + self.library_dirs.append(os.path.join(path, "ms")) + break + + def finalize_darwin(self): + """Finalize build system configuration on darwin platform.""" + self.libraries.append('ssl') + self.libraries.append('crypto') + + def finalize_options(self): + """Complete the build system configuation.""" + build_ext.finalize_options(self) + + self.include_dirs.append(".") + self.libraries.append("pq") + + try: + self.library_dirs.append(self.get_pg_config("libdir")) + self.include_dirs.append(self.get_pg_config("includedir")) + self.include_dirs.append(self.get_pg_config("includedir-server")) + try: + # Here we take a conservative approach: we suppose that + # *at least* PostgreSQL 7.4 is available (this is the only + # 7.x series supported by psycopg 2) + pgversion = self.get_pg_config("version").split()[1] + pgmajor, pgminor, pgpatch = pgversion.split('.') + except: + pgmajor, pgminor, pgpatch = 7, 4, 0 + define_macros.append(("PG_MAJOR_VERSION", pgmajor)) + define_macros.append(("PG_MINOR_VERSION", pgminor)) + define_macros.append(("PG_PATCH_VERSION", pgpatch)) + except Warning, w: + if self.pg_config == self.DEFAULT_PG_CONFIG: + sys.stderr.write("Warning: %s" % str(w)) + else: + sys.stderr.write("Error: %s" % str(w)) + sys.exit(1) + + if hasattr(self, "finalize_" + sys.platform): + getattr(self, "finalize_" + sys.platform)() + +# let's start with macro definitions (the ones not already in setup.cfg) +define_macros = [] +include_dirs = [] + +# python version +define_macros.append(('PY_MAJOR_VERSION', str(sys.version_info[0]))) +define_macros.append(('PY_MINOR_VERSION', str(sys.version_info[1]))) + +# some macros related to python versions and features +if sys.version_info[0] >= 2 and sys.version_info[1] >= 3: + define_macros.append(('HAVE_PYBOOL','1')) + +# gather information to build the extension module +ext = [] ; data_files = [] + +# sources + +sources = [ + 'psycopgmodule.c', 'pqpath.c', 'typecast.c', + 'microprotocols.c', 'microprotocols_proto.c', + 'connection_type.c', 'connection_int.c', 'cursor_type.c', 'cursor_int.c', + 'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c', + 'adapter_asis.c', 'adapter_list.c'] + +from ConfigParser import ConfigParser +parser = ConfigParser() +parser.read('setup.cfg') + +# Choose if to use Decimal type +use_decimal = int(parser.get('build_ext', 'use_decimal')) +if sys.version_info[0] >= 2 and ( + sys.version_info[1] >= 4 or (sys.version_info[1] == 3 and use_decimal)): + define_macros.append(('HAVE_DECIMAL','1')) + version_flags.append('dec') + +# Choose a datetime module +have_pydatetime = False +have_mxdatetime = False +use_pydatetime = int(parser.get('build_ext', 'use_pydatetime')) + +# check for mx package +if parser.has_option('build_ext', 'mx_include_dir'): + mxincludedir = parser.get('build_ext', 'mx_include_dir') +else: + mxincludedir = os.path.join(get_python_inc(plat_specific=1), "mx") +if os.path.exists(mxincludedir): + include_dirs.append(mxincludedir) + define_macros.append(('HAVE_MXDATETIME','1')) + sources.append('adapter_mxdatetime.c') + have_mxdatetime = True + version_flags.append('mx') + +# check for python datetime package +if os.path.exists(os.path.join(get_python_inc(plat_specific=1),"datetime.h")): + define_macros.append(('HAVE_PYDATETIME','1')) + sources.append('adapter_datetime.c') + have_pydatetime = True + version_flags.append('dt') + +# now decide which package will be the default for date/time typecasts +if have_pydatetime and use_pydatetime \ + or have_pydatetime and not have_mxdatetime: + define_macros.append(('PSYCOPG_DEFAULT_PYDATETIME','1')) +elif have_mxdatetime: + define_macros.append(('PSYCOPG_DEFAULT_MXDATETIME','1')) +else: + def e(msg): + sys.stderr.write("error: " + msg + "\n") + e("psycopg requires a datetime module:") + e(" mx.DateTime module not found") + e(" python datetime module not found") + e("Note that psycopg needs the module headers and not just the module") + e("itself. If you installed Python or mx.DateTime from a binary package") + e("you probably need to install its companion -dev or -devel package.") + sys.exit(1) + +# generate a nice version string to avoid confusion when users report bugs +for have in parser.get('build_ext', 'define').split(','): + if have == 'PSYCOPG_EXTENSIONS': + version_flags.append('ext') + elif have == 'HAVE_PQPROTOCOL3': + version_flags.append('pq3') +if version_flags: + PSYCOPG_VERSION_EX = PSYCOPG_VERSION + " (%s)" % ' '.join(version_flags) +else: + PSYCOPG_VERSION_EX = PSYCOPG_VERSION + +if sys.platform != 'win32': + define_macros.append(('PSYCOPG_VERSION', '"'+PSYCOPG_VERSION_EX+'"')) +else: + define_macros.append(('PSYCOPG_VERSION', '\\"'+PSYCOPG_VERSION_EX+'\\"')) + +# build the extension + +sources = map(lambda x: os.path.join('psycopg', x), sources) + +ext.append(Extension("psycopg2._psycopg", sources, + define_macros=define_macros, + include_dirs=include_dirs, + undef_macros=[])) + +setup(name="psycopg2", + version=PSYCOPG_VERSION, + maintainer="Federico Di Gregorio", + maintainer_email="fog@initd.org", + author="Federico Di Gregorio", + author_email="fog@initd.org", + url="http://initd.org/tracker/psycopg", + download_url = "http://initd.org/pub/software/psycopg2", + license="GPL with exceptions or ZPL", + platforms = ["any"], + description=__doc__.split("\n")[0], + long_description="\n".join(__doc__.split("\n")[2:]), + classifiers=filter(None, classifiers.split("\n")), + data_files=data_files, + package_dir={'psycopg2':'lib'}, + packages=['psycopg2'], + cmdclass={ 'build_ext': psycopg_build_ext }, + ext_modules=ext) diff --git a/psycopg2/tests/dbapi20.py b/psycopg2/tests/dbapi20.py new file mode 100644 index 0000000..4fc8c0c --- /dev/null +++ b/psycopg2/tests/dbapi20.py @@ -0,0 +1,850 @@ +#!/usr/bin/env python +''' Python DB API 2.0 driver compliance unit test suite. + + This software is Public Domain and may be used without restrictions. + + "Now we have booze and barflies entering the discussion, plus rumours of + DBAs on drugs... and I won't tell you what flashes through my mind each + time I read the subject line with 'Anal Compliance' in it. All around + this is turning out to be a thoroughly unwholesome unit test." + + -- Ian Bicking +''' + +__rcs_id__ = '$Id: dbapi20.py,v 1.10 2003/10/09 03:14:14 zenzen Exp $' +__version__ = '$Revision: 1.10 $'[11:-2] +__author__ = 'Stuart Bishop ' + +import unittest +import time + +# $Log: dbapi20.py,v $ +# Revision 1.10 2003/10/09 03:14:14 zenzen +# Add test for DB API 2.0 optional extension, where database exceptions +# are exposed as attributes on the Connection object. +# +# Revision 1.9 2003/08/13 01:16:36 zenzen +# Minor tweak from Stefan Fleiter +# +# Revision 1.8 2003/04/10 00:13:25 zenzen +# Changes, as per suggestions by M.-A. Lemburg +# - Add a table prefix, to ensure namespace collisions can always be avoided +# +# Revision 1.7 2003/02/26 23:33:37 zenzen +# Break out DDL into helper functions, as per request by David Rushby +# +# Revision 1.6 2003/02/21 03:04:33 zenzen +# Stuff from Henrik Ekelund: +# added test_None +# added test_nextset & hooks +# +# Revision 1.5 2003/02/17 22:08:43 zenzen +# Implement suggestions and code from Henrik Eklund - test that cursor.arraysize +# defaults to 1 & generic cursor.callproc test added +# +# Revision 1.4 2003/02/15 00:16:33 zenzen +# Changes, as per suggestions and bug reports by M.-A. Lemburg, +# Matthew T. Kromer, Federico Di Gregorio and Daniel Dittmar +# - Class renamed +# - Now a subclass of TestCase, to avoid requiring the driver stub +# to use multiple inheritance +# - Reversed the polarity of buggy test in test_description +# - Test exception heirarchy correctly +# - self.populate is now self._populate(), so if a driver stub +# overrides self.ddl1 this change propogates +# - VARCHAR columns now have a width, which will hopefully make the +# DDL even more portible (this will be reversed if it causes more problems) +# - cursor.rowcount being checked after various execute and fetchXXX methods +# - Check for fetchall and fetchmany returning empty lists after results +# are exhausted (already checking for empty lists if select retrieved +# nothing +# - Fix bugs in test_setoutputsize_basic and test_setinputsizes +# + +class DatabaseAPI20Test(unittest.TestCase): + ''' Test a database self.driver for DB API 2.0 compatibility. + This implementation tests Gadfly, but the TestCase + is structured so that other self.drivers can subclass this + test case to ensure compiliance with the DB-API. It is + expected that this TestCase may be expanded in the future + if ambiguities or edge conditions are discovered. + + The 'Optional Extensions' are not yet being tested. + + self.drivers should subclass this test, overriding setUp, tearDown, + self.driver, connect_args and connect_kw_args. Class specification + should be as follows: + + import dbapi20 + class mytest(dbapi20.DatabaseAPI20Test): + [...] + + Don't 'import DatabaseAPI20Test from dbapi20', or you will + confuse the unit tester - just 'import dbapi20'. + ''' + + # The self.driver module. This should be the module where the 'connect' + # method is to be found + driver = None + connect_args = () # List of arguments to pass to connect + connect_kw_args = {} # Keyword arguments for connect + table_prefix = 'dbapi20test_' # If you need to specify a prefix for tables + + ddl1 = 'create table %sbooze (name varchar(20))' % table_prefix + ddl2 = 'create table %sbarflys (name varchar(20))' % table_prefix + xddl1 = 'drop table %sbooze' % table_prefix + xddl2 = 'drop table %sbarflys' % table_prefix + + lowerfunc = 'lower' # Name of stored procedure to convert string->lowercase + + # Some drivers may need to override these helpers, for example adding + # a 'commit' after the execute. + def executeDDL1(self,cursor): + cursor.execute(self.ddl1) + + def executeDDL2(self,cursor): + cursor.execute(self.ddl2) + + def setUp(self): + ''' self.drivers should override this method to perform required setup + if any is necessary, such as creating the database. + ''' + pass + + def tearDown(self): + ''' self.drivers should override this method to perform required cleanup + if any is necessary, such as deleting the test database. + The default drops the tables that may be created. + ''' + con = self._connect() + try: + cur = con.cursor() + for ddl in (self.xddl1,self.xddl2): + try: + cur.execute(ddl) + con.commit() + except self.driver.Error: + # Assume table didn't exist. Other tests will check if + # execute is busted. + pass + finally: + con.close() + + def _connect(self): + try: + return self.driver.connect( + *self.connect_args,**self.connect_kw_args + ) + except AttributeError: + self.fail("No connect method found in self.driver module") + + def test_connect(self): + con = self._connect() + con.close() + + def test_apilevel(self): + try: + # Must exist + apilevel = self.driver.apilevel + # Must equal 2.0 + self.assertEqual(apilevel,'2.0') + except AttributeError: + self.fail("Driver doesn't define apilevel") + + def test_threadsafety(self): + try: + # Must exist + threadsafety = self.driver.threadsafety + # Must be a valid value + self.failUnless(threadsafety in (0,1,2,3)) + except AttributeError: + self.fail("Driver doesn't define threadsafety") + + def test_paramstyle(self): + try: + # Must exist + paramstyle = self.driver.paramstyle + # Must be a valid value + self.failUnless(paramstyle in ( + 'qmark','numeric','named','format','pyformat' + )) + except AttributeError: + self.fail("Driver doesn't define paramstyle") + + def test_Exceptions(self): + # Make sure required exceptions exist, and are in the + # defined heirarchy. + self.failUnless(issubclass(self.driver.Warning,StandardError)) + self.failUnless(issubclass(self.driver.Error,StandardError)) + self.failUnless( + issubclass(self.driver.InterfaceError,self.driver.Error) + ) + self.failUnless( + issubclass(self.driver.DatabaseError,self.driver.Error) + ) + self.failUnless( + issubclass(self.driver.OperationalError,self.driver.Error) + ) + self.failUnless( + issubclass(self.driver.IntegrityError,self.driver.Error) + ) + self.failUnless( + issubclass(self.driver.InternalError,self.driver.Error) + ) + self.failUnless( + issubclass(self.driver.ProgrammingError,self.driver.Error) + ) + self.failUnless( + issubclass(self.driver.NotSupportedError,self.driver.Error) + ) + + def test_ExceptionsAsConnectionAttributes(self): + # OPTIONAL EXTENSION + # Test for the optional DB API 2.0 extension, where the exceptions + # are exposed as attributes on the Connection object + # I figure this optional extension will be implemented by any + # driver author who is using this test suite, so it is enabled + # by default. + con = self._connect() + drv = self.driver + self.failUnless(con.Warning is drv.Warning) + self.failUnless(con.Error is drv.Error) + self.failUnless(con.InterfaceError is drv.InterfaceError) + self.failUnless(con.DatabaseError is drv.DatabaseError) + self.failUnless(con.OperationalError is drv.OperationalError) + self.failUnless(con.IntegrityError is drv.IntegrityError) + self.failUnless(con.InternalError is drv.InternalError) + self.failUnless(con.ProgrammingError is drv.ProgrammingError) + self.failUnless(con.NotSupportedError is drv.NotSupportedError) + + + def test_commit(self): + con = self._connect() + try: + # Commit must work, even if it doesn't do anything + con.commit() + finally: + con.close() + + def test_rollback(self): + con = self._connect() + # If rollback is defined, it should either work or throw + # the documented exception + if hasattr(con,'rollback'): + try: + con.rollback() + except self.driver.NotSupportedError: + pass + + def test_cursor(self): + con = self._connect() + try: + cur = con.cursor() + finally: + con.close() + + def test_cursor_isolation(self): + con = self._connect() + try: + # Make sure cursors created from the same connection have + # the documented transaction isolation level + cur1 = con.cursor() + cur2 = con.cursor() + self.executeDDL1(cur1) + cur1.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + cur2.execute("select name from %sbooze" % self.table_prefix) + booze = cur2.fetchall() + self.assertEqual(len(booze),1) + self.assertEqual(len(booze[0]),1) + self.assertEqual(booze[0][0],'Victoria Bitter') + finally: + con.close() + + def test_description(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + self.assertEqual(cur.description,None, + 'cursor.description should be none after executing a ' + 'statement that can return no rows (such as DDL)' + ) + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(len(cur.description),1, + 'cursor.description describes too many columns' + ) + self.assertEqual(len(cur.description[0]),7, + 'cursor.description[x] tuples must have 7 elements' + ) + self.assertEqual(cur.description[0][0].lower(),'name', + 'cursor.description[x][0] must return column name' + ) + self.assertEqual(cur.description[0][1],self.driver.STRING, + 'cursor.description[x][1] must return column type. Got %r' + % cur.description[0][1] + ) + + # Make sure self.description gets reset + self.executeDDL2(cur) + self.assertEqual(cur.description,None, + 'cursor.description not being set to None when executing ' + 'no-result statements (eg. DDL)' + ) + finally: + con.close() + + def test_rowcount(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + self.assertEqual(cur.rowcount,-1, + 'cursor.rowcount should be -1 after executing no-result ' + 'statements' + ) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.failUnless(cur.rowcount in (-1,1), + 'cursor.rowcount should == number or rows inserted, or ' + 'set to -1 after executing an insert statement' + ) + cur.execute("select name from %sbooze" % self.table_prefix) + self.failUnless(cur.rowcount in (-1,1), + 'cursor.rowcount should == number of rows returned, or ' + 'set to -1 after executing a select statement' + ) + self.executeDDL2(cur) + self.assertEqual(cur.rowcount,-1, + 'cursor.rowcount not being reset to -1 after executing ' + 'no-result statements' + ) + finally: + con.close() + + lower_func = 'lower' + def test_callproc(self): + con = self._connect() + try: + cur = con.cursor() + if self.lower_func and hasattr(cur,'callproc'): + r = cur.callproc(self.lower_func,('FOO',)) + self.assertEqual(len(r),1) + self.assertEqual(r[0],'FOO') + r = cur.fetchall() + self.assertEqual(len(r),1,'callproc produced no result set') + self.assertEqual(len(r[0]),1, + 'callproc produced invalid result set' + ) + self.assertEqual(r[0][0],'foo', + 'callproc produced invalid results' + ) + finally: + con.close() + + def test_close(self): + con = self._connect() + try: + cur = con.cursor() + finally: + con.close() + + # cursor.execute should raise an Error if called after connection + # closed + self.assertRaises(self.driver.Error,self.executeDDL1,cur) + + # connection.commit should raise an Error if called after connection' + # closed.' + self.assertRaises(self.driver.Error,con.commit) + + # connection.close should raise an Error if called more than once + self.assertRaises(self.driver.Error,con.close) + + def test_execute(self): + con = self._connect() + try: + cur = con.cursor() + self._paraminsert(cur) + finally: + con.close() + + def _paraminsert(self,cur): + self.executeDDL1(cur) + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.failUnless(cur.rowcount in (-1,1)) + + if self.driver.paramstyle == 'qmark': + cur.execute( + 'insert into %sbooze values (?)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'numeric': + cur.execute( + 'insert into %sbooze values (:1)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'named': + cur.execute( + 'insert into %sbooze values (:beer)' % self.table_prefix, + {'beer':"Cooper's"} + ) + elif self.driver.paramstyle == 'format': + cur.execute( + 'insert into %sbooze values (%%s)' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'pyformat': + cur.execute( + 'insert into %sbooze values (%%(beer)s)' % self.table_prefix, + {'beer':"Cooper's"} + ) + else: + self.fail('Invalid paramstyle') + self.failUnless(cur.rowcount in (-1,1)) + + cur.execute('select name from %sbooze' % self.table_prefix) + res = cur.fetchall() + self.assertEqual(len(res),2,'cursor.fetchall returned too few rows') + beers = [res[0][0],res[1][0]] + beers.sort() + self.assertEqual(beers[0],"Cooper's", + 'cursor.fetchall retrieved incorrect data, or data inserted ' + 'incorrectly' + ) + self.assertEqual(beers[1],"Victoria Bitter", + 'cursor.fetchall retrieved incorrect data, or data inserted ' + 'incorrectly' + ) + + def test_executemany(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + largs = [ ("Cooper's",) , ("Boag's",) ] + margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ] + if self.driver.paramstyle == 'qmark': + cur.executemany( + 'insert into %sbooze values (?)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'numeric': + cur.executemany( + 'insert into %sbooze values (:1)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'named': + cur.executemany( + 'insert into %sbooze values (:beer)' % self.table_prefix, + margs + ) + elif self.driver.paramstyle == 'format': + cur.executemany( + 'insert into %sbooze values (%%s)' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'pyformat': + cur.executemany( + 'insert into %sbooze values (%%(beer)s)' % ( + self.table_prefix + ), + margs + ) + else: + self.fail('Unknown paramstyle') + self.failUnless(cur.rowcount in (-1,2), + 'insert using cursor.executemany set cursor.rowcount to ' + 'incorrect value %r' % cur.rowcount + ) + cur.execute('select name from %sbooze' % self.table_prefix) + res = cur.fetchall() + self.assertEqual(len(res),2, + 'cursor.fetchall retrieved incorrect number of rows' + ) + beers = [res[0][0],res[1][0]] + beers.sort() + self.assertEqual(beers[0],"Boag's",'incorrect data retrieved') + self.assertEqual(beers[1],"Cooper's",'incorrect data retrieved') + finally: + con.close() + + def test_fetchone(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchone should raise an Error if called before + # executing a select-type query + self.assertRaises(self.driver.Error,cur.fetchone) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + self.executeDDL1(cur) + self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if a query retrieves ' + 'no rows' + ) + self.failUnless(cur.rowcount in (-1,0)) + + # cursor.fetchone should raise an Error if called after + # executing a query that cannnot return rows + cur.execute("insert into %sbooze values ('Victoria Bitter')" % ( + self.table_prefix + )) + self.assertRaises(self.driver.Error,cur.fetchone) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchone() + self.assertEqual(len(r),1, + 'cursor.fetchone should have retrieved a single row' + ) + self.assertEqual(r[0],'Victoria Bitter', + 'cursor.fetchone retrieved incorrect data' + ) + self.assertEqual(cur.fetchone(),None, + 'cursor.fetchone should return None if no more rows available' + ) + self.failUnless(cur.rowcount in (-1,1)) + finally: + con.close() + + samples = [ + 'Carlton Cold', + 'Carlton Draft', + 'Mountain Goat', + 'Redback', + 'Victoria Bitter', + 'XXXX' + ] + + def _populate(self): + ''' Return a list of sql commands to setup the DB for the fetch + tests. + ''' + populate = [ + "insert into %sbooze values ('%s')" % (self.table_prefix,s) + for s in self.samples + ] + return populate + + def test_fetchmany(self): + con = self._connect() + try: + cur = con.cursor() + + # cursor.fetchmany should raise an Error if called without + #issuing a query + self.assertRaises(self.driver.Error,cur.fetchmany,4) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchmany() + self.assertEqual(len(r),1, + 'cursor.fetchmany retrieved incorrect number of rows, ' + 'default of arraysize is one.' + ) + cur.arraysize=10 + r = cur.fetchmany(3) # Should get 3 rows + self.assertEqual(len(r),3, + 'cursor.fetchmany retrieved incorrect number of rows' + ) + r = cur.fetchmany(4) # Should get 2 more + self.assertEqual(len(r),2, + 'cursor.fetchmany retrieved incorrect number of rows' + ) + r = cur.fetchmany(4) # Should be an empty sequence + self.assertEqual(len(r),0, + 'cursor.fetchmany should return an empty sequence after ' + 'results are exhausted' + ) + self.failUnless(cur.rowcount in (-1,6)) + + # Same as above, using cursor.arraysize + cur.arraysize=4 + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchmany() # Should get 4 rows + self.assertEqual(len(r),4, + 'cursor.arraysize not being honoured by fetchmany' + ) + r = cur.fetchmany() # Should get 2 more + self.assertEqual(len(r),2) + r = cur.fetchmany() # Should be an empty sequence + self.assertEqual(len(r),0) + self.failUnless(cur.rowcount in (-1,6)) + + cur.arraysize=6 + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchmany() # Should get all rows + self.failUnless(cur.rowcount in (-1,6)) + self.assertEqual(len(rows),6) + self.assertEqual(len(rows),6) + rows = [r[0] for r in rows] + rows.sort() + + # Make sure we get the right data back out + for i in range(0,6): + self.assertEqual(rows[i],self.samples[i], + 'incorrect data retrieved by cursor.fetchmany' + ) + + rows = cur.fetchmany() # Should return an empty list + self.assertEqual(len(rows),0, + 'cursor.fetchmany should return an empty sequence if ' + 'called after the whole result set has been fetched' + ) + self.failUnless(cur.rowcount in (-1,6)) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + r = cur.fetchmany() # Should get empty sequence + self.assertEqual(len(r),0, + 'cursor.fetchmany should return an empty sequence if ' + 'query retrieved no rows' + ) + self.failUnless(cur.rowcount in (-1,0)) + + finally: + con.close() + + def test_fetchall(self): + con = self._connect() + try: + cur = con.cursor() + # cursor.fetchall should raise an Error if called + # without executing a query that may return rows (such + # as a select) + self.assertRaises(self.driver.Error, cur.fetchall) + + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + # cursor.fetchall should raise an Error if called + # after executing a a statement that cannot return rows + self.assertRaises(self.driver.Error,cur.fetchall) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows = cur.fetchall() + self.failUnless(cur.rowcount in (-1,len(self.samples))) + self.assertEqual(len(rows),len(self.samples), + 'cursor.fetchall did not retrieve all rows' + ) + rows = [r[0] for r in rows] + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'cursor.fetchall retrieved incorrect rows' + ) + rows = cur.fetchall() + self.assertEqual( + len(rows),0, + 'cursor.fetchall should return an empty list if called ' + 'after the whole result set has been fetched' + ) + self.failUnless(cur.rowcount in (-1,len(self.samples))) + + self.executeDDL2(cur) + cur.execute('select name from %sbarflys' % self.table_prefix) + rows = cur.fetchall() + self.failUnless(cur.rowcount in (-1,0)) + self.assertEqual(len(rows),0, + 'cursor.fetchall should return an empty list if ' + 'a select query returns no rows' + ) + + finally: + con.close() + + def test_mixedfetch(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + for sql in self._populate(): + cur.execute(sql) + + cur.execute('select name from %sbooze' % self.table_prefix) + rows1 = cur.fetchone() + rows23 = cur.fetchmany(2) + rows4 = cur.fetchone() + rows56 = cur.fetchall() + self.failUnless(cur.rowcount in (-1,6)) + self.assertEqual(len(rows23),2, + 'fetchmany returned incorrect number of rows' + ) + self.assertEqual(len(rows56),2, + 'fetchall returned incorrect number of rows' + ) + + rows = [rows1[0]] + rows.extend([rows23[0][0],rows23[1][0]]) + rows.append(rows4[0]) + rows.extend([rows56[0][0],rows56[1][0]]) + rows.sort() + for i in range(0,len(self.samples)): + self.assertEqual(rows[i],self.samples[i], + 'incorrect data retrieved or inserted' + ) + finally: + con.close() + + def help_nextset_setUp(self,cur): + ''' Should create a procedure called deleteme + that returns two result sets, first the + number of rows in booze then "name from booze" + ''' + raise NotImplementedError,'Helper not implemented' + #sql=""" + # create procedure deleteme as + # begin + # select count(*) from booze + # select name from booze + # end + #""" + #cur.execute(sql) + + def help_nextset_tearDown(self,cur): + 'If cleaning up is needed after nextSetTest' + raise NotImplementedError,'Helper not implemented' + #cur.execute("drop procedure deleteme") + + def test_nextset(self): + con = self._connect() + try: + cur = con.cursor() + if not hasattr(cur,'nextset'): + return + + try: + self.executeDDL1(cur) + sql=self._populate() + for sql in self._populate(): + cur.execute(sql) + + self.help_nextset_setUp(cur) + + cur.callproc('deleteme') + numberofrows=cur.fetchone() + assert numberofrows[0]== len(self.samples) + assert cur.nextset() + names=cur.fetchall() + assert len(names) == len(self.samples) + s=cur.nextset() + assert s == None,'No more return sets, should return None' + finally: + self.help_nextset_tearDown(cur) + + finally: + con.close() + + def test_nextset(self): + raise NotImplementedError,'Drivers need to override this test' + + def test_arraysize(self): + # Not much here - rest of the tests for this are in test_fetchmany + con = self._connect() + try: + cur = con.cursor() + self.failUnless(hasattr(cur,'arraysize'), + 'cursor.arraysize must be defined' + ) + finally: + con.close() + + def test_setinputsizes(self): + con = self._connect() + try: + cur = con.cursor() + cur.setinputsizes( (25,) ) + self._paraminsert(cur) # Make sure cursor still works + finally: + con.close() + + def test_setoutputsize_basic(self): + # Basic test is to make sure setoutputsize doesn't blow up + con = self._connect() + try: + cur = con.cursor() + cur.setoutputsize(1000) + cur.setoutputsize(2000,0) + self._paraminsert(cur) # Make sure the cursor still works + finally: + con.close() + + def test_setoutputsize(self): + # Real test for setoutputsize is driver dependant + raise NotImplementedError,'Driver need to override this test' + + def test_None(self): + con = self._connect() + try: + cur = con.cursor() + self.executeDDL1(cur) + cur.execute('insert into %sbooze values (NULL)' % self.table_prefix) + cur.execute('select name from %sbooze' % self.table_prefix) + r = cur.fetchall() + self.assertEqual(len(r),1) + self.assertEqual(len(r[0]),1) + self.assertEqual(r[0][0],None,'NULL value not returned as None') + finally: + con.close() + + def test_Date(self): + d1 = self.driver.Date(2002,12,25) + d2 = self.driver.DateFromTicks(time.mktime((2002,12,25,0,0,0,0,0,0))) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(d1),str(d2)) + + def test_Time(self): + t1 = self.driver.Time(13,45,30) + t2 = self.driver.TimeFromTicks(time.mktime((2001,1,1,13,45,30,0,0,0))) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(t1),str(t2)) + + def test_Timestamp(self): + t1 = self.driver.Timestamp(2002,12,25,13,45,30) + t2 = self.driver.TimestampFromTicks( + time.mktime((2002,12,25,13,45,30,0,0,0)) + ) + # Can we assume this? API doesn't specify, but it seems implied + # self.assertEqual(str(t1),str(t2)) + + def test_Binary(self): + b = self.driver.Binary('Something') + b = self.driver.Binary('') + + def test_STRING(self): + self.failUnless(hasattr(self.driver,'STRING'), + 'module.STRING must be defined' + ) + + def test_BINARY(self): + self.failUnless(hasattr(self.driver,'BINARY'), + 'module.BINARY must be defined.' + ) + + def test_NUMBER(self): + self.failUnless(hasattr(self.driver,'NUMBER'), + 'module.NUMBER must be defined.' + ) + + def test_DATETIME(self): + self.failUnless(hasattr(self.driver,'DATETIME'), + 'module.DATETIME must be defined.' + ) + + def test_ROWID(self): + self.failUnless(hasattr(self.driver,'ROWID'), + 'module.ROWID must be defined.' + ) + diff --git a/psycopg2/tests/extras_dictcursor.py b/psycopg2/tests/extras_dictcursor.py new file mode 100644 index 0000000..270d37f --- /dev/null +++ b/psycopg2/tests/extras_dictcursor.py @@ -0,0 +1,47 @@ +# extras_dictcursor - test if DictCursor extension class works +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +import psycopg2 +import psycopg2.extras +from unittest import TestCase, TestSuite, main + + +class ExtrasDictCursorTests(TestCase): + """Test if DictCursor extension class works.""" + + def setUp(self): + self.conn = psycopg2.connect("dbname=test") + curs = self.conn.cursor() + curs.execute("CREATE TABLE ExtrasDictCursorTests (foo text)") + + def testDictCursor(self): + curs = self.conn.cursor(cursor_factory=psycopg2.extras.DictCursor) + curs.execute("INSERT INTO ExtrasDictCursorTests VALUES ('bar')") + curs.execute("SELECT * FROM ExtrasDictCursorTests") + row = curs.fetchone() + self.failUnless(row['foo'] == 'bar') + self.failUnless(row[0] == 'bar') + +class ExtrasDictCursorSuite(TestSuite): + """Build a suite of all tests.""" + + def __init__(self): + """Build a list of tests.""" + self.tests = [x for x in dir(ExtrasDictCursorTests) + if x.startswith('test')] + TestSuite.__init__(self, map(TestModule, self.tests)) + + +if __name__ == "__main__": + main() diff --git a/psycopg2/tests/test_psycopg2_dbapi20.py b/psycopg2/tests/test_psycopg2_dbapi20.py new file mode 100644 index 0000000..028b718 --- /dev/null +++ b/psycopg2/tests/test_psycopg2_dbapi20.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +import dbapi20 +import unittest +import psycopg2 +import popen2 + +class test_Psycopg(dbapi20.DatabaseAPI20Test): + driver = psycopg2 + connect_args = () + connect_kw_args = {'dsn': 'dbname=dbapi20_test'} + + lower_func = 'lower' # For stored procedure test + + def setUp(self): + # Call superclass setUp In case this does something in the + # future + dbapi20.DatabaseAPI20Test.setUp(self) + + try: + con = self._connect() + con.close() + except: + cmd = "psql -c 'create database dbapi20_test' template1" + cout,cin = popen2.popen2(cmd) + cin.close() + cout.read() + + def tearDown(self): + dbapi20.DatabaseAPI20Test.tearDown(self) + + def test_nextset(self): pass + def test_setoutputsize(self): pass + +if __name__ == '__main__': + unittest.main() diff --git a/psycopg2/tests/types_basic.py b/psycopg2/tests/types_basic.py new file mode 100644 index 0000000..446ad15 --- /dev/null +++ b/psycopg2/tests/types_basic.py @@ -0,0 +1,87 @@ +# types_basic.py - tests for basic types conversions +# +# Copyright (C) 2004 Federico Di Gregorio +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +import sys +try: + import decimal +except: + pass +import psycopg2 +from unittest import TestCase, TestSuite, main + + +class TypesBasicTests(TestCase): + """Test presence of mandatory attributes and methods.""" + + def setUp(self): + self.conn = psycopg2.connect("dbname=test") + + def execute(self, *args): + curs = self.conn.cursor() + curs.execute(*args) + return curs.fetchone()[0] + + def testQuoting(self): + s = "Quote'this\\! ''ok?''" + self.failUnless(self.execute("SELECT %s AS foo", (s,)) == s, + "wrong quoting: " + s) + + def testUnicode(self): + s = u"Quote'this\\! ''ok?''" + self.failUnless(self.execute("SELECT %s AS foo", (s,)) == s, + "wrong unicode quoting: " + s) + + def testNumber(self): + s = self.execute("SELECT %s AS foo", (1971,)) + self.failUnless(s == 1971, "wrong integer quoting: " + str(s)) + s = self.execute("SELECT %s AS foo", (1971L,)) + self.failUnless(s == 1971L, "wrong integer quoting: " + str(s)) + # Python 2.4 defaults to Decimal? + if sys.version_info[0] >= 2 and sys.version_info[1] >= 4: + s = self.execute("SELECT %s AS foo", (19.10,)) + self.failUnless(s - decimal.Decimal("19.10") == 0, + "wrong decimal quoting: " + str(s)) + else: + s = self.execute("SELECT %s AS foo", (19.10,)) + self.failUnless(abs(s - 19.10) < 0.001, + "wrong float quoting: " + str(s)) + + def testBinary(self): + s = ''.join([chr(x) for x in range(256)]) + b = psycopg2.Binary(s) + r = str(self.execute("SELECT %s::bytea AS foo", (b,))) + self.failUnless(r == s, "wrong binary quoting") + # test to make sure an empty Binary is converted to an empty string + b = psycopg2.Binary('') + self.assertEqual(str(b), "''") + + def testArray(self): + s = self.execute("SELECT %s AS foo", ([[1,2],[3,4]],)) + self.failUnless(s == [[1,2],[3,4]], "wrong array quoting " + str(s)) + s = self.execute("SELECT %s AS foo", (['one', 'two', 'three'],)) + self.failUnless(s == ['one', 'two', 'three'], + "wrong array quoting " + str(s)) + + +class TypesBasicSuite(TestSuite): + """Build a suite of all tests.""" + + def __init__(self): + """Build a list of tests.""" + self.tests = [x for x in dir(TypesBasicTests) if x.startswith('test')] + TestSuite.__init__(self, map(TestModule, self.tests)) + + +if __name__ == "__main__": + main() -- 2.43.0