Skip to content

Commit 9316c6a

Browse files
committed
Optimizations to type casting (in preparation to array support.)
1 parent c639b92 commit 9316c6a

File tree

16 files changed

+118
-137
lines changed

16 files changed

+118
-137
lines changed

ChangeLog

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
1+
2005-03-12 Federico Di Gregorio <fog@debian.org>
2+
3+
* psycopg/cursor_type.c (_psyco_curs_buildrow_fill): modified to
4+
call typecast_cast().
5+
6+
* psycopg/typecast.c (typecast_call/typecast_cast): modified
7+
typecast_call to use the new typecast_cast that avoids one string
8+
conversion on every cast.
9+
110
2005-03-04 Federico Di Gregorio <fog@initd.org>
211

3-
* Release 1.99.13.1.
12+
* Release 1.99.12.1.
413

514
* psycopg/adapter_asis.c (asis_str): changed call to PyObject_Repr
615
to PyObject_Str to avoid problems with long integers.
716

17+
2005-03-03 Federico Di Gregorio <fog@debian.org>
18+
19+
* psycopg/typecast.h: added array casting functions.
20+
21+
* scripts/maketypes.sh: does not generate pgversion.h anymore.
22+
23+
* Updated all examples for the release.
24+
825
2005-03-02 Federico Di Gregorio <fog@debian.org>
926

10-
* Release 1.99.13.
27+
* Release 1.99.12.
1128

1229
* psycopg/adapter_*.c: added __conform__ to all adapters.
1330

examples/cursor.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
DSN = sys.argv[1]
2727

2828
print "Opening connection using dsn:", DSN
29-
3029
conn = psycopg.connect(DSN)
3130
print "Encoding for this connection is", conn.encoding
3231

@@ -51,7 +50,7 @@ def fetchone(self):
5150
raise NoDataError("no more data")
5251
return d
5352

54-
curs = conn.cursor(factory=Cursor)
53+
curs = conn.cursor(cursor_factory=Cursor)
5554
curs.execute("SELECT 1 AS foo")
5655
print "Result of fetchone():", curs.fetchone()
5756

examples/lastrowid.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@
4949
moid = curs.lastrowid
5050
print "Oid for %(name)s %(surname)s" % data[1], "is", moid
5151

52-
curs.execute("SELECT * FROM test_oid WHERE oid = %d", (foid,))
52+
curs.execute("SELECT * FROM test_oid WHERE oid = %s", (foid,))
5353
print "Oid", foid, "selected %s %s" % curs.fetchone()
5454

55-
curs.execute("SELECT * FROM test_oid WHERE oid = %d", (moid,))
55+
curs.execute("SELECT * FROM test_oid WHERE oid = %s", (moid,))
5656
print "Oid", moid, "selected %s %s" % curs.fetchone()
5757

5858
curs.execute("DROP TABLE test_oid")

examples/mogrify.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# mogrify.py - test all possible type mogrifications
1+
# mogrify.py - test all possible simple type mogrifications
22
# -*- encoding: latin1 -*-
33
#
44
# Copyright (C) 2004 Federico Di Gregorio <fog@debian.org>
@@ -33,14 +33,14 @@
3333
curs.execute("SELECT %(foo)s AS foo", {'foo':'bar'})
3434
curs.execute("SELECT %(foo)s AS foo", {'foo':None})
3535
curs.execute("SELECT %(foo)s AS foo", {'foo':True})
36-
curs.execute("SELECT %(foo)f AS foo", {'foo':42})
36+
curs.execute("SELECT %(foo)s AS foo", {'foo':42})
3737
curs.execute("SELECT %(foo)s AS foo", {'foo':u'yattà!'})
3838
curs.execute("SELECT %(foo)s AS foo", {'foo':u'bar'})
3939

4040
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':'bar'})
4141
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':None})
4242
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':True})
43-
print curs.mogrify("SELECT %(foo)f AS foo", {'foo':42})
43+
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':42})
4444
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':u'yattà!'})
4545
print curs.mogrify("SELECT %(foo)s AS foo", {'foo':u'bar'})
4646

