Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial commit.

  • Loading branch information...
commit da28f7fd70f80a86afdc415aee1da438000da711 0 parents
authored May 19, 2009

Showing 41 changed files with 3,215 additions and 0 deletions. Show diff stats Hide diff stats

  1. 301  CHANGELOG
  2. 30  LICENSE
  3. 9  MANIFEST.in
  4. 82  README
  5. 12  TODO
  6. 28  examples/wiki/README
  7. 28  examples/wiki/setup.sh
  8. 146  examples/wiki/wiki.py
  9. 58  pgasync/__init__.py
  10. BIN  pgasync/__init__.pyc
  11. 574  pgasync/cache.c
  12. 76  pgasync/cache.pyx
  13. BIN  pgasync/cache.so
  14. 15  pgasync/convert.c
  15. 17  pgasync/convert.h
  16. 34  pgasync/errors.py
  17. BIN  pgasync/errors.pyc
  18. 547  pgasync/fe.py
  19. BIN  pgasync/fe.pyc
  20. 55  pgasync/format.py
  21. BIN  pgasync/format.pyc
  22. 50  pgasync/net.py
  23. BIN  pgasync/net.pyc
  24. 205  pgasync/pgtypes.py
  25. BIN  pgasync/pgtypes.pyc
  26. 98  pgasync/pool.py
  27. BIN  pgasync/pool.pyc
  28. 425  pgasync/protocol.py
  29. BIN  pgasync/protocol.pyc
  30. 51  pgasync/registry.py
  31. BIN  pgasync/registry.pyc
  32. 27  pgasync/util.py
  33. BIN  pgasync/util.pyc
  34. 33  setup.py
  35. 7  tests/TOTEST
  36. 6  tests/makeTestDb.sh
  37. 3  tests/test.sh
  38. 269  tests/test_types.py
  39. BIN  tests/test_types.pyc
  40. 29  tests/testbase.py
  41. BIN  tests/testbase.pyc
301  CHANGELOG
... ...
@@ -0,0 +1,301 @@
  1
+2.01
  2
+=======================
  3
+
  4
+*issues*
  5
+--------------
  6
+
  7
+FIXD  - runQuery and runInteraction needed ConnectionPool._error, which was
  8
+        removed.  Fixed.
  9
+
  10
+2.0
  11
+=======================
  12
+
  13
+*issues*
  14
+--------------
  15
+
  16
+FIXD  - Errback handling fixes
  17
+        
  18
+FIXD  - Removed useless explicit conversion of integers to
  19
+        NUMBER when no special formatting is done on them
  20
+
  21
+FIXD  - Exposed __int__, __float__ and friends in NUMBER
  22
+        just in case a NUMBER instance is tossed to format()
  23
+
  24
+FIXD  - The above two fixes mean you can now do %03d style
  25
+        formatting in format()
  26
+
  27
+FIXD  - A trailing semicolon can be included on execute()
  28
+        commands now
  29
+
  30
+FIXD  - Added boolean support (thanks: Andrea Arcangeli)
  31
+        
  32
+*enhancements*
  33
+--------------
  34
+
  35
+ - Experimental Unicode Support (thanks Matt Goodall)
  36
+
  37
+ - Unix socket support added (thanks Stephen Early)
  38
+
  39
+ - convertBinary function to get stored binary back out
  40
+   of the database
  41
+
  42
+
  43
+
  44
+1.15b
  45
+=======================
  46
+
  47
+*issues*
  48
+--------------
  49
+
  50
+FIXD  - cleaned up a few circular references and added a gc.collect()
  51
+        to the pool's prune() routine to remove memory leaking
  52
+
  53
+FIXD  - Made it so the second attempt to errback in runOperation is 
  54
+        ignored on exception in cases that the errback has already been
  55
+		called
  56
+
  57
+
  58
+1.14b
  59
+=======================
  60
+
  61
+*issues*
  62
+--------------
  63
+
  64
+FIXD  - fixed typo in runOperation, improved errback handling
  65
+
  66
+FIXD  - fixed a few concurrency issues, dropped connection handling
  67
+
  68
+
  69
+1.13b
  70
+=======================
  71
+
  72
+*enhancements*
  73
+--------------
  74
+
  75
+ - Pool size control implemented
  76
+
  77
+
  78
+1.12b
  79
+=======================
  80
+
  81
+*issues*
  82
+--------------
  83
+
  84
+FIXD  - added connect() method to ConnectionPool
  85
+
  86
+
  87
+1.11b
  88
+=======================
  89
+
  90
+*enhancements*
  91
+--------------
  92
+
  93
+ - Transaction and ConnectionPool (adbapi compat) added
  94
+
  95
+
  96
+*issues*
  97
+--------------
  98
+
  99
+FIXD  - protocol layer no longer calls back with stale transaction 
  100
+        status flag
  101
+
  102
+
  103
+1.10b
  104
+=======================
  105
+
  106
+*issues*
  107
+--------------
  108
+
  109
+FIXD  - format() and execute() now take all pyformat argument
  110
+        types, not just dicts
  111
+
  112
+FIXD  - closed connections handle failed query execution more
  113
+        gracefully
  114
+
  115
+
  116
+1.9b
  117
+=======================
  118
+
  119
+*enhancements*
  120
+--------------
  121
+
  122
+ - connection.cursor() is no longer deferred; you get your cursor object
  123
+   immediately.  Now, everything is queued, including before a real
  124
+   connection is made to the db, and *no* callbacks are necessary unless 
  125
+   you care about a query response.
  126
+
  127
+ - pgasync knows the difference between "dirty" and "clean" transactions.
  128
+   It will avoid issuing ROLLBACK when only selects have been done, and
  129
+   similarly it will resume a select-only transaction across different 
  130
+   cursors to avoid a needless BEGIN
  131
+
  132
+ - connection.exFetch was implemented for convenience
  133
+
  134
+
  135
+1.8b
  136
+=======================
  137
+
  138
+*issues*
  139
+--------------
  140
+
  141
+FIXD  - str, int, float, True/False, datetime instances returned from 
  142
+        fetch() queries instead of pgtypes
  143
+
  144
+FIXD  - date/time/timestamp handling corrected
  145
+
  146
+FIXD  - None passed to execute/exFetch results in NULL insertion
  147
+
  148
+FIXD  - Premature cursor release issues resolved; removed automatic 
  149
+        cursor release 
  150
+
  151
+FIXD  - Simplified pgtypes for output-only usage; removed
  152
+        stack inspection
  153
