3
* Copyright (C) 2003 Vivien Malerba
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23
#include "mg-ref-base.h"
24
#include "mg-target.h"
25
#include "mg-xml-storage.h"
26
#include "mg-referer.h"
28
#include "mg-condition.h"
32
* Main static functions
34
static void mg_join_class_init (MgJoinClass * class);
35
static void mg_join_init (MgJoin * srv);
36
static void mg_join_dispose (GObject * object);
37
static void mg_join_finalize (GObject * object);
39
static void mg_join_set_property (GObject *object,
43
static void mg_join_get_property (GObject *object,
48
/* XML storage interface */
49
static void mg_join_xml_storage_init (MgXmlStorageIface *iface);
50
static gchar *mg_join_get_xml_id (MgXmlStorage *iface);
51
static xmlNodePtr mg_join_save_to_xml (MgXmlStorage *iface, GError **error);
52
static gboolean mg_join_load_from_xml (MgXmlStorage *iface, xmlNodePtr node, GError **error);
54
/* Referer interface */
55
static void mg_join_referer_init (MgRefererIface *iface);
56
static gboolean mg_join_activate (MgReferer *iface);
57
static void mg_join_deactivate (MgReferer *iface);
58
static gboolean mg_join_is_active (MgReferer *iface);
59
static GSList *mg_join_get_ref_objects (MgReferer *iface);
60
static void mg_join_replace_refs (MgReferer *iface, GHashTable *replacements);
62
/* When the Query or any of the refering MgTarget is nullified */
63
static void nullified_object_cb (GObject *obj, MgJoin *join);
64
static void target_ref_lost_cb (MgRefBase *ref, MgJoin *join);
65
static void target_removed_cb (MgQuery *query, MgTarget *target, MgJoin *join);
69
static void mg_join_dump (MgJoin *join, guint offset);
72
/* get a pointer to the parents to be able to call their destructor */
73
static GObjectClass *parent_class = NULL;
83
static gint mg_join_signals[LAST_SIGNAL] = { 0, 0 };
93
/* private structure */
106
GQuark mg_join_error_quark (void)
110
quark = g_quark_from_static_string ("mg_join_error");
116
mg_join_get_type (void)
118
static GType type = 0;
121
static const GTypeInfo info = {
122
sizeof (MgJoinClass),
123
(GBaseInitFunc) NULL,
124
(GBaseFinalizeFunc) NULL,
125
(GClassInitFunc) mg_join_class_init,
130
(GInstanceInitFunc) mg_join_init
133
static const GInterfaceInfo xml_storage_info = {
134
(GInterfaceInitFunc) mg_join_xml_storage_init,
139
static const GInterfaceInfo referer_info = {
140
(GInterfaceInitFunc) mg_join_referer_init,
145
type = g_type_register_static (MG_BASE_TYPE, "MgJoin", &info, 0);
146
g_type_add_interface_static (type, MG_XML_STORAGE_TYPE, &xml_storage_info);
147
g_type_add_interface_static (type, MG_REFERER_TYPE, &referer_info);
153
mg_join_xml_storage_init (MgXmlStorageIface *iface)
155
iface->get_xml_id = mg_join_get_xml_id;
156
iface->save_to_xml = mg_join_save_to_xml;
157
iface->load_from_xml = mg_join_load_from_xml;
161
mg_join_referer_init (MgRefererIface *iface)
163
iface->activate = mg_join_activate;
164
iface->deactivate = mg_join_deactivate;
165
iface->is_active = mg_join_is_active;
166
iface->get_ref_objects = mg_join_get_ref_objects;
167
iface->replace_refs = mg_join_replace_refs;
172
mg_join_class_init (MgJoinClass * class)
174
GObjectClass *object_class = G_OBJECT_CLASS (class);
176
parent_class = g_type_class_peek_parent (class);
178
mg_join_signals[TYPE_CHANGED] =
179
g_signal_new ("type_changed",
180
G_TYPE_FROM_CLASS (object_class),
182
G_STRUCT_OFFSET (MgJoinClass, type_changed),
184
marshal_VOID__VOID, G_TYPE_NONE,
186
mg_join_signals[CONDITION_CHANGED] =
187
g_signal_new ("condition_changed",
188
G_TYPE_FROM_CLASS (object_class),
190
G_STRUCT_OFFSET (MgJoinClass, condition_changed),
192
marshal_VOID__VOID, G_TYPE_NONE,
194
class->type_changed = NULL;
195
class->condition_changed = NULL;
197
object_class->dispose = mg_join_dispose;
198
object_class->finalize = mg_join_finalize;
201
object_class->set_property = mg_join_set_property;
202
object_class->get_property = mg_join_get_property;
203
g_object_class_install_property (object_class, PROP,
204
g_param_spec_pointer ("prop", NULL, NULL,
205
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
206
/* virtual functions */
208
MG_BASE_CLASS (class)->dump = (void (*)(MgBase *, guint)) mg_join_dump;
214
mg_join_init (MgJoin * mg_join)
216
mg_join->priv = g_new0 (MgJoinPrivate, 1);
217
mg_join->priv->join_type = MG_JOIN_TYPE_INNER;
218
mg_join->priv->query = NULL;
219
mg_join->priv->target1 = NULL;
220
mg_join->priv->target2 = NULL;
221
mg_join->priv->cond = NULL;
225
* mg_join_new_with_targets
226
* @query: a #MgQuery object in which the join will occur
227
* @target_1: the 1st #MgTarget object participating in the join
228
* @target_2: the 2nd #MgTarget object participating in the join
230
* Creates a new MgJoin object. Note: the #MgTarget ranks (1st and 2nd) does not matter, but
231
* is necessary since the join may not be symetrical (LEFT or RIGHT join). Also, the #MgJoin object
232
* may decide to swap the two if necessary.
234
* Returns: the new object
237
mg_join_new_with_targets (MgQuery *query, MgTarget *target_1, MgTarget *target_2)
243
g_return_val_if_fail (query && IS_MG_QUERY (query), NULL);
244
g_return_val_if_fail (target_1 && IS_MG_TARGET (target_1), NULL);
245
g_return_val_if_fail (target_2 && IS_MG_TARGET (target_2), NULL);
246
g_return_val_if_fail (mg_target_get_query (target_1) == query, NULL);
247
g_return_val_if_fail (mg_target_get_query (target_2) == query, NULL);
248
g_return_val_if_fail (target_1 != target_2, NULL);
250
conf = mg_base_get_conf (MG_BASE (query));
251
obj = g_object_new (MG_JOIN_TYPE, "conf", conf, NULL);
252
mg_join = MG_JOIN (obj);
253
mg_base_set_id (MG_BASE (mg_join), 0);
255
mg_join->priv->query = query;
256
mg_join->priv->target1 = MG_REF_BASE (mg_ref_base_new (conf));
257
mg_ref_base_set_ref_object (mg_join->priv->target1, MG_BASE (target_1));
259
mg_join->priv->target2 = MG_REF_BASE (mg_ref_base_new (conf));
260
mg_ref_base_set_ref_object (mg_join->priv->target2, MG_BASE (target_2));
262
g_signal_connect (G_OBJECT (query), "nullified",
263
G_CALLBACK (nullified_object_cb), mg_join);
265
g_signal_connect (G_OBJECT (query), "target_removed",
266
G_CALLBACK (target_removed_cb), mg_join);
268
/* if the references to the any target is lost then we want to nullify the join */
269
g_signal_connect (G_OBJECT (mg_join->priv->target1), "ref_lost",
270
G_CALLBACK (target_ref_lost_cb), mg_join);
271
g_signal_connect (G_OBJECT (mg_join->priv->target2), "ref_lost",
272
G_CALLBACK (target_ref_lost_cb), mg_join);
278
* mg_join_new_with_xml_ids
279
* @query: a #MgQuery object in which the join will occur
280
* @target_1_xml_id: the 1st #MgTarget object's XML id participating in the join
281
* @target_2_xml_id: the 2nd #MgTarget object's XML id participating in the join
283
* Creates a new MgJoin object. Note: the #MgTarget ranks (1st and 2nd) does not matter, but
284
* is necessary since the join may not be symetrical (LEFT or RIGHT join). Also, the #MgJoin object
285
* may decide to swap the two if necessary.
287
* Returns: the new object
290
mg_join_new_with_xml_ids (MgQuery *query, const gchar *target_1_xml_id, const gchar *target_2_xml_id)
295
gchar *qid, *ptr, *tok;
298
g_return_val_if_fail (query && IS_MG_QUERY (query), NULL);
299
g_return_val_if_fail (target_1_xml_id && *target_1_xml_id, NULL);
300
g_return_val_if_fail (target_2_xml_id && *target_2_xml_id, NULL);
301
g_return_val_if_fail (strcmp (target_1_xml_id, target_2_xml_id), NULL);
303
/* check that the XML Ids start with the query's XML Id */
304
qid = mg_xml_storage_get_xml_id (MG_XML_STORAGE (query));
305
tid = g_strdup (target_1_xml_id);
306
ptr = strtok_r (tid, ":", &tok);
307
g_return_val_if_fail (!strcmp (ptr, qid), NULL);
309
tid = g_strdup (target_2_xml_id);
310
ptr = strtok_r (tid, ":", &tok);
311
g_return_val_if_fail (!strcmp (ptr, qid), NULL);
316
conf = mg_base_get_conf (MG_BASE (query));
317
obj = g_object_new (MG_JOIN_TYPE, "conf", conf, NULL);
318
mg_join = MG_JOIN (obj);
319
mg_base_set_id (MG_BASE (mg_join), 0);
321
mg_join->priv->query = query;
322
mg_join->priv->target1 = MG_REF_BASE (mg_ref_base_new (conf));
323
mg_ref_base_set_ref_name (mg_join->priv->target1, MG_TARGET_TYPE, REFERENCE_BY_XML_ID, target_1_xml_id);
325
mg_join->priv->target2 = MG_REF_BASE (mg_ref_base_new (conf));
326
mg_ref_base_set_ref_name (mg_join->priv->target2, MG_TARGET_TYPE, REFERENCE_BY_XML_ID, target_2_xml_id);
328
g_signal_connect (G_OBJECT (query), "nullified",
329
G_CALLBACK (nullified_object_cb), mg_join);
331
g_signal_connect (G_OBJECT (query), "target_removed",
332
G_CALLBACK (target_removed_cb), mg_join);
334
/* if the references to the any target is lost then we want to nullify the join */
335
g_signal_connect (G_OBJECT (mg_join->priv->target1), "ref_lost",
336
G_CALLBACK (target_ref_lost_cb), mg_join);
337
g_signal_connect (G_OBJECT (mg_join->priv->target2), "ref_lost",
338
G_CALLBACK (target_ref_lost_cb), mg_join);
345
* @orig: a #MgJoin to make a copy of
346
* @replacements: a hash table to store replacements, or %NULL
350
* Returns: a the new copy of @orig
353
mg_join_new_copy (MgJoin *orig, GHashTable *replacements)
359
g_return_val_if_fail (orig && IS_MG_JOIN (orig), NULL);
361
conf = mg_base_get_conf (MG_BASE (orig));
362
obj = g_object_new (MG_JOIN_TYPE, "conf", conf, NULL);
363
mg_join = MG_JOIN (obj);
364
mg_base_set_id (MG_BASE (mg_join), 0);
366
g_hash_table_insert (replacements, orig, mg_join);
368
mg_join->priv->query = orig->priv->query;
369
g_signal_connect (G_OBJECT (orig->priv->query), "nullified",
370
G_CALLBACK (nullified_object_cb), mg_join);
372
g_signal_connect (G_OBJECT (orig->priv->query), "target_removed",
373
G_CALLBACK (target_removed_cb), mg_join);
375
mg_join->priv->target1 = MG_REF_BASE (mg_ref_base_new_copy (orig->priv->target1));
376
mg_join->priv->target2 = MG_REF_BASE (mg_ref_base_new_copy (orig->priv->target2));
377
mg_join->priv->join_type = orig->priv->join_type;
379
/* if the references to the any target is lost then we want to nullify the join */
380
g_signal_connect (G_OBJECT (mg_join->priv->target1), "ref_lost",
381
G_CALLBACK (target_ref_lost_cb), mg_join);
382
g_signal_connect (G_OBJECT (mg_join->priv->target2), "ref_lost",
383
G_CALLBACK (target_ref_lost_cb), mg_join);
386
if (orig->priv->cond) {
387
MgCondition *cond = mg_condition_new_copy (orig->priv->cond, replacements);
388
mg_join_set_condition (mg_join, cond);
389
g_object_unref (G_OBJECT (cond));
391
g_hash_table_insert (replacements, orig->priv->cond, cond);
398
nullified_object_cb (GObject *obj, MgJoin *join)
400
mg_base_nullify (MG_BASE (join));
404
target_ref_lost_cb (MgRefBase *ref, MgJoin *join)
406
mg_base_nullify (MG_BASE (join));
410
target_removed_cb (MgQuery *query, MgTarget *target, MgJoin *join)
413
gboolean to_nullify = FALSE;
415
t = mg_ref_base_get_ref_object (join->priv->target1);
416
if (t == (MgBase *) target)
419
t = mg_ref_base_get_ref_object (join->priv->target2);
420
if (t == (MgBase *) target)
425
mg_base_nullify (MG_BASE (join));
429
nullified_cond_cb (MgCondition *cond, MgJoin *join)
431
g_assert (cond == join->priv->cond);
432
g_signal_handlers_disconnect_by_func (G_OBJECT (join->priv->cond),
433
G_CALLBACK (nullified_cond_cb), join);
434
g_object_set (G_OBJECT (cond), "join", NULL, NULL);
435
g_object_unref (join->priv->cond);
436
join->priv->cond = NULL;
440
mg_join_dispose (GObject *object)
444
g_return_if_fail (object != NULL);
445
g_return_if_fail (IS_MG_JOIN (object));
447
mg_join = MG_JOIN (object);
449
mg_base_nullify_check (MG_BASE (object));
451
if (mg_join->priv->query) {
452
g_signal_handlers_disconnect_by_func (G_OBJECT (mg_join->priv->query),
453
G_CALLBACK (nullified_object_cb), mg_join);
454
g_signal_handlers_disconnect_by_func (G_OBJECT (mg_join->priv->query),
455
G_CALLBACK (target_removed_cb), mg_join);
456
mg_join->priv->query = NULL;
458
if (mg_join->priv->target1) {
459
g_signal_handlers_disconnect_by_func (G_OBJECT (mg_join->priv->target1),
460
G_CALLBACK (target_ref_lost_cb), mg_join);
461
g_object_unref (G_OBJECT (mg_join->priv->target1));
462
mg_join->priv->target1 = NULL;
464
if (mg_join->priv->target2) {
465
g_signal_handlers_disconnect_by_func (G_OBJECT (mg_join->priv->target2),
466
G_CALLBACK (target_ref_lost_cb), mg_join);
467
g_object_unref (G_OBJECT (mg_join->priv->target2));
468
mg_join->priv->target2 = NULL;
470
if (mg_join->priv->cond)
471
nullified_cond_cb (mg_join->priv->cond, mg_join);
475
parent_class->dispose (object);
479
mg_join_finalize (GObject * object)
483
g_return_if_fail (object != NULL);
484
g_return_if_fail (IS_MG_JOIN (object));
486
mg_join = MG_JOIN (object);
488
g_free (mg_join->priv);
489
mg_join->priv = NULL;
493
parent_class->finalize (object);
498
mg_join_set_property (GObject *object,
506
mg_join = MG_JOIN (object);
510
ptr = g_value_get_pointer (value);
517
mg_join_get_property (GObject *object,
523
mg_join = MG_JOIN (object);
534
* mg_join_set_join_type
535
* @join: a #MgJoin object
536
* @type: the new type of join
538
* Sets the type of @join
541
mg_join_set_join_type (MgJoin *join, MgJoinType type)
543
g_return_if_fail (join && IS_MG_JOIN (join));
544
g_return_if_fail (join->priv);
546
if (join->priv->join_type != type) {
547
join->priv->join_type = type;
548
mg_base_changed (MG_BASE (join));
553
* mg_join_get_join_type
554
* @join: a #MgJoin object
556
* Get the type of a join
558
* Returns: the type of @join
561
mg_join_get_join_type (MgJoin *join)
563
g_return_val_if_fail (join && IS_MG_JOIN (join), MG_JOIN_TYPE_CROSS);
564
g_return_val_if_fail (join->priv, MG_JOIN_TYPE_CROSS);
566
return join->priv->join_type;
572
* @join: a #MgJoin object
574
* Get the #MgQuery to which @join is attached to
576
* Returns: the #MgQuery
579
mg_join_get_query (MgJoin *join)
581
g_return_val_if_fail (join && IS_MG_JOIN (join), NULL);
582
g_return_val_if_fail (join->priv, NULL);
584
return join->priv->query;
588
* mg_join_get_target_1
589
* @join: a #MgJoin object
591
* Get the 1st #MgTarget participating in the join
593
* Returns: the #MgTarget
596
mg_join_get_target_1 (MgJoin *join)
600
g_return_val_if_fail (join && IS_MG_JOIN (join), NULL);
601
g_return_val_if_fail (join->priv, NULL);
603
base = mg_ref_base_get_ref_object (join->priv->target1);
605
return MG_TARGET (base);
611
* mg_join_get_target_2
612
* @join: a #MgJoin object
614
* Get the 2nd #MgTarget participating in the join
616
* Returns: the #MgTarget
619
mg_join_get_target_2 (MgJoin *join)
623
g_return_val_if_fail (join && IS_MG_JOIN (join), NULL);
624
g_return_val_if_fail (join->priv, NULL);
626
base = mg_ref_base_get_ref_object (join->priv->target2);
628
return MG_TARGET (base);
635
* mg_join_swap_targets
636
* @join: a #MgJoin object
638
* Changes the relative roles of the two #MgTarget objects. It does not
639
* change the join condition itself, and is usefull only for the internals
640
* of the #MgQuery object
643
mg_join_swap_targets (MgJoin *join)
646
g_return_if_fail (join && IS_MG_JOIN (join));
647
g_return_if_fail (join->priv);
649
ref = join->priv->target1;
650
join->priv->target1 = join->priv->target2;
651
join->priv->target2 = ref;
653
switch (join->priv->join_type) {
654
case MG_JOIN_TYPE_LEFT_OUTER:
655
join->priv->join_type = MG_JOIN_TYPE_RIGHT_OUTER;
657
case MG_JOIN_TYPE_RIGHT_OUTER:
658
join->priv->join_type = MG_JOIN_TYPE_LEFT_OUTER;
666
* mg_join_set_condition
667
* @join: a #MgJoin object
668
* @cond: a #MgCondition object, or %NULL to remove the join's condition
670
* Sets @cond to be @join's condition. This is possible only if @cond uses
671
* query fields which are either of type MgQfField and reference one of the two
672
* targets which @join uses, or any other query field type.
674
* Returns: TRUE if no error occurred
677
mg_join_set_condition (MgJoin *join, MgCondition *cond)
680
g_return_val_if_fail (join && IS_MG_JOIN (join), FALSE);
681
g_return_val_if_fail (join->priv, FALSE);
683
/* test if the condition is OK */
684
if (! mg_condition_represents_join (cond, &t1, &t2, NULL))
687
if (! (((mg_ref_base_get_ref_object (join->priv->target1) == (MgBase*) t1) &&
688
(mg_ref_base_get_ref_object (join->priv->target2) == (MgBase*) t2)) ||
689
((mg_ref_base_get_ref_object (join->priv->target1) == (MgBase*) t2) &&
690
(mg_ref_base_get_ref_object (join->priv->target2) == (MgBase*) t1))))
694
if (join->priv->cond && (join->priv->cond != cond))
695
nullified_cond_cb (join->priv->cond, join);
698
g_object_ref (G_OBJECT (cond));
699
g_signal_connect (G_OBJECT (cond), "nullified",
700
G_CALLBACK (nullified_cond_cb), join);
701
join->priv->cond = cond;
702
g_object_set (G_OBJECT (cond), "join", join, NULL);
709
* mg_join_get_condition
710
* @join: a #MgJoin object
712
* Get the join's associated condition
714
* Returns: the #MgCondition object
717
mg_join_get_condition (MgJoin *join)
719
g_return_val_if_fail (join && IS_MG_JOIN (join), NULL);
720
g_return_val_if_fail (join->priv, NULL);
722
return join->priv->cond;
727
* mg_join_render_type
728
* @join: a #MgJoin object
730
* Get the SQL version of the join type ("INNER JOIN", "LEFT JOIN", etc)
732
* Returns: the type as a const string
735
mg_join_render_type (MgJoin *join)
737
g_return_val_if_fail (join && IS_MG_JOIN (join), NULL);
738
g_return_val_if_fail (join->priv, NULL);
740
switch (join->priv->join_type) {
741
case MG_JOIN_TYPE_INNER:
743
case MG_JOIN_TYPE_LEFT_OUTER:
745
case MG_JOIN_TYPE_RIGHT_OUTER:
747
case MG_JOIN_TYPE_FULL_OUTER:
749
case MG_JOIN_TYPE_CROSS:
752
g_assert_not_reached ();
759
mg_join_dump (MgJoin *join, guint offset)
764
g_return_if_fail (join && IS_MG_JOIN (join));
766
/* string for the offset */
767
str = g_new0 (gchar, offset+1);
768
for (i=0; i<offset; i++)
774
g_print ("%s" D_COL_H1 "MgJoin" D_COL_NOR " %p ", str, join);
775
if (mg_join_is_active (MG_REFERER (join)))
776
g_print ("Active, Targets: %p -> %p ", mg_ref_base_get_ref_object (join->priv->target1),
777
mg_ref_base_get_ref_object (join->priv->target2));
779
g_print (D_COL_ERR "Non active" D_COL_NOR ", ");
780
g_print ("requested targets: %s & %s", mg_ref_base_get_ref_name (join->priv->target1, NULL, NULL),
781
mg_ref_base_get_ref_name (join->priv->target2, NULL, NULL));
782
if (join->priv->cond) {
783
g_print (", Condition:\n");
784
mg_base_dump (MG_BASE (join->priv->cond), offset+5);
790
g_print ("%s" D_COL_ERR "Using finalized object %p" D_COL_NOR, str, join);
797
* MgReferer interface implementation
800
mg_join_activate (MgReferer *iface)
803
g_return_val_if_fail (iface && IS_MG_JOIN (iface), FALSE);
804
g_return_val_if_fail (MG_JOIN (iface)->priv, FALSE);
806
retval = mg_ref_base_activate (MG_JOIN (iface)->priv->target1);
807
retval = mg_ref_base_activate (MG_JOIN (iface)->priv->target2) && retval;
813
mg_join_deactivate (MgReferer *iface)
815
g_return_if_fail (iface && IS_MG_JOIN (iface));
816
g_return_if_fail (MG_JOIN (iface)->priv);
818
mg_ref_base_deactivate (MG_JOIN (iface)->priv->target1);
819
mg_ref_base_deactivate (MG_JOIN (iface)->priv->target2);
823
mg_join_is_active (MgReferer *iface)
827
g_return_val_if_fail (iface && IS_MG_JOIN (iface), FALSE);
828
g_return_val_if_fail (MG_JOIN (iface)->priv, FALSE);
830
retval = mg_ref_base_is_active (MG_JOIN (iface)->priv->target1);
831
retval = retval && mg_ref_base_is_active (MG_JOIN (iface)->priv->target2);
837
mg_join_get_ref_objects (MgReferer *iface)
841
g_return_val_if_fail (iface && IS_MG_JOIN (iface), NULL);
842
g_return_val_if_fail (MG_JOIN (iface)->priv, NULL);
844
base = mg_ref_base_get_ref_object (MG_JOIN (iface)->priv->target1);
846
list = g_slist_append (list, base);
847
base = mg_ref_base_get_ref_object (MG_JOIN (iface)->priv->target2);
849
list = g_slist_append (list, base);
855
mg_join_replace_refs (MgReferer *iface, GHashTable *replacements)
858
g_return_if_fail (iface && IS_MG_JOIN (iface));
859
g_return_if_fail (MG_JOIN (iface)->priv);
861
join = MG_JOIN (iface);
862
if (join->priv->query) {
863
MgQuery *query = g_hash_table_lookup (replacements, join->priv->query);
865
g_signal_handlers_disconnect_by_func (G_OBJECT (join->priv->query),
866
G_CALLBACK (nullified_object_cb), join);
867
join->priv->query = query;
868
g_signal_connect (G_OBJECT (query), "nullified",
869
G_CALLBACK (nullified_object_cb), join);
873
mg_ref_base_replace_ref_object (join->priv->target1, replacements);
874
mg_ref_base_replace_ref_object (join->priv->target2, replacements);
875
if (join->priv->cond)
876
mg_referer_replace_refs (MG_REFERER (join->priv->cond), replacements);
880
* MgXmlStorage interface implementation
883
static const gchar *convert_join_type_to_str (MgJoinType type);
884
static MgJoinType convert_str_to_join_type (const gchar *str);
887
mg_join_get_xml_id (MgXmlStorage *iface)
889
g_return_val_if_fail (iface && IS_MG_JOIN (iface), NULL);
890
g_return_val_if_fail (MG_JOIN (iface)->priv, NULL);
896
mg_join_save_to_xml (MgXmlStorage *iface, GError **error)
898
xmlNodePtr node = NULL;
903
g_return_val_if_fail (iface && IS_MG_JOIN (iface), NULL);
904
g_return_val_if_fail (MG_JOIN (iface)->priv, NULL);
906
join = MG_JOIN (iface);
908
node = xmlNewNode (NULL, "MG_JOIN");
911
if (join->priv->target1) {
913
if (mg_ref_base_is_active (join->priv->target1)) {
914
MgBase *base = mg_ref_base_get_ref_object (join->priv->target1);
916
str = mg_xml_storage_get_xml_id (MG_XML_STORAGE (base));
919
str = g_strdup (mg_ref_base_get_ref_name (join->priv->target1, NULL, NULL));
922
xmlSetProp (node, "target1", str);
927
if (join->priv->target2) {
929
if (mg_ref_base_is_active (join->priv->target2)) {
930
MgBase *base = mg_ref_base_get_ref_object (join->priv->target2);
932
str = mg_xml_storage_get_xml_id (MG_XML_STORAGE (base));
935
str = g_strdup (mg_ref_base_get_ref_name (join->priv->target2, NULL, NULL));
938
xmlSetProp (node, "target2", str);
944
type = convert_join_type_to_str (join->priv->join_type);
945
xmlSetProp (node, "join_type", type);
948
if (join->priv->cond) {
949
xmlNodePtr sub = mg_xml_storage_save_to_xml (MG_XML_STORAGE (join->priv->cond), error);
951
xmlAddChild (node, sub);
963
mg_join_load_from_xml (MgXmlStorage *iface, xmlNodePtr node, GError **error)
967
gboolean t1 = FALSE, t2 = FALSE;
970
g_return_val_if_fail (iface && IS_MG_JOIN (iface), FALSE);
971
g_return_val_if_fail (MG_JOIN (iface)->priv, FALSE);
972
g_return_val_if_fail (node, FALSE);
974
join = MG_JOIN (iface);
975
if (strcmp (node->name, "MG_JOIN")) {
978
MG_JOIN_XML_LOAD_ERROR,
979
_("XML Tag is not <MG_JOIN>"));
983
prop = xmlGetProp (node, "target1");
985
if (join->priv->target1) {
986
mg_ref_base_set_ref_name (join->priv->target1, MG_TARGET_TYPE,
987
REFERENCE_BY_XML_ID, prop);
992
prop = xmlGetProp (node, "target2");
994
if (join->priv->target2) {
995
mg_ref_base_set_ref_name (join->priv->target2, MG_TARGET_TYPE,
996
REFERENCE_BY_XML_ID, prop);
1001
prop = xmlGetProp (node, "join_type");
1003
join->priv->join_type = convert_str_to_join_type (prop);
1007
/* children nodes */
1008
children = node->children;
1010
if (!strcmp (children->name, "MG_COND")) {
1013
cond = MG_CONDITION (mg_condition_new (join->priv->query, MG_CONDITION_NODE_AND));
1014
if (mg_xml_storage_load_from_xml (MG_XML_STORAGE (cond), children, error)) {
1015
mg_join_set_condition (join, cond);
1016
g_object_unref (G_OBJECT (cond));
1022
children = children->next;
1029
MG_JOIN_XML_LOAD_ERROR,
1030
_("Problem loading <MG_JOIN>"));
1035
static const gchar *
1036
convert_join_type_to_str (MgJoinType type)
1040
case MG_JOIN_TYPE_INNER:
1042
case MG_JOIN_TYPE_LEFT_OUTER:
1044
case MG_JOIN_TYPE_RIGHT_OUTER:
1046
case MG_JOIN_TYPE_FULL_OUTER:
1048
case MG_JOIN_TYPE_CROSS:
1054
convert_str_to_join_type (const gchar *str)
1059
return MG_JOIN_TYPE_INNER;
1061
return MG_JOIN_TYPE_LEFT_OUTER;
1063
return MG_JOIN_TYPE_RIGHT_OUTER;
1065
return MG_JOIN_TYPE_FULL_OUTER;
1067
return MG_JOIN_TYPE_CROSS;