Branch data Line data Source code
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 : 5 : pysqlite_microprotocols_init(PyObject *module) 37 : : { 38 : : /* create adapters dictionary and put it in module namespace */ 39 : 5 : pysqlite_state *state = pysqlite_get_state(module); 40 : 5 : state->psyco_adapters = PyDict_New(); 41 [ - + ]: 5 : if (state->psyco_adapters == NULL) { 42 : 0 : return -1; 43 : : } 44 : : 45 : 5 : return PyModule_AddObjectRef(module, "adapters", state->psyco_adapters); 46 : : } 47 : : 48 : : 49 : : /* pysqlite_microprotocols_add - add a reverse type-caster to the dictionary */ 50 : : 51 : : int 52 : 17 : pysqlite_microprotocols_add(pysqlite_state *state, PyTypeObject *type, 53 : : PyObject *proto, PyObject *cast) 54 : : { 55 : : PyObject* key; 56 : : int rc; 57 : : 58 : : assert(type != NULL); 59 : : assert(proto != NULL); 60 : 17 : key = PyTuple_Pack(2, (PyObject *)type, proto); 61 [ - + ]: 17 : if (!key) { 62 : 0 : return -1; 63 : : } 64 : : 65 : 17 : rc = PyDict_SetItem(state->psyco_adapters, key, cast); 66 : 17 : Py_DECREF(key); 67 : : 68 : 17 : return rc; 69 : : } 70 : : 71 : : /* pysqlite_microprotocols_adapt - adapt an object to the built-in protocol */ 72 : : 73 : : PyObject * 74 : 291 : pysqlite_microprotocols_adapt(pysqlite_state *state, PyObject *obj, 75 : : PyObject *proto, PyObject *alt) 76 : : { 77 : : 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 : : } 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 : : } 96 [ - + ]: 284 : if (PyErr_Occurred()) { 97 : 0 : return NULL; 98 : : } 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 : : } 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 : : } 111 [ - + - - ]: 1 : else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) { 112 : 1 : return adapted; 113 : : } 114 : : else { 115 : 0 : PyErr_Clear(); 116 : : } 117 : : } 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 : : } 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 : : } 130 [ + + + + ]: 6 : else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) { 131 : 4 : return adapted; 132 : : } 133 : : else { 134 : 2 : PyErr_Clear(); 135 : : } 136 : : } 137 : : 138 [ + + ]: 279 : if (alt) { 139 : 275 : return Py_NewRef(alt); 140 : : } 141 : : /* else set the right exception and return NULL */ 142 : 4 : PyErr_SetString(state->ProgrammingError, "can't adapt"); 143 : 4 : return NULL; 144 : : }