Home | History | Annotate | Download | only in _sqlite
      1 /* microprotocols.c - minimalist and non-validating protocols implementation
      2  *
      3  * Copyright (C) 2003-2004 Federico Di Gregorio <fog (at) 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         _Py_IDENTIFIER(__adapt__);
     99         PyObject *adapted = _PyObject_CallMethodId(proto, &PyId___adapt__, "O", obj);
    100 
    101         if (adapted) {
    102             if (adapted != Py_None) {
    103                 return adapted;
    104             } else {
    105                 Py_DECREF(adapted);
    106             }
    107         }
    108 
    109         if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError))
    110             return NULL;
    111     }
    112 
    113     /* and finally try to have the object adapt itself */
    114     if (PyObject_HasAttrString(obj, "__conform__")) {
    115         _Py_IDENTIFIER(__conform__);
    116         PyObject *adapted = _PyObject_CallMethodId(obj, &PyId___conform__,"O", proto);
    117 
    118         if (adapted) {
    119             if (adapted != Py_None) {
    120                 return adapted;
    121             } else {
    122                 Py_DECREF(adapted);
    123             }
    124         }
    125 
    126         if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) {
    127             return NULL;
    128         }
    129     }
    130 
    131     /* else set the right exception and return NULL */
    132     PyErr_SetString(pysqlite_ProgrammingError, "can't adapt");
    133     return NULL;
    134 }
    135 
    136 /** module-level functions **/
    137 
    138 PyObject *
    139 pysqlite_adapt(pysqlite_Cursor *self, PyObject *args)
    140 {
    141     PyObject *obj, *alt = NULL;
    142     PyObject *proto = (PyObject*)&pysqlite_PrepareProtocolType;
    143 
    144     if (!PyArg_ParseTuple(args, "O|OO", &obj, &proto, &alt)) return NULL;
    145     return pysqlite_microprotocols_adapt(obj, proto, alt);
    146 }
    147