00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <config.h>
00021 #include "simple_constraint.h"
00022 #include "midgard/midgard_object.h"
00023 #include "midgard/midgard_metadata.h"
00024 #include "midgard_mysql.h"
00025 #include <string.h>
00026 #include <stdlib.h>
00027
00028 static const char *operator[] = {
00029 "=", ">", "<", "<>", "<=", ">=", "LIKE", "NOT LIKE", "IN", "NOT IN", "INTREE",
00030 NULL
00031 };
00032
00033 static void add_sql_value(
00034 MidgardSimpleConstraint *constraint, GValue *value, GString *sql) {
00035 g_assert(constraint != NULL);
00036 g_assert(value != NULL);
00037 g_assert(sql != NULL);
00038
00039 GValue *target = g_new0(GValue, 1);
00040 g_value_init(target, G_PARAM_SPEC_VALUE_TYPE(constraint->spec));
00041
00042
00043 if (!g_param_value_convert((GParamSpec *)constraint->spec, value, target, FALSE)) {
00044
00045 if (G_VALUE_HOLDS_STRING(value) && G_VALUE_HOLDS_UINT(target)) {
00046 guint uvalue = strtoul(g_value_get_string(value), NULL, 0);
00047 g_value_set_uint(target, uvalue);
00048 } else {
00049 g_warning(
00050 "Invalid value conversion from %s to %s",
00051 G_VALUE_TYPE_NAME(value),
00052 G_VALUE_TYPE_NAME(target));
00053 }
00054 }
00055
00056
00057 if (G_VALUE_HOLDS_STRING(target)) {
00058 const gchar *strval = g_value_get_string(target);
00059 if(strval == NULL)
00060 strval = "";
00061 guint length = strlen(strval);
00062 gchar *escaped = g_new(gchar, 2 * length + 1);
00063
00064 mysql_real_escape_string(
00065 constraint->mgd->msql->mysql, escaped, strval, length);
00066 g_string_append_printf(sql, "'%s'", escaped);
00067 g_free(escaped);
00068 } else if (G_VALUE_HOLDS_BOOLEAN(target)) {
00069 if (g_value_get_boolean(target)) {
00070 g_string_append(sql, "TRUE");
00071 } else {
00072 g_string_append(sql, "FALSE");
00073 }
00074 } else if (G_VALUE_HOLDS_UINT(target)) {
00075 g_string_append_printf(sql, "%u", g_value_get_uint(target));
00076 } else if (G_VALUE_HOLDS_INT(target)) {
00077 g_string_append_printf(sql, "%d", g_value_get_int(target));
00078 } else if (G_VALUE_HOLDS_FLOAT(target)) {
00079 g_string_append_printf(sql, "%g", g_value_get_float(target));
00080 } else {
00081 g_warning(
00082 "Unexpected constraint value type %s",
00083 G_VALUE_TYPE_NAME(target));
00084 g_string_append(sql, "NULL");
00085 }
00086
00087 g_value_unset(target);
00088 g_free(target);
00089 }
00090
00091 static void add_sql(MidgardQueryConstraint *constraint, GString *sql) {
00092 g_assert(constraint);
00093 g_assert(sql);
00094
00095 MidgardSimpleConstraint *simple = MIDGARD_SIMPLE_CONSTRAINT(constraint);
00096 guint i;
00097
00098 const gchar *table = midgard_object_class_get_table(
00099 (MidgardObjectClass *)simple->initial_klass);
00100
00101
00102 GValue *value = simple->value;
00103 if (G_VALUE_HOLDS_POINTER(value)
00104 && G_IS_VALUE(g_value_get_pointer(value))) {
00105 value = (GValue *) g_value_get_pointer(value);
00106 }
00107
00108
00109
00110 if(g_ascii_strcasecmp(simple->spec->name, "sitegroup") == 0){
00111 gchar *sgfield = g_strconcat(
00112 midgard_object_class_get_table((MidgardObjectClass *)simple->klass),
00113 ".sitegroup",
00114 NULL);
00115 g_string_append(sql, sgfield);
00116 g_free(sgfield);
00117
00118 } else if (g_ascii_strcasecmp(simple->spec->name, "guid") == 0){
00119 gchar *sgfield = g_strconcat(
00120 midgard_object_class_get_table((MidgardObjectClass *)simple->klass),
00121 ".guid",
00122 NULL);
00123 g_string_append(sql, sgfield);
00124 g_free(sgfield);
00125 } else if (simple->ext_type == MIDGARD_TYPE_METADATA) {
00126 MidgardObjectClass *pklass =
00127 (MidgardObjectClass*) g_type_class_peek(simple->parent_type);
00128 if(pklass)
00129 table = midgard_object_class_get_table(pklass);
00130 g_string_append_printf(sql,
00131 "%s.%s",
00132 table,
00133 g_param_spec_get_nick((GParamSpec *) simple->spec));
00134 } else {
00135 g_string_append(sql, g_param_spec_get_nick((GParamSpec *) simple->spec));
00136 }
00137
00138 g_string_append_c(sql, ' ');
00139 if(g_str_equal(simple->op, "INTREE")){
00140 if(!G_VALUE_HOLDS(value, G_TYPE_UINT)){
00141 g_warning(" Only integers values supported by INTREE operator");
00142 return;
00143 }
00144
00145
00146
00147 const gchar *parent_field, *up_field = NULL;
00148 guint j = 0;
00149 parent_field =
00150 midgard_object_class_get_parent_property(
00151 (MidgardObjectClass *)simple->klass);
00152 if(parent_field == NULL)
00153 parent_field = "";
00154 up_field =
00155 midgard_object_class_get_up_property(
00156 (MidgardObjectClass *)simple->klass);
00157 if(up_field == NULL)
00158 up_field = "";
00159 if(!g_str_equal(parent_field, simple->spec->name))
00160 j++;
00161 if(!g_str_equal(up_field, simple->spec->name))
00162 j++;
00163 if(j > 1){
00164 g_warning("Constraint's property is neither parent nor up property");
00165 return;
00166 }
00167 g_string_append(sql, "IN");
00168 } else {
00169 g_string_append(sql, simple->op);
00170 }
00171 g_string_append_c(sql, ' ');
00172
00173 if (g_str_equal(simple->op, "IN") || g_str_equal(simple->op, "NOT IN")) {
00174 g_string_append_c(sql, '(');
00175 if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) {
00176 GValueArray *array = (GValueArray *) g_value_get_boxed(value);
00177 for (i = 0; i < array->n_values; i++) {
00178 if (i > 0) {
00179 g_string_append_c(sql, ',');
00180 }
00181 add_sql_value(simple, g_value_array_get_nth(array, i), sql);
00182 }
00183 } else {
00184 add_sql_value(simple, value, sql);
00185 }
00186 g_string_append_c(sql, ')');
00187
00188
00189
00190 } else if(g_str_equal(simple->op, "INTREE")) {
00191 table = midgard_object_class_get_table(
00192 (MidgardObjectClass *)simple->klass);
00193 gint *prnts =
00194 mgd_tree((midgard *)simple->mgd, table,
00195 simple->spec->name,
00196 g_value_get_uint(value),
00197 0, NULL);
00198 if(prnts) {
00199 g_string_append_c(sql, '(');
00200 i = 0;
00201 do {
00202 if(i > 0)
00203 g_string_append(sql,",");
00204
00205 g_string_append_printf(sql,
00206 "%d", prnts[i]);
00207 i++;
00208
00209 } while (prnts[i]);
00210 g_string_append_c(sql, ')');
00211 }
00212
00213 } else {
00214 add_sql_value(simple, value, sql);
00215 }
00216 }
00217
00218 G_DEFINE_TYPE(MidgardSimpleConstraint, midgard_simple_constraint, MIDGARD_TYPE_QUERY_CONSTRAINT)
00219
00220 static void midgard_simple_constraint_init(MidgardSimpleConstraint *self) {
00221 g_assert(self);
00222 }
00223
00224 static void midgard_simple_constraint_dispose(MidgardSimpleConstraint *simple) {
00225 g_assert(simple);
00226
00227 g_value_unset(simple->value);
00228 g_free(simple->value);
00229
00230 GObjectClass *parent =
00231 G_OBJECT_CLASS(midgard_simple_constraint_parent_class);
00232 parent->dispose(G_OBJECT(simple));
00233 }
00234
00235 static void midgard_simple_constraint_class_init(
00236 MidgardSimpleConstraintClass *klass) {
00237 g_assert(klass);
00238 MIDGARD_QUERY_CONSTRAINT_CLASS(klass)->add_sql = add_sql;
00239 G_OBJECT_CLASS(klass)->dispose =
00240 (void (*)(GObject *)) midgard_simple_constraint_dispose;
00241 }
00242
00252 MidgardSimpleConstraint *midgard_simple_constraint_new(
00253 midgard *mgd, GObjectClass *klass,
00254 const gchar *name, const gchar *op, const GValue *value) {
00255
00256 const GParamSpec *spec = g_object_class_find_property(klass, name);
00257
00258 if (spec == NULL) {
00259 g_warning("Invalid constraint property %s\n", name);
00260 return NULL;
00261 }
00262
00263
00264 guint i;
00265 for (i = 0; operator[i] != NULL; i++) {
00266 if (g_ascii_strcasecmp(op, operator[i]) == 0) {
00267 op = operator[i];
00268 break;
00269 }
00270 }
00271 if (operator[i] == NULL) {
00272 g_warning("Invalid comparison operator %s\n", op);
00273 return NULL;
00274 }
00275
00276
00277 GValue *new_value = g_new0(GValue, 1);
00278 g_value_init(new_value, G_VALUE_TYPE(value));
00279 g_value_copy(value, new_value);
00280
00281 MidgardSimpleConstraint *simple = MIDGARD_SIMPLE_CONSTRAINT(
00282 g_object_new(MIDGARD_TYPE_SIMPLE_CONSTRAINT, NULL));
00283 simple->mgd = mgd;
00284 simple->spec = spec;
00285 simple->op = op;
00286 simple->value = new_value;
00287 simple->klass = klass;
00288 return simple;
00289 }