+
  154
+
  155
+1.7b
  156
+=======================
  157
+
  158
+*issues*
  159
+--------------
  160
+
  161
+FIXD  - fetchone() was corrected to return values consistent
  162
+        with the PEP
  163
+
  164
+
  165
+1.6b
  166
+=======================
  167
+
  168
+*issues*
  169
+--------------
  170
+
  171
+FIXD  - STRING and BINARY types now inherit from str, not
  172
+        types.StringType
  173
+
  174
+
  175
+1.5b
  176
+=======================
  177
+
  178
+*issues*
  179
+--------------
  180
+
  181
+FIXD  - execute() now strips query when looking for SELECT
  182
+
  183
+FIXD  - params are optional to execute and exFetch
  184
+
  185
+FIXD  - docstrings reflect the new param style
  186
+
  187
+
  188
+1.4b
  189
+=======================
  190
+
  191
+*issues*
  192
+--------------
  193
+
  194
+FIXD  - Changed references to imaginary 'pystyle' format
  195
+        to 'pyformat'
  196
+
  197
+FIXD  - Changed execute/exFetch functions to accept a
  198
+        dictionary instead of kwargs in compliance with
  199
+		the DB API convention
  200
+
  201
+
  202
+1.3b
  203
+=======================
  204
+
  205
+*enhancements*
  206
+--------------
  207
+ - execute (and variants) can take a datetime.datetime now
  208
+   as a format argument
  209
+
  210
+*additions*
  211
+-----------
  212
+ - examples/wiki
  213
+
  214
+*issues*
  215
+--------------
  216
+
  217
+FIXD  - error handling is now corrected.  addErrback/errback works 
  218
+        for all library deferred exceptions
  219
+       
  220
+FIXD  - under high concurrency, release() is necessary to give the
  221
+        cursor back to the pool.. so release() was implemented
  222
+
  223
+
  224
+1.2b
  225
+=======================
  226
+
  227
+*issues*
  228
+--------------
  229
+
  230
+FIXD  - Old examples distributed instead of new
  231
+
  232
+
  233
+1.1b
  234
+=======================
  235
+Note: connection.cursor() returns a Deferred now
  236
+
  237
+*enhancements*
  238
+--------------
  239
+ - Query queues implemented.  Slight performance increase, and much cleaner 
  240
+   API.  
  241
+
  242
+*removals*
  243
+----------
  244
+ - adbapi compat layer.  
  245
+
  246
+*issues*
  247
+--------------
  248
+
  249
+FIXD  - Problem with setup.py *always* requiring Pyrex (credit: Bob Ippolito)
  250
+
  251
+
  252
+
  253
+1.0b
  254
+=======================
  255
+
  256
+*enhancements*
  257
+--------------
  258
+ - Change to twisted's deferreds
  259
+ - adbapi wrapper
  260
+
  261
+*issues*
  262
+--------------
  263
+
  264
+FIXD  - string quote escape sequence was "\'", now it's "''"
  265
+
  266
+
  267
+
  268
+3b
  269
+=======================
  270
+
  271
+*enhancements*
  272
+--------------
  273
+
  274
+ - connect is now an instantaneous operation
  275
+ - exFetch added to the fe.py.  
  276
+
  277
+
  278
+
  279
+2b
  280
+=======================
  281
+
  282
+*enhancements*
  283
+--------------
  284
+
  285
+ - Simplified the net.py code b/c we're *only using byte count terminators;
  286
+   moved it from my arraybuffer class to (c)StringIO.  Faster now.
  287
+ - Renamed cursor.conn to cursor.connection in compliance with optional
  288
+   DB API 2.0 spec
  289
+
  290
+*issues*
  291
+-------
  292
+
  293
+FIXD  - Hanging in C fixed when the move to cStringIO buffering happened
  294
+        strings when things speed up, concurrency issues
  295
+FIXD  - __del__ / gc wasn't happening because cursor._callbackInfo held a
  296
+        reference
  297
+FIXD  - cursor.rowcount reflects modifications on INSERT, UPDATE
  298
+FIXD  - cursor 'none' error 
  299
+FIXD  - Ensure that the convert.c things work correcty on Linux, other systems
  300
+FIXD  - Source documentation
  301
+FIXD  - Callbacks need a queue, not just a var
30  LICENSE
... ...
@@ -0,0 +1,30 @@
  1
+Modified BSD
  2
+------------
  3
+
  4
+All of the documentation and software included in this software 
  5
+is copyrighted by Jamie Turner <jamwt@jamwt.com>
  6
+
  7
+Copyright 2009 Jamie Turner.  All rights reserved.
  8
+
  9
+Redistribution and use in source and binary forms, with or without
  10
+modification, are permitted provided that the following conditions
  11
+are met:
  12
+1. Redistributions of source code must retain the above copyright
  13
+   notice, this list of conditions and the following disclaimer.
  14
+2. Redistributions in binary form must reproduce the above copyright
  15
+   notice, this list of conditions and the following disclaimer in the
  16
+   documentation and/or other materials provided with the distribution.
  17
+3. The name of the author may not be used to endorse or promote products 
  18
+   derived from this software without specific prior written permission.
  19
+
  20
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 
  21
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
  22
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
  23
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  24
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
  25
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  26
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  27
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  28
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  29
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30
+
9  MANIFEST.in
... ...
@@ -0,0 +1,9 @@
  1
+recursive-include pgasync *.py *.pyx *.c *.h
  2
+recursive-include examples *.py 
  3
+include examples/wiki/setup.sh
  4
+include examples/wiki/README
  5
+include TODO
  6
+include README
  7
+include LICENSE
  8
+include CHANGELOG
  9
+include setup.py
82  README
... ...
@@ -0,0 +1,82 @@
  1
+
  2
+                                 * pgasync *
  3
+
  4
+             An asyncronous, twisted-based PostgreSQL client library
  5
+
  6
+                   Written by Jamie Turner <jamwt@jamwt.com>
  7
+
  8
+
  9
+OVERVIEW
  10
+--------
  11
+
  12
+pgasync fully conforms to the DB 2.0 API.  
  13
+
  14
+In a single, dedicated thread, it generally runs about 1.8x as slow as syncronous 
  15
+psycopg, which is written entirely in C.
  16
+
  17
