Much better examples.

This commit is contained in:
Federico Di Gregorio 2005-02-27 15:25:24 +00:00
parent 4b94e54473
commit 55744b00cd
3 changed files with 146 additions and 1 deletions

View File

@ -88,7 +88,10 @@ class SQL_IN(object):
def __init__(self, seq): def __init__(self, seq):
self._seq = seq self._seq = seq
def prepare(self, conn):
pass
def getquoted(self): def getquoted(self):
# this is the important line: note how every object in the # this is the important line: note how every object in the
# list is adapted and then how getquoted() is called on it # list is adapted and then how getquoted() is called on it
@ -98,6 +101,7 @@ class SQL_IN(object):
return '(' + ', '.join(qobjs) + ')' return '(' + ', '.join(qobjs) + ')'
__str__ = getquoted __str__ = getquoted
# add our new adapter class to psycopg list of adapters # add our new adapter class to psycopg list of adapters
register_adapter(tuple, SQL_IN) register_adapter(tuple, SQL_IN)

123
examples/usercast.py Normal file
View File

@ -0,0 +1,123 @@
# usercast.py -- example of user defined typecasters
# -*- encoding: latin-1 -*-
#
# Copyright (C) 2001-2005 Federico Di Gregorio <fog@debian.org>
#
# 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, psycopg
import psycopg.extensions
import whrandom
if len(sys.argv) > 1:
DSN = sys.argv[1]
print "Opening connection using dns:", DSN
conn = psycopg.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:
"""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."""
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
__str__ = getquoted
def prepare(self, conn):
pass
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 = psycopg.extensions.new_type((boxoid,), "BOX", Rect)
psycopg.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()

View File

@ -34,6 +34,22 @@
/** void protocol implementation **/ /** void protocol implementation **/
/* prepare - prepare object for quotation */
#define psyco_isqlquote_prepare_doc \
"prepare(conn) -> prepare object with connection 'conn'"
static PyObject *
psyco_isqlquote_prepare(isqlquoteObject *self, PyObject *args)
{
PyObject* conn = NULL;
if (!PyArg_ParseTuple(args, "O", &conn)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
/* getquoted - return quoted representation for object */ /* getquoted - return quoted representation for object */
#define psyco_isqlquote_getquoted_doc \ #define psyco_isqlquote_getquoted_doc \
@ -90,6 +106,8 @@ static struct PyMethodDef isqlquoteObject_methods[] = {
METH_VARARGS, psyco_isqlquote_getbinary_doc}, METH_VARARGS, psyco_isqlquote_getbinary_doc},
{"getbuffer", (PyCFunction)psyco_isqlquote_getbuffer, {"getbuffer", (PyCFunction)psyco_isqlquote_getbuffer,
METH_VARARGS, psyco_isqlquote_getbuffer_doc}, METH_VARARGS, psyco_isqlquote_getbuffer_doc},
{"prepare", (PyCFunction)psyco_isqlquote_prepare,
METH_VARARGS, psyco_isqlquote_prepare_doc},
{NULL} {NULL}
}; };