/* microprotocols.c - minimalist and non-validating protocols implementation1*2* Copyright (C) 2003-2004 Federico Di Gregorio <[email protected]>3*4* This file is part of psycopg and was adapted for pysqlite. Federico Di5* Gregorio gave the permission to use it within pysqlite under the following6* license:7*8* This software is provided 'as-is', without any express or implied9* warranty. In no event will the authors be held liable for any damages10* arising from the use of this software.11*12* Permission is granted to anyone to use this software for any purpose,13* including commercial applications, and to alter it and redistribute it14* freely, subject to the following restrictions:15*16* 1. The origin of this software must not be misrepresented; you must not17* claim that you wrote the original software. If you use this software18* in a product, an acknowledgment in the product documentation would be19* appreciated but is not required.20* 2. Altered source versions must be plainly marked as such, and must not be21* misrepresented as being the original software.22* 3. This notice may not be removed or altered from any source distribution.23*/2425#include <Python.h>2627#include "cursor.h"28#include "microprotocols.h"29#include "prepare_protocol.h"303132/* pysqlite_microprotocols_init - initialize the adapters dictionary */3334int35pysqlite_microprotocols_init(PyObject *module)36{37/* create adapters dictionary and put it in module namespace */38pysqlite_state *state = pysqlite_get_state(module);39state->psyco_adapters = PyDict_New();40if (state->psyco_adapters == NULL) {41return -1;42}4344return PyModule_AddObjectRef(module, "adapters", state->psyco_adapters);45}464748/* pysqlite_microprotocols_add - add a reverse type-caster to the dictionary */4950int51pysqlite_microprotocols_add(pysqlite_state *state, PyTypeObject *type,52PyObject *proto, PyObject *cast)53{54PyObject* key;55int rc;5657assert(type != NULL);58assert(proto != NULL);59key = PyTuple_Pack(2, (PyObject *)type, proto);60if (!key) {61return -1;62}6364rc = PyDict_SetItem(state->psyco_adapters, key, cast);65Py_DECREF(key);6667return rc;68}6970/* pysqlite_microprotocols_adapt - adapt an object to the built-in protocol */7172PyObject *73pysqlite_microprotocols_adapt(pysqlite_state *state, PyObject *obj,74PyObject *proto, PyObject *alt)75{76PyObject *adapter, *key, *adapted;7778/* we don't check for exact type conformance as specified in PEP 24679because the PrepareProtocolType type is abstract and there is no80way to get a quotable object to be its instance */8182/* look for an adapter in the registry */83key = PyTuple_Pack(2, (PyObject *)Py_TYPE(obj), proto);84if (!key) {85return NULL;86}87adapter = PyDict_GetItemWithError(state->psyco_adapters, key);88Py_DECREF(key);89if (adapter) {90Py_INCREF(adapter);91adapted = PyObject_CallOneArg(adapter, obj);92Py_DECREF(adapter);93return adapted;94}95if (PyErr_Occurred()) {96return NULL;97}9899/* try to have the protocol adapt this object */100if (_PyObject_LookupAttr(proto, state->str___adapt__, &adapter) < 0) {101return NULL;102}103if (adapter) {104adapted = PyObject_CallOneArg(adapter, obj);105Py_DECREF(adapter);106107if (adapted == Py_None) {108Py_DECREF(adapted);109}110else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) {111return adapted;112}113else {114PyErr_Clear();115}116}117118/* and finally try to have the object adapt itself */119if (_PyObject_LookupAttr(obj, state->str___conform__, &adapter) < 0) {120return NULL;121}122if (adapter) {123adapted = PyObject_CallOneArg(adapter, proto);124Py_DECREF(adapter);125126if (adapted == Py_None) {127Py_DECREF(adapted);128}129else if (adapted || !PyErr_ExceptionMatches(PyExc_TypeError)) {130return adapted;131}132else {133PyErr_Clear();134}135}136137if (alt) {138return Py_NewRef(alt);139}140/* else set the right exception and return NULL */141PyErr_SetString(state->ProgrammingError, "can't adapt");142return NULL;143}144145146