+However, using adbapi (psycopg's twisted.enterprise w/the overhead of threading), 
  18
+it runs slightly faster than psycopg + enterprise at low load, 
  19
+and seems to be *much* more stable and scalable under heavy load.
  20
+
  21
+All execute(), exFetch(), and fetch*() methods return a 
  22
+twisted.internet.defer.Deferred.  Queries will be queued, so feel free to 
  23
+ignore these deferreds if you're not interested in the results: keep adding
  24
+more queries.
  25
+
  26
+The one exception is connection.cursor().  No queries should execute
  27
+until this function's deferred calls back.
  28
+
  29
+paramstyle is pyformat.  types are provided.
  30
+
  31
+Pooling/persistence happens, and the pool grows/shrinks based on activity.
  32
+
  33
+REQUIREMENTS
  34
+------------
  35
+
  36
+Twisted 1.3
  37
+Python 2.3+ (for datetime module)
  38
+PostgreSQL 7.4+ (protocol version 3.0)
  39
+
  40
+INSTALLATION
  41
+------------
  42
+
  43
+# python setup.py install
  44
+
  45
+BEFORE YOU BEGIN
  46
+----------------
  47
+
  48
+Read the notes on the website:
  49
+
  50
+ http://jamwt.com/pgasync/#notes
  51
+
  52
+SIMPLE EXAMPLE
  53
+--------------
  54
+
  55
+cur = db.cursor()
  56
+
  57
+# 1st arg 'rows' gets added; return value of async function
  58
+def printRows(rows,cur):
  59
+	print rows
  60
+	
  61
+# execute + fetch with one callback
  62
+cur.exFetch("SELECT * FROM users WHERE username = %(matchname)s",{matchname : "pete"}).addCallback(fetch,cur) 
  63
+
  64
+MORE EXAMPLES
  65
+-------------
  66
+
  67
+examples/ directory of this distribution.
  68
+
  69
+INSTALL NOTES
  70
+-------------
  71
+
  72
+It utillizes a Pyrex file to take care of one processor intesive thing.  This
  73
+cache.c file is pre-built for you and shipped with the distribution.  The cache.pyx
  74
+file is available in case you run into problems.  Set REBUILD_PYREX to True if you
  75
+want the pyx to be reprocessed (you'll need pyrex).
  76
+
  77
+Also: it builds a simple convert.c file that has some convenient byte order swapping
  78
+functions for the pyx.  This hasn't been tested on anything but FreeBSD and Linux
  79
+at the moment.  If there's a different header file needed for htonl/htons for your
  80
+system, please let me know.
  81
+
  82
+Cleartext and MD5 auth are supported.  
12  TODO
... ...
@@ -0,0 +1,12 @@
  1
+(in progress)
  2
+* unit tests
  3
+* check unicode/utf-8 support
  4
+
  5
+(done: moving to changelog for next release)
  6
+* mg's patch from list
  7
+* my patch.. fixing money type
  8
+* type adapter registry, cleanup
  9
+* binary fixes
  10
+* one-time connections
  11
+* explicit/multiple pools
  12
+* connection.close() now releases the connection back to the pool
28  examples/wiki/README
... ...
@@ -0,0 +1,28 @@
  1
+
  2
+                   Simple Wiki Example
  3
+
  4
+Description
  5
+-----------
  6
+
  7
+This wiki uses restructured text.  It's pretty minimal, but
  8
+it uses a db backend, and implements pgasync code in a scalable
  9
+way.
  10
+
  11
+Requirements
  12
+------------
  13
+
  14
+Beyond pgasync and its base requirements, the following are also
  15
+needed:
  16
+
  17
+ * Nevow 0.3
  18
+ * docutils (recent version)
  19
+
  20
+Running
  21
+-------
  22
+
  23
+Execute setup.sh as the PostgreSQL database owner account (often
  24
+called 'postgres'), then run:
  25
+
  26
+ twistd -noy wiki.py
  27
+
  28
+and browse to http://localhost:8080/
28  examples/wiki/setup.sh
... ...
@@ -0,0 +1,28 @@
  1
+#!/bin/sh
  2
+
  3
+echo "Attempting to set up database."
  4
+echo "Please make sure you execute this script as 'postgres' or"
  5
+echo "whatever you call the PostgreSQL database owner."
  6
+
  7
+echo ""
  8
+echo ""
  9
+
  10
+echo -n "Creating database:"
  11
+createdb wiki
  12
+
  13
+echo ""
  14
+echo -n "Creating user:"
  15
+psql -c "create user wiki with password 'wiki'" wiki
  16
+
  17
+echo ""
  18
+echo -n "Creating pages table:"
  19
+psql -c "create table pages (name varchar(100), contents text)" wiki
  20
+
  21
+echo ""
  22
+echo -n "Granting permission to user:"
  23
+psql -c "grant select,insert,update on pages to wiki " wiki
  24
+
  25
+echo ""
  26
+echo ""
  27
+
  28
+echo "Database is ready."
146  examples/wiki/wiki.py
... ...
@@ -0,0 +1,146 @@
  1
+import sys
  2
+sys.path.insert(0,".")
  3
+from twisted.application import service, internet
  4
+from twisted.internet.defer import Deferred
  5
+from nevow import appserver, inevow, loaders, rend, compy, url, tags as T, stan
  6
+from formless import annotate, webform, iformless
  7
+
  8
+from docutils.core import publish_string
  9
+
  10
+import pgasync
  11
+WIKI_DB_ARGS = {"dbname":"wiki","user":"wiki","password":"wiki"}
  12
+
  13
+import re
  14
+wikipage_re = re.compile("([A-Z][a-z]+[a-z0-9]*[A-Z]+\w+)",re.MULTILINE)
  15
+
  16
+pool = pgasync.ConnectionPool("pgasync",**WIKI_DB_ARGS)
  17
+
  18
+def format(text):
  19
+	html = publish_string(text, writer_name = 'html')
  20
+	frag = html[html.find('<body>')+6:html.find('</body>')].strip()
  21
+
  22
+	return re.sub(wikipage_re,r'<a href="\1">\1</a>',frag)
  23
+
  24
+class IWikiContent(compy.Interface): pass
  25
+class IPageTitle(compy.Interface): pass
  26
+
  27
+class IWikiForm(annotate.TypedInterface):
  28
+	def updateWiki(self,ctx=annotate.Context(),text=annotate.Text(), new=annotate.String(hidden=True)):
  29
+		pass
  30
+
  31
+	updateWiki = annotate.autocallable(updateWiki)
  32
+
  33
+class WikiEdit(rend.Page):
  34
+	__implements__ = IWikiForm, rend.Page.__implements__
  35
+
  36
+	def locateChild(self,ctx,segments):
  37
+		if len(segments) > 1:
  38
+			return rend.Page.locateChild(self,ctx,segments[1:])
  39
+		return self,()
  40
+
  41
+	def beforeRender(self, ctx):
  42
+		formDefs = iformless.IFormDefaults(ctx).getAllDefaults('updateWiki')
  43
+		content = IWikiContent(ctx)
  44
+		formDefs['new'] = "0"
  45
+		if content:
  46
+			formDefs['text'] = stan.xml(content)
  47
+		else:
  48
+			formDefs['new'] = "1"
  49
+
  50
+	def updateWiki(self, ctx, text, new):
  51
+		d = Deferred()
  52
+		connection = pool.connect()
  53
+		cur = connection.cursor()
  54
+		
  55
+		if new == "0":
  56
+			cur.execute("UPDATE pages SET contents = %(contents)s WHERE name = %(name)s",
  57
+				{"name" : IPageTitle(ctx),"contents" : text})
  58
+		else:
  59
+			cur.execute("INSERT INTO pages VALUES (%(name)s , %(contents)s)",
  60
+				{"name" : IPageTitle(ctx),"contents" : text})
  61
+
  62
+		def sendToContent(dc,d):
  63
+			request = ctx.locate(inevow.IRequest)
  64
+			request.setComponent(iformless.IRedirectAfterPost,"/%s" % IPageTitle(ctx))
  65
+			d.callback(None)
  66
+
  67
+		connection.commit().addCallback(sendToContent,d)
  68
+		cur.release()
  69
+
  70
+		return d
  71
+
  72
+	def title(self, ctx, data):
  73
+		return IPageTitle(ctx)
  74
+
  75
+	docFactory = loaders.stan([T.html[T.head[T.title["Wiki: ",title, " (edit)"]],
  76
+					T.body[T.span(_class="pageName")["Editing: ",title],webform.renderForms()]]])
  77
+
  78
+wikiEdit = WikiEdit()
  79
+	
  80
+class Wiki(rend.Page):
  81
+	def locateChild(self,ctx,segments):
  82
+		if segments == ('favicon.ico',):
  83
+			return rend.NotFound
  84
+
  85
+		if segments == ('',):
  86
+			segments = ('FrontPage',)
  87
+
  88
+		def finish(rows,cur,d,segments):
  89
+			if cur.rowcount:
  90
+				ctx.remember(rows[0][0],IWikiContent)
  91
+			else:
  92
+				ctx.remember(None,IWikiContent)
  93
+
  94
+			if len(segments) > 1:
  95
+				d.callback((wikiEdit,segments[1:]))
  96
+			else:
  97
+				d.callback((self,()))
  98
+
  99
+		page = segments[0]
  100
+		ctx.remember(page,IPageTitle)
  101
+
  102
+		d = Deferred()
  103
+
  104
+		cur = pool.connect().cursor()
  105
+		cur.exFetch("SELECT contents FROM pages WHERE name = %(name)s",{"name" : page}
  106
+		).addCallback(finish,cur,d,segments)
  107
+		cur.release()
  108
+		
  109
+		return d
  110
+
  111
+	def toolbar(self,ctx,data):
  112
+		content = ctx.locate(IWikiContent)
  113
+		return T.div(id="toolbar")[
  114
+			T.a(href=[IPageTitle(ctx),"/edit"],_class="toolbarLink")[
  115
+				content and "[Edit]" or "[Create]"
  116
+				]
  117
+			]
  118
+
  119
+	def pageContent(self,ctx,data):
  120
+		content = ctx.locate(IWikiContent)
  121
+		return T.div(style="margin:4px;")[
  122
+			content and 
  123
+				stan.xml(format(content)) or
  124
+				"This page does not yet exist."
  125
+			]
  126
+
  127
+	def title(self,ctx,data):
  128
+		return IPageTitle(ctx)
  129
+
  130
+	docFactory = loaders.stan([T.html[T.head[T.title["Wiki: ",title]],
  131
+					T.body[T.span(_class="pageName")[title],toolbar,T.hr(),pageContent]]])
  132
+
  133
+class ErrorPage(rend.Page):
  134
+	def error(self,ctx,data):
  135
+		return data
  136
+
  137
+	docFactory = loaders.stan([T.html[T.head[T.title["Database Error"]],
  138
+					T.body[T.h1["Database Error"],T.p[error]]]])
  139
+
  140
+application = service.Application("wiki")
  141
+internet.TCPServer(
  142
+    8080, 
  143
+    appserver.NevowSite(
  144
+        Wiki()
  145
+    )
  146
+).setServiceParent(application)
58  pgasync/__init__.py
... ...
@@ -0,0 +1,58 @@
  1
+from fe import *
  2
+from pgtypes import *
  3
+from util import *
  4
+from registry import *
  5
+
  6
+# Postgres Object ID constants
  7
+class PgOids:
  8
+	BOOL      = 16 
  9
+	BYTEA     = 17 
  10
+	CHAR      = 18
  11
+	INT8      = 20 
  12
+	INT2      = 21 
  13
+	INT4      = 23 
  14
+	TEXT      = 25 
  15
+	FLOAT4    = 700 
  16
+	FLOAT8    = 701 
  17
+	ABSTIME   = 702 
  18
+	RELTIME   = 703 
  19
+	TINTERVAL = 704
  20
+	CASH      = 790 
  21
+	BPCHAR    = 1042 
  22
+	VARCHAR   = 1043 
  23
+	DATE      = 1082 
  24
+	TIME      = 1083 
  25
+	TIMESTAMP = 1114 
  26
+	INTERVAL  = 1186
  27
+	_NUMERIC  = 1231
  28
+	NUMERIC   = 1700
  29
+	CSTRING   = 2275 
  30
+
  31
+import datetime
  32
+from decimal import Decimal
  33
+
  34
+# Standard registry
  35
+registerAdapter(NULL, [type(None)],[])
  36
+
  37
+registerAdapter(STRING, [str],[])
  38
+registerAdapter(BINARY, [unicode], [PgOids.BYTEA]) # No real unicode support in the default type registry
  39
+
  40
+registerAdapter(NUMBER, [],[])
  41
+registerAdapter(int, [],[PgOids.INT2, PgOids.INT4])
  42
+registerAdapter(float, [],[PgOids.FLOAT4, PgOids.FLOAT8])
  43
+registerAdapter(long, [],[PgOids.INT8])
  44
+registerAdapter(Decimal, [],[PgOids.NUMERIC, PgOids._NUMERIC])
  45
+registerAdapter(ROWID, [], []) # 
  46
+
  47
+registerAdapter(DATE, [datetime.date], [PgOids.DATE])
  48
+registerAdapter(TIME, [datetime.time], [PgOids.TIME,PgOids.ABSTIME,PgOids.RELTIME])
  49
+registerAdapter(DATETIME, [datetime.datetime], [PgOids.TIMESTAMP])
  50
+
  51
+registerAdapter(BOOL, [bool], [PgOids.BOOL])
  52
+
  53
+registerAdapter(MONEY, [], [PgOids.CASH])
  54
+
  55
+# Unicode
  56
+copyRegistry('__default__','unicode')
  57
+registerAdapter(UNICODE, [unicode],[PgOids.BPCHAR, PgOids.CHAR, 
  58
+				PgOids.TEXT, PgOids.VARCHAR,],regkey='unicode')
BIN  pgasync/__init__.pyc
Binary file not shown
574  pgasync/cache.c
... ...
@@ -0,0 +1,574 @@
  1
+/* Generated by Pyrex 0.9.3 on Fri Dec 10 19:48:23 2004 */
  2
+
  3
+#include "Python.h"
  4
+#include "structmember.h"
  5
+#ifndef PY_LONG_LONG
  6
+  #define PY_LONG_LONG LONG_LONG
  7
+#endif
  8
+#include "convert.h"
  9
+#include "stdlib.h"
  10
+#include "string.h"
  11
+
  12
+
  13
+typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
  14
+typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
  15
+static PyObject *__Pyx_UnpackItem(PyObject *, int); /*proto*/
  16
+static int __Pyx_EndUnpack(PyObject *, int); /*proto*/
  17
+static int __Pyx_PrintItem(PyObject *); /*proto*/
  18
+static int __Pyx_PrintNewline(void); /*proto*/
  19
+static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb); /*proto*/
  20
+static void __Pyx_ReRaise(void); /*proto*/
  21
+static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list); /*proto*/
  22
