/***************************** {{{ 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 "classConfig.h" #include "php_dbobj.h" #include #include #include "dbTypes.h" #include "objTypes.h" #include "objType/relation.h" #ifdef ZTS MUTEX_T dbobj_helper_class_configs_mutex; //to read classConfigs # define classConfigs_mutex dbobj_helper_class_configs_mutex static MUTEX_T dbobj_helper_add_config_write_mutex; //for writing classConfigs #endif //ZTS //config array name in php classes #define DBOBJ_STATIC_PROP_CONFIG_NAME "dbobj_config" /* * (className - classConfig) pairs * stores configuration for classes * ennek a hasznalatanak thread-safe-nek kell lennie! */ ZTS_VOLATILE HashTable dbobj_helper_class_configs; #define classConfigs dbobj_helper_class_configs //{{{ php_dbobj_MINIT_classConfig DBOBJ_API void php_dbobj_MINIT_classConfig(int module_number TSRMLS_DC) { # ifdef ZTS classConfigs_mutex = mutex_alloc(); dbobj_helper_add_config_write_mutex = mutex_alloc(); # endif if(zend_hash_init_ex((HashTable*)/*novolatile*/&classConfigs, 0, NULL, pe_permanent_ptr_freeer, 1, 0) == FAILURE) { DBOBJ_ERROR("error while initializing classConfigs"); } }//}}} //{{{ php_dbobj_MSHUTDOWN_classConfig DBOBJ_API void php_dbobj_MSHUTDOWN_classConfig(SHUTDOWN_FUNC_ARGS) { zend_hash_destroy((HashTable*)/*novolatile*/&classConfigs); # ifdef ZTS mutex_free(classConfigs_mutex); mutex_free(dbobj_helper_add_config_write_mutex); # endif }//}}} extern zend_class_entry *dbobj_class_entry_ptr; // {{{ accStr2accEnum DBOBJ_API int accStr2accEnum(char* str, int len TSRMLS_DC) { if(len > 1) { if(strncasecmp(str, "public",len) == 0) { return DBOBJ_ACC_PUBLIC; } if(strncasecmp(str, "private",len) == 0) { return DBOBJ_ACC_PRIVATE; } if(strncasecmp(str, "protected",len) == 0) { return DBOBJ_ACC_PROTECTED; } } DBOBJ_ERROR("unundersandable access type: '%s'", str); return -1; }//}}} /* {{{ is_basicProp_PK */ DBOBJ_API bool is_basicProp_PK(basicPropConfig conf) { return conf->PKIndex != PKINDEX_NOTPK; }//}}} /* {{{ is_complexProp_PK * akkor PK, ha minden forrasa PK */ DBOBJ_API bool is_complexProp_PK(complexPropConfig conf) { basicPropConfig *source; for(source=conf->sources; source; source++) if(!is_basicProp_PK(*source)) return 0; return 1; }//}}} //{{{ dbobj_helper_config_generate_propConfs static int dbobj_helper_config_generate_propConfs(classConfig config, HashTable* inpH TSRMLS_DC) { zval** retP; if(zend_hash_find(inpH, "properties",sizeof("properties"),(void**)&retP) == FAILURE) { DBOBJ_WARNING("'properties' nem talalhato a config array-ban"); return FAILURE; } bool cs = DBOBJ_G(case_sensitive); config->PKs = NULL; config->PKsL = 0; config->defaultLoad = NULL; config->defaultLoadL = 0; config->defaultLoadWithPKs = NULL; config->defaultLoadWithPKsL = 0; config->autoID = NULL; uint PKcounter = 0; convert_to_array(*retP); /* * vegtelen rekurzio ellen vedve vannak az egymasba agyazott objProp-ok, * mert szekvencialisan vannak ertelmezve. Nem lehet elore hivatkozni, * csak vissza. Ez az egyiranyusag ved a grafban kor kialakulasatol. */ {//for HashTable* inPropsH = Z_ARRVAL_PP(retP); HashPosition p; //int count = zend_hash_num_elements(inPropsH); HashTable* outDbPropsH = &(config->dbProps); HashTable* outObjPropsH = &(config->objProps); //first some quick counting for(zend_hash_internal_pointer_reset_ex(inPropsH, &p); zend_hash_get_current_data_ex(inPropsH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(inPropsH, &p)) { HashTable *inPropH; int is_PK = -1; //not defined int is_autoID = -1; //not defined //inPropH if((*retP)->type != IS_ARRAY) { DBOBJ_WARNING( "dbobj_helper::add_config objProps nem array"); return FAILURE; } inPropH = Z_ARRVAL_PP(retP); if(zend_hash_find(inPropH, "PK",sizeof("PK"),(void**)&retP) == SUCCESS) { zval tmp; tmp = **retP; zval_copy_ctor(&tmp); convert_to_boolean(&tmp); is_PK = Z_BVAL(tmp) ? 1 : 0; zval_dtor(&tmp); } if(zend_hash_find(inPropH, "autoID",sizeof("autoID"),(void**)&retP) == SUCCESS) { zval tmp; tmp = **retP; zval_copy_ctor(&tmp); convert_to_boolean(&tmp); is_autoID = Z_BVAL(tmp) ? 1 : 0; zval_dtor(&tmp); } switch (is_PK) { case -1: //not defined if(is_autoID == 1) //explicit true config->PKsL++; break; case 0: //false if(is_autoID == 1) { //explicit true DBOBJ_WARNING("autoID field has to be PK in class '%s'",config->className); return FAILURE; } break; case 1: //true config->PKsL++; break; } } config->PKs = pemalloc(config->PKsL * sizeof(*config->PKs), 1); for(zend_hash_internal_pointer_reset_ex(inPropsH, &p); zend_hash_get_current_data_ex(inPropsH, (void**) &retP, &p) == SUCCESS; zend_hash_move_forward_ex(inPropsH, &p)) { HashTable *inPropH; char* objPropConfKey; uint objPropConfKeyL; HashTable* inSourcesH = NULL; char *dbField = NULL; uint dbFieldL; objPropConfig objPropConf; inPropH = Z_ARRVAL_PP(retP); //Key (don't duplicate, we'll do it) if (zend_hash_get_current_key_ex(inPropsH, &objPropConfKey, &objPropConfKeyL, NULL, 0, &p) != HASH_KEY_IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config hibas config, minden objProps mezonek asszociativnak kell lennie"); return FAILURE; } objPropConfKeyL -= sizeof(""); //we don't need the contained '\0' assert(strlen(objPropConfKey) == objPropConfKeyL); objPropConfKey = zend_str_tolower_copy(pemalloc(objPropConfKeyL + sizeof(""), 1), STRINGLU(objPropConfKey)); zend_str_tolower(STRINGLU(objPropConfKey)); if(zend_hash_find(inPropH, "sources",sizeof("sources"),(void**)&retP) == SUCCESS) { convert_to_array(*retP); inSourcesH = Z_ARRVAL_PP(retP); } if(zend_hash_find(inPropH, "dbField",sizeof("dbField"), (void**)&retP) == SUCCESS) { if((*retP)->type != IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config dbField has to be string in class '%s'", config->className); return FAILURE; } dbField = Z_STRVAL_PP(retP); dbFieldL = Z_STRLEN_PP(retP); } else { if(!inSourcesH) { //if there is no sources and no dbField then this is a basicProp dbField = objPropConfKey; dbFieldL = objPropConfKeyL; } } //this is a complexPropConfig if (inSourcesH) { complexPropConfig complexPropConf; HashPosition inSourcesHP; complexPropConf = pemalloc(sizeof(*complexPropConf),1); objPropConf = (objPropConfig)complexPropConf; complexPropConf->sourcesL = zend_hash_num_elements(inSourcesH); complexPropConf->Class = OBJPROP_COMPLEX; if(!complexPropConf->sourcesL) { //there are no sources complexPropConf->sources = NULL; } else { //there are sources char* sourceName; uint sourceNameL; basicPropConfig *outSources; outSources = complexPropConf->sources = pemalloc(complexPropConf->sourcesL * sizeof(*complexPropConf->sources), 1); for( zend_hash_internal_pointer_reset_ex(inSourcesH, &inSourcesHP); zend_hash_get_current_data_ex(inSourcesH, (void**) &retP, &inSourcesHP) == SUCCESS; zend_hash_move_forward_ex(inSourcesH, &inSourcesHP)) { if((*retP)->type != IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config objProps.sources egy eleme nem string in class '%s'",config->className); return FAILURE; } sourceName = Z_STRVAL_PP(retP); sourceNameL = Z_STRLEN_PP(retP); *outSources = (basicPropConfig)classConfig_get_objPropConfig_handle_error(config, STRINGLU(sourceName) TSRMLS_CC); if(outSources[0]->Class != OBJPROP_BASIC) { DBOBJ_WARNING("complex object-property '%s' can only be composed of basic properties. '%s' is not basic.",objPropConfKey, sourceName); return FAILURE; } outSources++; } assert(complexPropConf->sources + complexPropConf->sourcesL == outSources); } } else { //this is a basicProp basicPropConfig basicPropConf; basicPropConf = pemalloc(sizeof(*basicPropConf),1); objPropConf = (objPropConfig)basicPropConf; basicPropConf->Class = OBJPROP_BASIC; //dbField if(cs) { basicPropConf->dbField = pemalloc(dbFieldL+sizeof("\"\""), 1); basicPropConf->dbField[0] = '"'; memcpy(basicPropConf->dbField+1, STRINGLU(dbField)); basicPropConf->dbField[dbFieldL+1] = '"'; basicPropConf->dbField[dbFieldL+2] = '\0'; basicPropConf->dbFieldL = dbFieldL + 2; } else { basicPropConf->dbField = zend_str_tolower_copy( pemalloc( dbFieldL+sizeof("") , 1), STRINGLU(dbField)); basicPropConf->dbFieldL = dbFieldL; } //is_autoID { zval tmp; if(zend_hash_find(inPropH, "autoID",sizeof("autoID"),(void**)&retP) == SUCCESS) { tmp = **retP; zval_copy_ctor(&tmp); convert_to_boolean(&tmp); if(Z_BVAL(tmp)) { if(config->autoID) DBOBJ_WARNING("only one dbField can be autoID! (in class '%s')",config->className); //in postgreSQL this must be a sequence //FIXME check this config->autoID = basicPropConf; } zval_dtor(&tmp); } } //is_PK { zval tmp; if(zend_hash_find(inPropH, "PK",sizeof("PK"),(void**)&retP) == SUCCESS || config->autoID == basicPropConf) { tmp = **retP; zval_copy_ctor(&tmp); convert_to_boolean(&tmp); if(Z_BVAL(tmp)) { uint PKIndex = PKcounter ++; basicPropConf->PKIndex = PKIndex; config->PKs[PKIndex] = basicPropConf; } else { basicPropConf->PKIndex = PKINDEX_NOTPK; } zval_dtor(&tmp); } else { //this is not in the primary key basicPropConf->PKIndex = PKINDEX_NOTPK; } } //defaultLoad { bool defaultLoad = 1; { zval tmp; if(zend_hash_find(inPropH, "defaultLoad",sizeof("defaultLoad"),(void**)&retP) == SUCCESS) { tmp = **retP; zval_copy_ctor(&tmp); convert_to_boolean(&tmp); if(!Z_BVAL(tmp)) { defaultLoad = 0; } zval_dtor(&tmp); } } if(defaultLoad && basicPropConf->PKIndex == PKINDEX_NOTPK) { if(!config->defaultLoad) { config->defaultLoad = pemalloc(sizeof(*config->defaultLoad), 1); *(config->defaultLoad) = NULL; } config->defaultLoad = perealloc(config->defaultLoad, sizeof(*config->defaultLoad)*(config->defaultLoadL+1),1); config->defaultLoad[config->defaultLoadL] = basicPropConf; config->defaultLoadL++; } if(defaultLoad || basicPropConf->PKIndex != PKINDEX_NOTPK) { if(!config->defaultLoadWithPKs) { config->defaultLoadWithPKs = pemalloc(sizeof(*config->defaultLoadWithPKs), 1); *(config->defaultLoadWithPKs) = NULL; } config->defaultLoadWithPKs = perealloc(config->defaultLoadWithPKs, sizeof(*config->defaultLoadWithPKs) * (config->defaultLoadWithPKsL + 1), 1); config->defaultLoadWithPKs[config->defaultLoadWithPKsL] = basicPropConf; config->defaultLoadWithPKsL++; } } //store assert(basicPropConf->Class == OBJPROP_BASIC); if(zend_hash_add(outDbPropsH, objPropConfKey, objPropConfKeyL, &basicPropConf, sizeof(basicPropConf), NULL) == FAILURE ) { DBOBJ_WARNING( "dbobj_helper add_config allocation error"); return FAILURE; } //name basicPropConf->name = objPropConfKey; basicPropConf->nameL = objPropConfKeyL; } //objType if(zend_hash_find(inPropH, "type",sizeof("type"),(void**)&retP) == FAILURE) { DBOBJ_WARNING("type nem talalhato az objProps array-ban"); return FAILURE; } if((*retP)->type != IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config objProps.type nem string"); return FAILURE; } switch(objPropConf->Class) { case OBJPROP_BASIC: { basicPropConfig basicPropConf = (basicPropConfig)objPropConf; if(!(basicPropConf->dbType = dbType_from_string(Z_STRINGLU_PP(retP), objPropConfKey, config->table TSRMLS_CC))) DBOBJ_WARNING("dbType_from_string error at '%s' in class '%s'", objPropConfKey, config->className); basicPropConf->basicType = basicPropConf->dbType->basicType; //this should no be destructed } break; case OBJPROP_COMPLEX: { complexPropConfig complexPropConf = (complexPropConfig)objPropConf; basicType *sourceTypes = emalloc(complexPropConf->sourcesL * sizeof(*sourceTypes)); uint i; for(i = 0; i < complexPropConf->sourcesL; i++) { sourceTypes[i] = complexPropConf->sources[i]->basicType; } if(!(complexPropConf->type = complexType_from_string(Z_STRINGLU_PP(retP), sourceTypes TSRMLS_CC))) { DBOBJ_WARNING("complexType_from_string error at '%s' in class '%s'", objPropConfKey, config->className); } efree(sourceTypes); } break; } //access if(zend_hash_find(inPropH, "access",sizeof("access"),(void**)&retP) == FAILURE) { objPropConf->readAccess = DBOBJ_ACC_PROTECTED; objPropConf->writeAccess = DBOBJ_ACC_PROTECTED; } else { //van access mezo if((*retP)->type != IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config objProps.access nem string"); return FAILURE; } objPropConf->writeAccess = objPropConf->readAccess = accStr2accEnum(Z_STRINGLU_PP(retP) TSRMLS_CC); }//if isset($inPropH[access]) if(zend_hash_find(inPropH, "read_access", sizeof("read_access"), (void**)&retP) == SUCCESS) { if((*retP)->type != IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config objProps.read_access nem string"); return FAILURE; } objPropConf->readAccess = accStr2accEnum(Z_STRINGLU_PP(retP) TSRMLS_CC); } if(zend_hash_find(inPropH, "write_access", sizeof("write_access"), (void**)&retP) == SUCCESS) { if((*retP)->type != IS_STRING) { DBOBJ_WARNING( "dbobj_helper::add_config objProps.write_access nem string"); return FAILURE; } objPropConf->writeAccess = accStr2accEnum(Z_STRINGLU_PP(retP) TSRMLS_CC); } //store assert(objPropConfKeyL == strlen(objPropConfKey)); if(zend_hash_add(outObjPropsH, objPropConfKey, objPropConfKeyL + sizeof(""), &objPropConf, sizeof(objPropConf), NULL) == FAILURE ) { DBOBJ_WARNING( "dbobj_helper add_config allocation error"); return FAILURE; } }} return SUCCESS; } //}}} // {{{ dbobj_helper_build_config static classConfig dbobj_helper_build_config(char* className, uint classNameL TSRMLS_DC) { HashTable* inpH; classConfig config; // {{{ enum dbobj_helper_build_config_phase enum dbobj_helper_build_config_phase { BUILD_CONFIG_PHASE_START, BUILD_CONFIG_PHASE_GET_CLASS_ENTRY, BUILD_CONFIG_PHASE_GET_CONFIG, BUILD_CONFIG_PHASE_INIT, BUILD_CONFIG_PHASE_INHERITENCE, BUILD_CONFIG_PHASE_CONNECTIONALIAS, BUILD_CONFIG_PHASE_TABLE, BUILD_CONFIG_PHASE_CLASSNAME, BUILD_CONFIG_PHASE_PROPERTIES, BUILD_CONFIG_PHASE_GET_CONFIG_DTOR, } readyphase = BUILD_CONFIG_PHASE_START; /* }}} */ bool cs = DBOBJ_G(case_sensitive); zval** retP; zend_class_entry *ce; zval* get_config_result = NULL; // {{{ get class_entry { zend_class_entry **cePP; if (zend_lookup_class(className, classNameL, &cePP TSRMLS_CC) == FAILURE) { goto buidConfigERR; } else { ce = *cePP; } } /* }}} */ readyphase = BUILD_CONFIG_PHASE_GET_CLASS_ENTRY; // {{{ get config { zval callback; zval*** params; zend_fcall_info fci; zend_fcall_info_cache fci_cache = empty_fcall_info_cache; bool error = 0; Z_TYPE(callback) = IS_STRING; Z_STRVAL(callback) = "__dbobj_get_config"; Z_STRLEN(callback) = sizeof("__dbobj_get_config")-1; params = emalloc(1 * sizeof(zval**)); params[0] = emalloc(sizeof(zval*)); ALLOC_INIT_ZVAL(*params[0]); Z_TYPE_PP(params[0]) = IS_STRING; Z_STRVAL_PP(params[0]) = className; Z_STRLEN_PP(params[0]) = classNameL; fci.size = sizeof(fci); fci.function_table = EG(function_table); fci.function_name = &callback; fci.symbol_table = NULL; fci.object_pp = NULL; fci.retval_ptr_ptr = &get_config_result; fci.param_count = 1; fci.params = ¶ms[0]; fci.no_separation = 0; do { if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS) { if( Z_TYPE_P(get_config_result) != IS_ARRAY) { if( Z_TYPE_P(get_config_result) == IS_NULL || ( Z_TYPE_P(get_config_result) == IS_BOOL && !(Z_BVAL_P(get_config_result)) ) ) { DBOBJ_NOTICE("dbobj_helper: dbobj_get_config(%s) returned NULL, can't build config", className); } else { DBOBJ_WARNING("dbobj_helper: dbobj_get_config(%s) bad return type", className); } error = 1;break; } else { //result is an array inpH = Z_ARRVAL_P(get_config_result); } } else { retP = zend_std_get_static_property(ce, DBOBJ_STATIC_PROP_CONFIG_NAME, sizeof(DBOBJ_STATIC_PROP_CONFIG_NAME) - 1, 1 TSRMLS_CC); if(!retP) { DBOBJ_WARNING("dbobj_helper: %s::$" DBOBJ_STATIC_PROP_CONFIG_NAME " is missing", className); error = 1;break; } if( Z_TYPE_PP(retP) != IS_ARRAY) { DBOBJ_WARNING("dbobj_helper: %s::$" DBOBJ_STATIC_PROP_CONFIG_NAME " is not an array", className); error = 1;break; } inpH = Z_ARRVAL_PP(retP); } } while(0); efree(*params[0]); //not zval_dtor intentionally! this is a string, and we don't want to free the char array in it efree(params[0]); efree(params); if(error) goto buidConfigERR; } /* }}} */ readyphase = BUILD_CONFIG_PHASE_GET_CONFIG; // {{{ initialization config = pemalloc(sizeof(*config), 1); zend_hash_init(&config->dbProps, 4, NULL, pe_permanent_ptr_freeer, 1); zend_hash_init(&config->objProps, 4, NULL, pe_permanent_ptr_freeer, 1); /* }}} */ readyphase = BUILD_CONFIG_PHASE_INIT; /*{{{ inheritence */ { zend_class_entry **cePP, *ce; classConfig pcc = NULL; if (zend_lookup_class(STRINGLU(className), &cePP TSRMLS_CC) == FAILURE) { DBOBJ_WARNING( "nemletezo class (%s) configjanak betoltese", className); goto buidConfigERR; } ce = *cePP; //find the nearest parent who has config for(ce = ce->parent; ce != dbobj_class_entry_ptr && ce; ce = ce->parent) { pcc = dbobj_helper_actual_get_class_config(ce->name, ce->name_length,1, /*ignoreWriteMutex*/1 TSRMLS_CC); if(pcc) { break; } } if(pcc) { config->table = pcc->table; zend_hash_copy(&config->dbProps, &pcc->dbProps, NULL, NULL, sizeof(struct _basicPropConfig)); zend_hash_copy(&config->objProps, &pcc->objProps, NULL, NULL, sizeof(struct _objPropConfig)); } }/*}}}*/ readyphase = BUILD_CONFIG_PHASE_INHERITENCE; /*{{{ connectionAlias */ { if(zend_hash_find(inpH, "conn",sizeof("conn"),(void**)&retP) == FAILURE) { DBOBJ_WARNING("conn nem talalhato a config array-ban"); goto buidConfigERR; } convert_to_string(*retP); config->connectionAlias = zend_str_tolower_copy(pemalloc(Z_STRLEN_PP(retP)+1, 1), Z_STRINGLU_PP(retP)); config->connectionAliasL = Z_STRLEN_PP(retP); }/*}}}*/ readyphase = BUILD_CONFIG_PHASE_CONNECTIONALIAS; /*{{{ table */ { if(zend_hash_find(inpH, "table",sizeof("table"),(void**)&retP) == FAILURE) { DBOBJ_WARNING("table nem talalhato a config array-ban"); goto buidConfigERR; } convert_to_string(*retP); if(cs) { config->table = pemalloc(Z_STRLEN_PP(retP)+1+2, 1); config->table[0] = '"'; memcpy(config->table+1, Z_STRINGLU_PP(retP)); config->table[Z_STRLEN_PP(retP)+1] = '"'; config->table[Z_STRLEN_PP(retP)+2] = '\0'; config->tableL = Z_STRLEN_PP(retP)+2; } else { config->table = zend_str_tolower_copy(pemalloc(Z_STRLEN_PP(retP)+1, 1), Z_STRINGLU_PP(retP)); config->tableL = Z_STRLEN_PP(retP); } }/*}}}*/ readyphase = BUILD_CONFIG_PHASE_TABLE; /*{{{ className */ { config->className = pemalloc(classNameL + 1, 1); strncpy(config->className, className,classNameL); config->className[classNameL] = '\0'; config->classNameL = classNameL; }/*}}}*/ readyphase = BUILD_CONFIG_PHASE_CLASSNAME; /*{{{ properties */ if(dbobj_helper_config_generate_propConfs(config, inpH TSRMLS_CC) == FAILURE) goto buidConfigERR; /*}}}*/ readyphase = BUILD_CONFIG_PHASE_PROPERTIES; /*{{{ get_config_dtor */ if(get_config_result && !--ZVAL_REFCOUNT(get_config_result)) { zval_dtor(get_config_result); } /*}}}*/ readyphase = BUILD_CONFIG_PHASE_GET_CONFIG_DTOR; return config; ////////////////// //error handling// ////////////////// buidConfigERR: { switch(readyphase) { //falthrough almost everywhere case BUILD_CONFIG_PHASE_GET_CONFIG_DTOR: case BUILD_CONFIG_PHASE_PROPERTIES: case BUILD_CONFIG_PHASE_CLASSNAME: pefree(config->className, 1); case BUILD_CONFIG_PHASE_TABLE: pefree(config->table, 1); case BUILD_CONFIG_PHASE_CONNECTIONALIAS: pefree(config->connectionAlias, 1); case BUILD_CONFIG_PHASE_INHERITENCE: case BUILD_CONFIG_PHASE_INIT: pefree(config, 1); zend_hash_destroy(&config->objProps); zend_hash_destroy(&config->dbProps); case BUILD_CONFIG_PHASE_GET_CONFIG: if(get_config_result && !--ZVAL_REFCOUNT(get_config_result)) { zval_dtor(get_config_result); } case BUILD_CONFIG_PHASE_GET_CLASS_ENTRY: case BUILD_CONFIG_PHASE_START: break; } return NULL; } } // }}} //{{{ dbobj_helper_actual_add_config static classConfig dbobj_helper_actual_add_config(STRINGLD(className), bool ignoreWriteMutex TSRMLS_DC) { classConfig config; classConfig* retP; zend_str_tolower(STRINGLU(className)); mutex_lock(classConfigs_mutex); if(!ignoreWriteMutex) mutex_lock(dbobj_helper_add_config_write_mutex); //check if the given className is already in classConfigs if(zend_hash_find((HashTable*)/*novolatile*/&classConfigs, STRINGLU(className),(void**)&retP) == SUCCESS) { mutex_unlock(classConfigs_mutex); if(!ignoreWriteMutex) mutex_unlock(dbobj_helper_add_config_write_mutex); return *retP; } //other threads can read while we build the new config mutex_unlock(classConfigs_mutex); config = dbobj_helper_build_config(STRINGLU(className) TSRMLS_CC); if(!config) { mutex_unlock(classConfigs_mutex); if (!ignoreWriteMutex) mutex_unlock(dbobj_helper_add_config_write_mutex); DBOBJ_ERROR("classConfig gerenation error"); return NULL; } else { //no reading while we write the config repository mutex_lock(classConfigs_mutex); zend_hash_add((HashTable*)/*novolatile*/&classConfigs, className, classNameL, &config, sizeof(config), NULL); //open read/write access once more mutex_unlock(classConfigs_mutex); if (!ignoreWriteMutex) mutex_unlock(dbobj_helper_add_config_write_mutex); return config; } }//}}} //{{{ dbobj_helper_add_config DBOBJ_API classConfig dbobj_helper_add_config(STRINGLD(className) TSRMLS_DC) { return dbobj_helper_actual_add_config(STRINGLU(className), 0 TSRMLS_CC); } //}}} //{{{ classConfig_get_objPropConfig_internal objPropConfig classConfig_get_objPropConfig_internal(classConfig cConf, STRINGLD(sourceName), bool supressError TSRMLS_DC) { objPropConfig *retP; zend_str_tolower(STRINGLU(sourceName)); if(zend_hash_find(&cConf->objProps, STRINGLU(sourceName) + sizeof(""), (void**)&retP) == FAILURE) { if(supressError) { return NULL; } else { DBOBJ_ERROR( "dbobj_helper::%s objProp(%s)-t nem talalom %s class-ban" , get_active_function_name(TSRMLS_C),sourceName,cConf->className); return NULL; } } //check if we need to generate relations for the class (that is needed if the requested objPropConfig is a relation) if(is_objType_relation((*retP)->type) == OBJTYPE_RELATION_INCOMPLETE_RELATION) { objType_relation_postTranslate(&(*retP)->type TSRMLS_CC); } return *retP; }//}}} //{{{ dbobj_helper_actual_get_class_config DBOBJ_API classConfig dbobj_helper_actual_get_class_config(char* className, zend_uint classNameL, bool supressError, bool ignoreWriteMutex TSRMLS_DC) { zval** retP; zend_str_tolower(STRINGLU(className)); mutex_lock(classConfigs_mutex); if(zend_hash_find((HashTable*)/*novolatile*/&classConfigs, className,classNameL,(void**)&retP) == SUCCESS) { mutex_unlock(classConfigs_mutex); return (classConfig)*retP; } mutex_unlock(classConfigs_mutex); return dbobj_helper_actual_add_config(className, classNameL, ignoreWriteMutex TSRMLS_CC); }//}}} //{{{ dbobj_helper_get_class_config classConfig dbobj_helper_get_class_config(char* className, zend_uint classNameL, bool supressError TSRMLS_DC) { return dbobj_helper_actual_get_class_config(STRINGLU(className),supressError, 0 TSRMLS_CC); }//}}} /* * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */