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         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 }
    143