|
1 /* microprotocols.c - minimalist and non-validating protocols implementation |
|
2 * |
|
3 * Copyright (C) 2003-2004 Federico Di Gregorio <fog@debian.org> |
|
4 * |
|
5 * This file is part of psycopg and was adapted for pysqlite. Federico Di |
|
6 * Gregorio gave the permission to use it within pysqlite under the following |
|
7 * license: |
|
8 * |
|
9 * This software is provided 'as-is', without any express or implied |
|
10 * warranty. In no event will the authors be held liable for any damages |
|
11 * arising from the use of this software. |
|
12 * |
|
13 * Permission is granted to anyone to use this software for any purpose, |
|
14 * including commercial applications, and to alter it and redistribute it |
|
15 * freely, subject to the following restrictions: |
|
16 * |
|
17 * 1. The origin of this software must not be misrepresented; you must not |
|
18 * claim that you wrote the original software. If you use this software |
|
19 * in a product, an acknowledgment in the product documentation would be |
|
20 * appreciated but is not required. |
|
21 * 2. Altered source versions must be plainly marked as such, and must not be |
|
22 * misrepresented as being the original software. |
|
23 * 3. This notice may not be removed or altered from any source distribution. |
|
24 */ |
|
25 |
|
26 #include <Python.h> |
|
27 #include <structmember.h> |
|
28 |
|
29 #include "cursor.h" |
|
30 #include "microprotocols.h" |
|
31 #include "prepare_protocol.h" |
|
32 |
|
33 |
|
34 /** the adapters registry **/ |
|
35 |
|
36 PyObject *psyco_adapters; |
|
37 |
|
38 /* pysqlite_microprotocols_init - initialize the adapters dictionary */ |
|
39 |
|
40 int |
|
41 pysqlite_microprotocols_init(PyObject *dict) |
|
42 { |
|
43 /* create adapters dictionary and put it in module namespace */ |
|
44 if ((psyco_adapters = PyDict_New()) == NULL) { |
|
45 return -1; |
|
46 } |
|
47 |
|
48 return PyDict_SetItemString(dict, "adapters", psyco_adapters); |
|
49 } |
|
50 |
|
51 |
|
52 /* pysqlite_microprotocols_add - add a reverse type-caster to the dictionary */ |
|
53 |
|
54 int |
|
55 pysqlite_microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) |
|
56 { |
|
57 PyObject* key; |
|
58 int rc; |
|
59 |
|
60 if (proto == NULL) proto = (PyObject*)&pysqlite_PrepareProtocolType; |
|
61 |
|
62 key = Py_BuildValue("(OO)", (PyObject*)type, proto); |
|
63 if (!key) { |
|
64 return -1; |
|
65 } |
|
66 |
|
67 rc = PyDict_SetItem(psyco_adapters, key, cast); |
|
68 Py_DECREF(key); |
|
69 |
|
70 return rc; |
|
71 } |
|
72 |
|
73 /* pysqlite_microprotocols_adapt - adapt an object to the built-in protocol */ |
|
74 |
|
75 PyObject * |
|
76 pysqlite_microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) |
|
77 { |
|
78 PyObject *adapter, *key; |
|
79 |
|
80 /* we don't check for exact type conformance as specified in PEP 246 |
|
81 because the pysqlite_PrepareProtocolType type is abstract and there is no |
|
82 way to get a quotable object to be its instance */ |
|
83 |
|
84 /* look for an adapter in the registry */ |
|
85 key = Py_BuildValue("(OO)", (PyObject*)obj->ob_type, proto); |
|
86 if (!key) { |
|
87 return NULL; |
|
88 } |
|
89 adapter = PyDict_GetItem(psyco_adapters, key); |
|
90 Py_DECREF(key); |
|
91 if (adapter) { |
|
92 PyObject *adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL); |
|
93 return adapted; |
|
94 } |
|
95 |
|
96 /* try to have the protocol adapt this object*/ |
|
97 if (PyObject_HasAttrString(proto, "__adapt__")) { |
|
98 PyObject *adapted = PyObject_CallMethod(proto, "__adapt__", "O", obj); |
|
99 if (adapted) { |
|
100 if (adapted != Py_None) { |
|
101 return adapted; |
|
102 } else { |
|
103 Py_DECREF(adapted); |
|
104 } |
|
105 } |
|
106 |
|
107 if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) |
|
108 return NULL; |
|
109 } |
|
110 |
|
111 /* and finally try to have the object adapt itself */ |
|
112 if (PyObject_HasAttrString(obj, "__conform__")) { |
|
113 PyObject *adapted = PyObject_CallMethod(obj, "__conform__","O", proto); |
|
114 if (adapted) { |
|
115 if (adapted != Py_None) { |
|
116 return adapted; |
|
117 } else { |
|
118 Py_DECREF(adapted); |
|
119 } |
|
120 } |
|
121 |
|
122 if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) { |
|
123 return NULL; |
|
124 } |
|
125 } |
|
126 |
|
127 /* else set the right exception and return NULL */ |
|
128 PyErr_SetString(pysqlite_ProgrammingError, "can't adapt"); |
|
129 return NULL; |
|
130 } |
|
131 |
|
132 /** module-level functions **/ |
|
133 |
|
134 PyObject * |
|
135 pysqlite_adapt(pysqlite_Cursor *self, PyObject *args) |
|
136 { |
|
137 PyObject *obj, *alt = NULL; |
|
138 PyObject *proto = (PyObject*)&pysqlite_PrepareProtocolType; |
|
139 |
|
140 if (!PyArg_ParseTuple(args, "O|OO", &obj, &proto, &alt)) return NULL; |
|
141 return pysqlite_microprotocols_adapt(obj, proto, alt); |
|
142 } |