/Users/erlendaasland/src/cpython.git/Modules/_sqlite/microprotocols.c
Line | Count | Source (jump to first uncovered line) |
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 | | |
28 | | #include "cursor.h" |
29 | | #include "microprotocols.h" |
30 | | #include "prepare_protocol.h" |
31 | | |
32 | | |
33 | | /* pysqlite_microprotocols_init - initialize the adapters dictionary */ |
34 | | |
35 | | int |
36 | | pysqlite_microprotocols_init(PyObject *module) |
37 | 1 | { |
38 | | /* create adapters dictionary and put it in module namespace */ |
39 | 1 | pysqlite_state *state = pysqlite_get_state(module); |
40 | 1 | state->psyco_adapters = PyDict_New(); |
41 | 1 | if (state->psyco_adapters == NULL) { |
42 | 0 | return -1; |
43 | 0 | } |
44 | | |
45 | 1 | return PyModule_AddObjectRef(module, "adapters", state->psyco_adapters); |
46 | 1 | } |
47 | | |
48 | | |
49 | | /* pysqlite_microprotocols_add - add a reverse type-caster to the dictionary */ |
50 | | |
51 | | int |
52 | | pysqlite_microprotocols_add(pysqlite_state *state, PyTypeObject *type, |
53 | | PyObject *proto, PyObject *cast) |
54 | 11 | { |
55 | 11 | PyObject* key; |
56 | 11 | int rc; |
57 | | |
58 | 11 | assert(type != NULL); |
59 | 0 | assert(proto != NULL); |
60 | 0 | key = PyTuple_Pack(2, (PyObject *)type, proto); |
61 | 11 | if (!key) { |
62 | 0 | return -1; |
63 | 0 | } |
64 | | |
65 | 11 | rc = PyDict_SetItem(state->psyco_adapters, key, cast); |
66 | 11 | Py_DECREF(key); |
67 | | |
68 | 11 | return rc; |
69 | 11 | } |
70 | | |
71 | | /* pysqlite_microprotocols_adapt - adapt an object to the built-in protocol */ |
72 | | |
73 | | PyObject * |
74 | | pysqlite_microprotocols_adapt(pysqlite_state *state, PyObject *obj, |
75 | | PyObject *proto, PyObject *alt) |
76 | 291 | { |
77 | 291 | PyObject *adapter, *key, *adapted; |
78 | | |
79 | | /* we don't check for exact type conformance as specified in PEP 246 |
80 | | because the PrepareProtocolType type is abstract and there is no |
81 | | way to get a quotable object to be its instance */ |
82 | | |
83 | | /* look for an adapter in the registry */ |
84 | 291 | key = PyTuple_Pack(2, (PyObject *)Py_TYPE(obj), proto); |
85 | 291 | if (!key) { |
86 | 0 | return NULL; |
87 | 0 | } |
88 | 291 | adapter = PyDict_GetItemWithError(state->psyco_adapters, key); |
89 | 291 | Py_DECREF(key); |
90 | 291 | if (adapter) { |
91 | 7 | Py_INCREF(adapter); |
92 | 7 | adapted = PyObject_CallOneArg(adapter, obj); |
93 | 7 | Py_DECREF(adapter); |
94 | 7 | return adapted; |
95 | 7 | } |
96 | 284 | if (PyErr_Occurred()) { |
97 | 0 | return NULL; |
98 | 0 | } |
99 | | |
100 | | /* try to have the protocol adapt this object */ |
101 | 284 | if (_PyObject_LookupAttr(proto, state->str___adapt__, &adapter) < 0) { |
102 | 0 | return NULL; |
103 | 0 | } |
104 | 284 | if (adapter) { |
105 | 2 | adapted = PyObject_CallOneArg(adapter, obj); |
106 | 2 | Py_DECREF(adapter); |
107 | | |
108 | 2 | if (adapted == Py_None) { |
109 | 1 | Py_DECREF(adapted); |
110 | 1 | } |
111 | 1 | else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) { |
112 | 1 | return adapted; |
113 | 1 | } |
114 | 0 | else { |
115 | 0 | PyErr_Clear(); |
116 | 0 | } |
117 | 2 | } |
118 | | |
119 | | /* and finally try to have the object adapt itself */ |
120 | 283 | if (_PyObject_LookupAttr(obj, state->str___conform__, &adapter) < 0) { |
121 | 0 | return NULL; |
122 | 0 | } |
123 | 283 | if (adapter) { |
124 | 7 | adapted = PyObject_CallOneArg(adapter, proto); |
125 | 7 | Py_DECREF(adapter); |
126 | | |
127 | 7 | if (adapted == Py_None) { |
128 | 1 | Py_DECREF(adapted); |
129 | 1 | } |
130 | 6 | else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) { |
131 | 4 | return adapted; |
132 | 4 | } |
133 | 2 | else { |
134 | 2 | PyErr_Clear(); |
135 | 2 | } |
136 | 7 | } |
137 | | |
138 | 279 | if (alt) { |
139 | 275 | return Py_NewRef(alt); |
140 | 275 | } |
141 | | /* else set the right exception and return NULL */ |
142 | 4 | PyErr_SetString(state->ProgrammingError, "can't adapt"); |
143 | 4 | return NULL; |
144 | 279 | } |