/* +----------------------------------------------------------------------+ | 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 | +----------------------------------------------------------------------+ */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "php_dbdo.h" extern ZEND_DECLARE_MODULE_GLOBALS(dbdo) const char *dbdo_object_gdavalue_get_type(GdaValueType v) { switch(v) { case GDA_VALUE_TYPE_NULL: return "GDA_VALUE_TYPE_NULL"; case GDA_VALUE_TYPE_BIGINT: return "GDA_VALUE_TYPE_BIGINT"; case GDA_VALUE_TYPE_BIGUINT: return "GDA_VALUE_TYPE_BIGUINT"; case GDA_VALUE_TYPE_BINARY: return "GDA_VALUE_TYPE_BINARY"; case GDA_VALUE_TYPE_BLOB: return "GDA_VALUE_TYPE_BLOB"; case GDA_VALUE_TYPE_BOOLEAN: return "GDA_VALUE_TYPE_BOOLEAN"; case GDA_VALUE_TYPE_DATE: return "GDA_VALUE_TYPE_DATE"; case GDA_VALUE_TYPE_DOUBLE: return "GDA_VALUE_TYPE_DOUBLE"; case GDA_VALUE_TYPE_GEOMETRIC_POINT: return "GDA_VALUE_TYPE_GEOMETRIC_POINT"; case GDA_VALUE_TYPE_GOBJECT: return "GDA_VALUE_TYPE_GOBJECT"; case GDA_VALUE_TYPE_INTEGER: return "GDA_VALUE_TYPE_INTEGER"; case GDA_VALUE_TYPE_LIST: return "GDA_VALUE_TYPE_LIST"; case GDA_VALUE_TYPE_MONEY: return "GDA_VALUE_TYPE_MONEY"; case GDA_VALUE_TYPE_NUMERIC: return "GDA_VALUE_TYPE_NUMERIC"; case GDA_VALUE_TYPE_SINGLE: return "GDA_VALUE_TYPE_SINGLE"; case GDA_VALUE_TYPE_SMALLINT: return "GDA_VALUE_TYPE_SMALLINT"; case GDA_VALUE_TYPE_SMALLUINT: return "GDA_VALUE_TYPE_SMALLUINT"; case GDA_VALUE_TYPE_STRING: return "GDA_VALUE_TYPE_STRING"; case GDA_VALUE_TYPE_TIME: return "GDA_VALUE_TYPE_TIME"; case GDA_VALUE_TYPE_TIMESTAMP: return "GDA_VALUE_TYPE_TIMESTAMP"; case GDA_VALUE_TYPE_TINYINT: return "GDA_VALUE_TYPE_TINYINT"; case GDA_VALUE_TYPE_TINYUINT: return "GDA_VALUE_TYPE_TINYUINT"; case GDA_VALUE_TYPE_TYPE: return "GDA_VALUE_TYPE_TYPE"; case GDA_VALUE_TYPE_UINTEGER: return "GDA_VALUE_TYPE_UINTEGER"; case GDA_VALUE_TYPE_UNKNOWN: return "GDA_VALUE_TYPE_UNKNOWN"; } return NULL; } /* }}} */ /* constructor! */ int dbdo_connect(dbdo_object *obj TSRMLS_DC) { dbdo_config *con; if (obj->con && GDA_IS_CONNECTION (obj->con)) { return 1; } /* we should do a speculative get really! */ con = dbdo_config_get(obj->table->dsn TSRMLS_CC); if (!con || !con->cnc_string || !con->provider) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "You tried to connect to a DSN that does not exist \"%s\"\n" "(make sure it matches the setting in DBDO::config('dsn','cnc',.....) ", obj->table->dsn ); return 0; } obj->con = gda_client_open_connection_from_string ( DBDO_G(client), con->provider, con->cnc_string, 0); DBDO_DEBUG2(16,"CONNECTING TO %s , %x",obj->table->dsn, (long) obj->con); if (!GDA_IS_CONNECTION (obj->con)) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Failed to connect to the database dsn %s: %s, with the configured username/password, check your connection configuration and the database is up.", con->provider, con->cnc_string); return 0; } return 1; } dbdo_table * dbdo_table_new(char *dsn, char *name TSRMLS_DC) { dbdo_table *tbls; int i; for (i=0;idsn, dsn)) && (0 == strcmp(tbls->name, name))) { /* got match */ DBDO_DEBUG3(16,"RETURNING EXISTING TABLE OBJECT: %s , %s : %x",dsn, name, tbls); return tbls; } } DBDO_DEBUG2(16,"CREATING NEW TABLE OBJECT: %s , %s",dsn, name); tbls = emalloc(sizeof(dbdo_table)); tbls->dsn = estrdup(dsn); tbls->name = estrdup(name); tbls->schema = NULL; tbls->sequenceColumn = NULL; tbls->sequenceName = NULL; tbls->sequenceIsNative = FALSE; tbls->sequenceAssigned = FALSE; tbls->keys_len = 0; tbls->keys = NULL; DBDO_G(tables_len)++; if (DBDO_G(tables)) { DBDO_G(tables) = (dbdo_table **) erealloc(DBDO_G(tables),DBDO_G(tables_len) * sizeof (dbdo_table *)); } else { DBDO_G(tables) = (dbdo_table **) emalloc(sizeof(dbdo_table *)); } DBDO_G(tables)[DBDO_G(tables_len)-1] = tbls; DBDO_DEBUG3(16,"RETURNING NEW TABLE OBJECT: %s , %s : %x",tbls->dsn, tbls->name, tbls); return tbls; } /* load the schema into the object. */ int dbdo_schema_load(dbdo_object *obj TSRMLS_DC) { /* loop through the schema and find it.. */ GdaParameterList * parm_list; if (obj->table->schema) { return 1; /* already got it... */ } /* big question? - should we cache this!!! */ if (!dbdo_connect(obj TSRMLS_CC)) { return 0; } parm_list = gda_parameter_list_new(); gda_parameter_list_add_parameter(parm_list, gda_parameter_new_string ("name", (const char *)obj->table->name)); obj->table->schema = gda_connection_get_schema(obj->con, GDA_CONNECTION_SCHEMA_FIELDS,parm_list); /* according to the source, get_schema returns null if it fails.. */ if (!obj->table->schema) { // Should we really show the real errors???? gda_connection_clear_error_list(obj->con); zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO - failed reading schema for table '%s'", obj->table->name); return 0; } return 1; } /* look for a matching row data named "eg. id" */ gint dbdo_schema_get_col_row(dbdo_object *obj, const char *name) { gint rows,column_id, row_id; GdaRow* row; GdaValue *value; gchar *string; gchar *title; TSRMLS_FETCH(); dbdo_schema_load(obj TSRMLS_CC); column_id = gda_data_model_get_column_position(obj->table->schema,"Field name"); if (column_id == -1) { return -1; } 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); if (strcmp(string,name)==0) { g_free(string); return row_id; } g_free(string); } return -1; } gchar * dbdo_schema_get_type(dbdo_object *obj, const char *name) { GdaRow *row; gint col,row_id; GdaValue *value; gchar *string; TSRMLS_FETCH(); dbdo_schema_load(obj TSRMLS_CC); row_id = dbdo_schema_get_col_row(obj,name); row = (GdaRow *) gda_data_model_get_row (obj->table->schema, row_id); col = gda_data_model_get_column_position(obj->table->schema, "Data type"); value = (GdaValue *) gda_row_get_value (row, col); string = gda_value_stringify (value); return string; } GdaValueType dbdo_value_type_from_column(dbdo_object *obj, char * name) { GdaDataModel *dm; gint rows; GdaRow *row; GdaValue *value; gchar *string; gint row_id; char *coltype; TSRMLS_FETCH(); coltype = dbdo_schema_get_type(obj, name); DBDO_DEBUG2(16,"dbdo_object.value_type_from_column getting type for column %s = %s", name ,coltype); dm = gda_connection_get_schema(obj->con, GDA_CONNECTION_SCHEMA_TYPES, NULL); rows = gda_data_model_get_n_rows (dm); for (row_id = 0; row_id < rows;row_id++) { GdaValue *rvalue; row = (GdaRow *) gda_data_model_get_row (dm, row_id); value = (GdaValue *) gda_row_get_value (row, 0); string = gda_value_stringify (value); DBDO_DEBUG2(16,"dbdo_object.value_type_from_column testing %s to %s", string,coltype); if (strcmp(string, coltype)) { g_free(string); continue; } g_free(string); g_free(coltype); return gda_value_get_vtype((GdaValue *) gda_row_get_value (row, 3)); } /* Fudges to fix missing types in gda backend */ if (strcmp(coltype,"int") ==0) { g_free(coltype); return GDA_VALUE_TYPE_INTEGER; } if (strcmp(coltype,"varchar") ==0) { g_free(coltype); return GDA_VALUE_TYPE_STRING; } g_print(" ***** BIG ERROR!!!!! **** returning unknown type - could not match column %s \n",coltype); g_free(coltype); return GDA_VALUE_TYPE_STRING; } GdaValue * dbdo_object_value_from_zval(dbdo_object *obj, char *name, zval *from TSRMLS_DC) { GdaValue *ret = NULL; GdaValueType type; zval value_copy, *c_ret = NULL; type = dbdo_value_type_from_column(obj, name); DBDO_DEBUG3(2,"value %s(%d) set to type %s", name, Z_TYPE_P(from), dbdo_object_gdavalue_get_type(type)); switch(type) { case GDA_VALUE_TYPE_LIST: case GDA_VALUE_TYPE_TYPE: case GDA_VALUE_TYPE_GOBJECT: case GDA_VALUE_TYPE_GEOMETRIC_POINT: case GDA_VALUE_TYPE_UNKNOWN: zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Failed to Assign Column %s: Unsupported Database Type", name); return NULL; } if (Z_TYPE_P(from) == IS_OBJECT) { /* call the toString */ zval *cmethod; if (!zend_hash_exists(&Z_OBJCE_P(from)->function_table, "tostring", strlen("tostring")+1)) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Failed to Assign Column %s: object does not have toString() method.", name); return NULL; } c_ret = NULL; ALLOC_ZVAL(cmethod); ZVAL_STRING(cmethod, "toString", 0); if (call_user_function_ex(EG(function_table), &from, cmethod, &c_ret, 0, NULL, 0, NULL TSRMLS_CC) == FAILURE) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Failed to Call toString on Object on Column %s", name); FREE_ZVAL(cmethod); return NULL; } FREE_ZVAL(cmethod); if (!c_ret) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "calling toString on Object on Column %s, did not return anything", name); return NULL; } from = c_ret; DBDO_DEBUG3(2,"value %s(%d) set to type %s", name, Z_TYPE_P(from), dbdo_object_gdavalue_get_type(type)); } switch (Z_TYPE_P(from)) { case IS_STRING: case IS_LONG: case IS_DOUBLE: case IS_BOOL: case IS_CONSTANT: case IS_NULL: /*??? what happens here! */ switch(type) { case GDA_VALUE_TYPE_NULL:/* should this type exists?? */ ret = g_new0 (GdaValue, 1); gda_value_set_null(ret); break; case GDA_VALUE_TYPE_BOOLEAN: ret = g_new0 (GdaValue, 1); convert_to_boolean(from); gda_value_set_boolean(ret, (gboolean)Z_BVAL_P(from)); break; /*numbers */ case GDA_VALUE_TYPE_BIGINT: case GDA_VALUE_TYPE_INTEGER: case GDA_VALUE_TYPE_UINTEGER: case GDA_VALUE_TYPE_SMALLINT: case GDA_VALUE_TYPE_SMALLUINT: case GDA_VALUE_TYPE_TINYINT: case GDA_VALUE_TYPE_TINYUINT: case GDA_VALUE_TYPE_BIGUINT: { ret = g_new0 (GdaValue, 1); convert_to_long(from); gda_value_set_bigint(ret, (int)Z_LVAL_P(from)); break; } /* strings, numeric and money */ case GDA_VALUE_TYPE_NUMERIC: case GDA_VALUE_TYPE_STRING: /* TODO: check strlen */ case GDA_VALUE_TYPE_MONEY: case GDA_VALUE_TYPE_TIME: case GDA_VALUE_TYPE_DATE: case GDA_VALUE_TYPE_TIMESTAMP: ret = g_new0 (GdaValue, 1); value_copy = *from; zval_copy_ctor(&value_copy); convert_to_string(&value_copy); gda_value_set_from_string(ret, Z_STRVAL_P(&value_copy),type); /* find a string */ if (type == GDA_VALUE_TYPE_STRING) { int row_id,col,fieldsize; GdaRow *row; row_id = dbdo_schema_get_col_row(obj,name); row = (GdaRow *) gda_data_model_get_row (obj->table->schema, row_id); col = gda_data_model_get_column_position(obj->table->schema, "Size"); fieldsize = gda_value_get_integer((GdaValue *) gda_row_get_value (row, col)); if (fieldsize > 0 && Z_STRLEN_P(&value_copy) > fieldsize) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Column '%s' max length is '%d' and not large enough for the string you assigned (%d characters)", name, fieldsize, Z_STRLEN_P(&value_copy)); return NULL; } } break; case GDA_VALUE_TYPE_SINGLE: ret = g_new0 (GdaValue, 1); convert_to_double(from); gda_value_set_single(ret, (gfloat)Z_DVAL_P(from)); break; case GDA_VALUE_TYPE_DOUBLE: ret = g_new0 (GdaValue, 1); convert_to_double(from); gda_value_set_single(ret, (gdouble)Z_DVAL_P(from)); break; case GDA_VALUE_TYPE_BINARY: case GDA_VALUE_TYPE_BLOB: default: zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Failed to set column %s to value", name); break; } break; case IS_ARRAY: zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Value of %s is an Array, This can not be used to set the value", name); return NULL; case IS_RESOURCE: /* TODO : BLOBS AND BINARIY */ zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Value of %s is an Array, This can not be used to set the value Yet", name); return NULL; } if (c_ret) { zval_dtor(c_ret); FREE_ZVAL(c_ret); } if (ret == NULL) { zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "Value of %s is An unknown unhandled type..", name); return NULL; } return ret; } void dbdo_value_to_zval(GdaValue *from, zval *value TSRMLS_DC) { DBDO_DEBUG(16,"converting from type %d\n", from->type); switch (from->type) { case GDA_VALUE_TYPE_NULL: ZVAL_NULL(value); return; /*longs*/ case GDA_VALUE_TYPE_BIGINT: ZVAL_LONG(value,gda_value_get_bigint(from)); return; case GDA_VALUE_TYPE_UINTEGER: ZVAL_LONG(value,gda_value_get_bigint(from)); return; case GDA_VALUE_TYPE_INTEGER: DBDO_DEBUG(16,"setting to int %d\n", gda_value_get_integer(from)); ZVAL_LONG(value,gda_value_get_integer(from)); return; case GDA_VALUE_TYPE_SMALLINT: ZVAL_LONG(value,gda_value_get_smallint(from)); return; case GDA_VALUE_TYPE_SMALLUINT: ZVAL_LONG(value,gda_value_get_smalluint(from)); return; case GDA_VALUE_TYPE_TINYINT: ZVAL_LONG(value,gda_value_get_tinyint(from)); return; case GDA_VALUE_TYPE_TINYUINT: ZVAL_LONG(value,gda_value_get_tinyuint(from)); return; case GDA_VALUE_TYPE_BIGUINT: ZVAL_LONG(value,gda_value_get_biguint(from)); return; /*bool*/ case GDA_VALUE_TYPE_BOOLEAN: ZVAL_BOOL(value, gda_value_get_boolean(from)); return; /*strings*/ case GDA_VALUE_TYPE_MONEY: case GDA_VALUE_TYPE_TIMESTAMP: case GDA_VALUE_TYPE_TIME: case GDA_VALUE_TYPE_STRING: case GDA_VALUE_TYPE_BINARY: case GDA_VALUE_TYPE_DATE: case GDA_VALUE_TYPE_BLOB: { gchar *str; str = gda_value_stringify(from); DBDO_DEBUG2(16,"ADDING STRING (%d) %s\n", strlen(str),str); ZVAL_STRINGL(value, str , strlen(str), 1); g_free(str); return; } /* doubles.. */ case GDA_VALUE_TYPE_DOUBLE: ZVAL_DOUBLE(value,gda_value_get_double(from)); return; case GDA_VALUE_TYPE_NUMERIC: { /* no idea if this will work! */ GdaValue *tmp = gda_value_new_double(0.0); gda_value_set_from_value(tmp, from); ZVAL_DOUBLE(value,gda_value_get_double(tmp)); return; } case GDA_VALUE_TYPE_SINGLE: ZVAL_DOUBLE(value,gda_value_get_single(from)); return; case GDA_VALUE_TYPE_LIST: php_error(E_WARNING, "%s(): Unsupported Database Type LIST", get_active_function_name(TSRMLS_C)); ZVAL_NULL(value); return; case GDA_VALUE_TYPE_TYPE: php_error(E_WARNING, "%s(): Unsupported Database Type TYPE", get_active_function_name(TSRMLS_C)); ZVAL_NULL(value); return; case GDA_VALUE_TYPE_GOBJECT: php_error(E_WARNING, "%s(): Unsupported Database Type GOBJECT", get_active_function_name(TSRMLS_C)); ZVAL_NULL(value); return; case GDA_VALUE_TYPE_GEOMETRIC_POINT: php_error(E_WARNING, "%s(): Unsupported Database Type GEOPOINT", get_active_function_name(TSRMLS_C)); ZVAL_NULL(value); return; case GDA_VALUE_TYPE_UNKNOWN: default: php_error(E_WARNING, "%s(): Unsupported Database Type UNKNONW", get_active_function_name(TSRMLS_C)); ZVAL_NULL(value); return; } ZVAL_NULL(value); /* never gets here! */ return; } char* dbdo_value_to_sql(GdaValue* from) { char *value = NULL, *str, *estr; TSRMLS_FETCH(); str = gda_value_stringify(from); estr = estrdup(str); g_free(str); DBDO_DEBUG2(16,"value (%s) to sql got type %d", estr, gda_value_get_type(from)); switch (gda_value_get_type(from)) { case GDA_VALUE_TYPE_NULL: efree(estr); value = estrdup("NULL"); return value; /*longs*/ case GDA_VALUE_TYPE_UINTEGER: case GDA_VALUE_TYPE_BIGINT: case GDA_VALUE_TYPE_INTEGER: case GDA_VALUE_TYPE_SMALLINT: case GDA_VALUE_TYPE_SMALLUINT: case GDA_VALUE_TYPE_TINYINT: case GDA_VALUE_TYPE_TINYUINT: case GDA_VALUE_TYPE_BIGUINT: case GDA_VALUE_TYPE_DOUBLE: case GDA_VALUE_TYPE_NUMERIC: case GDA_VALUE_TYPE_SINGLE: value = estr; return value; /*bool*/ case GDA_VALUE_TYPE_BOOLEAN: /* will this work? - will it stringify to 'true'; */ case GDA_VALUE_TYPE_MONEY: case GDA_VALUE_TYPE_TIMESTAMP: case GDA_VALUE_TYPE_TIME: case GDA_VALUE_TYPE_DATE: { value = emalloc(strlen(estr)+3); strcpy(value , "'"); strcat(value , estr); strcat(value , "'"); efree(estr); return value; } /*strings*/ case GDA_VALUE_TYPE_STRING: case GDA_VALUE_TYPE_BINARY: case GDA_VALUE_TYPE_BLOB: { int new_len; char *tmp_clean = NULL; tmp_clean = (char *) php_addslashes(estr, strlen(estr), &new_len, 1 TSRMLS_CC); //efree(estr); spprintf(&value, 0, "'%s'", tmp_clean); efree(tmp_clean); return value; } case GDA_VALUE_TYPE_LIST: php_error(E_WARNING, "%s(): Unsupported Database Type LIST", get_active_function_name(TSRMLS_C)); efree(estr); value = estrdup("''"); return value; case GDA_VALUE_TYPE_TYPE: php_error(E_WARNING, "%s(): Unsupported Database Type TYPE", get_active_function_name(TSRMLS_C)); efree(estr); value = estrdup("''"); return value; case GDA_VALUE_TYPE_GOBJECT: php_error(E_WARNING, "%s(): Unsupported Database Type GOBJECT", get_active_function_name(TSRMLS_C)); efree(estr); value = estrdup("''"); return value; case GDA_VALUE_TYPE_GEOMETRIC_POINT: efree(estr); php_error(E_WARNING, "%s(): Unsupported Database Type GEOPOINT", get_active_function_name(TSRMLS_C)); value = estrdup("''"); return value; case GDA_VALUE_TYPE_UNKNOWN: default: efree(estr); php_error(E_WARNING, "%s(): Unsupported Database Type UNKNONW", get_active_function_name(TSRMLS_C)); value = estrdup("''"); return value; } /* never gets here! */ return value; } void list_datasources (void) { GList *ds_list; GList *node; GdaDataSourceInfo *info; ds_list = gda_config_get_data_source_list (); TSRMLS_FETCH(); DBDO_DEBUG0(16,"datasources?"); for (node = g_list_first (ds_list); node != NULL; node = g_list_next (node)) { info = (GdaDataSourceInfo *) node->data; g_print ("NAME: %s PROVIDER: %s CNC: %s DESC: %s USER: %s PASSWORD: %s\n", info->name, info->provider, info->cnc_string, info->description, info->username, info->password); } g_print ("\n"); gda_config_free_data_source_list (ds_list); } void list_providers (void) { GList *prov_list; GList *node; GdaProviderInfo *info; 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; g_print ("ID: %s\n", info->id); } gda_config_free_provider_list (prov_list); } void dbdo_throw_errors (GdaConnection *connection TSRMLS_DC) { GList *list; GList *node; GdaError *error; list = (GList *) gda_connection_get_errors (connection); /* techncally this should throw more than one error!!!! - are we throwing the last one? */ for (node = g_list_first (list); node != NULL; node = g_list_next (node)) { error = (GdaError *) node->data; /*g_print("Throwing error: DBDO::database Error: \nError No: %d\nDescription: %s\nSource: %s\nSql State: %s", gda_error_get_number (error), gda_error_get_description (error), gda_error_get_source (error), gda_error_get_sqlstate (error) );*/ zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::database Error: \nError No: %d\nDescription: %s\nSource: %s\nSql State: %s", gda_error_get_number (error), gda_error_get_description (error), gda_error_get_source (error), gda_error_get_sqlstate (error) ); gda_connection_clear_error_list(connection); return; } zend_throw_exception_ex(dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO unknown connection error"); } char * dbdo_find_query_build(zval *object, dbdo_object *obj, int query_type TSRMLS_DC) { smart_str whereCond = {0}; smart_str cmd = {0}; char *ret = NULL; int started, where_added, rows, row_id; GdaRow *row; zval *zvalue, *ztitle=NULL; gchar *string, *title, *colname; if (query_type == DBDO_QUERY_BUILD_SELECT) { smart_str_appends(&cmd, "SELECT "); if (obj->condition->data_select) { 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); } /* build the conditions based on the object variables.. */ dbdo_schema_load(obj TSRMLS_CC); rows = gda_data_model_get_n_rows (obj->table->schema); started = 0; where_added = 0; if (query_type != DBDO_QUERY_BUILD_UPDATE) { for (row_id = 0; row_id < rows;row_id++) { char *colname, *tmp_str; GdaValue *gdav_tmp; colname = gda_value_stringify ( (GdaValue *) gda_data_model_get_value_at (obj->table->schema, 0, row_id)); if (!colname) { continue; } ALLOC_ZVAL(ztitle); ZVAL_STRING(ztitle, colname, 1); if (!std_object_handlers.has_property(object, ztitle, 0 TSRMLS_CC)) { zval_dtor(ztitle); FREE_ZVAL(ztitle); g_free(colname); ztitle=NULL; continue; } if (started) { smart_str_appends(&whereCond, " AND ("); } else { smart_str_appends(&whereCond, "("); } smart_str_appends(&whereCond, obj->table->name); smart_str_appends(&whereCond, "."); smart_str_appends(&whereCond, colname); smart_str_appends(&whereCond, "="); zvalue = std_object_handlers.read_property(object, ztitle, 0 TSRMLS_CC); zval_dtor(ztitle); FREE_ZVAL(ztitle); ztitle=NULL; if (zvalue->type != IS_STRING) { convert_to_string(zvalue); } gdav_tmp = g_new0 (GdaValue, 1); gda_value_set_from_string(gdav_tmp, (const gchar*) Z_STRVAL_P(zvalue), dbdo_value_type_from_column(obj, colname)); g_free(colname); tmp_str = dbdo_value_to_sql(gdav_tmp); smart_str_appends(&whereCond, tmp_str); efree(tmp_str); smart_str_appends(&whereCond, ")"); started = 1; } } if (obj->condition->where) { if (started) { smart_str_appends(&whereCond, " AND ("); } else { smart_str_appends(&whereCond, "("); } smart_str_appends(&whereCond, obj->condition->where); smart_str_appends(&whereCond, ")"); started = 1; } if (started) { smart_str_appends(&cmd, " WHERE "); smart_str_0(&whereCond); smart_str_appends(&cmd, whereCond.c); } smart_str_free(&whereCond); /* todo - join */ if (obj->condition->groupBy) { smart_str_appends(&cmd, " GROUP BY "); smart_str_appends(&cmd, obj->condition->groupBy); } if (obj->condition->having) { smart_str_appends(&cmd, " HAVING "); smart_str_appends(&cmd, obj->condition->having); } if (obj->condition->orderBy) { smart_str_appends(&cmd, " ORDER BY "); smart_str_appends(&cmd, obj->condition->orderBy); } /* limit !!!! */ if (obj->condition->limit_use) { char *provider; provider = (char*) gda_connection_get_provider(obj->con); int used_limit = 0; if (strcmp(provider,"MySQL") == 0) { /* LIMIT a,b */ smart_str_appends(&cmd, " LIMIT "); if (obj->condition->limit_from) { smart_str_append_long(&cmd, obj->condition->limit_from); smart_str_appends(&cmd, ","); } smart_str_append_long(&cmd, obj->condition->limit_qty); used_limit = 1; } if ((strcmp(provider,"PostgreSQL") == 0) || (strcmp(provider,"SQLite") == 0)){ smart_str_appends(&cmd, " LIMIT "); smart_str_append_long(&cmd, obj->condition->limit_qty); if (obj->condition->limit_from) { smart_str_appends(&cmd, " OFFSET "); smart_str_append_long(&cmd, obj->condition->limit_from); } used_limit = 1; } /* interbase: select x from y ... becomes SELECT FIRST {qty} SKIP {from} x from y oracle: SELECT $fields FROM (SELECT rownum as linenum, $fields FROM ($query) WHERE rownum <= {$from + $count} ) WHERE linenum >= {$from +1 }; freetds: unknown ibmdb2 : unknown? Sybase : unknown ODBC : unknown */ if (!used_limit) { smart_str_free(&cmd); zend_throw_exception_ex( dbdo_class_entry_exception_ce , 0 TSRMLS_CC, "DBDO::find can not handle limit request on '%s' yet.", provider); return NULL; } } if (!cmd.len) { return NULL; } smart_str_0(&cmd); ret = estrdup(cmd.c); smart_str_free(&cmd); DBDO_DEBUG(4,"condition builder returned %s\n",ret); return ret; } gboolean dbdo_sequence_guess(dbdo_object *obj) { gint row_id,column_id; TSRMLS_FETCH(); /* have we already tried to get it? */ if (obj->table->sequenceAssigned == TRUE) { return TRUE; } dbdo_schema_load(obj TSRMLS_CC); /* flag we have attempted this! */ obj->table->sequenceAssigned = TRUE; /* this should be a fixed postion? */ column_id = gda_data_model_get_column_position(obj->table->schema, "References"); if (column_id == -1) { return FALSE; } for (row_id = 0; row_id < gda_data_model_get_n_rows (obj->table->schema);row_id++) { gchar *string; GdaRow *row; GdaValue *value; 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); /* TODO SUPPORT MORE DATABASES HERE!! */ if (NULL != php_memnstr(string,"auto_increment",strlen("auto_increment"),string+strlen(string))) { /* g_print( "got it on row = %d\n",row_id); */ free(string); value = (GdaValue *) gda_row_get_value (row, 0); /* name */ string = gda_value_stringify (value); obj->table->sequenceColumn = estrdup(string); obj->table->sequenceIsNative = TRUE; obj->table->sequenceName = NULL; free(string); return TRUE; } g_free(string); } return FALSE; }