+static PyObject *__Pyx_GetExcValue(void); /*proto*/
  23
+static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed, char *name); /*proto*/
  24
+static int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type); /*proto*/
  25
+static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], int nargs, PyObject **args2, PyObject **kwds2); /*proto*/
  26
+static void __Pyx_WriteUnraisable(char *name); /*proto*/
  27
+static void __Pyx_AddTraceback(char *funcname); /*proto*/
  28
+static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size);  /*proto*/
  29
+static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
  30
+static int __Pyx_GetVtable(PyObject *dict, void *vtabptr); /*proto*/
  31
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name, char *modname); /*proto*/
  32
+static int __Pyx_InternStrings(__Pyx_InternTabEntry *t); /*proto*/
  33
+static int __Pyx_InitStrings(__Pyx_StringTabEntry *t); /*proto*/
  34
+static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
  35
+
  36
+static PyObject *__pyx_m;
  37
+static PyObject *__pyx_b;
  38
+static int __pyx_lineno;
  39
+static char *__pyx_filename;
  40
+staticforward char **__pyx_f;
  41
+
  42
+static char __pyx_mdoc[] = "A fast implementation to read in data rows.\n";
  43
+
  44
+/* Declarations from cache */
  45
+
  46
+staticforward PyTypeObject __pyx_type_5cache_Cache;
  47
