/* +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2004 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.0 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_0.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Author: Alan Knowles | +----------------------------------------------------------------------+ */ /* $Id: dbdo.c,v 1.97 2005/05/04 23:44:01 alan_k Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_dbdo.h" /* If you declare any globals in php_dbdo.h uncomment this: */ ZEND_DECLARE_MODULE_GLOBALS(dbdo) /* True global resources - no need for thread safety here */ static zend_object_handlers dbdo_object_handlers; static zend_object_handlers dbdo_object_exception_handlers; /* static void dbdo_objects_dtor(void *object, zend_object_handle handle TSRMLS_DC) { dbdo_object *intern = ( dbdo_object *) object; if (!intern) { return; } if (intern->zo.properties) { zend_hash_destroy(intern->zo.properties); FREE_HASHTABLE(intern->zo.properties); } efree(intern); } */ static void dbdo_object_free_storage(void *object TSRMLS_DC) { dbdo_object *intern = (dbdo_object *)object; if (!intern) { /* we must have free'd it already */ return; } zend_hash_destroy(intern->zo.properties); FREE_HASHTABLE(intern->zo.properties); if (G_IS_OBJECT(intern->result)) { g_object_unref (intern->result); intern->result = NULL; } if (intern->condition) { intern->condition->refcount--; if (intern->condition->refcount < 1) { if (intern->condition->where) { efree(intern->condition->where); } if (intern->condition->groupBy) { efree(intern->condition->groupBy); } if (intern->condition->orderBy) { efree(intern->condition->orderBy); } if (intern->condition->having) { efree(intern->condition->having); } if (intern->condition->data_select) { efree(intern->condition->data_select); } efree(intern->condition); } intern->condition = NULL; } /* we cant free intern, cause it contains pointers to values */ intern->table = NULL; efree(intern); } /* {{{ dbdo_objects_new */ PHP_DBDO_API zend_object_value dbdo_objects_new(zend_class_entry *class_type TSRMLS_DC) { zval *tmp; zend_object_value retval; dbdo_object *intern; intern = emalloc(sizeof(dbdo_object)); intern->zo.ce = class_type; intern->zo.in_get = 0; intern->zo.in_set = 0; intern->zo.properties = NULL; intern->con = NULL; intern->result = NULL; intern->row_id = -1; intern->table = NULL; intern->condition = emalloc(sizeof(dbdo_condition)); intern->condition->refcount = 1; intern->condition->where = NULL; intern->condition->groupBy = NULL; intern->condition->orderBy = NULL; intern->condition->having = NULL; intern->condition->limit_from = 0; intern->condition->limit_qty = 0; intern->condition->limit_use = FALSE; intern->condition->data_select = NULL; ALLOC_HASHTABLE(intern->zo.properties); zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) dbdo_object_free_storage, NULL TSRMLS_CC); retval.handlers = (zend_object_handlers *) & dbdo_object_handlers; return retval; } /* }}} */ PHP_DBDO_API zend_object_value dbdo_object_exception_new(zend_class_entry *class_type TSRMLS_DC) { zend_object_value retval; dbdo_object *intern; zval *tmp; /* we use the dbdo_object for exceptions, even thought we dont really use it. */ intern = emalloc(sizeof(dbdo_object)); intern->zo.ce = class_type; intern->zo.in_get = 0; intern->zo.in_set = 0; intern->zo.properties = NULL; ALLOC_HASHTABLE(intern->zo.properties); zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); retval.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) dbdo_object_free_storage, NULL TSRMLS_CC); retval.handlers = (zend_object_handlers *) & dbdo_object_exception_handlers; return retval; } /* {{{ dbdo_functions[] * * Every user visible function must have an entry in dbdo_functions[]. */ function_entry dbdo_functions[] = { {NULL, NULL, NULL} /* Must be the last line in dbdo_functions[] */ }; /* }}} */ function_entry dbdo_funcs_exception[] = { {NULL, NULL, NULL} }; ZEND_BEGIN_ARG_INFO(__call_args, 0) ZEND_ARG_PASS_INFO(0) ZEND_ARG_PASS_INFO(0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(__dbdo_call_args, 0) ZEND_ARG_PASS_INFO(0) ZEND_ARG_PASS_INFO(0) ZEND_ARG_PASS_INFO(0) ZEND_ARG_PASS_INFO(0) ZEND_ARG_PASS_INFO(1) ZEND_END_ARG_INFO() /* and now our object.. */ function_entry dbdo_class_functions[] = { PHP_ME(dbdo, __construct, NULL,0) PHP_ME(dbdo, factory, NULL, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) PHP_ME(dbdo, config, NULL, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) PHP_ME(dbdo, debugLevel, NULL, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) PHP_ME(dbdo, reproduce, NULL,0) PHP_ME(dbdo, get, NULL,0) PHP_ME(dbdo, fetch, NULL,0) PHP_ME(dbdo, fetchAll, NULL,0) PHP_ME(dbdo, count, NULL,0) PHP_ME(dbdo, insert, NULL,0) PHP_ME(dbdo, update, NULL,0) PHP_ME(dbdo, delete, NULL,0) PHP_ME(dbdo, query, NULL,0) PHP_ME(dbdo, toArray, NULL,0) PHP_ME(dbdo, assignFrom, NULL,0) PHP_ME(dbdo, valueSet, NULL,0) PHP_ME(dbdo, valueGet, NULL,0) PHP_ME(dbdo, schema, NULL,0) PHP_ME(dbdo, info, NULL, 0) PHP_ME(dbdo, sequenceKey, NULL,0) PHP_ME(dbdo, keys, NULL,0) PHP_ME(dbdo, selectAdd, NULL,0) PHP_ME(dbdo, whereAdd, NULL,0) PHP_ME(dbdo, limit, NULL,0) PHP_ME(dbdo, orderBy, NULL,0) PHP_ME(dbdo, groupBy, NULL,0) PHP_ME(dbdo, having, NULL,0) PHP_ME(dbdo, quoted, NULL,0) /* PHP_ME(dbdo, __sleep, NULL, 0) */ PHP_ME(dbdo, __call, __call_args, 0) ZEND_FENTRY(__dbdoCall, ZEND_FN(dbdo___call), __dbdo_call_args, 0) {NULL, NULL, NULL} }; /* {{{ dbdo_module_entry */ zend_module_entry dbdo_module_entry = { STANDARD_MODULE_HEADER, "dbdo", NULL, PHP_MINIT(dbdo), PHP_MSHUTDOWN(dbdo), PHP_RINIT(dbdo), PHP_RSHUTDOWN(dbdo), PHP_MINFO(dbdo), "0.1", /* Replace with version number for your extension */ STANDARD_MODULE_PROPERTIES }; /* }}} */ #ifdef COMPILE_DL_DBDO ZEND_GET_MODULE(dbdo) #endif /* {{{ PHP_INI */ /* Remove comments and fill if you need to have entries in php.ini PHP_INI_BEGIN() STD_PHP_INI_ENTRY("dbdo.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_dbdo_globals, dbdo_globals) STD_PHP_INI_ENTRY("dbdo.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_dbdo_globals, dbdo_globals) PHP_INI_END() */ /* }}} */ /* {{{ php_dbdo_init_globals */ /* Uncomment this function if you have INI entries */ static void php_dbdo_init_globals(zend_dbdo_globals *dbdo_globals) { dbdo_globals->client = NULL; /* QUESTION? what does the last parementer : persistant actually mean */ /* QUESTION? need a good example of a destructor callback.. */ dbdo_globals->debugLevel = 0; /* should this be on by default?? */ dbdo_globals->config = NULL; dbdo_globals->config_len = 0; dbdo_globals->tables = NULL; dbdo_globals->tables_len = 0; //dbdo_globals->transaction = NULL; } /* }}} */ static int le_pdbdo; int php_dbdo_list_entry(void) { return le_pdbdo; } ZEND_RSRC_DTOR_FUNC(php_dbdo_client_dtor) { if (rsrc->ptr) { gda_client_close_all_connections ((GdaClient *)rsrc->ptr); g_object_unref(G_OBJECT((GdaClient *)rsrc->ptr)); } rsrc->ptr = NULL; } /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION(dbdo) { /* If you have INI entries, uncomment these lines */ ZEND_INIT_MODULE_GLOBALS(dbdo, php_dbdo_init_globals, NULL); le_pdbdo = zend_register_list_destructors_ex(NULL, php_dbdo_client_dtor, /* php_dbdo_pdbdo_dtor, todo a a destructor */ "DBDO persistent client", module_number); /* REGISTER_INI_ENTRIES(); */ { /* main object */ int i; zend_class_entry ce; memcpy(&dbdo_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); dbdo_object_handlers.clone_obj = dbdo_clone; INIT_CLASS_ENTRY(ce, "DBDO", dbdo_class_functions); ce.create_object = dbdo_objects_new; dbdo_class_entry_ce = zend_register_internal_class(&ce TSRMLS_CC); } { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "DBDO_Exception", NULL); dbdo_class_entry_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default(), NULL TSRMLS_CC); zend_declare_property_null( dbdo_class_entry_exception_ce, "errorInfo", sizeof("errorInfo")-1, ZEND_ACC_PUBLIC TSRMLS_CC); } return SUCCESS; } /* }}} */ /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION(dbdo) { /* uncomment this line if you have INI entries UNREGISTER_INI_ENTRIES(); */ return SUCCESS; } /* }}} */ #define hash_add_assoc_long(__arg, __key, __val) hash_add_assoc_long_ex(__arg, __key, strlen(__key)+1, __val) int hash_add_assoc_long_ex(HashTable *arg, char *key, uint key_len, long n) { zval *tmp; tmp = (zval *) malloc(sizeof(zval)); INIT_PZVAL(tmp); ZVAL_LONG(tmp, n); return zend_symtable_update(arg, key, key_len, (void *) &tmp, sizeof(zval *), NULL); } /* Remove if there's nothing to do at request start */ /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION(dbdo) { int argc = 1, i, plen; char **argv = NULL, *hashkey = NULL; list_entry *le, le_new; zend_hash_init(&dbdo_class_entry_ce->constants_table, 0, NULL, NULL, 1); /* fetch all returns */ hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "OBJECTS", 0); hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "KEY_VALUE", 1); hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "VALUE", 2); hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "SINGLE", 3); /* update/delete build or use fetchedobject. */ hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "BUILD", 1); /* error constants */ hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "E_ALL", 3); hash_add_assoc_long(&(dbdo_class_entry_ce->constants_table), "E_FULL", 63); /* make sure we are connected on each request */ plen = spprintf(&hashkey,0,"DBDO::client"); if (SUCCESS == zend_hash_find(&EG(persistent_list), hashkey, plen+1, (void*)&le)) { if (Z_TYPE_P(le) == php_dbdo_list_entry()) { DBDO_G(client) = (GdaClient *) (le->ptr); } } if (!DBDO_G(client)) { argv = (char **)g_new(char *, argc); argv[0] = g_strdup("-"); gda_init ("TestGDA", "0.1", argc, argv); DBDO_G(client) = gda_client_new (); le_new.type = php_dbdo_list_entry(); le_new.ptr = (void *)(DBDO_G(client)); if (FAILURE == zend_hash_update(&EG(persistent_list), (char*)hashkey, plen, (void*)&le_new, sizeof(le_new), NULL)) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Failed to register persistent entry"); } } efree(hashkey); return SUCCESS; } /* }}} */ /* {{{ PHP_RSHUTDOWN_FUNCTION */ PHP_RSHUTDOWN_FUNCTION(dbdo) { /* TODO: free sequences, tables .. */ int i; /* free client */ /*if (DBDO_G(client)) { // gda_client_close_all_connections ( DBDO_G(client)); // g_object_unref(G_OBJECT( DBDO_G(client))); DBDO_G(client) = NULL; //} */ /* free config */ if (DBDO_G(config_len)) { for (i=0;idsn) { efree(con->dsn); con->dsn = NULL; } if (con->require_path) { efree(con->require_path); con->require_path = NULL; } if (con->class_name) { efree(con->class_name); con->class_name = NULL; } if (con->links) { efree(con->links); con->links = NULL; } if (con->provider) { efree(con->provider); con->provider = NULL; } if (con->cnc_string) { efree(con->cnc_string); con->cnc_string = NULL; } efree(con); DBDO_G(config)[i] = NULL; //DBDO_G(config) = NULL; } efree(DBDO_G(config)); } DBDO_G(config) = NULL; DBDO_G(config_len) = 0; // lets clear up the tables.. DBDO_DEBUG0(16,"CLEARING TABLES"); if (DBDO_G(tables)) { for (i=0;idsn,table->name); if (table->dsn) { efree(table->dsn); } if (table->name) { efree(table->name); } if (table->schema) { g_object_unref(table->schema); } if (table->sequenceColumn) { efree(table->sequenceColumn); } if (table->sequenceName) { efree(table->sequenceName); } for (j = 0; j < table->keys_len; j++) { efree(table->keys[j]); } if (table->keys_len) { efree(table->keys); } table->keys_len = 0; table->keys = NULL; table->dsn = NULL; table->name = NULL; table->schema = NULL; table->sequenceColumn = NULL; table->sequenceName = NULL; efree(table); DBDO_G(tables)[i] = NULL; } efree(DBDO_G(tables)); } DBDO_G(tables) = NULL; DBDO_G(tables_len) = 0; return SUCCESS; } /* }}} */ /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(dbdo) { GList *prov_list; GList *node; GdaProviderInfo *info; php_info_print_table_start(); php_info_print_table_header(2, "DBDO support", "enabled"); php_info_print_table_row(2, "CVS id", "$Id: dbdo.c,v 1.97 2005/05/04 23:44:01 alan_k Exp $"); prov_list = gda_config_get_provider_list (); for (node = g_list_first (prov_list); node != NULL; node = g_list_next (node)) { info = (GdaProviderInfo *) node->data; php_info_print_table_row(2, "Supported Driver", info->id); } gda_config_free_provider_list (prov_list); php_info_print_table_end(); /* Remove comments if you have entries in php.ini DISPLAY_INI_ENTRIES(); */ } /* }}} */ #define DBDO_INFO_LEN 23 static char *dbdo_info_values[] = { /* 0 */ "table", "dsn", /* 2 */ "database", "cnc", /* 4 */ "provider", "username", /* 6 */ "password", "row", /* 8 */ "rows", "fetched", /* 10*/ "config", "sequence_column", /* 12*/ "sequence_is_native", "sequence_assigned", "sequence_name", "keys", /* 16*/ "where", "group_by", "order_by", "having", /* 20*/ "limit_from", "limit_qty", "select" }; /* get the id for a specified column */ int dbdo_info_get_id(char * col) { int i; for (i=0;i< DBDO_INFO_LEN;i++) { if (!strcasecmp(dbdo_info_values[i],col)) { return i; } } return -1; } /* get the data for a specified id */ zval * dbdo_info_get(zval *object, zval *ret, int id TSRMLS_DC) { dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); switch (id) { case 0: /* tablename; */ ZVAL_STRING(ret,obj->table->name, 1); return ret; case 1: /* dsn */ ZVAL_STRING(ret,obj->table->dsn, 1); return ret; case 2: /* database */ DBDO_DEBUG(16,"returning DATABASE = %s", (char*) gda_connection_get_database(obj->con)); ZVAL_STRING(ret, (char*) gda_connection_get_database(obj->con), 1); return ret; case 3: /* cnc string */ ZVAL_STRING(ret, (char*) gda_connection_get_cnc_string(obj->con), 1); return ret; case 4: /* provider */ ZVAL_STRING(ret, (char*) gda_connection_get_provider(obj->con), 1); return ret; case 5: /* 5 = username; */ ZVAL_STRING(ret, (char*) gda_connection_get_username(obj->con), 1); return ret; case 6: /* password */ { char * pwd = (char*) gda_connection_get_password(obj->con); if (pwd) { ZVAL_STRING(ret, pwd, 1); } else { ZVAL_STRING(ret, "", 1); } return ret; } case 7: /* row */ ZVAL_LONG(ret, obj->row_id); return ret; case 8: /* rows in result. */ ZVAL_LONG(ret, obj->result ? gda_data_model_get_n_rows (obj->result) : 0 ); return ret; case 9: /* 9 = fetched */ { int column_id; GdaRow *row; array_init(ret); if (!obj->result) { return ret; } row = (GdaRow *) gda_data_model_get_row (obj->result, obj->row_id); if (!row) { return ret; } for (column_id = 0; column_id < gda_data_model_get_n_columns (obj->result); column_id++) { zval *value, *ztitle; GdaValue *gdavalue; char *title; ulong h; title = (gchar *) gda_data_model_get_column_title (obj->result, column_id); gdavalue = (GdaValue *) gda_row_get_value (row, column_id); MAKE_STD_ZVAL(value); dbdo_value_to_zval(gdavalue,value TSRMLS_CC); /* g_free(title);is this needed?? */ h = zend_hash_func(title, strlen(title)+1); zend_hash_quick_update((HashTable *) Z_ARRVAL_P(ret), title, strlen(title)+1, h, &value, sizeof(zval *), NULL); } return ret; } case 10: /* config */ { dbdo_config *config; array_init(ret); config = dbdo_config_get(obj->table->dsn TSRMLS_CC); add_assoc_string(ret,"require_path",config->require_path ? config->require_path : "", 1); add_assoc_string(ret,"class_name",config->class_name ? config->class_name : "", 1); add_assoc_string(ret,"links",config->links ? config->links : "", 1); add_assoc_long(ret,"quote_identifiers",(int) config->quote_identifiers); add_assoc_long(ret,"lowercase_columns",(int) config->lowercase_columns); return ret; } case 11: /* 11 = sequence Column */ if (!obj->table->sequenceColumn) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->table->sequenceColumn, 1); } return ret; case 12: /* 12 = sequence is native? */ ZVAL_BOOL(ret, obj->table->sequenceIsNative); return ret; case 13: /* 13 = assigned or guessed? */ ZVAL_BOOL(ret, obj->table->sequenceAssigned); return ret; case 14: /* 14 = sequenceName */ if (!obj->table->sequenceName) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->table->sequenceName, 1); } return ret; case 15: /* keys */ { zval **zconfig; int i; array_init(ret); if (!obj->table->keys_len) { return ret; } zconfig = emalloc(sizeof(zval *) * obj->table->keys_len); for (i = 0; i < obj->table->keys_len; i++) { MAKE_STD_ZVAL(zconfig[i]); ZVAL_STRING(zconfig[i], obj->table->keys[i] , 1); zend_hash_next_index_insert( HASH_OF(ret), (void *) &zconfig[i], sizeof(zval *), NULL); } efree(zconfig); return ret; } case 16: /*"where", */ if (!obj->condition->where) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->condition->where, 1); } return ret; case 17: /* "group_by", */ if (!obj->condition->groupBy) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->condition->groupBy, 1); } return ret; case 18: /* "order_by",*/ if (!obj->condition->orderBy) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->condition->orderBy, 1); } return ret; case 19: /* "having",*/ if (!obj->condition->having) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->condition->having, 1); } return ret; case 20: /* "limit_from",*/ if (!obj->condition->limit_use) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_LONG(ret, obj->condition->limit_from); } return ret; case 21: /* "limit_qty",*/ if (!obj->condition->limit_use) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_LONG(ret, obj->condition->limit_qty); } return ret; case 22: /* "select" */ if (!obj->condition->data_select) { ZVAL_BOOL(ret, FALSE); } else { ZVAL_STRING(ret, obj->condition->data_select, 1); } return ret; } FREE_ZVAL(ret); return NULL; } PHP_METHOD(dbdo,__construct) { zval *object = getThis(); char *database_name; char *table_name; int database_name_length; int table_name_length; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &database_name, &database_name_length, &table_name,&table_name_length) == FAILURE) { RETURN_FALSE; } if (!object) { DBDO_DEBUG0(16,"NO OBJECT!"); RETURN_FALSE; } obj->table = dbdo_table_new(database_name, table_name TSRMLS_CC); if (!dbdo_connect(obj TSRMLS_CC)) { DBDO_DEBUG0(16,"CONNECT FAILED!"); RETURN_FALSE; } /* should we allow anonymous (eg. no table ??) */ /* schema loading should be done as required, so cached calls work. if (!dbdo_schema_load(obj TSRMLS_CC)) { RETURN_FALSE; } */ DBDO_DEBUG0(16,"CONSTUCTOR DONE!!"); } /* {{{ proto mixed DBDO::factory ( $dsn, $table ) instantate a class based on the config. */ PHP_METHOD(dbdo,factory) { /* only supports dsn : key : valueat present */ zval *eretval, *c_ret, constructor; int v, dsn_len, table_len; char *cmd, *fn, *compiled_string_description, *dsn, *table, *classname, *lc_name, *dsn_cp, *table_cp; dbdo_config *con; zend_class_entry **ce; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &dsn, &dsn_len, &table, &table_len) == FAILURE) { RETURN_FALSE; } con = dbdo_config_get(dsn TSRMLS_CC); if (!con->class_name || !strlen(con->class_name)) { /* these are preventable errors: so php_error it.. */ php_error_docref(NULL TSRMLS_CC, E_ERROR, "DBDO::factory - configuration class_name is not set, \n" "class_name: %s", con->class_name ? con->class_name : "EMPTY" ); return; } /* a does the class exist */ spprintf(&classname, 0, con->class_name, table); DBDO_DEBUG(16, "looking for class name: %s", classname); /* now does the class exist!! (lowercase for searching?) */ lc_name = emalloc(strlen(classname) + 1); zend_str_tolower_copy(lc_name, classname, strlen(classname)); /* we need to dupe these values as they seem to get lost after doing any type of call stuff. */ if (SUCCESS != zend_hash_find(EG(class_table), lc_name, strlen(classname)+1, (void **) &ce)) { /* require_once '%s';\0 */ if (!con->require_path || !strlen(con->require_path)) { efree(classname); efree(lc_name); php_error_docref(NULL TSRMLS_CC, E_ERROR, "DBDO::factory - configuration problem: require_path is not set, \n" "require_path: %s", con->require_path ? con->require_path : "EMPTY" ); return; } /* I cant think of any better way to do this.. - this is cheesy but it works.. */ spprintf(&fn, 0, con->require_path, table); spprintf(&cmd, 0, "require_once '%s';",fn); efree(fn); eretval = emalloc(sizeof(zval)); compiled_string_description = zend_make_compiled_string_description("DBDO::factory()" TSRMLS_CC); zend_eval_string(cmd, eretval, compiled_string_description TSRMLS_CC); efree(compiled_string_description ); efree(cmd); zval_dtor(eretval); FREE_ZVAL(eretval); } /* create the instance */ if (SUCCESS != zend_hash_find(EG(class_table), lc_name, strlen(classname)+1, (void **) &ce)) { efree(lc_name); zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::factory - class %s does not exist", classname); efree(classname); return; } efree(lc_name); if ((*ce)->ce_flags & ZEND_ACC_INTERFACE) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::factory - class %s is an interface", classname); efree(classname); return; } /* now instantate it!! */ object_init_ex(return_value, *ce); zend_objects_store_add_ref(return_value TSRMLS_CC); /* call the constructor with dsn & tablename */ /* TODO should check if extends DBDO!! */ if (!zend_hash_exists(&Z_OBJCE_P(return_value)->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME))) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::factory - could not find constructor for class %s (make sure it extends DBDO)", classname); efree(classname); return; } { zval *cb_data[2]; zval **cb_args[2]; efree(classname); /* MAKE_STD_ZVAL(c_ret); */ c_ret = NULL; /*ALLOC_ZVAL(constructor); */ DBDO_DEBUG2(16,"calling constructor on object with args %s , %s",dsn, table); MAKE_STD_ZVAL(cb_data[0]); ZVAL_STRING(cb_data[0], dsn, 1); cb_args[0] = &cb_data[0]; MAKE_STD_ZVAL(cb_data[1]); ZVAL_STRING(cb_data[1], table, 1); cb_args[1] = &cb_data[1]; ZVAL_STRING(&constructor, ZEND_CONSTRUCTOR_FUNC_NAME, 1); if (call_user_function_ex(EG(function_table), &return_value, &constructor, &c_ret, 2, cb_args, 0, NULL TSRMLS_CC) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error calling constructor"); } zval_dtor(&constructor); zval_dtor(cb_data[0]); FREE_ZVAL(cb_data[0]); zval_dtor(cb_data[1]); FREE_ZVAL(cb_data[1]); if (c_ret) { zval_dtor(c_ret); FREE_ZVAL(c_ret); } } } /* {{{ proto mixed $dbdo->schema ( [string column] ) get schema info about a table (no args returns a list of columns), */ PHP_METHOD(dbdo,schema) { zval *object = getThis(); gint rows,column_id, row_id; GdaRow *row; gint col; GdaValue *value; gchar *string, *title, *ntitle; zval *zvalue; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *column_name; int column_name_length; ulong h; dbdo_schema_load(obj TSRMLS_CC); if (ZEND_NUM_ARGS() == 0) { column_id = gda_data_model_get_column_position(obj->table->schema,"Field name"); if (column_id == -1) { RETURN_FALSE; } array_init(return_value); rows = gda_data_model_get_n_rows (obj->table->schema); for (row_id = 0; row_id < rows;row_id++) { row = (GdaRow *) gda_data_model_get_row (obj->table->schema, row_id); value = (GdaValue *) gda_row_get_value (row, column_id); string = gda_value_stringify (value); MAKE_STD_ZVAL(zvalue); ZVAL_STRING(zvalue, string, 1); g_free(string); zend_hash_next_index_insert(HASH_OF(return_value), &zvalue, sizeof(zval *), NULL); } return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &column_name, &column_name_length) == FAILURE) { RETURN_FALSE; } row_id = dbdo_schema_get_col_row(obj,column_name); if (row_id < 0) { DBDO_DEBUG0(16,"lost it"); RETURN_FALSE; } array_init(return_value); row = (GdaRow *) gda_data_model_get_row (obj->table->schema, row_id); for (column_id = 0; column_id < (int) gda_data_model_get_n_columns (obj->table->schema); column_id++) { title = (gchar *)gda_data_model_get_column_title (obj->table->schema, column_id); ntitle = estrdup(title); value = (GdaValue *) gda_row_get_value (row, column_id); MAKE_STD_ZVAL(zvalue); string = gda_value_stringify (value); if (!string) { ZVAL_NULL(zvalue); } else { ZVAL_STRING(zvalue, string, 1); g_free(string); } h = zend_hash_func(title, strlen(title)+1); zend_hash_quick_update(HASH_OF(return_value), ntitle, strlen(title)+1, h, &zvalue, sizeof(zval *), NULL); efree(ntitle); } } /* {{{ proto mixed $dbdo->get ( [value|key] [value] ) perform the select on either the sequence key column = value, or a column=>value combo - fetching the result into the object. - returns 0 | 1 - throws exception if more than 1 row returned.. */ PHP_METHOD(dbdo,get) { zval *object = getThis(); char *search_key = NULL, *search_value = NULL; int key_len, value_len, rows; GdaCommand *gdacmd; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); smart_str cmd = {0}; if (G_IS_OBJECT(obj->result)) { php_error(E_WARNING, "DBDO::%s(): was run on a object with results", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } /* test ? - if I send it an it, are we going to be ok? */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &search_key, &key_len, &search_value, &value_len ) == FAILURE) { RETURN_FALSE; } smart_str_appends(&cmd, "SELECT "); if (obj->condition->data_select != NULL) { smart_str_appends(&cmd, obj->condition->data_select); } else { smart_str_appends(&cmd, "*"); } smart_str_appends(&cmd, " FROM "); smart_str_appends(&cmd, obj->table->name); smart_str_appends(&cmd, " WHERE "); /* 1 arg = use sequence keys.. */ if (!search_value) { GdaValue *gdav_tmp; gchar * sql_str; gchar *skey_cpy; /* get the sequence key - and try to guess the key */ dbdo_sequence_guess(obj); if (obj->table->sequenceColumn == NULL) { smart_str_free(&cmd); zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::get sequence unknown ", 0 TSRMLS_CC); return; } smart_str_appends(&cmd, obj->table->sequenceColumn); smart_str_appends(&cmd, " = "); gdav_tmp = g_new0 (GdaValue, 1); gda_value_set_from_string(gdav_tmp, search_key, dbdo_value_type_from_column(obj, obj->table->sequenceColumn)); sql_str = (char *) gda_connection_value_to_sql_string (obj->con, gdav_tmp); smart_str_appends(&cmd, sql_str); g_free(sql_str); } else { GdaValue *gdav_tmp; GdaValueType vtype; char *tmpstr; smart_str_appends(&cmd, search_key); smart_str_appends(&cmd, " = "); DBDO_DEBUG(16,"Look up type %s", search_key); vtype = dbdo_value_type_from_column(obj, search_key); DBDO_DEBUG(16,"Got Type %d", (int) vtype); if (vtype == GDA_VALUE_TYPE_UNKNOWN) { smart_str_free(&cmd); zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::get unknown column type for %s", search_key); return; } gdav_tmp = g_new0 (GdaValue, 1); tmpstr = estrdup(search_value); gda_value_set_from_string(gdav_tmp, (const gchar*) tmpstr, vtype); tmpstr = (char *) gda_connection_value_to_sql_string (obj->con, gdav_tmp); smart_str_appends(&cmd, tmpstr); g_free(tmpstr); } smart_str_0(&cmd); DBDO_DEBUG(1,"QUERY:\n%s\n",cmd.c); gdacmd = gda_command_new ((gchar*)cmd.c, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); obj->result = gda_connection_execute_single_command (obj->con, gdacmd, NULL); smart_str_free(&cmd); gda_command_free (gdacmd); /*? do we really want to do this? */ if (gda_connection_get_errors(obj->con) || (obj->result == NULL)) { dbdo_throw_errors (obj->con TSRMLS_CC); return; } g_object_ref(obj->result); rows = gda_data_model_get_n_rows (obj->result); /* flag it as got! - this is soooo clean! */ obj->row_id = -1; if (rows > 0) { obj->row_id = 0; } /* Throw exception if more than one row is returned. */ if (rows != 1) { g_object_unref(obj->result); obj->row_id = -1; obj->result = NULL; zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::%s failed to return only 1 row. (%d returned)", get_active_function_name(TSRMLS_C), rows); RETURN_FALSE; } dbdo_fetch_into_properties(object TSRMLS_CC); zend_objects_store_add_ref(object TSRMLS_CC); /* g_print("returning %d",rows); */ RETURN_LONG(rows); } /* {{{ proto mixed $dbdo->query ( [$query] ) Without arguments, it builds a query based on the object var values. with $query - sends a raw query to the database. */ PHP_METHOD(dbdo,query) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *cmd = NULL; int cmd_len; GdaCommand *gdacmd; GdaDataModel *dm; gint rows; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &cmd, &cmd_len) == FAILURE) { RETURN_FALSE; } /* it's pretty clear that we should not run a query on the same object using $obj->factory()->query('xxx') seems a reasonable trade off given the wierd situation that may occur trying to run a raw query on a existing object.. */ if (cmd) { /* if (cmd_len == 5 && strncasecmp(cmd, "BEGIN",5)) { dbdo_connect(obj); if (DBDO_G(transaction) !== NULL) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::Query BEGIN was run when Transaction already started", 0 TSRMLS_CC); return; } DBDO_G(transaction) = gda_transaction_new("dbdo"); gda_transaction_set_isolation_levelDBDO_G(transaction), GDA_TRANSACTION_ISOLATION_SERIALIZABLE); gda_connection_begin_transaction(obj->con,DBDO_G(transaction)); RETURN_TRUE; } */ if (obj->result && gda_data_model_get_n_rows (obj->result) > 0) { /* this should be an error!! = but we are trying out exeptions.. */ zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::Query was run on a object with results ", 0 TSRMLS_CC); return; } if (obj->result) { g_object_unref (obj->result); obj->result = NULL; } dbdo_connect(obj TSRMLS_CC); /* TODO: catch transaction queries : BEGIN,COMMIT,ROLLBACK Logging detecting SELECT etc. for returned rows or affected rows.. */ DBDO_DEBUG(1,"QUERY: \n%s\n",cmd); gdacmd = gda_command_new ((gchar*)cmd, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); if (gda_connection_get_errors(obj->con)) { dbdo_throw_errors (obj->con TSRMLS_CC); return; } obj->result = gda_connection_execute_single_command (obj->con, gdacmd, NULL); /* g_object_ref(obj->result); */ gda_command_free(gdacmd); /* if the first 6 characters of command = update|insert|delete then return the affected rows..? otherwise return number of rows returned.. */ } else { if (obj->result && G_IS_OBJECT(obj->result)) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::query was run on a object with results ", 0 TSRMLS_CC); return; } /* if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &autofetch) == FAILURE) { RETURN_FALSE; } */ obj->row_id = -1; cmd = dbdo_find_query_build(object, obj, DBDO_QUERY_BUILD_SELECT TSRMLS_CC); if (cmd == NULL) { /* on throw. */ return; } DBDO_DEBUG(1,"QUERY: \n%s\n",cmd); gdacmd = gda_command_new ((gchar*)cmd, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); obj->result = gda_connection_execute_single_command (obj->con, gdacmd, NULL); /*g_object_ref(obj->result); */ gda_command_free (gdacmd); /* ? do we really want to do this? */ efree(cmd); if (gda_connection_get_errors(obj->con) || (obj->result == NULL)) { dbdo_throw_errors (obj->con TSRMLS_CC); return; } } rows = gda_data_model_get_n_rows (obj->result); if (rows < 1) { /* we should keep obj->result, so that fetchAll works on empty results. g_object_unref (obj->result); obj->result = NULL; */ } /* zend_bool autofetch = FALSE; if (autofetch) { if (!rows) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::find(autofetch) failed, as there where no results" ); return; } else { obj->row_id = 0; } } */ RETURN_LONG(rows); } /* {{{ proto mixed $dbdo->fetchAll ( DBDO::OBJECTS | DBDO::VALUE | DBDO::KEY_VALUE | DBDO::SINGLE ) perform the fetch, and returl All the results, in various formats throws errors if return set is unexpected, php_errors, if you specified the wrong number of columns. */ PHP_METHOD(dbdo,fetchAll) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); gint rows,r; GdaCommand *gdacmd; GdaRow *row; GdaValue *value; char *cmd; int return_type = 0; /* DEFAULT = array of objects.. */ DBDO_DEBUG0(16,"run Fetchall SQL"); if (!obj->result || !G_IS_OBJECT(obj->result)) { /* maybe this should be a php_error */ zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::%s you must call query() before fetchAll", get_active_function_name(TSRMLS_C) ); return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &return_type) == FAILURE) { RETURN_FALSE; } if (obj->row_id != -1) { /* maybe this should be a php_error */ zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::%s() you can not run fetchAll() after calling fetch() or fetchAll on the same object", get_active_function_name(TSRMLS_C) ); return; } if (obj->result == NULL) { dbdo_throw_errors (obj->con TSRMLS_CC); return; } switch (return_type) { case 0: /* DBDO::OBJECTS - array of objects. */ array_init(return_value); /* use cloning */ for (r = 0; r < gda_data_model_get_n_rows (obj->result); r++) { zval *zclone; dbdo_object *dclone; MAKE_STD_ZVAL(zclone); zclone->type = IS_OBJECT; zclone->value.obj = dbdo_clone(object TSRMLS_CC); dclone = zend_object_store_get_object(zclone TSRMLS_CC); dclone->row_id = r; dbdo_fetch_into_properties(zclone TSRMLS_CC); zend_hash_next_index_insert(HASH_OF(return_value), &zclone, sizeof(zval *), NULL); } g_object_unref(obj->result); obj->result = NULL; return; case 1: /* DBDO::KEY_VALUE */ { zval *value_r; char *string; ulong h; if (gda_data_model_get_n_columns(obj->result) != 2) { php_error(E_WARNING, "DBDO::%s(DBDO::KEY_VALUE) you must select exactly 2 columns, %d returned", get_active_function_name(TSRMLS_C), gda_data_model_get_n_columns(obj->result)); obj->result = NULL; return; } array_init(return_value); for (r = 0; r < gda_data_model_get_n_rows (obj->result); r++) { zval *value_r; GdaValue *rvalue; gchar *gstr; value = (GdaValue *) gda_data_model_get_value_at (obj->result, 0, r); gstr = gda_value_stringify (value); string = estrdup(gstr); g_free(gstr); h = zend_hash_func(string, strlen(string)+1); rvalue = (GdaValue *) gda_data_model_get_value_at (obj->result, 1, r); MAKE_STD_ZVAL(value_r); dbdo_value_to_zval(rvalue,value_r TSRMLS_CC); gstr = gda_value_stringify(rvalue); DBDO_DEBUG2(16,"got row: %s,%s",string, gstr); g_free(gstr); zend_hash_quick_update(HASH_OF(return_value), string, strlen(string)+1, h, &value_r, sizeof(zval *), NULL); efree(string); } g_object_unref(obj->result); obj->result = NULL; return; } case 2: /* VALUE */ if (gda_data_model_get_n_columns(obj->result) != 1) { php_error(E_WARNING, "DBDO::%s(DBDO::VALUE) you must select exactly 1 column, %d returned", get_active_function_name(TSRMLS_C), gda_data_model_get_n_columns(obj->result)); g_object_unref(obj->result); obj->result = NULL; return; } array_init(return_value); for (r = 0; r < gda_data_model_get_n_rows (obj->result); r++) { gchar *gstr; zval *value_r; /*MAKE_STD_ZVAL(value_r); ZVAL_LONG(value_r,123); zend_hash_next_index_insert(HASH_OF(return_value), (void *) &value_r, sizeof(zval *), NULL); */ GdaValue *rvalue; rvalue = (GdaValue *) gda_data_model_get_value_at (obj->result, 0, r); MAKE_STD_ZVAL(value_r); dbdo_value_to_zval(rvalue,value_r TSRMLS_CC); gstr = gda_value_stringify(rvalue); DBDO_DEBUG(16,"got row: %s",gstr); g_free(gstr); zend_hash_next_index_insert(HASH_OF(return_value), (void *) &value_r, sizeof(zval *), NULL); } g_object_unref(obj->result); obj->result = NULL; return; case 3: /* SINGLE */ { zval *ret; rows = (gint) gda_data_model_get_n_rows (obj->result); if (!rows || rows > 1) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::%s(DBDO::SINGLE) must return exactly 1 row. %d returned", get_active_function_name(TSRMLS_C), rows ); obj->result = NULL; return; } rows = (gint) gda_data_model_get_n_columns (obj->result); if (!rows || rows > 1) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::selectAll(DBDO::SINGLE) must return exactly 1 column. %d returned", rows ); obj->result = NULL; return; } value = (GdaValue *) gda_data_model_get_value_at(obj->result, 0, 0); MAKE_STD_ZVAL(ret); dbdo_value_to_zval(value,ret TSRMLS_CC); zval_add_ref(&ret); *return_value = *ret; /*zval_dtor(ret);*/ FREE_ZVAL(ret); g_object_unref(obj->result); obj->result = NULL; return; } } } void dbdo_fetch_into_property(zval *object, GdaRow *row, int column_id TSRMLS_DC) { zval *znew_value = NULL; GdaValue *value; gchar *gtitle; char *title; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); gtitle = (gchar *) gda_data_model_get_column_title (obj->result, column_id); title = estrdup(gtitle); value = (GdaValue *) gda_row_get_value (row, column_id); if (!value) { efree(title); return; } MAKE_STD_ZVAL(znew_value); dbdo_value_to_zval(value, znew_value TSRMLS_CC); zend_update_property(Z_OBJCE_P(object), object, title, strlen(title), znew_value TSRMLS_CC); efree(title); } void dbdo_fetch_into_properties(zval *object TSRMLS_DC) { GdaRow *row; gint column_id; gint cols; /* TODO assert stuff */ dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); DBDO_DEBUG(16,"FETCH DATA AT ROW %d",obj->row_id); row = (GdaRow *) gda_data_model_get_row (obj->result, obj->row_id); if (!row) { return; } cols = gda_data_model_get_n_columns (obj->result); for (column_id = 0; column_id < cols; column_id++) { //if (column_id > 4) { // return; //} dbdo_fetch_into_property(object, row, column_id TSRMLS_CC); } } /* {{{ proto mixed $dbdo->fetch ( ) fetch the results into the object's properties */ PHP_METHOD(dbdo,fetch) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); zval *ztitle; GList *node; gint column_id; GdaValue *value; GdaRow *row; gchar *string; gchar *title; if (obj->result == NULL) { /* throw errror!! */ RETURN_FALSE; } /* destroy the row data hash */ obj->row_id++; if (obj->row_id >= gda_data_model_get_n_rows (obj->result)) { /*g_print("fetched all? %d >= %d unreffing dm?\n",obj->row_id , gda_data_model_get_n_rows (obj->dm)); */ /* we cant free it here as it may be used later! */ /* g_object_unref (obj->dm); */ if (obj->result && G_IS_OBJECT(obj->result)) { g_object_unref(obj->result); obj->result = NULL; } /* obj->dm = NULL; */ RETURN_FALSE; } dbdo_fetch_into_properties(object TSRMLS_CC); zend_objects_store_add_ref(object TSRMLS_CC); RETURN_TRUE; } /* {{{ proto mixed $dbdo->count ( what ) fetch the number of results that would be returned old args where: whereAddOnly ... is this necessary?????? Probably not..! should we add a clear method??!! (to removed assigned args) countWhat .. used to do distinct(xxxx) */ PHP_METHOD(dbdo,count) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *old_data_select; char *str = NULL; int str_len =0; gint rows; GdaCommand *gdacmd; GdaDataModel *dm; GdaRow *row; GdaValue *value; char *cmd; zval *ret; /* $quoteIdentifiers = !empty($_DB_DATAOBJECT['CONFIG']['quote_identifiers']); */ /* the old design didnt allow this to happen after a fetch we keep the query args after a find, so we could use them however - it has a horrible snag that we may get upredictable results based on the fact that you dont know if it would/should use the result values. so we will stick with the old behavior.. */ if (G_IS_OBJECT(obj->result)) { /* programming error!! - not exception! */ zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::count was run on a object with results", 0 TSRMLS_CC); return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &str, &str_len ) == FAILURE) { RETURN_FALSE; } /* magic trickery - replace out the obj->condition. */ old_data_select = obj->condition->data_select; obj->condition->data_select = NULL; if (str != NULL) { spprintf(&(obj->condition->data_select), 0, "count(%s) as DATAOBJECT_NUM",str); } else { /* %s.%s as DATAOBJECT_NUM */ int size; /* load sequence */ dbdo_sequence_guess(obj); if (obj->table->sequenceColumn == NULL) { obj->condition->data_select = old_data_select; zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::count sequence unknown ", 0 TSRMLS_CC); return; } spprintf(&(obj->condition->data_select), 0, "count(%s.%s) as DATAOBJECT_NUM", obj->table->name, obj->table->sequenceColumn); } cmd = dbdo_find_query_build(object, obj, DBDO_QUERY_BUILD_SELECT TSRMLS_CC); /* restore */ efree(obj->condition->data_select); obj->condition->data_select = old_data_select; if (cmd == NULL) { /* exception situation. */ return; } old_data_select = obj->condition->data_select; obj->condition->data_select = NULL; DBDO_DEBUG(16,"find SQL: %s",cmd); gdacmd = gda_command_new ((gchar*)cmd, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); dm = gda_connection_execute_single_command (obj->con, gdacmd, NULL); gda_command_free (gdacmd); /* ? do we really want to do this? */ efree(cmd); if (gda_connection_get_errors(obj->con)) { dbdo_throw_errors (obj->con TSRMLS_CC); return; } value = (GdaValue *) gda_data_model_get_value_at(dm, 0, 0); MAKE_STD_ZVAL(return_value); dbdo_value_to_zval(value,return_value TSRMLS_CC); zval_add_ref(&return_value); } /* {{{ proto array $do->toArray ( [ string $format ] ) get the result as an array from the object, and optionally format it. */ PHP_METHOD(dbdo,toArray) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *format = NULL; int format_len = 0, column_id; GdaRow *row; gchar *title,*ftitle; /* TODO: barf it not a column ?*/ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &format, &format_len) == FAILURE) { RETURN_FALSE; } array_init(return_value); row = (GdaRow *) gda_data_model_get_row (obj->result, obj->row_id); for (column_id = 0; column_id < gda_data_model_get_n_columns (obj->result); column_id++) { zval *value = NULL, *ztitle = NULL; GdaValue *gdavalue; ulong h; title = (gchar *) gda_data_model_get_column_title (obj->result, column_id); MAKE_STD_ZVAL(ztitle); ZVAL_STRING(ztitle, title, 1); value = std_object_handlers.read_property(object, ztitle, BP_VAR_IS TSRMLS_CC); zval_dtor(ztitle); FREE_ZVAL(ztitle); if (!format_len) { ftitle = estrdup(title); } else { spprintf(&ftitle, 0, format, title); } zval_add_ref(&value); /* g_free(title);is this needed?? */ DBDO_DEBUG2(16,"ADDING %s, %x", ftitle, value); h = zend_hash_func(ftitle, strlen(ftitle)+1); zend_hash_quick_update((HashTable *) Z_ARRVAL_P(return_value), ftitle, strlen(ftitle)+1, h, &value, sizeof(zval *), NULL); efree(ftitle); if (format_len) { /* efree(title); */ } } } /* {{{ proto array $do->assignFrom ( [ array|object $from ], $format ) assign object variable from a array or object. */ PHP_METHOD(dbdo,assignFrom) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *format = NULL; int format_len = 0; zval *from; gint rows,row_id; zval *ztitle; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|s", &from, &format, &format_len) == FAILURE) { RETURN_FALSE; } if ((Z_TYPE_P(from) != IS_OBJECT) && (Z_TYPE_P(from) != IS_ARRAY)) { RETURN FALSE; php_error_docref(NULL TSRMLS_CC, E_ERROR, "DBDO::assignFrom invalid type provided '%s'\n",zend_zval_type_name(from)); } dbdo_schema_load(obj TSRMLS_CC); /* loop through schema - skip sequenceKey. - if object: - if formated value exists use = .... - else continue; - if formated value in array use = .... - if (!use) continue - if setter exists on self - use it. - if setter throws exception.. - return..) continue; - if use = array|object throw exception. - TODO:: run it through assignValue('name',$value) - assign value ontinue; */ rows = gda_data_model_get_n_rows (obj->table->schema); for (row_id = 0; row_id < rows;row_id++) { char *colname; char *setter; zval *use = NULL; zval *zotitle; GdaValue *gdav_tmp; colname = (gchar *) gda_value_get_string ( (GdaValue *) gda_data_model_get_value_at (obj->table->schema, 0, row_id)); MAKE_STD_ZVAL(ztitle); if (!format_len) { ZVAL_STRING(ztitle, colname, 1); } else { char *tmp_col = NULL; spprintf(&tmp_col, 0, format, colname); ZVAL_STRING(ztitle, tmp_col, 0); } if (Z_TYPE_P(from) == IS_OBJECT) { if (!Z_OBJ_HT_P(object)->has_property(from, ztitle, 0 TSRMLS_CC)) { zval_dtor(ztitle); FREE_ZVAL(ztitle); continue; } use = Z_OBJ_HT_P(object)->read_property(from, ztitle, BP_VAR_IS TSRMLS_CC); /* not sure if this is going to be needed here.. or should we call toArray??? */ /* zval_copy_ctor(&use); */ } if (Z_TYPE_P(from) == IS_ARRAY) { zval **element; if (zend_hash_find(HASH_OF(from), Z_STRVAL_P(ztitle), Z_STRLEN_P(ztitle)+1, (void **) &element) == FAILURE) { zval_dtor(ztitle); FREE_ZVAL(ztitle); continue; } use = *element; /* zval_copy_ctor(use); */ } /* should never happen really.. */ if (use == NULL) { zval_dtor(ztitle); FREE_ZVAL(ztitle); continue; } spprintf(&setter, 0, "set%s",colname); /* call setter ! */ if (zend_hash_exists(&Z_OBJCE_P(object)->function_table, setter, strlen(setter)+1)) { zval *c_ret = NULL; zval **cb_args[1]; zval zsetter; /* MAKE_STD_ZVAL(c_ret); */ /*ALLOC_ZVAL(constructor); */ cb_args[0] = &use; ZVAL_STRING(&zsetter, setter, 0); if (call_user_function_ex(EG(function_table), &object, &zsetter, &c_ret, 1, cb_args, 0, NULL TSRMLS_CC) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "DBDO::assignFrom Error calling setter"); /* TODO : - what happens here!!! */ } zval_dtor(&zsetter); /* return if it threw an exception */ if (c_ret) { zval_dtor(c_ret); FREE_ZVAL(c_ret); } zval_dtor(ztitle); FREE_ZVAL(ztitle); continue; } else { efree(setter); setter = NULL; zval_dtor(ztitle); FREE_ZVAL(ztitle); } /* TODO: implement toValue() */ /* set it manually.. */ zval_add_ref(&use); zend_update_property(Z_OBJCE_P(object), object, colname, strlen(colname), use TSRMLS_CC); } /* no idea if this is needed.. */ zend_objects_store_add_ref(object TSRMLS_CC); RETURN_TRUE; } /* {{{ */ /* Local zend_object_value creation (on stack) Load the 'other' object Create a new empty object (See spl_ce_dir_object_new_ex) Open the directory Clone other members (properties) */ static zend_object_value dbdo_clone(zval *zobject TSRMLS_DC) { zend_object_value new_obj_val; zend_object *old_object; zend_object *new_object; zend_object_handle handle = Z_OBJ_HANDLE_P(zobject); dbdo_object *intern; dbdo_object *old_obj; old_object = zend_objects_get_address(zobject TSRMLS_CC); old_obj = zend_object_store_get_object(zobject TSRMLS_CC); /*new_obj_val = dbdo_object_new_ex(old_object->ce, &intern TSRMLS_CC); */ { zend_class_entry *class_type = old_object->ce; zval *tmp; intern = emalloc(sizeof(dbdo_object)); intern->zo.ce = class_type; intern->zo.in_get = 0; intern->zo.in_set = 0; intern->zo.properties = NULL; intern->con = old_obj->con; intern->result = old_obj->result; if (G_IS_OBJECT(intern->result)) { g_object_ref(intern->result); } intern->row_id = old_obj->row_id; /* ALL THESE need refcounting */ intern->table = old_obj->table; intern->condition = old_obj->condition; if (intern->condition) { old_obj->condition->refcount++; } ALLOC_HASHTABLE(intern->zo.properties); zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); new_obj_val.handle = zend_objects_store_put(intern, NULL, (zend_objects_free_object_storage_t) dbdo_object_free_storage, NULL TSRMLS_CC); new_obj_val.handlers = (zend_object_handlers *) & dbdo_object_handlers; } new_object = &intern->zo; zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC); return new_obj_val; } /* {{{ void $dbdo->sequenceKey ($name,$isNative=false,$sequence_name=NULL) ) set the tables sequence column and details. */ PHP_METHOD(dbdo,sequenceKey) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *column,*sequenceName; gboolean isNative; int column_length, sequenceName_length; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bs", &column, &column_length, &isNative, &sequenceName,&sequenceName_length ) == FAILURE) { RETURN_FALSE; } obj->table->sequenceAssigned = TRUE; /* free up the old values */ if (obj->table->sequenceColumn) { efree(obj->table->sequenceColumn); obj->table->sequenceColumn = NULL; } if (obj->table->sequenceName) { efree(obj->table->sequenceName); obj->table->sequenceName = NULL; } obj->table->sequenceColumn = estrdup(column); obj->table->sequenceIsNative = (ZEND_NUM_ARGS()>1) ? isNative : FALSE; if (ZEND_NUM_ARGS()>2) { obj->table->sequenceName = estrdup( sequenceName); } RETURN_TRUE; } /* {{{ proto mixed $dbdo->key ($name [,$name [,.....]] ) set the key columsn */ PHP_METHOD(dbdo,keys) { zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); int i,row_id; zval ***args; dbdo_schema_load(obj TSRMLS_CC); /* should this be (void **) &sequence_struct */ args = emalloc(sizeof(zval **) * ZEND_NUM_ARGS()); zend_get_parameters_array_ex( ZEND_NUM_ARGS(), args); for (i = 0; i < ZEND_NUM_ARGS(); i++) { if (Z_TYPE_PP(args[i]) != IS_STRING) { php_error(E_ERROR,"All arguments must be strings"); efree(args); return; } row_id = dbdo_schema_get_col_row(obj,Z_STRVAL_PP(args[i])); if (row_id == -1) { php_error(E_ERROR,"Table does not have a column called '%s'",Z_STRVAL_PP(args[i])); efree(args); return; } } /* not likely to happen much - so we are pretty messy with it. */ for (i=0;i< obj->table->keys_len; i++) { efree(obj->table->keys[i]); } if (obj->table->keys_len) { efree(obj->table->keys); } obj->table->keys = NULL; obj->table->keys = emalloc(sizeof(char *) * ZEND_NUM_ARGS()); for (i = 0; i < ZEND_NUM_ARGS(); i++) { obj->table->keys[i] = estrdup(Z_STRVAL_PP(args[i])); } obj->table->keys_len = ZEND_NUM_ARGS(); efree(args); RETURN_TRUE; } /* {{{ proto mixed $dbdo->insert ( ) insert the contents of the object properties into the database */ PHP_METHOD(dbdo,insert) { zval *object = getThis(); zval *zvalue, value_copy; long ret_int = 0; char **result_cols; GdaValue **result_values; GList *node; gboolean errors = FALSE; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); gint column_id,rows,row_id; GdaValue *value; GdaDataModel *dm; GdaRow *row; gchar *string = NULL, *seqname = NULL, *ret_str = NULL; smart_str cmd = {0}; int started = 0, skippedseq; int nextId = 0; GdaCommand *gda_cmd; dbdo_schema_load(obj TSRMLS_CC); dbdo_sequence_guess(obj); if (obj->table->sequenceColumn == NULL) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::insert sequence unknown ", 0 TSRMLS_CC); return; } /* TODO: sequenceName usage */ if (obj->table->sequenceName) { php_error(E_ERROR, "DBDO::insert with sequenceName not implemented yet."); return; } if (obj->result && (gda_data_model_get_n_rows (obj->result) > 0)) { php_error(E_ERROR,"DBDO::insert(), you can not insert from an existing result, \n" "use: $new->assignFrom($do); $new->insert() "); return; } smart_str_appends(&cmd, "INSERT INTO "); smart_str_appends(&cmd, obj->table->name); smart_str_appends(&cmd, " ( "); rows = gda_data_model_get_n_rows (obj->table->schema); started = 0; skippedseq = 0; result_cols = emalloc(sizeof(char *) * rows); result_values = emalloc(sizeof(GdaValue *) * rows); for (row_id = 0; row_id < rows;row_id++) { gchar *colname; /* reset our result store */ result_cols[row_id] = NULL; result_values[row_id] = NULL; /* g_print("get from schema row:%d, col:%d\n",row_id,0); */ colname = (gchar *) gda_value_get_string ( (GdaValue *) gda_data_model_get_value_at (obj->table->schema, 0, row_id)); /* dont assign the sequence column */ if (!skippedseq && !strcmp(colname,obj->table->sequenceColumn)) { skippedseq = 1; /* g_print("Skipping matches column: %s\n",colname); */ continue; } /* insert from selected row ? */ zvalue = zend_read_property(Z_OBJCE_P(object), object, colname, strlen(colname), BP_VAR_IS TSRMLS_CC); if (zvalue == EG(uninitialized_zval_ptr)) { continue; } if (started) { smart_str_appends(&cmd, " , "); } DBDO_DEBUG(16,"::insert() ADDING %s",colname); result_cols[row_id] = colname; smart_str_appends(&cmd, colname); started = 1; } if (!started) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::insert No data found to assign to columns", 0 TSRMLS_CC); smart_str_free(&cmd); return; } DBDO_DEBUG0(16,"DONE LEFT:"); smart_str_appends(&cmd, " ) VALUES ( "); started = 0; skippedseq = 0; for (row_id = 0; row_id < rows;row_id++) { char *tmp_str, *tmp_str2; char *colname; GdaValueType gv; GdaValue *gvColname; gvColname = (GdaValue *) gda_data_model_get_value_at (obj->table->schema, 0, row_id); colname = (gchar *) gda_value_get_string ( gvColname ); DBDO_DEBUG(16,"col: %s", colname); if (!skippedseq && !strcmp(colname,obj->table->sequenceColumn)) { skippedseq = 1; continue; } /* if (!std_object_handlers.has_property(object, ztitle, 0 TSRMLS_CC)) { zval_dtor(ztitle); FREE_ZVAL(ztitle); continue; } */ zvalue = zend_read_property(Z_OBJCE_P(object), object, colname, strlen(colname), BP_VAR_IS TSRMLS_CC); if (zvalue == EG(uninitialized_zval_ptr)) { continue; } /* test that we can set it as a gdavalue (eg. it's the correct type ) */ value = dbdo_object_value_from_zval(obj, colname, zvalue TSRMLS_CC); if (!value) { zval_dtor(zvalue); smart_str_free(&cmd); return; } /* perhaps we should copy here.. */ /* zval_dtor(zvalue); */ DBDO_DEBUG0(16,"Succeeded!"); if (started) { smart_str_appends(&cmd, " , "); } /* TODO: -- use prepare /execute !!! */ tmp_str2 = (char *) gda_connection_value_to_sql_string (obj->con, value); smart_str_appends(&cmd, tmp_str2); g_free(tmp_str2); result_values[row_id] = value; started = 1; } smart_str_appends(&cmd, " )"); smart_str_0(&cmd); DBDO_DEBUG(1,"QUERY:\n%s\n", cmd.c); /* now get the autoincrement back!!! :) */ gda_cmd = gda_command_new ((gchar*)cmd.c, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); smart_str_free(&cmd); dm = gda_connection_execute_single_command (obj->con, gda_cmd, NULL); gda_command_free (gda_cmd); DBDO_DEBUG(16,"sent query", cmd.c); if (gda_connection_get_errors(obj->con)) { dbdo_throw_errors(obj->con TSRMLS_CC); RETURN_FALSE; } /* TODO: implement a wrapper around get_last_insert_id() */ ret_str = gda_connection_get_last_insert_id(obj->con, dm); DBDO_DEBUG(2,"returning %s", ret_str); ret_int = atol(ret_str); g_free(ret_str); /* make the dataset for the object from the args.. */ { GdaDataModel *model; int i,no_cols=0; GList *value_list = NULL; /* work out how may columns we have.. */ for (i=0;iresult = gda_data_model_array_new (no_cols+1); gda_data_model_set_column_title (obj->result, 0,obj->table->sequenceColumn); value_list = g_list_append (value_list, gda_value_new_integer ((gint) ret_int)); no_cols = 1; for (i=0;iresult, no_cols,result_cols[i]); /* printf("adding value %s\n", gda_value_stringify(result_values[i])); */ value_list = g_list_append (value_list, result_values[i]); no_cols++; } if (!gda_data_model_append_values (GDA_DATA_MODEL (obj->result), value_list)) { DBDO_DEBUG0(1,"error inserting rows."); return; } g_list_foreach (value_list, (GFunc) gda_value_free, NULL); g_list_free (value_list); g_object_ref(obj->result); obj->row_id = 0; } /* write_property the value to the object */ { zval *znew_value=NULL; MAKE_STD_ZVAL(znew_value); ZVAL_LONG(znew_value,ret_int); zend_update_property(Z_OBJCE_P(object), object, obj->table->sequenceColumn, strlen(obj->table->sequenceColumn), znew_value TSRMLS_CC); zend_objects_store_add_ref(object TSRMLS_CC); } efree(result_cols); efree(result_values); RETURN_LONG(ret_int); } int dbdo_str_in_array(char *str, char** strings, int len) { int i; if (!len) { return 0; } for (i=0; i < len; i++) { if (!strcmp(str, strings[i])) { return 1; } } return 0; } /* {{{ proto mixed $dbdo->update ( [DBDO::BUILD] ) update the database with contents of the object properties, TODO: utilize whereAdd() / limit() values (done when DBDO::BUILD used) */ PHP_METHOD(dbdo,update) { zval *object = getThis(); zval *zvalue,*ztitle; GdaCommand *gdacmd; GList *node; gboolean errors = FALSE; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); gint column_id,rows,row_id; GdaValue *value, *gdav; GdaRow *row; gchar *string, *colname, *sql_str; smart_str cmd = {0}; int started = 0, found_key = 0, i, build = 0; gint update_id; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &build) == FAILURE) { RETURN_FALSE; } dbdo_schema_load(obj TSRMLS_CC); smart_str_appends(&cmd, "UPDATE "); smart_str_appends(&cmd, obj->table->name); smart_str_appends(&cmd, " SET "); if (!build) { /* not build = use Sequence Key to update.. set : changes in everything except for sequenceKey (or keys if set) where = sequenceKeys or keys() */ DBDO_DEBUG0(16,"Building Changed Values"); dbdo_sequence_guess(obj); if ((obj->table->sequenceColumn == NULL) && (!obj->table->keys_len)) { /* TODO: is this really an exception - more a configuration error! */ php_error(E_ERROR,"DBDO::update no sequence or keys defined for table '%'",obj->table->name); return; } rows = gda_data_model_get_n_rows (obj->table->schema); started = 0; for (row_id = 0; row_id < rows;row_id++) { /* g_print ("rows: %d\n", title,string); */ int skip = 0, gdacolid = -1; row = (GdaRow *) gda_data_model_get_row (obj->table->schema, row_id); value = (GdaValue *) gda_row_get_value (row, 0); colname = gda_value_stringify (value); /* g_print("Col: %s\n",string); */ DBDO_DEBUG(16,"Finding Value for %s", colname); /* skip empty values, sequence columns or keys.. */ if (obj->table->sequenceColumn && !strcmp(colname,obj->table->sequenceColumn)) { skip++; } if (dbdo_str_in_array(colname, obj->table->keys, obj->table->keys_len)) { skip++; } zvalue = zend_read_property(Z_OBJCE_P(object), object, colname, strlen(colname), BP_VAR_IS TSRMLS_CC); if (zvalue == EG(uninitialized_zval_ptr)) { skip++; } /* TODO: has the value changed?? */ gdav = dbdo_object_value_from_zval(obj,colname, zvalue TSRMLS_CC); sql_str = (char *) gda_connection_value_to_sql_string (obj->con, gdav); if (obj->result && G_IS_OBJECT(obj->result) && (gdacolid = gda_data_model_get_column_position(obj->result, colname) > -1) ) { GdaValue *r_gvalue; char *sql_str_old; r_gvalue = (GdaValue *) gda_data_model_get_value_at ( obj->result, gda_data_model_get_column_position(obj->result, colname), obj->row_id); sql_str_old = (char *) gda_connection_value_to_sql_string (obj->con,r_gvalue); if (!strcmp(sql_str_old,sql_str)) { skip = 1; } g_free(sql_str_old); } if (skip > 0) { DBDO_DEBUG(16,"Skipping is sequence, is key or has no property (%s)",colname); g_free(sql_str); g_free(colname); g_free(gdav); continue; } if (started) { smart_str_appends(&cmd, " , "); } smart_str_appends(&cmd, colname); smart_str_appends(&cmd, "="); /* FIXME = use zend_read_property() */ smart_str_appends(&cmd, sql_str); g_free(sql_str); g_free(colname); g_free(gdav); /* TODO: quoting colname. */ started = 1; } if (!started) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::update no values changed. ", 0 TSRMLS_CC); smart_str_free(&cmd); return; } smart_str_appends(&cmd, " WHERE ("); /* now find it's value. ? */ DBDO_DEBUG0(16,"Looking for where part"); for (i = -1; i < obj->table->keys_len; i++) { char *col_name; col_name = (i == -1) ? obj->table->sequenceColumn : obj->table->keys[i]; if (!col_name) { continue; } DBDO_DEBUG2(16,"Looking for %s,%x ", col_name,obj->result); DBDO_DEBUG(16,"isobject ? %d ", G_IS_OBJECT(obj->result) ? 1 : 0); DBDO_DEBUG(16,"colpos? ? %d ", gda_data_model_get_column_position(obj->result, col_name)); /* favour existing database value of assigned one! */ if (obj->result && G_IS_OBJECT(obj->result) && (gda_data_model_get_column_position(obj->result, col_name) > -1) ) { GdaValue *r_gvalue; r_gvalue = (GdaValue *) gda_data_model_get_value_at ( obj->result, gda_data_model_get_column_position(obj->result, col_name), obj->row_id); sql_str = (char *) gda_connection_value_to_sql_string (obj->con,r_gvalue); DBDO_DEBUG2(16,"ADDING value from result %s,%s", col_name, sql_str); if (found_key) { smart_str_appends(&cmd, " AND "); } smart_str_appends(&cmd, "("); smart_str_appends(&cmd, col_name); smart_str_appends(&cmd, " = "); smart_str_appends(&cmd, sql_str); smart_str_appends(&cmd, ")"); g_free(sql_str); found_key = 1; continue; } /* otherwise - is the php value set.. */ DBDO_DEBUG(1,"Looking at object for value? %s", col_name); zvalue = zend_read_property(Z_OBJCE_P(object), object, col_name, strlen(col_name), BP_VAR_IS TSRMLS_CC); if (zvalue != EG(uninitialized_zval_ptr)) { dbdo_object_value_from_zval(obj, col_name, zvalue TSRMLS_CC); sql_str = (char *) gda_connection_value_to_sql_string (obj->con, gdav); g_free(obj); if (found_key) { smart_str_appends(&cmd, " AND "); } smart_str_appends(&cmd, "("); smart_str_appends(&cmd, col_name); smart_str_appends(&cmd, " = "); smart_str_appends(&cmd, sql_str); smart_str_appends(&cmd, ")"); g_free(sql_str); found_key = 1; } } if (!found_key) { /* use the result.. ??? what if no dm..... */ zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::update sequence value not set (perhaps use DBDO::BUILD?) ", 0 TSRMLS_CC); smart_str_free(&cmd); return; } smart_str_appends(&cmd, ")"); } else { /* use all the object values to update set. */ char *condition; /* build run on an existing object? */ if (obj->result) { php_error(E_ERROR, "DBDO::update(BUILD) run on an object with a result set."); smart_str_free(&cmd); return; } rows = gda_data_model_get_n_rows (obj->table->schema); started = 0; for (row_id = 0; row_id < rows;row_id++) { /* g_print ("rows: %d\n", title,string); */ row = (GdaRow *) gda_data_model_get_row (obj->table->schema, row_id); value = (GdaValue *) gda_row_get_value (row, 0); colname = gda_value_stringify (value); /* g_print("Col: %s\n",string); */ /* skip empty values.. */ zvalue = zend_read_property(Z_OBJCE_P(object), object, colname, strlen(colname), BP_VAR_IS TSRMLS_CC); if (zvalue == EG(uninitialized_zval_ptr)) { g_free(colname); continue; } /* skip values that have not changed.. */ if (started) { smart_str_appends(&cmd, " , "); } smart_str_appends(&cmd, colname); smart_str_appends(&cmd, "="); gdav = dbdo_object_value_from_zval(obj, colname, zvalue TSRMLS_CC); sql_str = (char *) gda_connection_value_to_sql_string (obj->con, gdav); smart_str_appends(&cmd, sql_str); g_free(sql_str); g_free(gdav); /* TODO: quoting colname. */ started = 1; } if (!started) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::update no values changed. ", 0 TSRMLS_CC); smart_str_free(&cmd); return; } condition = dbdo_find_query_build(object, obj, DBDO_QUERY_BUILD_UPDATE TSRMLS_CC); if (!condition) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::update no conditions available to create condition.", 0 TSRMLS_CC); smart_str_free(&cmd); return; } smart_str_appends(&cmd, condition); efree(condition); } smart_str_0(&cmd); DBDO_DEBUG(1,"QUERY:\n%s\n", cmd.c); gdacmd = gda_command_new ((gchar*)cmd.c, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); smart_str_free(&cmd); gda_connection_execute_single_command (obj->con, gdacmd, NULL); gda_command_free (gdacmd); if (gda_connection_get_errors(obj->con)) { dbdo_throw_errors(obj->con TSRMLS_CC); RETURN_FALSE; } /* TODO : rows Affected */ RETURN_TRUE; } /* {{{ proto mixed $dbdo->selectAdd ( ) modfy the select condition part. */ PHP_METHOD(dbdo,selectAdd) { char *select; zval *object = getThis(); int select_length; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (ZEND_NUM_ARGS() ==0) { if (!obj->condition->data_select) { RETURN_NULL(); } /* g_print("selectAdd:%s\n",obj->condition->data_select); */ RETVAL_STRING(obj->condition->data_select, 1); efree(obj->condition->data_select); obj->condition->data_select = NULL; return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &select, &select_length) == FAILURE) { RETURN_FALSE; } if (!obj->condition->data_select) { obj->condition->data_select = estrdup(select); /* g_print("selectAdd:set to %s\n",obj->condition->data_select); */ RETURN_TRUE; } obj->condition->data_select = erealloc(obj->condition->data_select,select_length + strlen(obj->condition->data_select) + 4); strcat(obj->condition->data_select," , "); strcat(obj->condition->data_select,select); RETURN_TRUE; } /* {{{ proto mixed $dbdo->whereAdd ( ) modify the where part.. */ PHP_METHOD(dbdo,whereAdd) { char *where, *whereCond = NULL, *old; int where_len, whereCond_len; zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if(ZEND_NUM_ARGS() == 0) { if (!obj->condition->where) { RETURN_NULL(); } /* g_print("selectAdd:%s\n",obj->condition->data_select); */ RETVAL_STRING(obj->condition->where, 1); efree(obj->condition->where); obj->condition->where = NULL; return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &where, &where_len, &whereCond, &whereCond_len) == FAILURE) { RETURN_FALSE; } if (!whereCond) { whereCond_len = 3; } /* start! */ if (!obj->condition->where) { obj->condition->where = estrdup(where); /* g_print("selectAdd:set to %s\n",obj->condition->data_select); */ RETURN_TRUE; } /* append.. */ old = estrdup(obj->condition->where); efree(obj->condition->where); if (ZEND_NUM_ARGS()=1) { whereCond_len = 3; } obj->condition->where = emalloc(strlen(old) + where_len + 3 + whereCond_len); strcpy(obj->condition->where,old); efree(old); strcat(obj->condition->where," "); if (ZEND_NUM_ARGS()>1) { strcat(obj->condition->where,whereCond); } else { strcat(obj->condition->where,"AND"); } strcat(obj->condition->where," "); strcat(obj->condition->where,where); RETURN_TRUE; } /* {{{ proto mixed $dbdo->limit ( [$num, [$num]] ) modify the limit part.. */ PHP_METHOD(dbdo,limit) { zval *object = getThis(); long arg1, arg2; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &arg1, &arg2) == FAILURE) { RETURN_FALSE; } switch (ZEND_NUM_ARGS()) { case 0: obj->condition->limit_from = 0; obj->condition->limit_qty = 0; obj->condition->limit_use = FALSE; break; case 1: obj->condition->limit_from = 0; obj->condition->limit_qty = arg1; obj->condition->limit_use = TRUE; break; case 2: obj->condition->limit_from = arg1; obj->condition->limit_qty = arg2; obj->condition->limit_use = TRUE; break; } RETURN_TRUE; } /* {{{ proto mixed $dbdo->orderBy ( ) modify the orderBy */ PHP_METHOD(dbdo,orderBy) { char *orderBy; zval *object = getThis(); int orderBy_length; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (ZEND_NUM_ARGS() ==0) { if (!obj->condition->orderBy) { RETURN_NULL(); } /* g_print("selectAdd:%s\n",obj->condition->data_select); */ RETVAL_STRING(obj->condition->orderBy, 1); efree(obj->condition->orderBy); obj->condition->orderBy = NULL; return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &orderBy, &orderBy_length) == FAILURE) { RETURN_FALSE; } if (!obj->condition->orderBy) { obj->condition->orderBy = estrdup(orderBy); /* g_print("selectAdd:set to %s\n",obj->condition->data_select);*/ RETURN_TRUE; } obj->condition->orderBy = erealloc(obj->condition->orderBy,orderBy_length + strlen(obj->condition->orderBy) + 4); strcat(obj->condition->orderBy," , "); strcat(obj->condition->orderBy,orderBy); RETURN_TRUE; } /* {{{ proto mixed $dbdo->groupBy ( ) modify the groupBy */ PHP_METHOD(dbdo,groupBy) { char *groupBy; zval *object = getThis(); int groupBy_length; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (ZEND_NUM_ARGS() ==0) { if (!obj->condition->groupBy) { RETURN_NULL(); } /* g_print("selectAdd:%s\n",obj->condition->data_select);*/ RETVAL_STRING(obj->condition->groupBy, 1); efree(obj->condition->groupBy); obj->condition->groupBy = NULL; return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &groupBy, &groupBy_length) == FAILURE) { RETURN_FALSE; } if (!obj->condition->groupBy) { obj->condition->groupBy = estrdup(groupBy); /* g_print("selectAdd:set to %s\n",obj->condition->data_select); */ RETURN_TRUE; } obj->condition->groupBy = erealloc(obj->condition->groupBy,groupBy_length + strlen(obj->condition->groupBy) + 4); strcat(obj->condition->groupBy," , "); strcat(obj->condition->groupBy,groupBy); RETURN_TRUE; } /* {{{ proto bool $dbdo->having ( string $having , [ string $and_or ]) modify the having clause */ PHP_METHOD(dbdo,having) { zval *object = getThis(); char *having, *havingCond = NULL; int having_len, havingCond_len; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (ZEND_NUM_ARGS() ==0) { if (!obj->condition->having) { RETURN_NULL(); } /* g_print("selectAdd:%s\n",obj->condition->data_select); */ RETVAL_STRING(obj->condition->having, 1); efree(obj->condition->having); obj->condition->having = NULL; return; } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &having, &having_len, &havingCond, &havingCond_len) == FAILURE) { RETURN_FALSE; } if (!obj->condition->having) { obj->condition->having = estrdup(having); /* g_print("selectAdd:set to %s\n",obj->condition->data_select); */ RETURN_TRUE; } obj->condition->having = erealloc(obj->condition->having,having_len + strlen(obj->condition->having) + 6); if (!havingCond) { strcat(obj->condition->having," AND "); } else if (0 == strcasecmp("AND", havingCond)) { strcat(obj->condition->having, " AND "); } else if (0 == strcasecmp("OR", havingCond)) { strcat(obj->condition->having," OR "); } else { obj->condition->having = erealloc(obj->condition->having, strlen(obj->condition->having)); php_error(E_WARNING, "%s(): Second argument should be (AND or OR)", get_active_function_name(TSRMLS_C)); RETURN_FALSE; } strcat(obj->condition->having,having); /* reduce the size of having to fit.. - probaly not necessary... */ obj->condition->having = erealloc(obj->condition->having, strlen(obj->condition->having)); RETURN_TRUE; } /* {{{ proto array $dbdo->info ( [string $what] ) Retrieve information about an object. */ PHP_METHOD(dbdo,info) { /* info retreieved: - tablename - dsn - database name - connection string - provider - username - ???password??? - current row - numrows - retrieved data - config ? - sequenceColumn - sequenceAssigned - sequenceIsNative - sequenceName - where ... all condition variables... */ zval *object = getThis(); zval *rv[DBDO_INFO_LEN]; int i,key_len; char *key = NULL; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &key, &key_len) == FAILURE) { RETURN_FALSE; } if (key) { i = dbdo_info_get_id(key); if (i == -1) { php_error(E_ERROR, "DBDO::info() no information for unknown key %s", key); RETURN_FALSE; } dbdo_info_get(object, return_value, i TSRMLS_CC); return; } array_init(return_value); for (i=0;idsn,dsn)==0) { return cons; } } DBDO_G(config_len)++; if (DBDO_G(config) != NULL) { DBDO_G(config) = (dbdo_config **) erealloc(DBDO_G(config),DBDO_G(config_len) * sizeof(dbdo_config *)); } else { DBDO_G(config) = (dbdo_config **) emalloc(sizeof(dbdo_config *)); } con = emalloc(sizeof(dbdo_config)); con->require_path = NULL; con->class_name = NULL; con->links = NULL; con->lowercase_columns = FALSE; con->quote_identifiers = FALSE; con->dsn = estrdup(dsn); con->provider = NULL; con->cnc_string = NULL; DBDO_G(config)[DBDO_G(config_len)-1] = con; return con; } #define DBDO_CONFIG_LEN 7 static char *dbdo_config_values[] = { /* 0 */ "require_path", "class_name", /* 2 */ "links", "provider", /* 4 */ "cnc", "lowercase_passwords", /* 6 */ "quote_identifiers" }; /* get the id for a specified column */ int dbdo_config_get_id(char * col) { int i; for (i=0;i< DBDO_CONFIG_LEN;i++) { if (!strcasecmp(dbdo_config_values[i],col)) { return i; } } return -1; } /* {{{ proto DBDO::config ( $dsn, $key, $value) set any of the config variables.. */ PHP_METHOD(dbdo,config) { /* only supports dsn : key : valueat present */ int dsn_len,key_len,value_len; char *dsn, *key,*value; gboolean bvalue; dbdo_config *con; int id = 0; if (zend_parse_parameters(2 TSRMLS_CC, "ss", &dsn, &dsn_len, &key, &key_len) == FAILURE) { RETURN_FALSE; } id = dbdo_config_get_id(key); if (id == -1) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid configuration key: %s", key); RETURN_FALSE; } con = dbdo_config_get(dsn TSRMLS_CC); if (ZEND_NUM_ARGS() == 2) { if (!con) { RETURN_FALSE; } switch(id) { case 0: if (!con->require_path) { RETURN_FALSE; } RETURN_STRING(con->require_path,1); case 1: if (!con->class_name) { RETURN_FALSE; } RETURN_STRING(con->class_name,1); case 2: if (!con->links) { RETURN_FALSE; } RETURN_STRING(con->links,1); case 3: if (!con->provider) { RETURN_FALSE; } RETURN_STRING(con->provider,1) case 4: if (!con->cnc_string) { RETURN_FALSE; } RETURN_STRING(con->cnc_string,1) case 5: RETURN_LONG(con->lowercase_columns); case 6: RETURN_LONG(con->quote_identifiers); } RETURN_FALSE; /* should not get here! */ } /* not amazingly efficient code.. but it should work.. */ if (id < 5) { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss", &dsn, &dsn_len, &key, &key_len,&value, &value_len) == FAILURE) { RETURN_FALSE; } } else { if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssi", &dsn, &dsn_len, &key, &key_len,&bvalue) == FAILURE) { RETURN_FALSE; } } switch(id) { case 0: if (con->require_path) { efree(con->require_path); } con->require_path =estrdup(value); break; case 1: if (con->class_name) { efree(con->class_name); } con->class_name = estrdup(value); break; case 2: if (con->links) { efree(con->links); } con->links =estrdup(value); break; case 3: if (con->provider) { efree(con->provider); } con->provider =estrdup(value); break; case 4: if (con->cnc_string) { efree(con->cnc_string); } con->cnc_string =estrdup(value); break; case 5: con->lowercase_columns = bvalue; break; case 6: con->quote_identifiers = bvalue; break; } RETURN_TRUE; } /* {{{ proto DBDO::debugLevel (mixed int) set the debug behavior. (debugging messages are issued as E_NOTICE, preceded by DBDO:) you can capture them by using set_error_handler.. */ PHP_METHOD(dbdo,debugLevel) { int newlevel; if (!ZEND_NUM_ARGS()) { RETURN_LONG(DBDO_G(debugLevel)); } if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &newlevel) == FAILURE) { RETURN_FALSE; } DBDO_G(debugLevel) = newlevel; RETURN_LONG(DBDO_G(debugLevel)); } /* {{{ proto $dbdo->delete([DBDO::BUILD]) without paramenters only deletes items with matching keys (eg. single), with DBDO::BUILD, uses whereAdd and object variables to determine what to delete. */ PHP_METHOD(dbdo,delete) { int build =0; zval *object = getThis(); zval *ztitle; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); smart_str cmd = {0}; char *condition; int started = 0; gint update_id; GdaCommand *gdacmd; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &build) == FAILURE) { RETURN_FALSE; } dbdo_schema_load(obj TSRMLS_CC); smart_str_appends(&cmd, "DELETE FROM "); smart_str_appends(&cmd, obj->table->name); /* either built (using conditions) or defaults to use the native sequence */ if (!build) { smart_str_appends(&cmd, " WHERE "); dbdo_sequence_guess(obj); if (!build && obj->table->sequenceColumn == NULL) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::delete sequence unknown ", 0 TSRMLS_CC); smart_str_free(&cmd); return; } smart_str_appends(&cmd, obj->table->sequenceColumn); smart_str_appends(&cmd, " = "); /* if we have set the value - use that */ MAKE_STD_ZVAL(ztitle); ZVAL_STRING(ztitle, obj->table->sequenceColumn, 1); if (std_object_handlers.has_property(object, ztitle, 0 TSRMLS_CC)) { zval *zvalue; GdaValue *gdav; gchar *sql_str; zvalue = std_object_handlers.read_property(object, ztitle, BP_VAR_IS TSRMLS_CC); gdav = dbdo_object_value_from_zval(obj, obj->table->sequenceColumn, zvalue TSRMLS_CC); sql_str = (char *) gda_connection_value_to_sql_string (obj->con, gdav); g_free(gdav); smart_str_appends(&cmd, sql_str); g_free(sql_str); /* TODO: free the gvalue */ } else { GdaValue *r_gvalue; int col = -1; gchar *sql_str; zval_dtor(ztitle); FREE_ZVAL(ztitle); if (obj->result) { col = gda_data_model_get_column_position(obj->result, obj->table->sequenceColumn); } if (!obj->result || (obj->row_id < 0) || (col < 0)) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::delete sequence value not set", 0 TSRMLS_CC); smart_str_free(&cmd); return; } r_gvalue = (GdaValue *) gda_data_model_get_value_at ( obj->result, col, obj->row_id); sql_str = (char *) gda_connection_value_to_sql_string (obj->con, r_gvalue); smart_str_appends(&cmd, sql_str); g_free(sql_str); /* TODO: free the gvalue */ } } else { condition = dbdo_find_query_build(object, obj, DBDO_QUERY_BUILD_DELETE TSRMLS_CC); if (!condition) { zend_throw_exception(dbdo_class_entry_exception_ce , "DBDO::delete no values available to create condition.", 0 TSRMLS_CC); smart_str_free(&cmd); return; } smart_str_appends(&cmd, condition); efree(condition); } smart_str_0(&cmd); DBDO_DEBUG(1,"QUERY:\n%s\n", cmd.c); gdacmd = gda_command_new ((gchar*)cmd.c, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS); smart_str_free(&cmd); gda_connection_execute_single_command (obj->con, gdacmd, NULL); gda_command_free (gdacmd); if (gda_connection_get_errors(obj->con)) { dbdo_throw_errors (obj->con TSRMLS_CC); return; } /* TODO : check return value */ RETURN_TRUE; } /* {{{ proto $dbdo->valueSet(string column, mixed value) sets the value of a column to a value, doing checks to see if it is valid. */ PHP_METHOD(dbdo,valueSet) { zval *value, *ztitle; zval *object = getThis(); char *col; int col_len, row_id; GdaValueType target_type; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); GdaValue *test; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &col, &col_len, &value) == FAILURE) { RETURN_FALSE; } dbdo_schema_load(obj TSRMLS_CC); row_id = dbdo_schema_get_col_row(obj,col); if (row_id == -1) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::valueSet() unknown column: %s", col); RETURN_FALSE; } /* test that we can set it as a gdavalue (eg. it's the correct type ) */ test = dbdo_object_value_from_zval(obj, col, value TSRMLS_CC); if (NULL == test) { RETURN_FALSE; } g_free(test); MAKE_STD_ZVAL(ztitle); ZVAL_STRING(ztitle, col, 1); /* set it manually.. */ std_object_handlers.write_property(object, ztitle, value TSRMLS_CC); zval_dtor(ztitle); FREE_ZVAL(ztitle); RETURN_TRUE; } /* {{{ proto DBDO::valueGet(string column) fetches the value of a column, intended to be used internally when making everything private.. */ PHP_METHOD(dbdo,valueGet) { zval *member; zval *object = getThis(); zval *ret; char *col; int col_len, row_id; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &col, &col_len) == FAILURE) { RETURN_FALSE; } /* we get it again (as it's easier to sent to getproperty.. */ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &member) == FAILURE) { RETURN_FALSE; } /* we have no idea what type (3rd arg means but we are sticking 1 in there */ ret = std_object_handlers.read_property(object, member, BP_VAR_IS TSRMLS_CC); RETURN_ZVAL(ret, 1, 0); } /* {{{ proto $dbdo->reproduce() creates a clean new instance of the object with object properties and resultset removed. */ PHP_METHOD(dbdo,reproduce) { zval *tmp; zval *object = getThis(); zval *zclone; dbdo_object *dclone; zend_class_entry *ce = zend_objects_get_address(object TSRMLS_CC)->ce; object_init_ex(return_value, ce); return_value->value.obj = dbdo_clone(object TSRMLS_CC); dclone = zend_object_store_get_object(return_value TSRMLS_CC); dclone->row_id = -1; if (G_IS_OBJECT(dclone->result)) { g_object_unref(dclone->result); } dclone->result = NULL; if (dclone->condition) { dclone->condition->refcount--; } dclone->condition = NULL; zend_hash_destroy(dclone->zo.properties); zend_hash_init(dclone->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0); zend_hash_copy(dclone->zo.properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); } /* }}} */ /* {{{ proto $dbdo->__call( string function_name [, array arguments]) implements setters and getters. */ PHP_METHOD(dbdo, __call) { char *function; int function_len; zval *args; zval **real_args = NULL; int arg_count,row_id; zval *object = getThis(); dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); GdaValue *test; HashPosition pos; zval **param, *value, *ztitle ; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &function, &function_len, &args) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Invalid arguments"); return; } DBDO_DEBUG(16,"CALLING __call with %s", function); arg_count = zend_hash_num_elements(Z_ARRVAL_P(args)); if ((0 != strncasecmp(function,"get",3)) && (0 != strncasecmp(function,"set",3 ))) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Unknown Method '%s'",function); return; } if (function[0] == 'G' || function[0] == 'g') { if (arg_count != 0 ) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "To many arguments to '%s'",function); } zval *member, *ret; MAKE_STD_ZVAL(member); ZVAL_STRING(member, function+3, 0); /* we have no idea what type (3rd arg means but we are sticking 1 in there */ ret = std_object_handlers.read_property(object, member, BP_VAR_IS TSRMLS_CC); FREE_ZVAL(member); RETURN_ZVAL(ret, 1, 0); return; } /* otherwise it will be set!!! */ if (arg_count < 1) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "'%s' expects at least one argument",function); return; } if (arg_count != 1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "'%s' expects at least one argument",function); return; } zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(args), &pos); zend_hash_get_current_data_ex(Z_ARRVAL_P(args), (void **) ¶m, &pos) == SUCCESS; value = *param; dbdo_schema_load(obj TSRMLS_CC); row_id = dbdo_schema_get_col_row(obj, function+3); if (row_id == -1) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::%s() unknown column: %s", function, function+3); RETURN_FALSE; } /* test that we can set it as a gdavalue (eg. it's the correct type ) */ test = dbdo_object_value_from_zval(obj, function+3, value TSRMLS_CC); if (NULL == test) { RETURN_FALSE; } g_free(test); MAKE_STD_ZVAL(ztitle); ZVAL_STRING(ztitle, function+3, 1); /* set it manually.. */ std_object_handlers.write_property(object, ztitle, value TSRMLS_CC); zval_dtor(ztitle); FREE_ZVAL(ztitle); RETURN_TRUE; } /* }}} */ /* {{{ proto $dbdo->quoted() returns a string quoted, eg. slashes added and ' ' quotes around it.. */ PHP_METHOD(dbdo, quoted) { zval *object = getThis(); int str_len; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *str; char *ret_str; GdaValue *gdav_tmp; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments"); return; } if (!dbdo_connect(obj TSRMLS_CC)) { DBDO_DEBUG0(16,"CONNECT FAILED!"); RETURN_FALSE; } gdav_tmp = gda_value_new_string((const gchar*) str); ret_str = (char *) gda_connection_value_to_sql_string (obj->con, gdav_tmp); ZVAL_STRING(return_value, ret_str, 1); gda_value_free(gdav_tmp); g_free(ret_str); } /* {{{ proto $dbdo->__sleep() writes internal data out.. = borked = use new serialation interface later.. */ /* PHP_METHOD(dbdo, __sleep) { zval *object = getThis(); zval *rv[DBDO_INFO_LEN]; int i,key_len; dbdo_object *obj = zend_object_store_get_object(object TSRMLS_CC); char *col; array_init(return_value); for (i=0;i