/* KInterbasDB Python Package - Implementation of Core ** ** Version 3.1 ** ** The following contributors hold Copyright (C) over their respective ** portions of code (see license.txt for details): ** ** [Original Author (maintained through version 2.0-0.3.1):] ** 1998-2001 [alex] Alexander Kuznetsov ** [Maintainers (after version 2.0-0.3.1):] ** 2001-2002 [maz] Marek Isalski ** 2002-2004 [dsr] David Rushby ** [Contributors:] ** 2001 [eac] Evgeny A. Cherkashin ** 2001-2002 [janez] Janez Jere */ #include "_kinterbasdb.h" #ifdef ENABLE_DB_EVENT_SUPPORT #include "_kievents.h" #endif #include "_kilock.h" /****************** "PRIVATE" DECLARATIONS:BEGIN *******************/ static int _conn_require_open(ConnectionObject *self, char *failure_message); static int init_kidb_ibase_header_constants(PyObject *); static void _init_kidb_ibase_header_constants_transaction_parameters(PyObject *); static void _init_kidb_ibase_header_constants_database_info(PyObject *); static void _free_cursor_exec_proc_results_cache(CursorObject *); /****************** "PRIVATE" DECLARATIONS:END *******************/ /******************** GLOBAL VARIABLES:BEGIN ********************/ /* These min/max constants are initialized in init_kinterbasdb. */ PyObject *SHRT_MIN_As_PyObject = NULL; PyObject *SHRT_MAX_As_PyObject = NULL; PyObject *INT_MIN_As_PyObject = NULL; PyObject *INT_MAX_As_PyObject = NULL; PyObject *LONG_MIN_As_PyObject = NULL; PyObject *LONG_MAX_As_PyObject = NULL; PyObject *LONG_LONG_MIN_As_PyObject = NULL; PyObject *LONG_LONG_MAX_As_PyObject = NULL; /* Global references to this module's exception type objects, as documented ** in the Python DB API (initialized by init_kidb_exceptions). */ PyObject *Warning = NULL; PyObject *Error = NULL; PyObject *InterfaceError = NULL; PyObject *DatabaseError = NULL; PyObject *DataError = NULL; PyObject *OperationalError = NULL; PyObject *IntegrityError = NULL; PyObject *InternalError = NULL; PyObject *ProgrammingError = NULL; PyObject *NotSupportedError = NULL; /* 2002.10.14:begin block */ /* See the relevant section of function init_kinterbasdb for documentation. */ #include "_ki_brute_threadmodule.h" PyObject *module_python_thread_lock_object = NULL; /* Virtually all database API operation will be synchronized around this lock. */ PyThread_type_lock module_thread_lock = NULL; /* 2002.10.14:end block */ /******************** GLOBAL VARIABLES:END ********************/ /******************** IMPLEMENTATION:BEGIN ********************/ #include "_kinterbasdb_exception_functions.c" #include "_kicore_transaction.c" #include "_kiconversion.c" #include "_kicore_connection.c" #include "_kicore_xsqlda.c" #include "_kicore_cursor.c" #include "_kicore_execution.c" #include "_kicore_fetch.c" /******************** IMPLEMENTATION:END ********************/ /********************** MODULE INFRASTRUCTURE:BEGIN ***********************/ static PyMethodDef kinterbasdb_GlobalMethods[] = { /*********** ConnectionObject methods: ***********/ { "create_database", pyob_create_database, METH_VARARGS }, { "drop_database", pyob_drop_database, METH_VARARGS }, { "attach_db", pyob_attach_db, METH_VARARGS }, { "has_transaction", pyob_has_transaction, METH_VARARGS }, /* 2003.10.06: */ { "is_purportedly_open", pyob_is_purportedly_open, METH_VARARGS }, { "begin", pyob_begin, METH_VARARGS }, /* 2003.08.28: Added option for manual control over phases of 2PC. */ { "prepare", pyob_prepare, METH_VARARGS }, { "execute_immediate", pyob_execute_immediate, METH_VARARGS }, { "commit", pyob_commit, METH_VARARGS }, { "rollback", pyob_rollback, METH_VARARGS }, /* 2003.04.27: distributed transaction support: */ { "get_group", pyob_get_group, METH_VARARGS }, { "set_group", pyob_set_group, METH_VARARGS }, { "distributed_begin", pyob_distributed_begin, METH_VARARGS }, /* 2003.08.28: Added option for manual control over phases of 2PC. */ { "distributed_prepare", pyob_distributed_prepare, METH_VARARGS }, { "distributed_commit", pyob_distributed_commit, METH_VARARGS }, { "distributed_rollback", pyob_distributed_rollback, METH_VARARGS }, { "close_connection", pyob_close_connection, METH_VARARGS }, { "cursor", pyob_cursor, METH_VARARGS }, { "database_info", pyob_database_info, METH_VARARGS }, #ifdef ENABLE_DB_EVENT_SUPPORT { "event_conduit_new", pyob_event_conduit_new, METH_VARARGS }, { "event_conduit_wait", pyob_event_conduit_wait, METH_VARARGS }, { "event_conduit_flush_queue", pyob_event_conduit_flush_queue,METH_VARARGS }, { "event_conduit_cancel", pyob_event_conduit_cancel, METH_VARARGS }, #endif /* ENABLE_DB_EVENT_SUPPORT */ /* Dynamic type trans getters/setters for ConnectionObject: */ { "set_con_type_trans_out",pyob_con_set_type_trans_out, METH_VARARGS }, { "get_con_type_trans_out",pyob_con_get_type_trans_out, METH_VARARGS }, { "set_con_type_trans_in", pyob_con_set_type_trans_in, METH_VARARGS }, { "get_con_type_trans_in", pyob_con_get_type_trans_in, METH_VARARGS }, #ifdef INTERBASE6_OR_LATER { "get_dialect", pyob_get_dialect, METH_VARARGS }, { "set_dialect", pyob_set_dialect, METH_VARARGS }, #endif /* INTERBASE6_OR_LATER */ /*********** CursorObject methods: ***********/ { "close_cursor", pyob_close_cursor, METH_VARARGS }, { "execute", pyob_execute, METH_VARARGS }, { "fetch", pyob_fetch, METH_VARARGS }, /* Cursor name support (for SQL statements that use WHERE CURRENT OF %name): */ { "set_cursor_name", pyob_set_cursor_name, METH_VARARGS }, { "get_cursor_name", pyob_get_cursor_name, METH_VARARGS }, /* Dynamic type trans getters/setters for CursorObject: */ { "set_cur_type_trans_out",pyob_cur_set_type_trans_out, METH_VARARGS }, { "get_cur_type_trans_out",pyob_cur_get_type_trans_out, METH_VARARGS }, { "set_cur_type_trans_in", pyob_cur_set_type_trans_in, METH_VARARGS }, { "get_cur_type_trans_in", pyob_cur_get_type_trans_in, METH_VARARGS }, /* 2003.05.15: */ { "get_rowcount", pyob_rowcount, METH_VARARGS }, /* The end: */ { NULL, NULL } }; static int init_kidb_exceptions( PyObject *d ) { /* YYY: This function ought to be more responsible about low memory conditions. */ Warning = PyErr_NewException( "kinterbasdb.Warning", PyExc_StandardError, NULL ); Error = PyErr_NewException( "kinterbasdb.Error", PyExc_StandardError, NULL ); InterfaceError = PyErr_NewException( "kinterbasdb.InterfaceError", Error, NULL ); DatabaseError = PyErr_NewException( "kinterbasdb.DatabaseError", Error, NULL ); DataError = PyErr_NewException( "kinterbasdb.DataError", DatabaseError, NULL ); OperationalError = PyErr_NewException( "kinterbasdb.OperationalError", DatabaseError, NULL ); IntegrityError = PyErr_NewException( "kinterbasdb.IntegrityError", DatabaseError, NULL ); InternalError = PyErr_NewException( "kinterbasdb.InternalError", DatabaseError, NULL ); ProgrammingError = PyErr_NewException( "kinterbasdb.ProgrammingError", DatabaseError, NULL ); NotSupportedError = PyErr_NewException( "kinterbasdb.NotSupportedError", DatabaseError, NULL ); if ( !Warning || !Error || !InterfaceError || !DatabaseError || !DataError || !OperationalError || !IntegrityError || !InternalError || !ProgrammingError || !NotSupportedError ) return -1; PyDict_SetItemString( d, "Error", Error ); PyDict_SetItemString( d, "Warning", Warning ); PyDict_SetItemString( d, "InterfaceError", InterfaceError ); PyDict_SetItemString( d, "DatabaseError", DatabaseError ); PyDict_SetItemString( d, "DataError", DataError ); PyDict_SetItemString( d, "OperationalError", OperationalError ); PyDict_SetItemString( d, "IntegrityError", IntegrityError ); PyDict_SetItemString( d, "InternalError", InternalError ); PyDict_SetItemString( d, "ProgrammingError", ProgrammingError ); PyDict_SetItemString( d, "NotSupportedError", NotSupportedError ); return 0; } /* init_kidb_exceptions */ PyTypeObject ConnectionType = { PyObject_HEAD_INIT(NULL) 0, "kinterbasdb.ConnectionType", sizeof(ConnectionObject), 0, pyob_connection_del, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; PyTypeObject CursorType = { PyObject_HEAD_INIT(NULL) 0, "kinterbasdb.CursorType", sizeof(CursorObject), 0, pyob_cursor_del, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* 2003.04.27: */ PyTypeObject TransactionHandleType = { PyObject_HEAD_INIT(NULL) 0, "kinterbasdb.TransactionHandleType", sizeof(TransactionHandleObject), 0, pyob_transaction_handle_del, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; DL_EXPORT(void) init_kinterbasdb(void) { PyObject *m, *d; ConnectionObject *null_connection; m = Py_InitModule("_kinterbasdb", kinterbasdb_GlobalMethods); d = PyModule_GetDict(m); ConnectionType.ob_type = &PyType_Type; CursorType.ob_type = &PyType_Type; TransactionHandleType.ob_type = &PyType_Type; #if SHOULD_MANAGE_GIL /* Create a Python object of type thread.LockType, then extract a reference ** to its underlying C-level lock. ** The C-level lock (module_thread_lock) is used to serialize all database ** client library calls when the GIL is released, because the database client ** library is not threadsafe (see the ENTER_* and LEAVE_* definitions in ** _kilock.h). ** The Python lock object module_python_thread_lock_object that's founded ** on the C object module_thread_lock will be available to sublibraries of ** kinterbasdb (such as the services module--see ** _kiservices.c/pyob_initialize_from) as: ** kinterbasdb._module_python_thread_lock_object */ { PyObject *threadModule; PyObject *allocateThreadLockFunction; threadModule = PyImport_ImportModule("thread"); if (threadModule == NULL) { return; /* Exception will already be set. */ } allocateThreadLockFunction = PyObject_GetAttrString(threadModule, "allocate_lock"); if (allocateThreadLockFunction == NULL) { PyErr_SetString(PyExc_AttributeError, "Python thread module has no attribute 'allocate_lock'." ); return; } module_python_thread_lock_object = PyObject_CallFunction(allocateThreadLockFunction, NULL); if (module_python_thread_lock_object == NULL) { return; /* Exception will already be set. */ } module_thread_lock = ((_bruteforce_lockobject *) module_python_thread_lock_object)->lock_lock; PyObject_SetAttrString(m, "_module_python_thread_lock_object", module_python_thread_lock_object ); } #endif /* SHOULD_MANAGE_GIL */ /* Initialize module-global Python objects to hold min/max values for integer ** types. */ SHRT_MIN_As_PyObject = PyInt_FromLong(SHRT_MIN); SHRT_MAX_As_PyObject = PyInt_FromLong(SHRT_MAX); INT_MIN_As_PyObject = PyInt_FromLong(INT_MIN); INT_MAX_As_PyObject = PyInt_FromLong(INT_MAX); LONG_MIN_As_PyObject = PyInt_FromLong(LONG_MIN); LONG_MAX_As_PyObject = PyInt_FromLong(LONG_MAX); LONG_LONG_MIN_As_PyObject = PyLong_FromLongLong(LONG_LONG_MIN); LONG_LONG_MAX_As_PyObject = PyLong_FromLongLong(LONG_LONG_MAX); /* DSR added null_connection when moving connection state detection from the ** Python level to the C level. From the perspective of the Python-level ** kinterbasdb code, _kinterbasdb.null_connection is a null value like ** Python's None, except that it is of type ConnectionType instead of ** NoneType. ** The kinterbasdb.Connection Python class can set its reference to its ** equivalent C type (self._C_conn) to _kinterbasdb.null_connection to ** indicate that the underlying connection is no longer valid. Then the ** pyob_* functions in this C code that demand an argument of ConnectionType ** are satisfied by null_connection long enough to detect that it is not open ** (and that therefore the requested operation is not allowed). */ null_connection = new_connection(); if (null_connection == NULL) { PyErr_SetString(PyExc_ImportError, "Unable to create null_connection"); return; } PyDict_SetItemString(d, "null_connection", (PyObject *) null_connection); if ( init_kidb_ibase_header_constants(d) != 0 ) { PyErr_SetString(PyExc_ImportError, "Unable to initialize header constants"); return; } if ( init_kidb_exceptions(d) != 0 ) { PyErr_SetString(PyExc_ImportError, "Unable to initialize kinterbasdb exceptions"); return; } /* 2003.03.30: */ if ( init_kidb_type_translation() != 0 ) { PyErr_SetString(PyExc_ImportError, "Unable to initialize kinterbasdb type translation"); return; } } /* init_kinterbasdb */ #include "_kinterbasdb_constants.c" /********************** MODULE INFRASTRUCTURE:END ***********************/