+
  48
+struct __pyx_obj_5cache_Cache {
  49
+  PyObject_HEAD
  50
+  char (*buffer);
  51
+  int blen;
  52
+  PyObject *list;
  53
+};
  54
+
  55
+static PyTypeObject *__pyx_ptype_5cache_Cache = 0;
  56
+
  57
+/* Implementation of cache */
  58
+
  59
+static int __pyx_f_5cache_5Cache___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
  60
+static int __pyx_f_5cache_5Cache___new__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  61
+  int __pyx_r;
  62
+  PyObject *__pyx_1 = 0;
  63
+  static char *__pyx_argnames[] = {0};
  64
+  if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return -1;
  65
+  Py_INCREF(__pyx_v_self);
  66
+
  67
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":24 */
  68
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer = 0;
  69
+
  70
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":25 */
  71
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen = 0;
  72
+
  73
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":26 */
  74
+  __pyx_1 = PyList_New(0); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 26; goto __pyx_L1;}
  75
+  Py_DECREF(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list);
  76
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list = __pyx_1;
  77
+  __pyx_1 = 0;
  78
+
  79
+  __pyx_r = 0;
  80
+  goto __pyx_L0;
  81
+  __pyx_L1:;
  82
+  Py_XDECREF(__pyx_1);
  83
+  __Pyx_AddTraceback("cache.Cache.__new__");
  84
+  __pyx_r = -1;
  85
+  __pyx_L0:;
  86
+  Py_DECREF(__pyx_v_self);
  87
+  return __pyx_r;
  88
+}
  89
+
  90
