/***************************** {{{ LICENSE ********************************\ * dbobj, the relational object persistence module for PHP * * Copyright (C) 2006 Adam Banko * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * \***************************** LICENSE }}} ********************************/ #include "dbDriver.h" #include "dbDriver/pgsql.h" typedef struct _dbDriver_listItem { dbDriver* module; struct _dbDriver_listItem* next; } *dbDriver_listItem; static dbDriver_listItem driverList = NULL; /* {{{ dbDriver_register */ DBOBJ_API void dbDriver_register(dbDriver *module) { dbDriver_listItem prev, curr, newitem; newitem = pemalloc(sizeof(*newitem),1); newitem->module = module; for(prev=NULL, curr = driverList; curr; curr = curr->next) { if(curr->module->nameL == module->nameL && strncmp(curr->module->name, module->name, module->nameL) < 0) break; prev = curr; } if(!prev) { newitem->next = driverList; driverList = newitem; } else { prev->next = newitem; newitem->next = curr; } } /* }}} */ /* {{{dbDriver_getConnection * FIXME relays to each module's own getConnection method * @improvement if we need to have different connections that only differ in configArray, we should somehow serialize it. we might create a new virtual function in the module that returns the relevant data from configArr serialized (as a string) */ DBOBJ_API DBConnection dbDriver_getConnection(STRINGLD(driver), STRINGLD(dsn), STRINGLD(user), STRINGLD(password), HashTable* configArray TSRMLS_DC) { char *connID; uint connIDL; //{{{generate connID { char *connIDp; connIDL = driverL + sizeof("://")-1; if(user) { connIDL += userL + sizeof("@")-1; } if(password) { connIDL += passwordL + sizeof(":")-1; } connIDL += dsnL; connIDL += sizeof(""); connIDp = connID = safe_alloca(connIDL); {//driver memcpy(connIDp, driver, driverL); connIDp += driverL; *connIDp++ = ':'; *connIDp++ = '/'; *connIDp++ = '/'; } if(user) { memcpy(connIDp, user, userL); connIDp += userL; } if(password) { *connIDp++ = ':'; memcpy(connIDp, password, passwordL); connIDp += passwordL; } if(user) { *connIDp++ = '@'; } memcpy(connIDp, dsn, dsnL); connIDp += dsnL; *connIDp++ = '\0'; assert(connIDp - connID == connIDL); }//}}} //{{{lookup connID in the pool { DBConnection *retP; if(zend_hash_find(&DBOBJ_G(dbConnections), connID, connIDL, (void**)&retP) == SUCCESS) { free_safe_alloca(connID, connIDL); return *retP; } free_safe_alloca(connID, connIDL); }//}}} //{{{if not in the pool, generate it { dbDriver_listItem curr; DBConnection conn = NULL; for(curr = driverList; curr; curr = curr->next) { if(curr->module->nameL == driverL && strncmp(curr->module->name, driver, driverL) == 0) { conn = curr->module->getConnection(STRINGLU(dsn), STRINGLU(user), STRINGLU(password), configArray TSRMLS_CC); break; } } if(!conn) { DBOBJ_ERROR("Database connection driver unknown: '%s'", driver); } //{{{register it { zend_hash_add(&DBOBJ_G(dbConnections), connID, connIDL, &conn, sizeof(conn), NULL); }//}}} //{{{ BEGIN transaction { CALMT(conn, beginTransaction); }//}}} return conn; }//}}} }//}}} static void dbConn_dtor(void *ptr) { TSRMLS_FETCH(); DBConnection conn = *(DBConnection*)ptr; /* TODO when should we commit/rollback the transaction? (and how?) * use case 1. script ran normaly, there was no explicit commit * use case 2. script ran normaly, there was an explicit commit * use case 3. script called die() * use case 4. script had an E_ERROR * use case 5. script timeouted * use case 6. script was cancelled from the client side */ CALMT(conn, commitTransaction); CALMT(conn, destroy); efree(conn); } DBOBJ_API void php_dbobj_MINIT_dbDriver(TSRMLS_D) { dbDriver_register(&dbDriver_pgsql); } DBOBJ_API void php_dbobj_RINIT_dbDriver(TSRMLS_D) { if(zend_hash_init_ex(&DBOBJ_G(dbConnections), 0, NULL, dbConn_dtor, 1, 0) == FAILURE) { DBOBJ_ERROR_CRIT("dbobj init error"); } } DBOBJ_API void php_dbobj_RSHUTDOWN_dbDriver(TSRMLS_D) { zend_hash_destroy(&DBOBJ_G(dbConnections)); } /* * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */