static gchar *
__initialize_statement_delete_query_string (MidgardDBObjectClass *klass, gboolean add_workspace)
{
	const gchar *table = MGD_DBCLASS_TABLENAME (klass);
	MidgardMetadataClass *metadata = MGD_DBCLASS_METADATA_CLASS (klass);
	g_return_val_if_fail (table != NULL, NULL);

	GString *sql = g_string_new ("");
	g_string_append_printf (sql, "UPDATE %s SET ", table); 

	if (metadata) {
		g_string_append (sql, 
				"metadata_revisor=##metadata_revisor::string, "
				"metadata_revised=##metadata_revised::string, "
				"metadata_revision=##metadata_revision::guint, "
				"metadata_deleted=##metadata_deleted::guint ");
	} else {
		g_string_append_printf (sql,
				"%s=%s::guint ",
				midgard_core_object_get_deleted_field (klass),
				midgard_core_object_get_deleted_field (klass));
	}

	if (add_workspace) 
		g_string_append_printf (sql, " WHERE guid=##guid::string  AND %s=##%s::guint", 
				MGD_WORKSPACE_ID_FIELD, MGD_WORKSPACE_ID_FIELD);
	else 
		g_string_append (sql, " WHERE guid=##guid::string ");		

	return g_string_free (sql, FALSE);
}
static void
__statement_update_add_metadata_fields (MidgardDBObjectClass *klass, GString *sql)
{
	MidgardMetadataClass *mklass = MGD_DBCLASS_METADATA_CLASS (klass);
	if (!mklass)
		return;

	guint i;
	guint n_prop;
	GParamSpec **pspecs = g_object_class_list_properties (G_OBJECT_CLASS (mklass), &n_prop);

	if (!pspecs)
		return;

	for (i = 0; i < n_prop; i++) {
		const gchar *col_name = midgard_core_class_get_property_colname (MIDGARD_DBOBJECT_CLASS (mklass), pspecs[i]->name);
		if (!col_name)
			continue;
		const gchar *type_name = g_type_name (pspecs[i]->value_type);
		if (pspecs[i]->value_type == MIDGARD_TYPE_TIMESTAMP)
			type_name = "string";
		g_string_append_printf (sql, ", %s=##%s::%s", col_name, col_name, type_name);
	}

	g_free (pspecs);
}
static void __get_property_attribute (xmlNode *node, gchar **property_string, 
		gchar **target_name, MgdSchemaPropertyAttr **prop_attr, MidgardDBObjectClass *klass)
{
	*target_name = property_string[1];

	if (property_string[2] != NULL && !g_str_equal (*target_name, "metadata")) {
		__view_error (node, "%s not allowed in view configuration", target_name);
		return;	
	}

	/* Check metadata */
	if (property_string[2] != NULL && g_str_equal (*target_name, "metadata")) {

		if (!MGD_DBCLASS_METADATA_CLASS (klass)) {
			__view_error (node, "No metadata registered for %s class", G_OBJECT_CLASS_NAME (klass));
			return;
		}

		*target_name = property_string[2];
		*prop_attr = g_hash_table_lookup (MIDGARD_DBOBJECT_CLASS (MGD_DBCLASS_METADATA_CLASS (klass))->dbpriv->storage_data->prophash, *target_name);
	
		if (!*prop_attr)
			__view_error (node, "%s not found. Not registered for %s.metadata ?", *target_name, property_string[0]);
	}

	/* Fallback to custom properties, metadata class doesn't exist in MgdSchema scope */	
	if (!*prop_attr) {
		*prop_attr = g_hash_table_lookup (klass->dbpriv->storage_data->prophash, *target_name);
		if (!*prop_attr)
			__view_error(node, "%s not found. Not registered for %s ?", *target_name, property_string[0]);

		if ((*prop_attr)->is_private)
			__view_error (node, "Private property %s.%s can not be added to view.",
					G_OBJECT_CLASS_NAME (G_OBJECT_CLASS (klass)), (*prop_attr)->name);
	}
}
Beispiel #4
0
GList *
midgard_core_qb_set_object_from_query (MidgardQueryBuilder *builder, guint select_type, MidgardObject **nobject)
{
        g_assert(builder != NULL);
 
        guint ret_rows, ret_fields;
	MidgardConnection *mgd = builder->priv->mgd;
      
	gchar *sql = midgard_core_qb_get_sql(
			builder, select_type, 
			midgard_query_builder_get_object_select(builder, select_type));

	GSList *olist = NULL;
	MidgardDBObjectClass *dbklass = MIDGARD_DBOBJECT_CLASS(g_type_class_peek(builder->priv->type));

	if (!dbklass) {

		MIDGARD_ERRNO_SET_STRING (mgd, MGD_ERR_INTERNAL, "Failed to peek MidgardDBObjectClass pointer");
		return NULL;
	}

	if (dbklass->dbpriv->set_from_sql) {

		if (select_type != MQB_SELECT_GUID) {

			olist = dbklass->dbpriv->set_from_sql(mgd, builder->priv->type, ((const gchar *)sql));
			g_free(sql);

			return (GList *)olist;
		}
	}

	GdaDataModel *model = midgard_core_query_get_model(builder->priv->mgd, sql);
	g_free(sql);

	if(!model) 
		return NULL;	

	MidgardObject *object = NULL;
	gint rows, columns;
	const GValue *gvalue = NULL;

	ret_rows = gda_data_model_get_n_rows(model);
	ret_fields =  gda_data_model_get_n_columns(model);

	/* records found , allocate as many objects as many returned rows */ 
	GList *list = NULL;

	if(ret_rows == 0) {
		g_object_unref(model);
		return list;
	}

	/* We count rows only */
	if(select_type == MQB_SELECT_GUID) {
		
		gvalue = midgard_data_model_get_value_at(model, 0, 0);	
	
		if (!gvalue || !G_IS_VALUE (gvalue)) {
			
			g_object_unref (model);
			return 0;
		}

		MidgardTypeHolder *holder = g_new(MidgardTypeHolder, 1);

		GValue val = {0, };
		g_value_init (&val, G_TYPE_INT64);
		g_value_transform (gvalue, &val);

		holder->elements = (guint)g_value_get_int64((GValue*)&val);
		
		list = g_list_append(list, holder);	
		
		g_object_unref(model);
		g_value_unset (&val);

		return list;		
	}

	/* Get every row */
	for (rows = 0; rows < ret_rows; rows++) {
	
		if(!nobject)
			object = g_object_new (builder->priv->type, "connection", mgd, NULL);
		else 
			object = *nobject;

		MGD_OBJECT_IN_STORAGE (object) = TRUE;	
				
		if(dbklass->dbpriv->__set_from_sql != NULL) {
			
			dbklass->dbpriv->__set_from_sql(MIDGARD_DBOBJECT(object), 
					model, rows); 

		} else {
		
			/* Compute number of metadata properties */
			guint n_md_props = 0;
			MidgardMetadata *mklass = (MidgardMetadata *)MGD_DBCLASS_METADATA_CLASS (dbklass);
			if (mklass) 
				n_md_props = g_hash_table_size (MGD_DBCLASS_STORAGE_DATA (mklass)->prophash);

			guint __cols = n_md_props + 1; /* Add one for guid */

			/* we have guid and metadata columns first */
			for (columns = __cols; columns < ret_fields; columns++) {	
				
				gvalue = midgard_data_model_get_value_at(model, columns, rows);
				const gchar *coltitle =
					gda_data_model_get_column_title(model, columns);
				GParamSpec *pspec =
					g_object_class_find_property(G_OBJECT_GET_CLASS(object), coltitle);

				if(G_IS_VALUE(gvalue)) {

					if (!pspec) {
						
						g_warning("Failed to found (unregistered) %s property (%s class)", 
								coltitle, G_OBJECT_TYPE_NAME(object));
						continue;
					}

					if (G_VALUE_TYPE (gvalue) == GDA_TYPE_BINARY
							&& G_TYPE_FUNDAMENTAL (pspec->value_type) == G_TYPE_STRING) {

						gchar *stringified = midgard_core_query_binary_stringify ((GValue *)gvalue);
						g_object_set (G_OBJECT (object), coltitle, stringified, NULL);
				   		g_free (stringified);
					
					} else if (pspec->value_type != G_VALUE_TYPE (gvalue)) {

						GValue _convert = {0, };
						g_value_init (&_convert, pspec->value_type);	
				
						if (g_value_transform (gvalue, &_convert)) {

							/* FIXME, remove workaround once it's fixed in GDA */
							/* https://bugzilla.gnome.org/show_bug.cgi?id=617550 */
							guint dbtype = mgd->priv->config->priv->dbtype;
							if (dbtype == MIDGARD_DB_TYPE_MYSQL && G_VALUE_TYPE (gvalue) == GDA_TYPE_BLOB) {
								gchar *tmp_str = __default_unescape_string (g_value_get_string (&_convert));
								if (tmp_str)
									g_value_take_string (&_convert, tmp_str);
							}

							g_object_set_property (G_OBJECT (object), coltitle, &_convert);
					
						} else {

							g_warning ("Failed to convert %s to %s for %s property",
									G_VALUE_TYPE_NAME (gvalue),
									G_VALUE_TYPE_NAME (&_convert), 
									coltitle);
						}

						g_value_unset (&_convert);

					} else {

						g_object_set_property(G_OBJECT(object), coltitle, gvalue);
					}	
				
				} else if (gda_value_is_null(gvalue)) {			

					switch (pspec->value_type) {

						case G_TYPE_INT:
						case G_TYPE_UINT:
							g_object_set(G_OBJECT(object), coltitle, 0, NULL);
							break;

						case G_TYPE_STRING:
							g_object_set(G_OBJECT(object), coltitle, "", NULL);
							break;

						default:
							g_warning("Found (%s) not a value at %d.%d (%s)", 
									g_type_name(pspec->value_type), 
									columns, rows, 
									gda_data_model_get_column_title(model, columns));
							break;
					}
				}
			}	
		}

		/* Set guid */
		const gchar *guid;
		gvalue = midgard_data_model_get_value_at(model, 0, rows);
		if(G_IS_VALUE(gvalue) && G_VALUE_HOLDS_STRING(gvalue)){
			guid = g_value_get_string(gvalue);   
			g_free((gchar *)MIDGARD_DBOBJECT(object)->dbpriv->guid);
			MIDGARD_DBOBJECT(object)->dbpriv->guid = g_strdup(guid);
		}
		
		/* Set metadata */
		MidgardMetadata *metadata = MGD_DBOBJECT_METADATA (object);
	     	if (metadata) {
			GParamSpec *pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(object), "metadata");
			if (pspec)
				__mqb_set_metadata(metadata, model, rows);
		}	

		list = g_list_append(list, G_OBJECT(object));                		
	}

	g_object_unref(model);
	return list;	
}
static void
_midgard_query_select_execute (MidgardExecutable *iface, gboolean async, GError **error)
{
	g_return_if_fail (iface != NULL);
	MidgardQuerySelect *self = MIDGARD_QUERY_SELECT (iface);
	MidgardQueryExecutor *executor = MIDGARD_QUERY_EXECUTOR (self);

	GError *err = NULL;
	midgard_validable_validate (MIDGARD_VALIDABLE (self), &err);
	if (err) {
		g_propagate_error (error, err);
		return;
	}

	MidgardDBObjectClass *klass = executor->priv->storage->priv->klass;
	MidgardConnection *mgd = executor->priv->mgd;
	GdaConnection *cnc = mgd->priv->connection;
	GdaSqlStatement *sql_stm;
	GdaSqlStatementSelect *sss;

	sql_stm = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT);
	sss = (GdaSqlStatementSelect*) sql_stm->contents;
	g_assert (GDA_SQL_ANY_PART (sss)->type == GDA_SQL_ANY_STMT_SELECT);
	MIDGARD_QUERY_EXECUTOR (self)->priv->stmt = sql_stm;
	sss->from = gda_sql_select_from_new (GDA_SQL_ANY_PART (sss));

	/* Initialize top base expresion and operation with default AND operator type */
	GdaSqlExpr *base_where = gda_sql_expr_new (GDA_SQL_ANY_PART (sss));
	GdaSqlOperation *base_operation = gda_sql_operation_new (GDA_SQL_ANY_PART (base_where));
	base_operation->operator_type = GDA_SQL_OPERATOR_TYPE_AND;
	base_where->cond = base_operation;
	gda_sql_statement_select_take_where_cond (sql_stm, base_where);

	/* Create targets (FROM) */
	GdaSqlSelectTarget *s_target = gda_sql_select_target_new (GDA_SQL_ANY_PART (sss->from));
	s_target->table_name = g_strdup (midgard_core_class_get_table (klass));
	s_target->as = g_strdup_printf ("t%d", ++MIDGARD_QUERY_EXECUTOR (self)->priv->tableid);
	MIDGARD_QUERY_EXECUTOR (self)->priv->table_alias = g_strdup (s_target->as);
	gda_sql_select_from_take_new_target (sss->from, s_target);

	/* Set target expression */	
	GdaSqlExpr *texpr = gda_sql_expr_new (GDA_SQL_ANY_PART (s_target));
	GValue *tval = g_new0 (GValue, 1);
	g_value_init (tval, G_TYPE_STRING);
	g_value_set_string (tval, s_target->table_name);
	texpr->value = tval;
	s_target->expr = texpr;

	/* Add fields for all properties registered per class (SELECT a,b,c...) */
	klass->dbpriv->add_fields_to_select_statement (klass, mgd, sss, s_target->as);

	GdaSqlExpr *where = sss->where_cond;
	GdaSqlOperation *operation = where->cond;
	/* Add joins, LEFT JOIN tbl2 ON... */
	__query_select_add_joins (MIDGARD_QUERY_SELECT (self), operation, &err);
	if (err) {
	 	g_propagate_error (error, err);
		goto return_false;
	}

	/* Add constraints' conditions (WHERE a=1, b=2...) */
	if (MIDGARD_QUERY_EXECUTOR (self)->priv->constraint) {
		MIDGARD_QUERY_CONSTRAINT_SIMPLE_GET_INTERFACE (MIDGARD_QUERY_EXECUTOR (self)->priv->constraint)->priv->add_conditions_to_statement 			(MIDGARD_QUERY_EXECUTOR (self), MIDGARD_QUERY_EXECUTOR (self)->priv->constraint, sql_stm, base_where, &err);
		if (err) {
			g_propagate_error (error, err);
			goto return_false;
		}
		if (MIDGARD_QUERY_EXECUTOR (self)->priv->n_constraints == 1) 
			__add_second_dummy_constraint (sss, operation);
		/* Add dummy constraint if operation has only one operand */
		if (operation->operands && (g_slist_length (operation->operands) == 1))
			__add_dummy_constraint (sss, operation);
	} else { 
		/* no constraints, add dummy '1=1 AND 0<1' to satisfy top constraint group */
		__add_dummy_constraint (sss, operation); 
		__add_second_dummy_constraint (sss, operation); 
	}

	/* Add orders , ORDER BY t1.field... */
	if (!__query_select_add_orders (executor, &err)) { 
		if (err)
			g_propagate_error (error, err);
		goto return_false;
	}

	/* Exclude deleted */
	if (MGD_DBCLASS_METADATA_CLASS (klass) && !executor->priv->include_deleted)
		__add_exclude_deleted_constraints (executor, sss, operation, klass);

	/* Add limit, LIMIT x */
	if (executor->priv->limit > 0) {
		GdaSqlExpr *limit_expr = gda_sql_expr_new (GDA_SQL_ANY_PART (sss));
		GValue *limit_val = g_new0 (GValue, 1);
		g_value_init (limit_val, G_TYPE_STRING);
		g_value_take_string (limit_val, g_strdup_printf ("%d", executor->priv->limit));
		limit_expr->value = limit_val;
		sss->limit_count = limit_expr;
	}

	/* Add offset, OFFSET x */
	if (executor->priv->offset >= 0) {
		GdaSqlExpr *offset_expr = gda_sql_expr_new (GDA_SQL_ANY_PART (sss));
		GValue *offset_val = g_new0 (GValue, 1);
		g_value_init (offset_val, G_TYPE_STRING);
		g_value_take_string (offset_val, g_strdup_printf ("%d", executor->priv->offset));
		offset_expr->value = offset_val;
		sss->limit_offset = offset_expr;
	}	

	/* Check structure */
	if (!gda_sql_statement_check_structure (sql_stm, &err)) {
		g_set_error (error, MIDGARD_EXECUTION_ERROR, MIDGARD_EXECUTION_ERROR_INTERNAL,
				"Can't build SELECT statement: %s)", err && err->message ? err->message : _("Unknown reason"));
		if (err)
			g_clear_error (&err);
		goto return_false;
	} 

	/* Create statement */
	GdaStatement *stmt = gda_statement_new ();	
	g_object_set (G_OBJECT (stmt), "structure", sql_stm, NULL);
	gda_sql_statement_free (sql_stm);
	sql_stm = NULL;

	if (MGD_CNC_DEBUG (mgd)) {
		gchar *debug_sql = gda_connection_statement_to_sql (cnc, stmt, NULL, GDA_STATEMENT_SQL_PRETTY, NULL, NULL);
		g_debug ("QuerySelect: %s", debug_sql);
		g_free (debug_sql);
	}

	/* execute statement */
	GdaDataModel *model = NULL;
	midgard_executable_execution_start (MIDGARD_EXECUTABLE(self));
	model = gda_connection_statement_execute_select (cnc, stmt, NULL, &err);
	g_object_unref (stmt);

	if (!model && !err) {
		g_set_error (error, MIDGARD_EXECUTION_ERROR, MIDGARD_EXECUTION_ERROR_INTERNAL,
				"Execute error - Unknown reason, underlying error is NULL");
		goto return_false;
	}

	if (err) {
		g_set_error (error, MIDGARD_EXECUTION_ERROR, MIDGARD_EXECUTION_ERROR_INTERNAL,
				"Execute error - %s", err->message);
		g_error_free (err);
		goto return_false;
	}
	
	executor->priv->results_count = gda_data_model_get_n_rows (model);
	if (executor->priv->resultset && G_IS_OBJECT (executor->priv->resultset))
		g_object_unref (G_OBJECT (executor->priv->resultset));
	executor->priv->resultset = (gpointer) model;

	return;

