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 "midgard/midgard_schema.h"
00022 #include "midgard/types.h"
00023 #include "midgard/midgard_legacy.h"
00024 #include <libxml/parser.h>
00025 #include <libxml/tree.h>
00026 #include "midgard/midgard_datatypes.h"
00027 #include "midgard/midgard_type.h"
00028 #include "schema.h"
00029
00030
00031
00032
00033
00034
00035
00036 static GSList *schema_trash = NULL;
00037
00038
00039
00040 static const gchar *parsed_schema = NULL;
00041
00042
00043 void _copy_schemas(gpointer key, gpointer value, gpointer userdata);
00044
00045 static MgdSchemaPropertyAttr *_mgd_schema_property_attr_new(){
00046
00047 MgdSchemaPropertyAttr *prop = g_new(MgdSchemaPropertyAttr, 1);
00048 prop->gtype = G_TYPE_NONE;
00049 prop->type = NULL;
00050 prop->dbtype = NULL;
00051 prop->field = NULL;
00052 prop->table = NULL;
00053 prop->upfield = NULL;
00054 prop->parentfield = NULL;
00055 prop->primaryfield = NULL;
00056 prop->is_multilang = FALSE;
00057 prop->link = NULL;
00058 prop->link_target = NULL;
00059 prop->is_primary = FALSE;
00060 prop->is_reversed = FALSE;
00061 prop->is_link = FALSE;
00062
00063 return prop;
00064 }
00065
00066 static void _mgd_schema_property_attr_free(MgdSchemaPropertyAttr *prop)
00067 {
00068 g_assert(prop != NULL);
00069
00070 g_free((gchar *)prop->type);
00071 g_free((gchar *)prop->dbtype);
00072 g_free((gchar *)prop->field);
00073 g_free((gchar *)prop->table);
00074 g_free((gchar *)prop->upfield);
00075 g_free((gchar *)prop->parentfield);
00076 g_free((gchar *)prop->primaryfield);
00077 g_free((gchar *)prop->link);
00078 g_free((gchar *)prop->link_target);
00079
00080 g_free(prop);
00081 }
00082
00083 void _destroy_property_hash(gpointer key, gpointer value, gpointer userdata)
00084 {
00085 MgdSchemaPropertyAttr *prop = (MgdSchemaPropertyAttr *) value;
00086 gchar *name = (gchar *) key;
00087
00088 if(prop)
00089 _mgd_schema_property_attr_free(prop);
00090
00091 if(name)
00092 g_free(name);
00093 }
00094
00095 static MgdSchemaTypeQuery *_mgd_schema_type_query_new()
00096 {
00097 MgdSchemaTypeQuery *query = g_new(MgdSchemaTypeQuery, 1);
00098 query->select = NULL;
00099 query->select_full = NULL;
00100 query->from = NULL;
00101 query->where = NULL;
00102 query->table = NULL;
00103 query->link = NULL;
00104 query->tables = g_strdup("");
00105 query->primary = NULL;
00106 query->parentfield = NULL;
00107 query->upfield = NULL;
00108 query->use_lang = FALSE;
00109
00110 return query;
00111 }
00112
00113 static void _mgd_schema_type_query_free(MgdSchemaTypeQuery *query)
00114 {
00115 g_assert(query != NULL);
00116
00117 g_free((gchar *)query->select);
00118 g_free((gchar *)query->select_full);
00119
00120 g_free((gchar *)query->where);
00121 g_free((gchar *)query->table);
00122 g_free((gchar *)query->primary);
00123 g_free((gchar *)query->link);
00124 g_free((gchar *)query->tables);
00125 g_free((gchar *)query->parentfield);
00126 g_free((gchar *)query->upfield);
00127
00128
00129 g_free(query);
00130 }
00131
00132 void _destroy_query_hash(gpointer key, gpointer value, gpointer userdata)
00133 {
00134 MgdSchemaTypeQuery *query = (MgdSchemaTypeQuery *) value;
00135 gchar *name = (gchar *) key;
00136
00137 if(query)
00138 _mgd_schema_type_query_free(query);
00139
00140 if(name)
00141 g_free(name);
00142 }
00143
00144 static MgdSchemaTypeAttr *_mgd_schema_type_attr_new()
00145 {
00146 MgdSchemaTypeAttr *type = g_new(MgdSchemaTypeAttr, 1);
00147 type->base_index = 0;
00148 type->num_properties = 0;
00149 type->params = NULL;
00150 type->properties = NULL;
00151 type->table = NULL;
00152 type->parent = NULL;
00153 type->primary = NULL;
00154 type->property_up = NULL;
00155 type->property_parent = NULL;
00156 type->property_count = 0;
00157 type->use_lang = FALSE;
00158 type->tables = g_hash_table_new(g_str_hash, g_str_equal);
00159 type->prophash = g_hash_table_new(g_str_hash, g_str_equal);
00160 type->query = _mgd_schema_type_query_new();
00161 type->childs = NULL;
00162
00163 return type;
00164 }
00165
00166 static void _mgd_schema_type_attr_free(MgdSchemaTypeAttr *type)
00167 {
00168 g_assert(type != NULL);
00169
00170 g_free((gchar *)type->table);
00171 g_free((gchar *)type->parent);
00172 g_free((gchar *)type->primary);
00173 g_free((gchar *)type->property_up);
00174 g_free((gchar *)type->property_parent);
00175
00176 g_hash_table_foreach(type->tables, _destroy_query_hash, NULL);
00177 g_hash_table_destroy(type->tables);
00178
00179 g_hash_table_foreach(type->prophash, _destroy_property_hash, NULL);
00180 g_hash_table_destroy(type->prophash);
00181
00182 _mgd_schema_type_query_free(type->query);
00183
00184 g_free(type->params);
00185 g_free(type->properties);
00186
00187 g_free(type);
00188 }
00189
00190
00191 MgdSchemaTypeAttr *
00192 midgard_schema_lookup_type (MidgardSchema *schema, gchar *name)
00193 {
00194 g_assert(schema != NULL);
00195 g_assert(name != NULL);
00196
00197 return (MgdSchemaTypeAttr *) g_hash_table_lookup(schema->types, name);
00198 }
00199
00200
00212 GHashTable *
00213 midgard_schema_lookup_type_member(MidgardSchema *schema, const gchar *typename, gchar *property)
00214 {
00215 g_assert(schema != NULL);
00216 g_assert(typename != NULL);
00217 g_assert(property != NULL);
00218
00219 MgdSchemaTypeAttr *sts;
00220
00221 sts = midgard_schema_lookup_type(schema, (gchar *)typename);
00222
00223 if (sts != NULL)
00224 return g_hash_table_lookup(sts->prophash, property);
00225
00226 return NULL;
00227 }
00228
00229
00230
00231
00232 static const gchar *mgd_complextype[] = { "type", "property", "Schema", "description", "include", NULL };
00233 static const gchar *mgd_attribute[] = { "name", "table", "parent", "parentfield",
00234 "type", "link", "upfield", "field", "multilang", "reverse", "primaryfield", "dbtype", NULL };
00235
00236
00237 static const gchar *rtypes[] = {
00238 "midgard_sitegroup",
00239 "midgard_account",
00240 NULL
00241 };
00242
00243
00244 static const gchar *rtables[] = {
00245 "sitegroup",
00246 "repligard",
00247 "midgard_account",
00248 NULL
00249 };
00250
00251
00252 static const gchar *rcolumns[] = {
00253 "metadata_",
00254 "sitegroup",
00255 "group",
00256 NULL
00257 };
00258
00259 static gboolean strv_contains(const char **strv, const xmlChar *str) {
00260 g_assert(strv != NULL);
00261 g_assert(str != NULL);
00262 while (*strv != NULL) {
00263 if (g_str_equal(*strv++, str)) {
00264 return TRUE;
00265 }
00266 }
00267 return FALSE;
00268 }
00269
00270 static void check_metadata_column(const xmlChar *column){
00271
00272 if(g_str_has_prefix((const gchar *)column, "metadata_"))
00273 g_critical("Column names prefixed with 'metadata_' are reserved ones");
00274 }
00275
00276 static void check_property_name(const xmlChar *name, const gchar *typename){
00277
00278 g_assert(name != NULL);
00279
00280 if(g_strrstr_len((const gchar *)name, strlen((const gchar *)name), "_") != NULL)
00281 g_critical("Type '%s', property '%s'. Underscore not allowed in property names!",
00282 typename, name);
00283
00284
00285 if(!g_str_equal(typename, "midgard_quota"))
00286 if(g_str_equal(name, "sitegroup"))
00287 g_critical("Type '%s'.Property name 'sitegroup' is reserved!",
00288 typename);
00289
00290 if(g_str_equal(name, "guid"))
00291 g_critical("Type '%s'.Property name 'guid' is reserved!",
00292 typename);
00293
00294 }
00295
00296
00297
00298 static void
00299 _get_type_attributes(xmlNode * node, MgdSchemaTypeAttr *type_attr)
00300 {
00301 xmlAttr *attr;
00302 xmlChar *attrval;
00303
00304 if (node != NULL){
00305
00306 attr = node->properties;
00307 attr = attr->next;
00308
00309 while (attr != NULL){
00310
00311 if(!strv_contains(mgd_attribute, attr->name)){
00312 g_warning("Wrong attribute '%s' in '%s' on line %ld",
00313 attr->name, parsed_schema, xmlGetLineNo(node));
00314 }
00315 attrval = xmlNodeListGetString (node->doc, attr->children, 1);
00316
00317 if(g_str_equal(attr->name, "table")) {
00318
00319 if (strv_contains(rtables, attrval)) {
00320 g_critical("'%s' is reserved table name",
00321 attrval);
00322 }
00323 type_attr->table = g_strdup((const gchar *)attrval);
00324 }
00325
00326 if(g_str_equal(attr->name, "parent"))
00327 type_attr->parent = g_strdup((gchar *)attrval);
00328
00329 xmlFree(attrval);
00330 attr = attr->next;
00331 }
00332 }
00333 }
00334
00335
00336 static void
00337 _get_property_attributes(xmlNode * node,
00338 MgdSchemaTypeAttr *type_attr, MgdSchemaPropertyAttr *prop_attr)
00339 {
00340 xmlAttr *attr;
00341 xmlChar *attrval;
00342
00343 if (node != NULL){
00344
00345 attr = node->properties;
00346 attr = attr->next;
00347
00348 while (attr != NULL){
00349
00350 attrval = xmlNodeListGetString (node->doc, attr->children, 1);
00351
00352 if(!strv_contains(mgd_attribute, attr->name)){
00353 g_warning("Wrong attribute '%s' in '%s' on line %ld",
00354 attr->name, parsed_schema, xmlGetLineNo(node));
00355 }
00356
00357 if(g_str_equal(attr->name, "type")){
00358 prop_attr->type = g_strdup((const gchar*)attrval);
00359
00360 if(g_str_equal(attrval, "string"))
00361 prop_attr->gtype = MGD_TYPE_STRING;
00362
00363 if(g_str_equal(attrval, "integer"))
00364 prop_attr->gtype = MGD_TYPE_INT;
00365
00366 if(g_str_equal(attrval, "unsigned integer"))
00367 prop_attr->gtype = MGD_TYPE_UINT;
00368
00369 if(g_str_equal(attrval, "float"))
00370 prop_attr->gtype = MGD_TYPE_FLOAT;
00371
00372 if(g_str_equal(attrval, "boolean"))
00373 prop_attr->gtype = MGD_TYPE_BOOLEAN;
00374
00375 if(g_str_equal(attrval, "bool"))
00376 prop_attr->gtype = MGD_TYPE_BOOLEAN;
00377
00378 if(g_str_equal(attrval, "datetime"))
00379 prop_attr->gtype = MGD_TYPE_TIMESTAMP;
00380
00381 if(g_str_equal(attrval, "longtext"))
00382 prop_attr->gtype = MGD_TYPE_LONGTEXT;
00383
00384 if(g_str_equal(attrval, "text"))
00385 prop_attr->gtype = MGD_TYPE_LONGTEXT;
00386
00387 if(g_str_equal(attrval, "guid"))
00388 prop_attr->gtype = MGD_TYPE_GUID;
00389
00390 }
00391
00392 if(g_str_equal(attr->name, "dbtype"))
00393 prop_attr->dbtype = g_strdup((gchar *)attrval);
00394
00395 if(g_str_equal(attr->name, "field")){
00396
00397 check_metadata_column(attrval);
00398 if (strv_contains(rcolumns, attrval)) {
00399 g_critical("'%s' is reserved column name",
00400 attrval);
00401 }
00402 prop_attr->field = g_strdup((gchar *)attrval);
00403 }
00404
00405 if(g_str_equal(attr->name, "table")){
00406
00407 if (strv_contains(rtables, attrval)) {
00408 g_critical("'%s' is reserved table name",
00409 attrval);
00410 }
00411 prop_attr->table = g_strdup((gchar *)attrval);
00412 }
00413
00414 if(g_str_equal(attr->name, "upfield")){
00415 check_metadata_column(attrval);
00416
00417 if (strv_contains(rcolumns, attrval)) {
00418 g_critical("'%s' is reserved column name",
00419 attrval);
00420 }
00421 if(!type_attr->property_up){
00422 xmlChar *tmpattr =
00423 xmlGetProp (node, (const xmlChar *)"name");
00424 type_attr->property_up = g_strdup((gchar *)tmpattr);
00425 type_attr->query->upfield = g_strdup((gchar *)attrval);
00426 xmlFree(tmpattr);
00427 } else {
00428 g_warning("upfield redefined!");
00429 }
00430 prop_attr->upfield = g_strdup((gchar *)attrval);
00431 }
00432
00433 if(g_str_equal(attr->name, "parentfield")){
00434 check_metadata_column(attrval);
00435
00436 if (strv_contains(rcolumns, attrval)) {
00437 g_critical("'%s' is reserved column name",
00438 attrval);
00439 }
00440 if(!type_attr->property_parent){
00441 xmlChar *tmpattr = xmlGetProp (node, (const xmlChar *)"name");
00442 type_attr->property_parent = g_strdup((gchar *)tmpattr);
00443 type_attr->query->parentfield = g_strdup((gchar *)attrval);
00444 xmlFree(tmpattr);
00445 } else {
00446 g_warning("parentfield redefined!");
00447 }
00448 prop_attr->parentfield = g_strdup((gchar *)attrval);
00449 }
00450
00451 if(g_str_equal(attr->name, "multilang")) {
00452 if(g_str_equal(attrval, "yes")) {
00453 prop_attr->is_multilang = TRUE;
00454 type_attr->use_lang = TRUE;
00455 }
00456 }
00457
00458 if(g_str_equal(attr->name, "primaryfield")) {
00459 check_metadata_column(attrval);
00460
00461 if (strv_contains(rcolumns, attrval)) {
00462 g_critical("'%s' is reserved column name",
00463 attrval);
00464 }
00465 prop_attr->primaryfield = g_strdup((gchar *)attrval);
00466 prop_attr->is_primary = TRUE;
00467 xmlChar *tmpattr = xmlGetProp (node, (const xmlChar *)"name");
00468 type_attr->primary = g_strdup((gchar *)tmpattr);
00469 type_attr->query->primary = g_strdup((gchar *)attrval);
00470 xmlFree(tmpattr);
00471 }
00472
00473 if(g_str_equal(attr->name, "reverse")) {
00474 if(g_str_equal(attrval, "yes"))
00475 prop_attr->is_reversed = TRUE;
00476 }
00477
00478 if(g_str_equal(attr->name, "link")) {
00479 gchar **link = g_strsplit((gchar *)attrval, ":", -1);
00480 prop_attr->link = g_strdup((gchar *)link[0]);
00481 prop_attr->is_link = TRUE;
00482 if(link[1])
00483 prop_attr->link_target =
00484 g_strdup((gchar *)link[1]);
00485 else
00486 prop_attr->link_target =
00487 g_strdup("guid");
00488
00489 g_strfreev(link);
00490 }
00491
00492 xmlFree(attrval);
00493 attr = attr->next;
00494 }
00495 }
00496 }
00497
00498
00499
00500
00501
00502
00503
00504 static void
00505 _get_element_names (xmlNode * curn , MgdSchemaTypeAttr *type_attr, MidgardSchema *schema)
00506 {
00507 xmlNode *obj = NULL;
00508 xmlChar *nv = NULL, *dparent;
00509 MgdSchemaTypeAttr *duplicate;
00510 MgdSchemaPropertyAttr *prop_attr;
00511 gchar *tmpstr;
00512
00513 for (obj = curn; obj; obj = obj->next){
00514
00515 if (obj->type == XML_ELEMENT_NODE){
00516
00517 nv = xmlGetProp (obj, (const xmlChar *)"name");
00518
00519 if(!strv_contains(mgd_complextype, obj->name)){
00520 g_warning("Wrong node name '%s' in '%s' on line %ld",
00521 obj->name, parsed_schema, xmlGetLineNo(obj));
00522 }
00523
00524 if(g_str_equal(obj->name, "type")) {
00525
00526
00527 if (strv_contains(rtypes, nv)) {
00528 g_critical("'%s' is reserved type name",
00529 nv);
00530
00531 }
00532
00533 if (g_str_equal(obj->name, "type")) {
00534 duplicate = midgard_schema_lookup_type(
00535 schema, (gchar *)nv);
00536
00537 if (duplicate != NULL) {
00538 g_error("%s:%s already added to schema!",
00539 obj->name, nv);
00540 } else {
00541 type_attr = _mgd_schema_type_attr_new();
00542 g_hash_table_insert(schema->types,
00543 g_strdup((gchar *)nv), type_attr);
00544 _get_type_attributes (obj, type_attr);
00545 }
00546 }
00547 }
00548
00549 if (g_str_equal(obj->name, "property")){
00550
00551 dparent = xmlGetProp(obj->parent,
00552 (const xmlChar *)"name");
00553 check_property_name(nv, (const gchar *)dparent);
00554
00555 prop_attr = g_hash_table_lookup(
00556 type_attr->prophash, (gchar *)nv);
00557
00558 if (prop_attr != NULL) {
00559 g_warning("Property '%s' already added to %s",
00560 nv ,dparent);
00561 } else {
00562
00563
00564 prop_attr = _mgd_schema_property_attr_new();
00565 _get_property_attributes(obj, type_attr, prop_attr);
00566 if(prop_attr->is_primary
00567 && prop_attr->gtype != MGD_TYPE_UINT){
00568 tmpstr = (gchar *)xmlGetProp(obj->parent,
00569 (const xmlChar *)"name");
00570 g_message(" %s - type for primaryfield not defined"
00571 " as 'unsigned integer'."
00572 " Forcing uint type"
00573 , tmpstr);
00574 g_free(tmpstr);
00575 }
00576 g_hash_table_insert(type_attr->prophash,
00577 g_strdup((gchar *)nv), prop_attr);
00578 }
00579 xmlFree(dparent);
00580 }
00581 if(g_str_equal(obj->name, "description")){
00582
00583 xmlChar *value = xmlGetProp(obj, (const xmlChar *)"value");
00584 xmlFree(value);
00585 }
00586 xmlFree(nv);
00587 if (obj->children != NULL)
00588 _get_element_names (obj->children, type_attr, schema);
00589 }
00590 }
00591 }
00592
00593
00594
00595
00596 void __get_pdata_foreach(gpointer key, gpointer value, gpointer user_data)
00597 {
00598 MgdSchemaTypeAttr *type_attr = (MgdSchemaTypeAttr *) user_data;
00599 MgdSchemaPropertyAttr *prop_attr = (MgdSchemaPropertyAttr *) value;
00600 const gchar *table, *tables, *primary, *parentname, *ext_table = NULL;
00601 gchar *tmp_sql = NULL , *nick = "";
00602 MgdSchemaTypeQuery *tquery;
00603
00604
00605 guint n = ++type_attr->num_properties;;
00606 const gchar *pname = (gchar *) key;
00607 const gchar *fname = NULL, *upfield = NULL, *parentfield = NULL;
00608 gchar *tmpstr = NULL;
00609 GParamSpec **params = type_attr->params;
00610 GString *tmp_gstring_sql, *table_sql;
00611
00612
00613 if(!prop_attr->type) {
00614 prop_attr->type = g_strdup("string");
00615 prop_attr->gtype = MGD_TYPE_STRING;
00616 }
00617
00618 table = prop_attr->table;
00619 tables = type_attr->query->tables;
00620 parentname = table;
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 upfield = prop_attr->upfield;
00632 parentfield = prop_attr->parentfield;
00633 primary = prop_attr->primaryfield;
00634
00635 ext_table = table;
00636
00637
00638
00639
00640 if (ext_table != NULL){
00641
00642
00643 if ((tquery = g_hash_table_lookup(type_attr->tables, ext_table)) == NULL){
00644 tquery = _mgd_schema_type_query_new();
00645 g_hash_table_insert(type_attr->tables, g_strdup(ext_table), tquery);
00646 }
00647
00648 if(g_strstr_len (tables, strlen(tables), ext_table) == NULL){
00649 tmpstr = g_strconcat(tables, ext_table, ",", NULL);
00650 g_free((gchar *)tables);
00651 type_attr->query->tables = g_strdup(tmpstr);
00652 g_free(tmpstr);
00653 }
00654
00655 table_sql = g_string_new("");
00656 if(tquery->select)
00657 g_string_append(table_sql, tquery->select);
00658
00659 if (prop_attr->is_multilang)
00660 tquery->use_lang = TRUE;
00661
00662 tquery->from = (gchar *)ext_table;
00663 fname = prop_attr->field;
00664
00665 if (fname != NULL) {
00666 tmpstr = g_strjoin(".", ext_table, fname,NULL);
00667 } else {
00668 tmpstr = g_strjoin(".", ext_table, pname,NULL);
00669 }
00670 nick = g_strdup(tmpstr);
00671
00672 tmp_gstring_sql = g_string_new(" ");
00673 if(prop_attr->gtype == MGD_TYPE_TIMESTAMP) {
00674 g_string_append_printf(tmp_gstring_sql,
00675 "NULLIF(%s,'0000-00-00 00:00:00') AS %s",
00676 tmpstr, pname);
00677 } else {
00678 g_string_append_printf(tmp_gstring_sql,
00679 "%s AS %s",
00680 tmpstr, pname);
00681 }
00682 g_free(tmpstr);
00683 tmpstr = g_string_free(tmp_gstring_sql, FALSE);
00684
00685 if(tquery->select)
00686 g_string_append(table_sql, ", ");
00687 g_string_append(table_sql, tmpstr);
00688 g_free(tmpstr);
00689 g_free(tquery->select);
00690 tquery->select = g_string_free(table_sql, FALSE);
00691
00692 g_hash_table_insert(type_attr->tables, (gchar *)ext_table, tquery);
00693
00694 }
00695
00696 table = type_attr->table;
00697
00698 if (ext_table == NULL) {
00699 tmpstr = NULL;
00700 type_attr->query->from = (gchar *)table;
00701 fname = prop_attr->field;
00702 if ( (fname == NULL ) && ((upfield == NULL) && (parentfield == NULL))
00703 && (primary == NULL)){
00704 tmpstr = g_strjoin(".", table, pname,NULL);
00705 } else if((fname != NULL) && ((parentfield == NULL) || (upfield == NULL))) {
00706 tmpstr = g_strjoin(".", table, fname,NULL);
00707 }
00708 if(tmpstr){
00709 table_sql = g_string_new("");
00710 if(type_attr->query->select)
00711 g_string_append(table_sql, type_attr->query->select);
00712 nick = g_strdup(tmpstr);
00713 tmp_gstring_sql = g_string_new(" ");
00714 if(prop_attr->gtype == MGD_TYPE_TIMESTAMP) {
00715 g_string_append_printf(tmp_gstring_sql,
00716 "NULLIF(%s,'0000-00-00 00:00:00') AS %s",
00717 tmpstr, pname);
00718 } else {
00719 g_string_append_printf(tmp_gstring_sql,
00720 "%s AS %s",
00721 tmpstr, pname);
00722 }
00723 g_free(tmpstr);
00724 tmpstr = g_string_free(tmp_gstring_sql, FALSE);
00725
00726 if(type_attr->query->select)
00727 g_string_append(table_sql, ",");
00728 g_string_append(table_sql, tmpstr);
00729 g_free(tmpstr);
00730 g_free(type_attr->query->select);
00731 type_attr->query->select = g_string_free(table_sql, FALSE);
00732 }
00733 }
00734
00735 if(!type_attr->query->primary)
00736 type_attr->query->primary = g_strdup("guid");
00737
00738 if(!type_attr->primary){
00739 type_attr->primary = g_strdup("guid");
00740 }
00741
00742
00743 if(primary != NULL) {
00744 nick = g_strjoin(".", table, primary, NULL);
00745 tmpstr = g_strconcat(nick, " AS ", pname, NULL);
00746 tmp_sql = g_strjoin(",", tmpstr, type_attr->query->select,NULL);
00747 if(type_attr->query->select)
00748 g_free(type_attr->query->select);
00749 type_attr->query->select = g_strdup(tmp_sql);
00750 g_free(tmpstr);
00751 g_free(tmp_sql);
00752 }
00753
00754
00755
00756 if(upfield != NULL) {
00757 nick = g_strjoin(".", table, upfield, NULL);
00758 tmpstr = g_strconcat(nick, " AS ", pname, NULL);
00759 tmp_sql = g_strjoin(",", tmpstr, type_attr->query->select,NULL);
00760 if(type_attr->query->select)
00761 g_free(type_attr->query->select);
00762 type_attr->query->select = g_strdup(tmp_sql);
00763 g_free(tmpstr);
00764 g_free(tmp_sql);
00765 }
00766
00767
00768 if(parentfield != NULL) {
00769 nick = g_strjoin(".", table, parentfield, NULL);
00770 tmpstr = g_strconcat(nick, " AS ", pname, NULL);
00771 tmp_sql = g_strjoin(",", tmpstr, type_attr->query->select,NULL);
00772 if(type_attr->query->select)
00773 g_free(type_attr->query->select);
00774 type_attr->query->select = g_strdup(tmp_sql);
00775 g_free(tmpstr);
00776 g_free(tmp_sql);
00777 }
00778
00779
00780 if((prop_attr->is_primary) && (prop_attr->gtype != G_TYPE_UINT))
00781 prop_attr->gtype = G_TYPE_UINT;
00782
00783
00784 switch (prop_attr->gtype) {
00785
00786 case MGD_TYPE_STRING:
00787 params[n-1] = g_param_spec_string(
00788 pname, nick, "",
00789 "", G_PARAM_READWRITE);
00790 break;
00791
00792 case MGD_TYPE_UINT:
00793 params[n-1] = g_param_spec_uint(
00794 pname, nick, "",
00795 0, G_MAXUINT32, 0, G_PARAM_READWRITE);
00796 break;
00797
00798 case MGD_TYPE_INT:
00799 params[n-1] = g_param_spec_int(
00800 pname, nick, "",
00801 G_MININT32, G_MAXINT32, 0, G_PARAM_READWRITE);
00802 break;
00803
00804 case MGD_TYPE_FLOAT:
00805 params[n-1] = g_param_spec_float(
00806 pname, nick, "",
00807 -G_MAXFLOAT, G_MAXFLOAT, 0, G_PARAM_READWRITE);
00808 break;
00809
00810 case MGD_TYPE_BOOLEAN:
00811 params[n-1] = g_param_spec_boolean(
00812 pname, nick, "",
00813 FALSE, G_PARAM_READWRITE);
00814 break;
00815
00816 default:
00817 params[n-1] = g_param_spec_string(
00818 pname, nick, "",
00819 "", G_PARAM_READWRITE);
00820
00821 }
00822 g_free(nick);
00823 }
00824
00825
00826 void _set_object_full_select(gpointer key, gpointer value, gpointer userdata)
00827 {
00828 GString *fullselect = (GString *) userdata;
00829 MgdSchemaTypeQuery *query = (MgdSchemaTypeQuery *) value;
00830
00831 g_string_append_printf(fullselect,
00832 ",%s", query->select);
00833 }
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843 void __get_tdata_foreach(gpointer key, gpointer value, gpointer user_data)
00844 {
00845 GType new_type;
00846 MgdSchemaTypeAttr *type_attr = (MgdSchemaTypeAttr *) value;
00847 guint np;
00848 gchar *tmpstr;
00849
00850 if(g_type_from_name(key))
00851 return;
00852
00853 np = g_hash_table_size(type_attr->prophash);
00854
00855 type_attr->params = g_malloc(sizeof(GParamSpec*)*(np+1));
00856
00857 if (np > 0) {
00858 g_hash_table_foreach(type_attr->prophash, __get_pdata_foreach, type_attr);
00859
00860
00861
00862
00863 type_attr->params[np] = NULL;
00864
00865
00866
00867 if (type_attr->table != NULL ) {
00868 tmpstr = g_strconcat(type_attr->query->tables, type_attr->table, NULL);
00869 g_free((gchar *)type_attr->query->tables);
00870 type_attr->query->tables = g_strdup(tmpstr);
00871 g_free(tmpstr);
00872 }
00873
00874
00875
00876
00877
00878 type_attr->childs = NULL;
00879
00880 GString *fullselect = g_string_new("");
00881 g_string_append(fullselect , type_attr->query->select );
00882 g_hash_table_foreach(type_attr->tables, _set_object_full_select, fullselect);
00883 type_attr->query->select_full = g_string_free(fullselect, FALSE);
00884
00885
00886
00887
00888 if (type_attr->params != NULL) {
00889
00890 new_type = midgard_type_register(key, type_attr);
00891 if (new_type){
00892 GObject *foo = g_object_new(new_type, NULL);
00893 g_object_unref(foo);
00894 }
00895 }
00896
00897 } else {
00898 g_warning("Type %s has less than 1 property!", (gchar *)key);
00899 }
00900 }
00901
00902
00903
00904 void _copy_schemas(gpointer key, gpointer value, gpointer userdata)
00905 {
00906 gchar *typename = (gchar *)key;
00907 MgdSchemaTypeAttr *type = (MgdSchemaTypeAttr *)value;
00908 MgdSchema *ts = (MgdSchema *) userdata;
00909
00910 if(!g_hash_table_lookup(ts->types, typename)) {
00911
00912 if(type != NULL)
00913 g_hash_table_insert(ts->types, g_strdup(typename), type);
00914 }
00915 }
00916
00917
00918
00919
00920
00921
00922 void __postconfig_schema_foreach(gpointer key, gpointer value, gpointer user_data)
00923 {
00924 MgdSchemaTypeAttr *type_attr = (MgdSchemaTypeAttr *) value, *parenttype;
00925 MidgardSchema *schema = (MidgardSchema *) user_data;
00926 gchar *typename = (gchar *) key;
00927 const gchar *parentname;
00928
00929 parentname = type_attr->parent;
00930
00931 if (parentname != NULL ){
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948 if ((parenttype = midgard_schema_lookup_type(schema, (gchar *)parentname)) != NULL){
00949
00950 if (!g_slist_find(parenttype->childs,
00951 (gpointer)g_type_from_name(typename))) {
00952 parenttype->childs =
00953 g_slist_append(parenttype->childs,
00954 (gpointer)g_type_from_name(typename));
00955 }
00956 }
00957 }
00958 }
00959
00964 static const char *NAMESPACE = "http://www.midgard-project.org/repligard/1.4";
00965
00966
00967 static void read_schema_directory(GHashTable *files, const char *directory);
00968 static void read_schema_file(GHashTable *files, const char *file);
00969
00975 static void read_schema_path(GHashTable *files, const char *path) {
00976 g_assert(files != NULL);
00977 g_assert(path != NULL);
00978 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
00979 read_schema_directory(files, path);
00980 } else if (g_file_test(path, G_FILE_TEST_EXISTS)) {
00981 read_schema_file(files, path);
00982 } else {
00983 g_warning("Schema path %s not found", path);
00984 }
00985 }
00986
00997 static void read_schema_file(GHashTable *files, const char *file) {
00998 g_assert(files != NULL);
00999 g_assert(file != NULL);
01000
01001
01002 if (g_hash_table_lookup(files, file) != NULL) {
01003 g_warning("Skipping already seen schema file %s", file);
01004 return;
01005 }
01006
01007
01008
01009 xmlDocPtr doc = xmlParseFile(file);
01010 if (doc == NULL) {
01011 g_warning("Skipping malformed schema file %s", file);
01012 return;
01013 }
01014 xmlNodePtr root = xmlDocGetRootElement(doc);
01015 if (root == NULL
01016 || root->ns == NULL
01017 || !g_str_equal(root->ns->href, NAMESPACE)
01018 || !g_str_equal(root->name, "Schema")) {
01019 g_warning("Skipping invalid schema file %s", file);
01020 xmlFreeDoc(doc);
01021 return;
01022 }
01023
01024
01025 g_hash_table_insert(files, g_strdup(file), doc);
01026
01027
01028 xmlNodePtr node = root->children;
01029 while (node != NULL) {
01030 xmlChar *attr = xmlGetNoNsProp(node, (xmlChar *) "name");
01031 if (node->type == XML_ELEMENT_NODE
01032 && node->ns != NULL
01033 && g_str_equal(node->ns->href, NAMESPACE)
01034 && g_str_equal(node->name, "include")
01035 && attr != NULL) {
01036 GError *error = NULL;
01037 gchar *name = g_filename_from_utf8(
01038 (const gchar *) attr, -1, NULL, NULL, &error);
01039 if (name == NULL) {
01040 g_warning("g_filename_from_utf8: %s", error->message);
01041 g_error_free(error);
01042 } else if (g_path_is_absolute(name)) {
01043 read_schema_path(files, name);
01044 g_free(name);
01045 } else {
01046 gchar *dir = g_path_get_dirname(file);
01047 gchar *path = g_build_filename(dir, name, NULL);
01048 read_schema_path(files, path);
01049 g_free(path);
01050 g_free(dir);
01051 g_free(name);
01052 }
01053 }
01054 if (attr != NULL) {
01055 xmlFree(attr);
01056 }
01057 node = node->next;
01058 }
01059
01060 }
01061
01069 static void read_schema_directory(GHashTable *files, const char *directory) {
01070 g_assert(files != NULL);
01071 g_assert(directory != NULL);
01072
01073 GError *error = NULL;
01074 GDir *dir = g_dir_open(directory, 0, &error);
01075 if (dir != NULL) {
01076 const gchar *file = g_dir_read_name(dir);
01077 while (file != NULL) {
01078 gchar *path = g_build_filename(directory, file, NULL);
01079 if (g_str_has_prefix(file, ".")) {
01080
01081 } else if (g_str_has_prefix(file, "#")) {
01082
01083 } else if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
01084
01085 read_schema_directory(files, path);
01086 } else if (g_str_has_suffix(file, ".xml")) {
01087
01088 read_schema_file(files, path);
01089 }
01090 g_free(path);
01091 file = g_dir_read_name(dir);
01092 }
01093 g_dir_close(dir);
01094 } else {
01095 g_warning("g_dir_open: %s", error->message);
01096 g_error_free(error);
01097 }
01098 }
01099
01109 static GHashTable *read_schema_files(const char *path) {
01110 g_assert(path != NULL);
01111 GHashTable *files = g_hash_table_new_full(
01112 g_str_hash, g_str_equal, g_free, (GDestroyNotify) xmlFreeDoc);
01113 read_schema_path(files, path);
01114 return files;
01115 }
01116
01117 static void parse_schema(gpointer key, gpointer value, gpointer user_data) {
01118 g_assert(key != NULL);
01119 g_assert(value != NULL);
01120 g_assert(user_data != NULL);
01121 parsed_schema = (const gchar *)key;
01122
01123 MidgardSchema *schema = (MidgardSchema *) user_data;
01124 xmlDocPtr doc = (xmlDocPtr) value;
01125 xmlNodePtr root = xmlDocGetRootElement(doc);
01126 _get_element_names(root, NULL, schema);
01127 }
01128
01129
01130
01131
01132 void midgard_schema_init(MidgardSchema *self){
01133
01134 g_assert(self != NULL);
01135 midgard_schema_read_file(self, MIDGARD_GLOBAL_SCHEMA);
01136 }
01137
01138
01139 gboolean midgard_schema_type_exists(MidgardSchema *self, const gchar *classname)
01140 {
01141 g_assert(self != NULL);
01142 g_assert(classname != NULL);
01143
01144 if(g_hash_table_lookup(self->types, classname))
01145 return TRUE;
01146
01147 return FALSE;
01148 }
01149
01150 void midgard_schema_read_file(
01151 MidgardSchema *schema, const gchar *filename)
01152 {
01153 g_assert(schema != NULL);
01154 g_assert(filename != NULL);
01155
01156 GHashTable *files = read_schema_files(filename);
01157 g_hash_table_foreach(files, parse_schema, schema);
01158 g_hash_table_destroy(files);
01159
01160
01161 g_hash_table_foreach(schema->types, __get_tdata_foreach, schema);
01162
01163
01164 g_hash_table_foreach(schema->types, __postconfig_schema_foreach, schema);
01165 }
01166
01167 gboolean midgard_schema_read_dir(
01168 MidgardSchema *gschema, const gchar *dirname)
01169 {
01170 const gchar *fname = NULL;
01171 gchar *fpfname = NULL ;
01172 GDir *dir;
01173 gint visible = 0;
01174
01175 dir = g_dir_open(dirname, 0, NULL);
01176
01177 if (dir != NULL) {
01178
01179 while ((fname = g_dir_read_name(dir)) != NULL) {
01180
01181 visible = 1;
01182 fpfname = g_strconcat(dirname, "/", fname, NULL);
01183
01184
01185
01186 if (!g_file_test (fpfname, G_FILE_TEST_IS_DIR)
01187 && g_str_has_suffix(fname, ".xml")){
01188
01189
01190 if(g_str_has_prefix(fname, "."))
01191 visible = 0;
01192
01193
01194 if(g_str_has_prefix(fname, "#"))
01195 visible = 0;
01196
01197 if ( visible == 0)
01198 g_warning("File %s ignored!", fpfname);
01199
01200 if(visible == 1){
01201
01202 midgard_schema_read_file(gschema, fpfname);
01203 }
01204 }
01205 g_free(fpfname);
01206
01207
01208
01209 }
01210 g_dir_close(dir);
01211 return TRUE;
01212 }
01213 return FALSE;
01214 }
01215
01216
01217
01218
01219 static void _get_schema_trash(gpointer key, gpointer val, gpointer userdata)
01220 {
01221 MgdSchemaTypeAttr *stype = (MgdSchemaTypeAttr *) val;
01222
01223
01224 if(!g_slist_find(schema_trash, stype)) {
01225
01226 schema_trash = g_slist_append(schema_trash, stype);
01227 }
01228 }
01229
01230
01231
01232
01233 static void
01234 _schema_instance_init(GTypeInstance *instance, gpointer g_class)
01235 {
01236 MidgardSchema *self = (MidgardSchema *) instance;
01237 self->types = g_hash_table_new(g_str_hash, g_str_equal);
01238 }
01239
01240
01241 static void _midgard_schema_finalize(GObject *object)
01242 {
01243 g_assert(object != NULL);
01244 MidgardSchema *self = (MidgardSchema *) object;
01245
01246 g_hash_table_foreach(self->types, _get_schema_trash, NULL);
01247 g_hash_table_destroy(self->types);
01248
01249 for( ; schema_trash ; schema_trash = schema_trash->next){
01250 _mgd_schema_type_attr_free((MgdSchemaTypeAttr *) schema_trash->data);
01251 }
01252 g_slist_free(schema_trash);
01253 }
01254
01255
01256 static void _midgard_schema_class_init(
01257 gpointer g_class, gpointer g_class_data)
01258 {
01259 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
01260 MidgardSchemaClass *klass = MIDGARD_SCHEMA_CLASS (g_class);
01261
01262 gobject_class->set_property = NULL;
01263 gobject_class->get_property = NULL;
01264 gobject_class->finalize = _midgard_schema_finalize;
01265
01266 klass->init = midgard_schema_init;
01267 klass->read_dir = midgard_schema_read_dir;
01268 klass->read_file = midgard_schema_read_file;
01269 klass->type_exists = midgard_schema_type_exists;
01270 }
01271
01272
01273 GType
01274 midgard_schema_get_type (void)