examples/threads.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def insert_func(conn_or_pool, rows):
8181
conn = conn_or_pool.getconn()
8282
c = conn.cursor()
8383
try:
84-
c.execute("INSERT INTO test_threads VALUES (%s, %d, %f)",
84+
c.execute("INSERT INTO test_threads VALUES (%s, %s, %s)",
8585
(str(i), i, float(i)))
8686
except psycopg.ProgrammingError, err:
8787
print name, ": an error occurred; skipping this insert"

psycopg/cursor_type.c

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "psycopg/cursor.h"
3131
#include "psycopg/connection.h"
3232
#include "psycopg/pqpath.h"
33+
#include "psycopg/typecast.h"
3334
#include "psycopg/microprotocols.h"
3435
#include "psycopg/microprotocols_proto.h"
3536
#include "pgversion.h"
@@ -545,31 +546,26 @@ static PyObject *
545546
_psyco_curs_buildrow_fill(cursorObject *self, PyObject *res,
546547
int row, int n, int istuple)
547548
{
548-
int i;
549-
PyObject *str, *val;
549+
int i, len;
550+
unsigned char *str;
551+
PyObject *val;
550552

551553
for (i=0; i < n; i++) {
552554
if (PQgetisnull(self->pgres, row, i)) {
553-
Py_INCREF(Py_None);
554-
str = Py_None;
555+
str = NULL;
556+
len = 0;
555557
}
556558
else {
557-
char *s = PQgetvalue(self->pgres, row, i);
558-
int l = PQgetlength(self->pgres, row, i);
559-
str = PyString_FromStringAndSize(s, l);
560-
561-
Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %i",
562-
self->row, i, l);
559+
str = PQgetvalue(self->pgres, row, i);
560+
len = PQgetlength(self->pgres, row, i);
563561
}
564562

565-
Dprintf("_psyco_curs_buildrow: str->refcnt = %d", str->ob_refcnt);
566-
val = PyObject_CallFunction(PyTuple_GET_ITEM(self->casts, i), "OO",
567-
str, self);
568-
/* here we DECREF str because the typecaster should already have
569-
INCREFfed it, if necessary and we don't need it anymore */
570-
Py_DECREF(str);
571-
Dprintf("_psyco_curs_buildrow: str->refcnt = %d", str->ob_refcnt);
572-
563+
Dprintf("_psyco_curs_buildrow: row %ld, element %d, len %i",
564+
self->row, i, len);
565+
566+
val = typecast_cast(PyTuple_GET_ITEM(self->casts, i), str, len,
567+
(PyObject*)self);
568+
573569
if (val) {
574570
Dprintf("_psyco_curs_buildrow: val->refcnt = %d", val->ob_refcnt);
575571
if (istuple) {
@@ -590,7 +586,6 @@ _psyco_curs_buildrow_fill(cursorObject *self, PyObject *res,
590586
}
591587
}
592588
return res;
593-
594589
}
595590

596591
static PyObject *

psycopg/microprotocols_proto.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,6 @@
3434

3535
/** void protocol implementation **/
3636

37-
/* prepare - prepare object for quotation */
38-
39-
#define psyco_isqlquote_prepare_doc \
40-
"prepare(conn) -> prepare object with connection 'conn'"
41-
42-
static PyObject *
43-
psyco_isqlquote_prepare(isqlquoteObject *self, PyObject *args)
44-
{
45-
PyObject* conn = NULL;
46-
47-
if (!PyArg_ParseTuple(args, "O", &conn)) return NULL;
48-
49-
Py_INCREF(Py_None);
50-
return Py_None;
51-
}
5237

5338
/* getquoted - return quoted representation for object */
5439

psycopg/typecast.c

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -305,31 +305,15 @@ typecast_destroy(typecastObject *self)
305305
static PyObject *
306306
typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
307307
{
308-
PyObject *string, *cursor, *res;
309-
310-
typecastObject *self = (typecastObject *)obj;
308+
PyObject *string, *cursor;
311309

312310
if (!PyArg_ParseTuple(args, "OO", &string, &cursor)) {
313311
return NULL;
314312
}
315313

316-
if (self->ccast) {
317-
Dprintf("typecast_call: calling C cast function");
318-
res = self->ccast(string, cursor);
319-
}
320-
else if (self->pcast) {
321-
Dprintf("typecast_call: calling python callable");
322-
Py_INCREF(string);
323-
res = PyObject_CallFunction(self->pcast, "OO", string, cursor);
324-
}
325-
else {
326-
Py_INCREF(Py_None);
327-
res = Py_None;
328-
}
329-
330-
Dprintf("typecast_call: string argument has refcnt = %d",
331-
string->ob_refcnt);
332-
return res;
314+
return typecast_cast(obj,
315+
PyString_AsString(string), PyString_Size(string),
316+
cursor);
333317
}
334318

335319

@@ -436,4 +420,21 @@ typecast_from_c(typecastObject_initlist *type)
436420
return (PyObject *)obj;
437421
}
438422

423+
PyObject *
424+
typecast_cast(PyObject *obj, unsigned char *str, int len, PyObject *curs)
425+
{
426+
typecastObject *self = (typecastObject *)obj;
439427

428+
if (self->ccast) {
429+
Dprintf("typecast_call: calling C cast function");
430+
return self->ccast(str, len, curs);
431+
}
432+
else if (self->pcast) {
433+
Dprintf("typecast_call: calling python callable");
434+
return PyObject_CallFunction(self->pcast, "s#O", str, len, curs);
435+
}
436+
else {
437+
PyErr_SetString(Error, "internal error: no casting function found");
438+
return NULL;
439+
}
440+
}

psycopg/typecast.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ extern "C" {
2929
#endif
3030

3131
/* type of type-casting functions (both C and Python) */
32-
typedef PyObject *(*typecast_function)(PyObject *, PyObject *);
32+
typedef PyObject *(*typecast_function)(unsigned char *, int len, PyObject *);
3333

3434
/** typecast type **/
3535

@@ -73,5 +73,9 @@ extern PyObject *typecast_from_c(typecastObject_initlist *type);
7373
/* the python callable typecast creator function */
7474
extern PyObject *typecast_from_python(
7575
PyObject *self, PyObject *args, PyObject *keywds);
76+
77+
/* the function used to dispatch typecasting calls */
78+
extern PyObject *typecast_cast(
79+
PyObject *self, unsigned char *str, int len, PyObject *curs);
7680

7781
#endif /* !defined(PSYCOPG_TYPECAST_H) */

psycopg/typecast_basic.c

Lines changed: 27 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,59 +20,57 @@
2020
*/
2121

2222
#include <libpq-fe.h>
23+
#include <stdlib.h>
2324

2425
/** INTEGER - cast normal integers (4 bytes) to python int **/
2526

2627
static PyObject *
27-
typecast_INTEGER_cast(PyObject *s, PyObject *curs)
28+
typecast_INTEGER_cast(unsigned char *s, int len, PyObject *curs)
2829
{
29-
if (s == Py_None) {Py_INCREF(s); return s;}
30-
return PyNumber_Int(s);
30+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
31+
return PyInt_FromString(s, NULL, 0);
3132
}
3233

3334
/** LONGINTEGER - cast long integers (8 bytes) to python long **/
3435

3536
static PyObject *
36-
typecast_LONGINTEGER_cast(PyObject *s, PyObject *curs)
37+
typecast_LONGINTEGER_cast(unsigned char *s, int len, PyObject *curs)
3738
{
38-
if (s == Py_None) {Py_INCREF(s); return s;}
39-
return PyNumber_Long(s);
39+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
40+
return PyLong_FromString(s, NULL, 0);
4041
}
4142

4243
/** FLOAT - cast floating point numbers to python float **/
4344

4445
static PyObject *
45-
typecast_FLOAT_cast(PyObject *s, PyObject *curs)
46+
typecast_FLOAT_cast(unsigned char *s, int len, PyObject *curs)
4647
{
47-
if (s == Py_None) {Py_INCREF(s); return s;}
48-
return PyNumber_Float(s);
48+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
49+
return PyFloat_FromDouble(atof(s));
4950
}
5051

5152
/** STRING - cast strings of any type to python string **/
5253

5354
static PyObject *
54-
typecast_STRING_cast(PyObject *s, PyObject *curs)
55+
typecast_STRING_cast(unsigned char *s, int len, PyObject *curs)
5556
{
56-
Py_INCREF(s);
57-
return s;
57+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
58+
return PyString_FromStringAndSize(s, len);
5859
}
5960

6061
/** UNICODE - cast strings of any type to a python unicode object **/
6162

6263
static PyObject *
63-
typecast_UNICODE_cast(PyObject *s, PyObject *curs)
64+
typecast_UNICODE_cast(unsigned char *s, int len, PyObject *curs)
6465
{
6566
PyObject *enc;
66-
67-
if (s == Py_None) {Py_INCREF(s); return s;}
67+
68+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
6869

6970
enc = PyDict_GetItemString(psycoEncodings,
7071
((cursorObject*)curs)->conn->encoding);
7172
if (enc) {
72-
return PyUnicode_Decode(PyString_AsString(s),
73-
PyString_Size(s),
74-
PyString_AsString(enc),
75-
NULL);
73+
return PyUnicode_Decode(s, strlen(s), PyString_AsString(enc), NULL);
7674
}
7775
else {
7876
PyErr_Format(InterfaceError,
@@ -134,15 +132,15 @@ typecast_BINARY_cast_unescape(unsigned char *str, size_t *to_length)
134132
#endif
135133

136134
static PyObject *
137-
typecast_BINARY_cast(PyObject *s, PyObject *curs)
135+
typecast_BINARY_cast(unsigned char *s, int l, PyObject *curs)
138136
{
139137
PyObject *res;
140138
unsigned char *str;
141139
size_t len;
142140

143-
if (s == Py_None) {Py_INCREF(s); return s;}
141+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
144142

145-
str = PQunescapeBytea(PyString_AS_STRING(s), &len);
143+
str = PQunescapeBytea(s, &len);
146144
Dprintf("typecast_BINARY_cast: unescaped %d bytes", len);
147145

148146
/* TODO: using a PyBuffer would make this a zero-copy operation but we'll
@@ -159,13 +157,13 @@ typecast_BINARY_cast(PyObject *s, PyObject *curs)
159157
/** BOOLEAN - cast boolean value into right python object **/
160158

161159
static PyObject *
162-
typecast_BOOLEAN_cast(PyObject *s, PyObject *curs)
160+
typecast_BOOLEAN_cast(unsigned char *s, int len, PyObject *curs)
163161
{
164162
PyObject *res;
165-
166-
if (s == Py_None) {Py_INCREF(s); return s;}
167163

168-
if (PyString_AS_STRING(s)[0] == 't')
164+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
165+
166+
if (s[0] == 't')
169167
res = Py_True;
170168
else
171169
res = Py_False;
@@ -178,10 +176,10 @@ typecast_BOOLEAN_cast(PyObject *s, PyObject *curs)
178176

179177
#ifdef HAVE_DECIMAL
180178
static PyObject *
181-
typecast_DECIMAL_cast(PyObject *s, PyObject *curs)
179+
typecast_DECIMAL_cast(unsigned char *s, int len, PyObject *curs)
182180
{
183-
if (s == Py_None) {Py_INCREF(s); return s;}
184-
return PyObject_CallFunction(decimalType, "O", s);
181+
if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
182+
return PyObject_CallFunction(decimalType, "s", s);
185183
}
186184
#else
187185
#define typecast_DECIMAL_cast typecast_FLOAT_cast

0 commit comments

Comments
 (0)