return_false:
	if (sql_stm)
		gda_sql_statement_free (sql_stm);

	return;
}
/* Create GdaSqlSelectField for every property registered for the class. */
void
_add_fields_to_select_statement (MidgardDBObjectClass *klass, MidgardConnection *mgd, GdaSqlStatementSelect *select, const gchar *table_name)
{
	guint n_prop;
	guint i;
	GdaSqlSelectField *select_field;
	GdaSqlExpr *expr;
	GValue *val;
	gchar *table_field;
	GdaConnection *cnc = mgd->priv->connection;

	GParamSpec **pspecs = g_object_class_list_properties (G_OBJECT_CLASS (klass), &n_prop);
	if (!pspecs)
		return;

	const gchar *property_table = NULL;

	for (i = 0; i < n_prop; i++) {

		const gchar *property = pspecs[i]->name;
		const gchar *property_field = midgard_core_class_get_property_colname (klass, property);
		property_table = midgard_core_class_get_property_table (klass, property); 
		if (property_table && table_name)
			property_table = table_name;

		/* Ignore properties with NULL storage and those of object type */
		if (!property_table || pspecs[i]->value_type == G_TYPE_OBJECT)
			continue;

       		select_field = gda_sql_select_field_new (GDA_SQL_ANY_PART (select));
		/*select_field->field_name = g_strdup (property_field);
		select_field->table_name = g_strdup (property_table);*/
		select_field->as = gda_connection_quote_sql_identifier (cnc, property);
		select->expr_list = g_slist_append (select->expr_list, select_field);
		expr = gda_sql_expr_new (GDA_SQL_ANY_PART (select_field));
		val = g_new0 (GValue, 1);
		g_value_init (val, G_TYPE_STRING);
		gchar *q_table = gda_connection_quote_sql_identifier (cnc, property_table);
		gchar *q_field = gda_connection_quote_sql_identifier (cnc, property_field);
		table_field = g_strconcat (q_table, ".", q_field, NULL);
		g_value_set_string (val, table_field);
		g_free (q_table);
		g_free (q_field);
		g_free (table_field);
		expr->value = val;
		select_field->expr = expr;
	}	

	g_free (pspecs);

	if (!klass->dbpriv->has_metadata)
		return;

	/* Check if metadata provides own method to add fields. If not, use given class storage. */
	if (MIDGARD_IS_OBJECT_CLASS (klass)) {

		MidgardMetadataClass *mklass = MGD_DBCLASS_METADATA_CLASS (klass);
		if (!mklass)
			return;

		if (MIDGARD_DBOBJECT_CLASS (mklass)->dbpriv->add_fields_to_select_statement) {
			MIDGARD_DBOBJECT_CLASS (mklass)->dbpriv->add_fields_to_select_statement (MIDGARD_DBOBJECT_CLASS (mklass), mgd, select, table_name);
			return;
		}

		const gchar *table = midgard_core_class_get_table (klass);
		if (table_name)
			table = table_name;

		/* TODO, Once we stabilize use case, refactor this below to minimize code usage */
		GParamSpec **pspecs = g_object_class_list_properties (G_OBJECT_CLASS (mklass), &n_prop);
		if (!pspecs)
			return;
		
		for (i = 0; i < n_prop; i++) {

			const gchar *property = pspecs[i]->name;
			const gchar *property_field = midgard_core_class_get_property_colname (MIDGARD_DBOBJECT_CLASS (mklass), property);	

			if (pspecs[i]->value_type == G_TYPE_OBJECT || !property_field)
				continue;
			
			select_field = gda_sql_select_field_new (GDA_SQL_ANY_PART (select));
			/*select_field->field_name = g_strdup (property_field);
			select_field->table_name = g_strdup (table);*/
			select_field->as = g_strconcat ("metadata_", property, NULL);
			select->expr_list = g_slist_append (select->expr_list, select_field);
			expr = gda_sql_expr_new (GDA_SQL_ANY_PART (select_field));
			val = g_new0 (GValue, 1);
			g_value_init (val, G_TYPE_STRING);
			table_field = g_strconcat (table, ".", property_field, NULL);
			g_value_set_string (val, table_field);
			g_free (table_field);
			expr->value = val;
			select_field->expr = expr;
		}

		g_free (pspecs);
	}

	return;
}