+static PyObject *__pyx_f_5cache_5Cache_realloc(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
  91
+static PyObject *__pyx_f_5cache_5Cache_realloc(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  92
+  PyObject *__pyx_r;
  93
+  int __pyx_1;
  94
+  static char *__pyx_argnames[] = {0};
  95
+  if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0;
  96
+  Py_INCREF(__pyx_v_self);
  97
+
  98
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":29 */
  99
+  __pyx_1 = (((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen == 0);
  100
+  if (__pyx_1) {
  101
+
  102
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":30 */
  103
+    ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen = 1024;
  104
+    goto __pyx_L2;
  105
+  }
  106
+  /*else*/ {
  107
+
  108
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":32 */
  109
+    ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen = (((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen * 2);
  110
+
  111
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":33 */
  112
+    free(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer);
  113
+  }
  114
+  __pyx_L2:;
  115
+
  116
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":34 */
  117
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer = ((char (*))malloc(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen));
  118
+
  119
+  __pyx_r = Py_None; Py_INCREF(__pyx_r);
  120
+  goto __pyx_L0;
  121
+  __pyx_L1:;
  122
+  __Pyx_AddTraceback("cache.Cache.realloc");
  123
+  __pyx_r = 0;
  124
+  __pyx_L0:;
  125
+  Py_DECREF(__pyx_v_self);
  126
+  return __pyx_r;
  127
+}
  128
+
  129
+static PyObject *__pyx_n_append;
  130
+static PyObject *__pyx_n_realloc;
  131
+
  132
+static PyObject *__pyx_f_5cache_5Cache_add(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
  133
+static char __pyx_doc_5cache_5Cache_add[] = "Adds a new row to the table.\n		";
  134
+static PyObject *__pyx_f_5cache_5Cache_add(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  135
+  PyObject *__pyx_v_ps = 0;
  136
+  unsigned short __pyx_v_ncol;
  137
+  int __pyx_v_fsiz;
  138
+  char (*__pyx_v_s);
  139
+  int __pyx_v_bitset;
  140
+  PyObject *__pyx_v_row;
  141
+  PyObject *__pyx_v_i;
  142
+  PyObject *__pyx_r;
  143
+  char (*__pyx_1);
  144
+  PyObject *__pyx_2 = 0;
  145
+  long __pyx_3;
  146
+  int __pyx_4;
  147
+  PyObject *__pyx_5 = 0;
  148
+  PyObject *__pyx_6 = 0;
  149
+  static char *__pyx_argnames[] = {"ps",0};
  150
+  if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_ps)) return 0;
  151
+  Py_INCREF(__pyx_v_self);
  152
+  Py_INCREF(__pyx_v_ps);
  153
+  __pyx_v_row = Py_None; Py_INCREF(__pyx_v_row);
  154
+  __pyx_v_i = Py_None; Py_INCREF(__pyx_v_i);
  155
+
  156
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":44 */
  157
+  __pyx_1 = PyString_AsString(__pyx_v_ps); if (PyErr_Occurred()) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 44; goto __pyx_L1;}
  158
+  __pyx_v_s = __pyx_1;
  159
+
  160
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":46 */
  161
+  __pyx_2 = PyList_New(0); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 46; goto __pyx_L1;}
  162
+  Py_DECREF(__pyx_v_row);
  163
+  __pyx_v_row = __pyx_2;
  164
+  __pyx_2 = 0;
  165
+
  166
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":47 */
  167
+  __pyx_v_ncol = convertUShort(__pyx_v_s);
  168
+
  169
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":49 */
  170
+  __pyx_v_s = (&(__pyx_v_s[2]));
  171
+
  172
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":51 */
  173
+  for (__pyx_3 = 0; __pyx_3 < __pyx_v_ncol; ++__pyx_3) {
  174
+    __pyx_2 = PyInt_FromLong(__pyx_3); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; goto __pyx_L1;}
  175
+    Py_DECREF(__pyx_v_i);
  176
+    __pyx_v_i = __pyx_2;
  177
+    __pyx_2 = 0;
  178
+
  179
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":52 */
  180
+    __pyx_v_fsiz = convertInt(__pyx_v_s);
  181
+
  182
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":54 */
  183
+    __pyx_v_s = (&(__pyx_v_s[4]));
  184
+
  185
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":56 */
  186
+    __pyx_4 = (__pyx_v_fsiz <= 0);
  187
+    if (__pyx_4) {
  188
+
  189
+      /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":57 */
  190
+      __pyx_2 = PyObject_GetAttr(__pyx_v_row, __pyx_n_append); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; goto __pyx_L1;}
  191
+      __pyx_5 = PyTuple_New(1); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; goto __pyx_L1;}
  192
+      Py_INCREF(Py_None);
  193
+      PyTuple_SET_ITEM(__pyx_5, 0, Py_None);
  194
+      __pyx_6 = PyObject_CallObject(__pyx_2, __pyx_5); if (!__pyx_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 57; goto __pyx_L1;}
  195
+      Py_DECREF(__pyx_2); __pyx_2 = 0;
  196
+      Py_DECREF(__pyx_5); __pyx_5 = 0;
  197
+      Py_DECREF(__pyx_6); __pyx_6 = 0;
  198
+
  199
+      /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":58 */
  200
+      goto __pyx_L2;
  201
+      goto __pyx_L4;
  202
+    }
  203
+    __pyx_L4:;
  204
+
  205
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":60 */
  206
+    while (1) {
  207
+      __pyx_L5:;
  208
+      __pyx_4 = ((__pyx_v_fsiz + 1) > ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen);
  209
+      if (!__pyx_4) break;
  210
+
  211
+      /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":61 */
  212
+      __pyx_2 = PyObject_GetAttr(__pyx_v_self, __pyx_n_realloc); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; goto __pyx_L1;}
  213
+      __pyx_5 = PyTuple_New(0); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; goto __pyx_L1;}
  214
+      __pyx_6 = PyObject_CallObject(__pyx_2, __pyx_5); if (!__pyx_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 61; goto __pyx_L1;}
  215
+      Py_DECREF(__pyx_2); __pyx_2 = 0;
  216
+      Py_DECREF(__pyx_5); __pyx_5 = 0;
  217
+      Py_DECREF(__pyx_6); __pyx_6 = 0;
  218
+    }
  219
+    __pyx_L6:;
  220
+
  221
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":63 */
  222
+    strncpy(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer,__pyx_v_s,__pyx_v_fsiz);
  223
+
  224
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":64 */
  225
+    (((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer[__pyx_v_fsiz]) = 0;
  226
+
  227
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":65 */
  228
+    __pyx_2 = PyObject_GetAttr(__pyx_v_row, __pyx_n_append); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 65; goto __pyx_L1;}
  229
+    __pyx_5 = PyString_FromString(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 65; goto __pyx_L1;}
  230
+    __pyx_6 = PyTuple_New(1); if (!__pyx_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 65; goto __pyx_L1;}
  231
+    PyTuple_SET_ITEM(__pyx_6, 0, __pyx_5);
  232
+    __pyx_5 = 0;
  233
+    __pyx_5 = PyObject_CallObject(__pyx_2, __pyx_6); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 65; goto __pyx_L1;}
  234
+    Py_DECREF(__pyx_2); __pyx_2 = 0;
  235
+    Py_DECREF(__pyx_6); __pyx_6 = 0;
  236
+    Py_DECREF(__pyx_5); __pyx_5 = 0;
  237
+
  238
+    /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":66 */
  239
+    __pyx_v_s = (&(__pyx_v_s[__pyx_v_fsiz]));
  240
+    __pyx_L2:;
  241
+  }
  242
+  __pyx_L3:;
  243
+
  244
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":68 */
  245
+  __pyx_2 = PyObject_GetAttr(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list, __pyx_n_append); if (!__pyx_2) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; goto __pyx_L1;}
  246
+  __pyx_6 = PyTuple_New(1); if (!__pyx_6) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; goto __pyx_L1;}
  247
+  Py_INCREF(__pyx_v_row);
  248
