• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /** the adapters registry **/
33 
34 static PyObject *psyco_adapters = NULL;
35 
36 /* pysqlite_microprotocols_init - initialize the adapters dictionary */
37 
38 int
pysqlite_microprotocols_init(PyObject * module)39 pysqlite_microprotocols_init(PyObject *module)
40 {
41     /* create adapters dictionary and put it in module namespace */
42     if ((psyco_adapters = PyDict_New()) == NULL) {
43         return -1;
44     }
45 
46     int res = PyModule_AddObjectRef(module, "adapters", psyco_adapters);
47     Py_DECREF(psyco_adapters);
48 
49     return res;
50 }
51 
52 
53 /* pysqlite_microprotocols_add - add a reverse type-caster to the dictionary */
54 
55 int
pysqlite_microprotocols_add(PyTypeObject * type,PyObject * proto,PyObject * cast)56 pysqlite_microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast)
57 {
58     PyObject* key;
59     int rc;
60 
61     if (proto == NULL) proto = (PyObject*)pysqlite_PrepareProtocolType;
62 
63     key = Py_BuildValue("(OO)", (PyObject*)type, proto);
64     if (!key) {
65         return -1;
66     }
67 
68     rc = PyDict_SetItem(psyco_adapters, key, cast);
69     Py_DECREF(key);
70 
71     return rc;
72 }
73 
74 /* pysqlite_microprotocols_adapt - adapt an object to the built-in protocol */
75 
76 PyObject *
pysqlite_microprotocols_adapt(PyObject * obj,PyObject * proto,PyObject * alt)77 pysqlite_microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt)
78 {
79     _Py_IDENTIFIER(__adapt__);
80     _Py_IDENTIFIER(__conform__);
81     PyObject *adapter, *key, *adapted;
82 
83     /* we don't check for exact type conformance as specified in PEP 246
84        because the pysqlite_PrepareProtocolType type is abstract and there is no
85        way to get a quotable object to be its instance */
86 
87     /* look for an adapter in the registry */
88     key = Py_BuildValue("(OO)", (PyObject*)Py_TYPE(obj), proto);
89     if (!key) {
90         return NULL;
91     }
92     adapter = PyDict_GetItemWithError(psyco_adapters, key);
93     Py_DECREF(key);
94     if (adapter) {
95         Py_INCREF(adapter);
96         adapted = PyObject_CallOneArg(adapter, obj);
97         Py_DECREF(adapter);
98         return adapted;
99     }
100     if (PyErr_Occurred()) {
101         return NULL;
102     }
103 
104     /* try to have the protocol adapt this object */
105     if (_PyObject_LookupAttrId(proto, &PyId___adapt__, &adapter) < 0) {
106         return NULL;
107     }
108     if (adapter) {
109         adapted = PyObject_CallOneArg(adapter, obj);
110         Py_DECREF(adapter);
111 
112         if (adapted == Py_None) {
113             Py_DECREF(adapted);
114         }
115         else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) {
116             return adapted;
117         }
118         else {
119             PyErr_Clear();
120         }
121     }
122 
123     /* and finally try to have the object adapt itself */
124     if (_PyObject_LookupAttrId(obj, &PyId___conform__, &adapter) < 0) {
125         return NULL;
126     }
127     if (adapter) {
128         adapted = PyObject_CallOneArg(adapter, proto);
129         Py_DECREF(adapter);
130 
131         if (adapted == Py_None) {
132             Py_DECREF(adapted);
133         }
134         else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) {
135             return adapted;
136         }
137         else {
138             PyErr_Clear();
139         }
140     }
141 
142     if (alt) {
143         return Py_NewRef(alt);
144     }
145     /* else set the right exception and return NULL */
146     PyErr_SetString(pysqlite_ProgrammingError, "can't adapt");
147     return NULL;
148 }
149