+  PyTuple_SET_ITEM(__pyx_6, 0, __pyx_v_row);
  249
+  __pyx_5 = PyObject_CallObject(__pyx_2, __pyx_6); if (!__pyx_5) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 68; goto __pyx_L1;}
  250
+  Py_DECREF(__pyx_2); __pyx_2 = 0;
  251
+  Py_DECREF(__pyx_6); __pyx_6 = 0;
  252
+  Py_DECREF(__pyx_5); __pyx_5 = 0;
  253
+
  254
+  __pyx_r = Py_None; Py_INCREF(__pyx_r);
  255
+  goto __pyx_L0;
  256
+  __pyx_L1:;
  257
+  Py_XDECREF(__pyx_2);
  258
+  Py_XDECREF(__pyx_5);
  259
+  Py_XDECREF(__pyx_6);
  260
+  __Pyx_AddTraceback("cache.Cache.add");
  261
+  __pyx_r = 0;
  262
+  __pyx_L0:;
  263
+  Py_DECREF(__pyx_v_row);
  264
+  Py_DECREF(__pyx_v_i);
  265
+  Py_DECREF(__pyx_v_self);
  266
+  Py_DECREF(__pyx_v_ps);
  267
+  return __pyx_r;
  268
+}
  269
+
  270
+static PyObject *__pyx_f_5cache_5Cache_finish(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
  271
+static PyObject *__pyx_f_5cache_5Cache_finish(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
  272
+  PyObject *__pyx_v_l;
  273
+  PyObject *__pyx_r;
  274
+  PyObject *__pyx_1 = 0;
  275
+  static char *__pyx_argnames[] = {0};
  276
+  if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0;
  277
+  Py_INCREF(__pyx_v_self);
  278
+  __pyx_v_l = Py_None; Py_INCREF(__pyx_v_l);
  279
+
  280
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":71 */
  281
+  free(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer);
  282
+
  283
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":72 */
  284
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->buffer = 0;
  285
+
  286
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":73 */
  287
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->blen = 0;
  288
+
  289
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":74 */
  290
+  Py_INCREF(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list);
  291
+  Py_DECREF(__pyx_v_l);
  292
+  __pyx_v_l = ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list;
  293
+
  294
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":75 */
  295
+  __pyx_1 = PyList_New(0); if (!__pyx_1) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; goto __pyx_L1;}
  296
+  Py_DECREF(((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list);
  297
+  ((struct __pyx_obj_5cache_Cache *)__pyx_v_self)->list = __pyx_1;
  298
+  __pyx_1 = 0;
  299
+
  300
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":76 */
  301
+  Py_INCREF(__pyx_v_l);
  302
+  __pyx_r = __pyx_v_l;
  303
+  goto __pyx_L0;
  304
+
  305
+  __pyx_r = Py_None; Py_INCREF(__pyx_r);
  306
+  goto __pyx_L0;
  307
+  __pyx_L1:;
  308
+  Py_XDECREF(__pyx_1);
  309
+  __Pyx_AddTraceback("cache.Cache.finish");
  310
+  __pyx_r = 0;
  311
+  __pyx_L0:;
  312
+  Py_DECREF(__pyx_v_l);
  313
+  Py_DECREF(__pyx_v_self);
  314
+  return __pyx_r;
  315
+}
  316
+
  317
+static __Pyx_InternTabEntry __pyx_intern_tab[] = {
  318
+  {&__pyx_n_append, "append"},
  319
+  {&__pyx_n_realloc, "realloc"},
  320
+  {0, 0}
  321
+};
  322
+
  323
+static PyObject *__pyx_tp_new_5cache_Cache(PyTypeObject *t, PyObject *a, PyObject *k) {
  324
+  PyObject *o = (*t->tp_alloc)(t, 0);
  325
+  struct __pyx_obj_5cache_Cache *p = (struct __pyx_obj_5cache_Cache *)o;
  326
+  p->list = Py_None; Py_INCREF(p->list);
  327
+  if (__pyx_f_5cache_5Cache___new__(o, a, k) < 0) {
  328
+    Py_DECREF(o); o = 0;
  329
+  }
  330
+  return o;
  331
+}
  332
+
  333
+static void __pyx_tp_dealloc_5cache_Cache(PyObject *o) {
  334
+  struct __pyx_obj_5cache_Cache *p = (struct __pyx_obj_5cache_Cache *)o;
  335
+  Py_XDECREF(p->list);
  336
+  (*o->ob_type->tp_free)(o);
  337
+}
  338
+
  339
+static int __pyx_tp_traverse_5cache_Cache(PyObject *o, visitproc v, void *a) {
  340
+  int e;
  341
+  struct __pyx_obj_5cache_Cache *p = (struct __pyx_obj_5cache_Cache *)o;
  342
+  if (p->list) {
  343
+    e = (*v)(p->list, a); if (e) return e;
  344
+  }
  345
+  return 0;
  346
+}
  347
+
  348
+static int __pyx_tp_clear_5cache_Cache(PyObject *o) {
  349
+  struct __pyx_obj_5cache_Cache *p = (struct __pyx_obj_5cache_Cache *)o;
  350
+  Py_XDECREF(p->list);
  351
+  p->list = Py_None; Py_INCREF(p->list);
  352
+  return 0;
  353
+}
  354
+
  355
+static struct PyMethodDef __pyx_methods_5cache_Cache[] = {
  356
+  {"realloc", (PyCFunction)__pyx_f_5cache_5Cache_realloc, METH_VARARGS|METH_KEYWORDS, 0},
  357
+  {"add", (PyCFunction)__pyx_f_5cache_5Cache_add, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5cache_5Cache_add},
  358
+  {"finish", (PyCFunction)__pyx_f_5cache_5Cache_finish, METH_VARARGS|METH_KEYWORDS, 0},
  359
+  {0, 0, 0, 0}
  360
+};
  361
+
  362
+static PyNumberMethods __pyx_tp_as_number_Cache = {
  363
+  0, /*nb_add*/
  364
+  0, /*nb_subtract*/
  365
+  0, /*nb_multiply*/
  366
+  0, /*nb_divide*/
  367
+  0, /*nb_remainder*/
  368
+  0, /*nb_divmod*/
  369
+  0, /*nb_power*/
  370
+  0, /*nb_negative*/
  371
+  0, /*nb_positive*/
  372
+  0, /*nb_absolute*/
  373
+  0, /*nb_nonzero*/
  374
+  0, /*nb_invert*/
  375
+  0, /*nb_lshift*/
  376
+  0, /*nb_rshift*/
  377
+  0, /*nb_and*/
  378
+  0, /*nb_xor*/
  379
+  0, /*nb_or*/
  380
+  0, /*nb_coerce*/
  381
+  0, /*nb_int*/
  382
+  0, /*nb_long*/
  383
+  0, /*nb_float*/
  384
+  0, /*nb_oct*/
  385
+  0, /*nb_hex*/
  386
+  0, /*nb_inplace_add*/
  387
+  0, /*nb_inplace_subtract*/
  388
+  0, /*nb_inplace_multiply*/
  389
+  0, /*nb_inplace_divide*/
  390
+  0, /*nb_inplace_remainder*/
  391
+  0, /*nb_inplace_power*/
  392
+  0, /*nb_inplace_lshift*/
  393
+  0, /*nb_inplace_rshift*/
  394
+  0, /*nb_inplace_and*/
  395
+  0, /*nb_inplace_xor*/
  396
+  0, /*nb_inplace_or*/
  397
+  0, /*nb_floor_divide*/
  398
+  0, /*nb_true_divide*/
  399
+  0, /*nb_inplace_floor_divide*/
  400
+  0, /*nb_inplace_true_divide*/
  401
+};
  402
+
  403
+static PySequenceMethods __pyx_tp_as_sequence_Cache = {
  404
+  0, /*sq_length*/
  405
+  0, /*sq_concat*/
  406
+  0, /*sq_repeat*/
  407
+  0, /*sq_item*/
  408
+  0, /*sq_slice*/
  409
+  0, /*sq_ass_item*/
  410
+  0, /*sq_ass_slice*/
  411
+  0, /*sq_contains*/
  412
+  0, /*sq_inplace_concat*/
  413
+  0, /*sq_inplace_repeat*/
  414
+};
  415
+
  416
+static PyMappingMethods __pyx_tp_as_mapping_Cache = {
  417
+  0, /*mp_length*/
  418
+  0, /*mp_subscript*/
  419
+  0, /*mp_ass_subscript*/
  420
+};
  421
+
  422
+static PyBufferProcs __pyx_tp_as_buffer_Cache = {
  423
+  0, /*bf_getreadbuffer*/
  424
+  0, /*bf_getwritebuffer*/
  425
+  0, /*bf_getsegcount*/
  426
+  0, /*bf_getcharbuffer*/
  427
+};
  428
+
  429
+statichere PyTypeObject __pyx_type_5cache_Cache = {
  430
+  PyObject_HEAD_INIT(0)
  431
+  0, /*ob_size*/
  432
+  "cache.Cache", /*tp_name*/
  433
+  sizeof(struct __pyx_obj_5cache_Cache), /*tp_basicsize*/
  434
+  0, /*tp_itemsize*/
  435
+  __pyx_tp_dealloc_5cache_Cache, /*tp_dealloc*/
  436
+  0, /*tp_print*/
  437
+  0, /*tp_getattr*/
  438
+  0, /*tp_setattr*/
  439
+  0, /*tp_compare*/
  440
+  0, /*tp_repr*/
  441
+  &__pyx_tp_as_number_Cache, /*tp_as_number*/
  442
+  &__pyx_tp_as_sequence_Cache, /*tp_as_sequence*/
  443
+  &__pyx_tp_as_mapping_Cache, /*tp_as_mapping*/
  444
+  0, /*tp_hash*/
  445
+  0, /*tp_call*/
  446
+  0, /*tp_str*/
  447
+  0, /*tp_getattro*/
  448
+  0, /*tp_setattro*/
  449
+  &__pyx_tp_as_buffer_Cache, /*tp_as_buffer*/
  450
+  Py_TPFLAGS_DEFAULT|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/
  451
+  "A Cache class for data rows.\n	", /*tp_doc*/
  452
+  __pyx_tp_traverse_5cache_Cache, /*tp_traverse*/
  453
+  __pyx_tp_clear_5cache_Cache, /*tp_clear*/
  454
+  0, /*tp_richcompare*/
  455
+  0, /*tp_weaklistoffset*/
  456
+  0, /*tp_iter*/
  457
+  0, /*tp_iternext*/
  458
+  __pyx_methods_5cache_Cache, /*tp_methods*/
  459
+  0, /*tp_members*/
  460
+  0, /*tp_getset*/
  461
+  0, /*tp_base*/
  462
+  0, /*tp_dict*/
  463
+  0, /*tp_descr_get*/
  464
+  0, /*tp_descr_set*/
  465
+  0, /*tp_dictoffset*/
  466
+  0, /*tp_init*/
  467
+  0, /*tp_alloc*/
  468
+  __pyx_tp_new_5cache_Cache, /*tp_new*/
  469
+  0, /*tp_free*/
  470
+  0, /*tp_is_gc*/
  471
+  0, /*tp_bases*/
  472
+  0, /*tp_mro*/
  473
+  0, /*tp_cache*/
  474
+  0, /*tp_subclasses*/
  475
+  0, /*tp_weaklist*/
  476
+};
  477
+
  478
+static struct PyMethodDef __pyx_methods[] = {
  479
+  {0, 0, 0, 0}
  480
+};
  481
+
  482
+DL_EXPORT(void) initcache(void); /*proto*/
  483
+DL_EXPORT(void) initcache(void) {
  484
+  __pyx_m = Py_InitModule4("cache", __pyx_methods, __pyx_mdoc, 0, PYTHON_API_VERSION);
  485
+  if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
  486
+  __pyx_b = PyImport_AddModule("__builtin__");
  487
+  if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
  488
+  if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
  489
+  if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
  490
+  __pyx_type_5cache_Cache.tp_free = _PyObject_GC_Del;
  491
+  if (PyType_Ready(&__pyx_type_5cache_Cache) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; goto __pyx_L1;}
  492
+  if (PyObject_SetAttrString(__pyx_m, "Cache", (PyObject *)&__pyx_type_5cache_Cache) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; goto __pyx_L1;}
  493
+  __pyx_ptype_5cache_Cache = &__pyx_type_5cache_Cache;
  494
+
  495
+  /* "/usr/home/jamwt/devel/pgasync/pgasync/cache.pyx":70 */
  496
+  return;
  497
+  __pyx_L1:;
  498
+  __Pyx_AddTraceback("cache");
  499
+}
  500
+
  501
+static char *__pyx_filenames[] = {
  502
+  "cache.pyx",
  503
+};
  504
+statichere char **__pyx_f = __pyx_filenames;