00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026 #include <glib.h>
00027 #include "qof.h"
00028
00029 static QofLogModule log_module = QOF_MOD_MERGE;
00030
00031
00032 struct QofBookMergeRuleIterate
00033 {
00034 QofBookMergeRuleForeachCB fcn;
00035 QofBookMergeData *data;
00036 QofBookMergeRule *rule;
00037 GList *ruleList;
00038 guint remainder;
00039 };
00040
00041
00042
00043
00044
00045
00046
00047 #define DEFAULT_MERGE_WEIGHT 1
00048 #define QOF_STRING_WEIGHT 3
00049 #define QOF_DATE_STRING_LENGTH MAX_DATE_LENGTH
00050
00051 static QofBookMergeRule *
00052 qof_book_merge_update_rule (QofBookMergeRule * currentRule, gboolean match,
00053 gint weight)
00054 {
00055 gboolean absolute;
00056
00057 absolute = currentRule->mergeAbsolute;
00058 if (absolute && match && currentRule->mergeResult == MERGE_UNDEF)
00059 currentRule->mergeResult = MERGE_ABSOLUTE;
00060 if (absolute && !match)
00061 currentRule->mergeResult = MERGE_UPDATE;
00062 if (!absolute && match && currentRule->mergeResult == MERGE_UNDEF)
00063 currentRule->mergeResult = MERGE_DUPLICATE;
00064 if (!absolute && !match)
00065 {
00066 currentRule->difference += weight;
00067 if (currentRule->mergeResult == MERGE_DUPLICATE)
00068 currentRule->mergeResult = MERGE_REPORT;
00069 }
00070 return currentRule;
00071 }
00072
00073 struct collect_list_s
00074 {
00075 GSList *linkedEntList;
00076 };
00077
00078 static void
00079 collect_reference_cb (QofEntity * ent, gpointer user_data)
00080 {
00081 struct collect_list_s *s;
00082
00083 s = (struct collect_list_s *) user_data;
00084 if (!ent || !s)
00085 return;
00086 s->linkedEntList = g_slist_prepend (s->linkedEntList, ent);
00087 }
00088
00089 static gint
00090 qof_book_merge_compare (QofBookMergeData * mergeData)
00091 {
00092 QofBookMergeRule *currentRule;
00093 QofCollection *mergeColl, *targetColl;
00094 gchar *stringImport, *stringTarget;
00095 QofEntity *mergeEnt, *targetEnt, *referenceEnt;
00096 const GUID *guidImport, *guidTarget;
00097 QofParam *qtparam;
00098 KvpFrame *kvpImport, *kvpTarget;
00099 QofIdType mergeParamName;
00100 QofType mergeType;
00101 GSList *paramList;
00102 gboolean absolute, mergeError, knowntype, mergeMatch, booleanImport,
00103 booleanTarget, (*boolean_getter) (QofEntity *, QofParam *);
00104 QofNumeric numericImport, numericTarget,
00105 (*numeric_getter) (QofEntity *, QofParam *);
00106 gdouble doubleImport, doubleTarget, (*double_getter) (QofEntity *,
00107 QofParam *);
00108 gint32 i32Import, i32Target, (*int32_getter) (QofEntity *, QofParam *);
00109 gint64 i64Import, i64Target, (*int64_getter) (QofEntity *, QofParam *);
00110 gchar charImport, charTarget, (*char_getter) (QofEntity *, QofParam *);
00111
00112 g_return_val_if_fail ((mergeData != NULL), -1);
00113 currentRule = mergeData->currentRule;
00114 g_return_val_if_fail ((currentRule != NULL), -1);
00115 absolute = currentRule->mergeAbsolute;
00116 mergeEnt = currentRule->importEnt;
00117 targetEnt = currentRule->targetEnt;
00118 paramList = currentRule->mergeParam;
00119 currentRule->difference = 0;
00120 currentRule->mergeResult = MERGE_UNDEF;
00121 currentRule->linkedEntList = NULL;
00122 g_return_val_if_fail ((targetEnt) || (mergeEnt) || (paramList), -1);
00123 kvpImport = kvp_frame_new ();
00124 kvpTarget = kvp_frame_new ();
00125 mergeError = FALSE;
00126 while (paramList != NULL)
00127 {
00128 mergeMatch = FALSE;
00129 knowntype = FALSE;
00130 qtparam = paramList->data;
00131 mergeParamName = qtparam->param_name;
00132 g_return_val_if_fail (mergeParamName != NULL, -1);
00133 mergeType = qtparam->param_type;
00134 if (safe_strcmp (mergeType, QOF_TYPE_STRING) == 0)
00135 {
00136 stringImport = qtparam->param_getfcn (mergeEnt, qtparam);
00137 stringTarget = qtparam->param_getfcn (targetEnt, qtparam);
00138
00139 if (stringImport == NULL)
00140 stringImport = "";
00141 if (stringTarget == NULL)
00142 stringTarget = "";
00143 if (safe_strcmp (stringImport, stringTarget) == 0)
00144 mergeMatch = TRUE;
00145
00146 currentRule = qof_book_merge_update_rule (currentRule,
00147 mergeMatch, QOF_STRING_WEIGHT);
00148 stringImport = stringTarget = NULL;
00149 knowntype = TRUE;
00150 }
00151 if (safe_strcmp (mergeType, QOF_TYPE_TIME) == 0)
00152 {
00153 QofTime *qtImport, *qtTarget;
00154
00155 qtImport = qtparam->param_getfcn (mergeEnt, qtparam);
00156 qtTarget = qtparam->param_getfcn (targetEnt, qtparam);
00157 if (qof_time_cmp (qtImport, qtTarget) == 0)
00158 currentRule = qof_book_merge_update_rule (currentRule,
00159 mergeMatch, DEFAULT_MERGE_WEIGHT);
00160 knowntype = TRUE;
00161 }
00162 if ((safe_strcmp (mergeType, QOF_TYPE_NUMERIC) == 0) ||
00163 (safe_strcmp (mergeType, QOF_TYPE_DEBCRED) == 0))
00164 {
00165 numeric_getter =
00166 (QofNumeric (*)(QofEntity *, QofParam *)) qtparam->
00167 param_getfcn;
00168 numericImport = numeric_getter (mergeEnt, qtparam);
00169 numericTarget = numeric_getter (targetEnt, qtparam);
00170 if (qof_numeric_compare (numericImport, numericTarget) == 0)
00171 mergeMatch = TRUE;
00172 currentRule = qof_book_merge_update_rule (currentRule,
00173 mergeMatch, DEFAULT_MERGE_WEIGHT);
00174 knowntype = TRUE;
00175 }
00176 if (safe_strcmp (mergeType, QOF_TYPE_GUID) == 0)
00177 {
00178 guidImport = qtparam->param_getfcn (mergeEnt, qtparam);
00179 guidTarget = qtparam->param_getfcn (targetEnt, qtparam);
00180 if (guid_compare (guidImport, guidTarget) == 0)
00181 mergeMatch = TRUE;
00182 currentRule = qof_book_merge_update_rule (currentRule,
00183 mergeMatch, DEFAULT_MERGE_WEIGHT);
00184 knowntype = TRUE;
00185 }
00186 if (safe_strcmp (mergeType, QOF_TYPE_INT32) == 0)
00187 {
00188 int32_getter =
00189 (gint32 (*)(QofEntity *,
00190 QofParam *)) qtparam->param_getfcn;
00191 i32Import = int32_getter (mergeEnt, qtparam);
00192 i32Target = int32_getter (targetEnt, qtparam);
00193 if (i32Target == i32Import)
00194 mergeMatch = TRUE;
00195 currentRule = qof_book_merge_update_rule (currentRule,
00196 mergeMatch, DEFAULT_MERGE_WEIGHT);
00197 knowntype = TRUE;
00198 }
00199 if (safe_strcmp (mergeType, QOF_TYPE_INT64) == 0)
00200 {
00201 int64_getter =
00202 (gint64 (*)(QofEntity *,
00203 QofParam *)) qtparam->param_getfcn;
00204 i64Import = int64_getter (mergeEnt, qtparam);
00205 i64Target = int64_getter (targetEnt, qtparam);
00206 if (i64Target == i64Import)
00207 mergeMatch = TRUE;
00208 currentRule = qof_book_merge_update_rule (currentRule,
00209 mergeMatch, DEFAULT_MERGE_WEIGHT);
00210 knowntype = TRUE;
00211 }
00212 if (safe_strcmp (mergeType, QOF_TYPE_DOUBLE) == 0)
00213 {
00214 double_getter =
00215 (double (*)(QofEntity *,
00216 QofParam *)) qtparam->param_getfcn;
00217 doubleImport = double_getter (mergeEnt, qtparam);
00218 doubleTarget = double_getter (mergeEnt, qtparam);
00219 if (doubleImport == doubleTarget)
00220 mergeMatch = TRUE;
00221 currentRule = qof_book_merge_update_rule (currentRule,
00222 mergeMatch, DEFAULT_MERGE_WEIGHT);
00223 knowntype = TRUE;
00224 }
00225 if (safe_strcmp (mergeType, QOF_TYPE_BOOLEAN) == 0)
00226 {
00227 boolean_getter =
00228 (gboolean (*)(QofEntity *,
00229 QofParam *)) qtparam->param_getfcn;
00230 booleanImport = boolean_getter (mergeEnt, qtparam);
00231 booleanTarget = boolean_getter (targetEnt, qtparam);
00232 if (booleanImport != FALSE && booleanImport != TRUE)
00233 booleanImport = FALSE;
00234 if (booleanTarget != FALSE && booleanTarget != TRUE)
00235 booleanTarget = FALSE;
00236 if (booleanImport == booleanTarget)
00237 mergeMatch = TRUE;
00238 currentRule = qof_book_merge_update_rule (currentRule,
00239 mergeMatch, DEFAULT_MERGE_WEIGHT);
00240 knowntype = TRUE;
00241 }
00242 if (safe_strcmp (mergeType, QOF_TYPE_KVP) == 0)
00243 {
00244 kvpImport =
00245 kvp_frame_copy (qtparam->param_getfcn (mergeEnt, qtparam));
00246 kvpTarget =
00247 kvp_frame_copy (qtparam->param_getfcn (targetEnt,
00248 qtparam));
00249 if (kvp_frame_compare (kvpImport, kvpTarget) == 0)
00250 mergeMatch = TRUE;
00251 currentRule = qof_book_merge_update_rule (currentRule,
00252 mergeMatch, DEFAULT_MERGE_WEIGHT);
00253 knowntype = TRUE;
00254 }
00255 if (safe_strcmp (mergeType, QOF_TYPE_CHAR) == 0)
00256 {
00257 char_getter =
00258 (gchar (*)(QofEntity *, QofParam *)) qtparam->param_getfcn;
00259 charImport = char_getter (mergeEnt, qtparam);
00260 charTarget = char_getter (targetEnt, qtparam);
00261 if (charImport == charTarget)
00262 mergeMatch = TRUE;
00263 currentRule = qof_book_merge_update_rule (currentRule,
00264 mergeMatch, DEFAULT_MERGE_WEIGHT);
00265 knowntype = TRUE;
00266 }
00267
00268
00269 if (safe_strcmp (mergeType, QOF_ID_BOOK) == 0)
00270 knowntype = TRUE;
00271 if (safe_strcmp (mergeType, QOF_TYPE_COLLECT) == 0)
00272 {
00273 struct collect_list_s s;
00274 s.linkedEntList = NULL;
00275 mergeColl = qtparam->param_getfcn (mergeEnt, qtparam);
00276 targetColl = qtparam->param_getfcn (targetEnt, qtparam);
00277 s.linkedEntList = g_slist_copy (currentRule->linkedEntList);
00278 qof_collection_foreach (mergeColl, collect_reference_cb, &s);
00279 currentRule->linkedEntList = g_slist_copy (s.linkedEntList);
00280 if (0 == qof_collection_compare (mergeColl, targetColl))
00281 mergeMatch = TRUE;
00282 currentRule = qof_book_merge_update_rule (currentRule,
00283 mergeMatch, DEFAULT_MERGE_WEIGHT);
00284 knowntype = TRUE;
00285 }
00286 if (safe_strcmp (mergeType, QOF_TYPE_CHOICE) == 0)
00287 {
00288 referenceEnt = qtparam->param_getfcn (mergeEnt, qtparam);
00289 currentRule->linkedEntList =
00290 g_slist_prepend (currentRule->linkedEntList, referenceEnt);
00291 if (referenceEnt == qtparam->param_getfcn (targetEnt, qtparam))
00292 mergeMatch = TRUE;
00293 knowntype = TRUE;
00294 }
00295 if (knowntype == FALSE)
00296 {
00297 referenceEnt = qtparam->param_getfcn (mergeEnt, qtparam);
00298 if ((referenceEnt != NULL)
00299 && (safe_strcmp (referenceEnt->e_type, mergeType) == 0))
00300 {
00301 currentRule->linkedEntList =
00302 g_slist_prepend (currentRule->linkedEntList,
00303 referenceEnt);
00304 if (referenceEnt ==
00305 qtparam->param_getfcn (targetEnt, qtparam))
00306 mergeMatch = TRUE;
00307 currentRule = qof_book_merge_update_rule (currentRule,
00308 mergeMatch, DEFAULT_MERGE_WEIGHT);
00309 }
00310 }
00311 paramList = g_slist_next (paramList);
00312 }
00313 mergeData->currentRule = currentRule;
00314 g_free (kvpImport);
00315 g_free (kvpTarget);
00316 return 0;
00317 }
00318
00319 static void
00320 qof_book_merge_commit_foreach_cb (gpointer rule, gpointer arg)
00321 {
00322 struct QofBookMergeRuleIterate *qiter;
00323
00324 g_return_if_fail (arg != NULL);
00325 qiter = (struct QofBookMergeRuleIterate *) arg;
00326 g_return_if_fail (qiter->data != NULL);
00327 qiter->fcn (qiter->data, (QofBookMergeRule *) rule,
00328 qiter->remainder);
00329 qiter->remainder--;
00330 }
00331
00332 static void
00333 qof_book_merge_commit_foreach (QofBookMergeRuleForeachCB cb,
00334 QofBookMergeResult mergeResult, QofBookMergeData * mergeData)
00335 {
00336 struct QofBookMergeRuleIterate qiter;
00337 QofBookMergeRule *currentRule;
00338 GList *subList, *node;
00339
00340 g_return_if_fail (cb != NULL);
00341 g_return_if_fail (mergeData != NULL);
00342 currentRule = mergeData->currentRule;
00343 g_return_if_fail (currentRule != NULL);
00344 g_return_if_fail (mergeResult > 0);
00345 g_return_if_fail ((mergeResult != MERGE_INVALID) ||
00346 (mergeResult != MERGE_UNDEF) ||
00347 (mergeResult != MERGE_REPORT));
00348
00349 qiter.fcn = cb;
00350 subList = NULL;
00351 qiter.ruleList = NULL;
00352 for (node = mergeData->mergeList; node != NULL; node = node->next)
00353 {
00354 currentRule = node->data;
00355 if (currentRule->mergeResult == mergeResult)
00356 subList = g_list_prepend (subList, currentRule);
00357 }
00358 qiter.remainder = g_list_length (subList);
00359 qiter.data = mergeData;
00360 g_list_foreach (subList, qof_book_merge_commit_foreach_cb, &qiter);
00361 }
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 static gboolean
00390 qof_book_merge_rule_cmp (gconstpointer a, gconstpointer b)
00391 {
00392 QofBookMergeRule *ra = (QofBookMergeRule *) a;
00393 QofBookMergeRule *rb = (QofBookMergeRule *) b;
00394 if (ra->difference == rb->difference)
00395 return TRUE;
00396 else
00397 return FALSE;
00398 }
00399
00400 static void
00401 qof_book_merge_orphan_check (double difference,
00402 QofBookMergeRule * mergeRule, QofBookMergeData * mergeData)
00403 {
00404
00405
00406
00407 QofBookMergeRule *rule;
00408
00409 g_return_if_fail (mergeRule != NULL);
00410 g_return_if_fail (mergeData != NULL);
00411 if (g_hash_table_size (mergeData->target_table) == 0)
00412 return;
00413 rule =
00414 (QofBookMergeRule *) g_hash_table_lookup (mergeData->target_table,
00415 mergeRule->targetEnt);
00416
00417 if (rule == NULL)
00418 return;
00419
00420 if (difference >= rule->difference)
00421 return;
00422 rule->targetEnt = NULL;
00423 rule->mergeResult = MERGE_UNDEF;
00424 mergeData->orphan_list = g_slist_append (mergeData->orphan_list, rule);
00425 }
00426
00427 static void
00428 qof_book_merge_match_orphans (QofBookMergeData * mergeData)
00429 {
00430 GSList *orphans, *targets;
00431 QofBookMergeRule *rule, *currentRule;
00432 QofEntity *best_matchEnt;
00433 double difference;
00434
00435 g_return_if_fail (mergeData != NULL);
00436 currentRule = mergeData->currentRule;
00437 g_return_if_fail (currentRule != NULL);
00438
00439
00440 orphans = mergeData->orphan_list;
00441 targets = g_slist_copy (mergeData->targetList);
00442 while (orphans != NULL)
00443 {
00444 rule = orphans->data;
00445 g_return_if_fail (rule != NULL);
00446 difference = g_slist_length (mergeData->mergeObjectParams);
00447 if (rule->targetEnt == NULL)
00448 {
00449 rule->mergeResult = MERGE_NEW;
00450 rule->difference = 0;
00451 mergeData->mergeList =
00452 g_list_prepend (mergeData->mergeList, rule);
00453 orphans = g_slist_next (orphans);
00454 continue;
00455 }
00456 mergeData->currentRule = rule;
00457 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00458 if (difference > mergeData->currentRule->difference)
00459 {
00460 best_matchEnt = currentRule->targetEnt;
00461 difference = currentRule->difference;
00462 rule = currentRule;
00463 mergeData->mergeList =
00464 g_list_prepend (mergeData->mergeList, rule);
00465 qof_book_merge_orphan_check (difference, rule, mergeData);
00466 }
00467 orphans = g_slist_next (orphans);
00468 }
00469 g_slist_free (mergeData->orphan_list);
00470 g_slist_free (targets);
00471 }
00472
00473 static void
00474 qof_book_merge_foreach_target (QofEntity * targetEnt, gpointer user_data)
00475 {
00476 QofBookMergeData *mergeData;
00477
00478 g_return_if_fail (user_data != NULL);
00479 mergeData = (QofBookMergeData *) user_data;
00480 g_return_if_fail (targetEnt != NULL);
00481 mergeData->targetList =
00482 g_slist_prepend (mergeData->targetList, targetEnt);
00483 }
00484
00485 static void
00486 qof_book_merge_foreach_type_target (QofObject * merge_obj,
00487 gpointer user_data)
00488 {
00489 QofBookMergeData *mergeData;
00490 QofBookMergeRule *currentRule;
00491
00492 g_return_if_fail (user_data != NULL);
00493 mergeData = (QofBookMergeData *) user_data;
00494 currentRule = mergeData->currentRule;
00495 g_return_if_fail (currentRule != NULL);
00496 g_return_if_fail (merge_obj != NULL);
00497 if (safe_strcmp (merge_obj->e_type,
00498 currentRule->importEnt->e_type) == 0)
00499 {
00500 qof_object_foreach (currentRule->importEnt->e_type,
00501 mergeData->targetBook,
00502 qof_book_merge_foreach_target, user_data);
00503 }
00504 }
00505
00506 static void
00507 qof_book_merge_foreach (QofEntity * mergeEnt, gpointer user_data)
00508 {
00509 QofBookMergeRule *mergeRule, *currentRule;
00510 QofBookMergeData *mergeData;
00511 QofEntity *targetEnt, *best_matchEnt;
00512 GUID *g;
00513 double difference;
00514 GSList *c;
00515
00516 g_return_if_fail (user_data != NULL);
00517 mergeData = (QofBookMergeData *) user_data;
00518 g_return_if_fail (mergeEnt != NULL);
00519 currentRule = mergeData->currentRule;
00520 g_return_if_fail (currentRule != NULL);
00521 g = guid_malloc ();
00522 *g = mergeEnt->guid;
00523 mergeRule = g_new0 (QofBookMergeRule, 1);
00524 mergeRule->importEnt = mergeEnt;
00525 mergeRule->difference = difference = 0;
00526 mergeRule->mergeAbsolute = FALSE;
00527 mergeRule->mergeResult = MERGE_UNDEF;
00528 mergeRule->updated = FALSE;
00529 mergeRule->mergeType = mergeEnt->e_type;
00530 mergeRule->mergeLabel = qof_object_get_type_label (mergeEnt->e_type);
00531 mergeRule->mergeParam = g_slist_copy (mergeData->mergeObjectParams);
00532 mergeRule->linkedEntList = NULL;
00533 mergeData->currentRule = mergeRule;
00534 targetEnt = best_matchEnt = NULL;
00535 targetEnt =
00536 qof_collection_lookup_entity (qof_book_get_collection
00537 (mergeData->targetBook, mergeEnt->e_type), g);
00538 if (targetEnt != NULL)
00539 {
00540 mergeRule->mergeAbsolute = TRUE;
00541 mergeRule->targetEnt = targetEnt;
00542 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00543 mergeRule->linkedEntList =
00544 g_slist_copy (currentRule->linkedEntList);
00545 mergeData->mergeList =
00546 g_list_prepend (mergeData->mergeList, mergeRule);
00547 return;
00548 }
00549
00550 g_slist_free (mergeData->targetList);
00551 mergeData->targetList = NULL;
00552 qof_object_foreach_type (qof_book_merge_foreach_type_target,
00553 mergeData);
00554 if (g_slist_length (mergeData->targetList) == 0)
00555 mergeRule->mergeResult = MERGE_NEW;
00556 difference = g_slist_length (mergeRule->mergeParam);
00557 c = g_slist_copy (mergeData->targetList);
00558 while (c != NULL)
00559 {
00560 mergeRule->targetEnt = c->data;
00561 currentRule = mergeRule;
00562
00563 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00564 if (mergeRule->difference == 0)
00565 {
00566
00567 best_matchEnt = mergeRule->targetEnt;
00568 mergeRule->mergeResult = MERGE_DUPLICATE;
00569 difference = 0;
00570 mergeRule->linkedEntList =
00571 g_slist_copy (currentRule->linkedEntList);
00572 g_slist_free (c);
00573 guid_free (g);
00574
00575 return;
00576 }
00577 if (difference > mergeRule->difference)
00578 {
00579
00580
00581 best_matchEnt = mergeRule->targetEnt;
00582 difference = mergeRule->difference;
00583
00584
00585
00586
00587 qof_book_merge_orphan_check (difference, mergeRule, mergeData);
00588 }
00589 c = g_slist_next (c);
00590 }
00591 g_slist_free (c);
00592 if (best_matchEnt != NULL)
00593 {
00594 mergeRule->targetEnt = best_matchEnt;
00595 mergeRule->difference = difference;
00596
00597
00598 g_hash_table_insert (mergeData->target_table, mergeRule->targetEnt,
00599 mergeRule);
00600
00601 g_return_if_fail (qof_book_merge_compare (mergeData) != -1);
00602 mergeRule->linkedEntList =
00603 g_slist_copy (currentRule->linkedEntList);
00604 }
00605 else
00606 {
00607 mergeRule->targetEnt = NULL;
00608 mergeRule->difference = 0;
00609 mergeRule->mergeResult = MERGE_NEW;
00610 mergeRule->linkedEntList =
00611 g_slist_copy (currentRule->linkedEntList);
00612 }
00613 mergeData->mergeList =
00614 g_list_prepend (mergeData->mergeList, mergeRule);
00615 guid_free (g);
00616
00617 }
00618
00619 static void
00620 qof_book_merge_foreach_param (QofParam * param, gpointer user_data)
00621 {
00622 QofBookMergeData *mergeData;
00623
00624 g_return_if_fail (user_data != NULL);
00625 mergeData = (QofBookMergeData *) user_data;
00626 g_return_if_fail (param != NULL);
00627 if ((param->param_getfcn != NULL) && (param->param_setfcn != NULL))
00628 {
00629 mergeData->mergeObjectParams =
00630 g_slist_append (mergeData->mergeObjectParams, param);
00631 }
00632 }
00633
00634 static void
00635 qof_book_merge_foreach_type (QofObject * merge_obj, gpointer user_data)
00636 {
00637 QofBookMergeData *mergeData;
00638
00639 g_return_if_fail (user_data != NULL);
00640 mergeData = (QofBookMergeData *) user_data;
00641 g_return_if_fail ((merge_obj != NULL));
00642
00643 if ((merge_obj->create == NULL) || (merge_obj->foreach == NULL))
00644 {
00645 DEBUG (" merge_obj QOF support failed %s", merge_obj->e_type);
00646 return;
00647 }
00648 if (mergeData->mergeObjectParams != NULL)
00649 g_slist_free (mergeData->mergeObjectParams);
00650 mergeData->mergeObjectParams = NULL;
00651 qof_class_param_foreach (merge_obj->e_type,
00652 qof_book_merge_foreach_param, mergeData);
00653 qof_object_foreach (merge_obj->e_type, mergeData->mergeBook,
00654 qof_book_merge_foreach, mergeData);
00655 }
00656
00657 static void
00658 qof_book_merge_rule_cb (gpointer rule, gpointer arg)
00659 {
00660 struct QofBookMergeRuleIterate *qiter;
00661 QofBookMergeData *mergeData;
00662
00663 g_return_if_fail (arg != NULL);
00664 qiter = (struct QofBookMergeRuleIterate *) arg;
00665 mergeData = qiter->data;
00666 g_return_if_fail (mergeData != NULL);
00667 g_return_if_fail (mergeData->abort == FALSE);
00668 qiter->fcn (mergeData, (QofBookMergeRule *) rule, qiter->remainder);
00669 qiter->data = mergeData;
00670 qiter->remainder--;
00671 }
00672
00673 static void
00674 qof_book_merge_commit_rule_loop (QofBookMergeData * mergeData,
00675 QofBookMergeRule * rule, guint remainder __attribute__ ((unused)))
00676 {
00677 QofInstance *inst;
00678 gboolean registered_type;
00679 QofEntity *referenceEnt;
00680
00681 QofCollection *cm_coll;
00682 QofParam *cm_param;
00683 gchar *cm_string;
00684 const GUID *cm_guid;
00685 KvpFrame *cm_kvp;
00686 QofTime *cm_qt;
00687
00688 QofNumeric cm_numeric, (*numeric_getter) (QofEntity *, QofParam *);
00689 gdouble cm_double, (*double_getter) (QofEntity *, QofParam *);
00690 gboolean cm_boolean, (*boolean_getter) (QofEntity *, QofParam *);
00691 gint32 cm_i32, (*int32_getter) (QofEntity *, QofParam *);
00692 gint64 cm_i64, (*int64_getter) (QofEntity *, QofParam *);
00693 gchar cm_char, (*char_getter) (QofEntity *, QofParam *);
00694
00695 void (*string_setter) (QofEntity *, const gchar *);
00696 void (*time_setter) (QofEntity *, QofTime *);
00697 void (*numeric_setter) (QofEntity *, QofNumeric);
00698 void (*guid_setter) (QofEntity *, const GUID *);
00699 void (*double_setter) (QofEntity *, double);
00700 void (*boolean_setter) (QofEntity *, gboolean);
00701 void (*i32_setter) (QofEntity *, gint32);
00702 void (*i64_setter) (QofEntity *, gint64);
00703 void (*char_setter) (QofEntity *, gchar);
00704 void (*kvp_frame_setter) (QofEntity *, KvpFrame *);
00705 void (*reference_setter) (QofEntity *, QofEntity *);
00706 void (*collection_setter) (QofEntity *, QofCollection *);
00707
00708 g_return_if_fail (rule != NULL);
00709 g_return_if_fail (mergeData != NULL);
00710 g_return_if_fail (mergeData->targetBook != NULL);
00711 g_return_if_fail ((rule->mergeResult != MERGE_NEW)
00712 || (rule->mergeResult != MERGE_UPDATE));
00713
00714
00715 if (rule->mergeResult == MERGE_NEW)
00716 {
00717 inst =
00718 (QofInstance *) qof_object_new_instance (rule->importEnt->
00719 e_type, mergeData->targetBook);
00720 g_return_if_fail (inst != NULL);
00721 rule->targetEnt = &inst->entity;
00722 qof_entity_set_guid (rule->targetEnt,
00723 qof_entity_get_guid (rule->importEnt));
00724 }
00725
00726
00727
00728
00729
00730 while (rule->mergeParam != NULL)
00731 {
00732 registered_type = FALSE;
00733 g_return_if_fail (rule->mergeParam->data);
00734 cm_param = rule->mergeParam->data;
00735 rule->mergeType = cm_param->param_type;
00736 if (safe_strcmp (rule->mergeType, QOF_TYPE_STRING) == 0)
00737 {
00738 cm_string = cm_param->param_getfcn (rule->importEnt, cm_param);
00739 string_setter =
00740 (void (*)(QofEntity *,
00741 const gchar *)) cm_param->param_setfcn;
00742 if (string_setter != NULL)
00743 string_setter (rule->targetEnt, cm_string);
00744 registered_type = TRUE;
00745 }
00746 if (safe_strcmp (rule->mergeType, QOF_TYPE_TIME) == 0)
00747 {
00748 QofTime *(*time_getter) (QofEntity *, QofParam *);
00749
00750 time_getter =
00751 (QofTime* (*)(QofEntity *, QofParam *))cm_param->param_getfcn;
00752 cm_qt = qof_time_copy (
00753 time_getter (rule->importEnt, cm_param));
00754 time_setter =
00755 (void (*)(QofEntity *, QofTime *))
00756 cm_param->param_setfcn;
00757 if ((time_setter != NULL) && (qof_time_is_valid (cm_qt)))
00758 time_setter (rule->targetEnt, cm_qt);
00759 registered_type = TRUE;
00760 }
00761 if ((safe_strcmp (rule->mergeType, QOF_TYPE_NUMERIC) == 0) ||
00762 (safe_strcmp (rule->mergeType, QOF_TYPE_DEBCRED) == 0))
00763 {
00764 numeric_getter =
00765 (QofNumeric (*)(QofEntity *, QofParam *)) cm_param->
00766 param_getfcn;
00767 cm_numeric = numeric_getter (rule->importEnt, cm_param);
00768 numeric_setter =
00769 (void (*)(QofEntity *,
00770 QofNumeric)) cm_param->param_setfcn;
00771 if (numeric_setter != NULL)
00772 numeric_setter (rule->targetEnt, cm_numeric);
00773 registered_type = TRUE;
00774 }
00775 if (safe_strcmp (rule->mergeType, QOF_TYPE_GUID) == 0)
00776 {
00777 cm_guid = cm_param->param_getfcn (rule->importEnt, cm_param);
00778 guid_setter =
00779 (void (*)(QofEntity *,
00780 const GUID *)) cm_param->param_setfcn;
00781 if (guid_setter != NULL)
00782 guid_setter (rule->targetEnt, cm_guid);
00783 registered_type = TRUE;
00784 }
00785 if (safe_strcmp (rule->mergeType, QOF_TYPE_INT32) == 0)
00786 {
00787 int32_getter =
00788 (gint32 (*)(QofEntity *,
00789 QofParam *)) cm_param->param_getfcn;
00790 cm_i32 = int32_getter (rule->importEnt, cm_param);
00791 i32_setter =
00792 (void (*)(QofEntity *, gint32)) cm_param->param_setfcn;
00793 if (i32_setter != NULL)
00794 i32_setter (rule->targetEnt, cm_i32);
00795 registered_type = TRUE;
00796 }
00797 if (safe_strcmp (rule->mergeType, QOF_TYPE_INT64) == 0)
00798 {
00799 int64_getter =
00800 (gint64 (*)(QofEntity *,
00801 QofParam *)) cm_param->param_getfcn;
00802 cm_i64 = int64_getter (rule->importEnt, cm_param);
00803 i64_setter =
00804 (void (*)(QofEntity *, gint64)) cm_param->param_setfcn;
00805 if (i64_setter != NULL)
00806 i64_setter (rule->targetEnt, cm_i64);
00807 registered_type = TRUE;
00808 }
00809 if (safe_strcmp (rule->mergeType, QOF_TYPE_DOUBLE) == 0)
00810 {
00811 double_getter =
00812 (double (*)(QofEntity *,
00813 QofParam *)) cm_param->param_getfcn;
00814 cm_double = double_getter (rule->importEnt, cm_param);
00815 double_setter =
00816 (void (*)(QofEntity *, double)) cm_param->param_setfcn;
00817 if (double_setter != NULL)
00818 double_setter (rule->targetEnt, cm_double);
00819 registered_type = TRUE;
00820 }
00821 if (safe_strcmp (rule->mergeType, QOF_TYPE_BOOLEAN) == 0)
00822 {
00823 boolean_getter =
00824 (gboolean (*)(QofEntity *, QofParam *)) cm_param->
00825 param_getfcn;
00826 cm_boolean = boolean_getter (rule->importEnt, cm_param);
00827 boolean_setter =
00828 (void (*)(QofEntity *, gboolean)) cm_param->param_setfcn;
00829 if (boolean_setter != NULL)
00830 boolean_setter (rule->targetEnt, cm_boolean);
00831 registered_type = TRUE;
00832 }
00833 if (safe_strcmp (rule->mergeType, QOF_TYPE_KVP) == 0)
00834 {
00835 cm_kvp =
00836 kvp_frame_copy (cm_param->
00837 param_getfcn (rule->importEnt, cm_param));
00838 kvp_frame_setter =
00839 (void (*)(QofEntity *, KvpFrame *)) cm_param->param_setfcn;
00840 if (kvp_frame_setter != NULL)
00841 kvp_frame_setter (rule->targetEnt, cm_kvp);
00842 registered_type = TRUE;
00843 }
00844 if (safe_strcmp (rule->mergeType, QOF_TYPE_CHAR) == 0)
00845 {
00846 char_getter =
00847 (gchar (*)(QofEntity *,
00848 QofParam *)) cm_param->param_getfcn;
00849 cm_char = char_getter (rule->importEnt, cm_param);
00850 char_setter =
00851 (void (*)(QofEntity *, gchar)) cm_param->param_setfcn;
00852 if (char_setter != NULL)
00853 char_setter (rule->targetEnt, cm_char);
00854 registered_type = TRUE;
00855 }
00856 if (safe_strcmp (rule->mergeType, QOF_TYPE_COLLECT) == 0)
00857 {
00858 cm_coll = cm_param->param_getfcn (rule->importEnt, cm_param);
00859 collection_setter =
00860 (void (*)(QofEntity *, QofCollection *)) cm_param->
00861 param_setfcn;
00862 if (collection_setter != NULL)
00863 collection_setter (rule->targetEnt, cm_coll);
00864 registered_type = TRUE;
00865 }
00866 if (safe_strcmp (rule->mergeType, QOF_TYPE_CHOICE) == 0)
00867 {
00868 referenceEnt =
00869 cm_param->param_getfcn (rule->importEnt, cm_param);
00870 reference_setter =
00871 (void (*)(QofEntity *,
00872 QofEntity *)) cm_param->param_setfcn;
00873 if (reference_setter != NULL)
00874 reference_setter (rule->targetEnt, referenceEnt);
00875 registered_type = TRUE;
00876 }
00877 if (registered_type == FALSE)
00878 {
00879 referenceEnt =
00880 cm_param->param_getfcn (rule->importEnt, cm_param);
00881 if (referenceEnt)
00882 {
00883 reference_setter =
00884 (void (*)(QofEntity *, QofEntity *)) cm_param->
00885 param_setfcn;
00886 if (reference_setter != NULL)
00887 {
00888 reference_setter (rule->targetEnt, referenceEnt);
00889 }
00890 }
00891 }
00892 rule->mergeParam = g_slist_next (rule->mergeParam);
00893 }
00894 }
00895
00896
00897
00898
00899 QofBookMergeData *
00900 qof_book_merge_init (QofBook * importBook, QofBook * targetBook)
00901 {
00902 QofBookMergeData *mergeData;
00903 QofBookMergeRule *currentRule;
00904 GList *check;
00905
00906 g_return_val_if_fail ((importBook != NULL)
00907 && (targetBook != NULL), NULL);
00908 mergeData = g_new0 (QofBookMergeData, 1);
00909 mergeData->abort = FALSE;
00910 mergeData->mergeList = NULL;
00911 mergeData->targetList = NULL;
00912 mergeData->mergeBook = importBook;
00913 mergeData->targetBook = targetBook;
00914 mergeData->mergeObjectParams = NULL;
00915 mergeData->orphan_list = NULL;
00916 mergeData->target_table =
00917 g_hash_table_new (g_direct_hash, qof_book_merge_rule_cmp);
00918 currentRule = g_new0 (QofBookMergeRule, 1);
00919 mergeData->currentRule = currentRule;
00920 qof_object_foreach_type (qof_book_merge_foreach_type, mergeData);
00921 g_return_val_if_fail (mergeData->mergeObjectParams, NULL);
00922 if (mergeData->orphan_list != NULL)
00923 qof_book_merge_match_orphans (mergeData);
00924 for (check = mergeData->mergeList; check != NULL; check = check->next)
00925 {
00926 currentRule = check->data;
00927 if (currentRule->mergeResult == MERGE_INVALID)
00928 {
00929 mergeData->abort = TRUE;
00930 return (NULL);
00931 }
00932 }
00933 return mergeData;
00934 }
00935
00936 void
00937 qof_book_merge_abort (QofBookMergeData * mergeData)
00938 {
00939 QofBookMergeRule *currentRule;
00940
00941 g_return_if_fail (mergeData != NULL);
00942 while (mergeData->mergeList != NULL)
00943 {
00944 currentRule = mergeData->mergeList->data;
00945 g_slist_free (currentRule->linkedEntList);
00946 g_slist_free (currentRule->mergeParam);
00947 g_free (mergeData->mergeList->data);
00948 if (currentRule)
00949 {
00950 g_slist_free (currentRule->linkedEntList);
00951 g_slist_free (currentRule->mergeParam);
00952 g_free (currentRule);
00953 }
00954 mergeData->mergeList = g_list_next (mergeData->mergeList);
00955 }
00956 g_list_free (mergeData->mergeList);
00957 g_slist_free (mergeData->mergeObjectParams);
00958 g_slist_free (mergeData->targetList);
00959 if (mergeData->orphan_list != NULL)
00960 g_slist_free (mergeData->orphan_list);
00961 g_hash_table_destroy (mergeData->target_table);
00962 g_free (mergeData);
00963 }
00964
00965 QofBookMergeData *
00966 qof_book_merge_update_result (QofBookMergeData * mergeData,
00967 QofBookMergeResult tag)
00968 {
00969 QofBookMergeRule *resolved;
00970
00971 g_return_val_if_fail ((mergeData != NULL), NULL);
00972 g_return_val_if_fail ((tag > 0), NULL);
00973 g_return_val_if_fail ((tag != MERGE_REPORT), NULL);
00974 resolved = mergeData->currentRule;
00975 g_return_val_if_fail ((resolved != NULL), NULL);
00976 if ((resolved->mergeAbsolute == TRUE) && (tag == MERGE_DUPLICATE))
00977 tag = MERGE_ABSOLUTE;
00978 if ((resolved->mergeAbsolute == TRUE) && (tag == MERGE_NEW))
00979 tag = MERGE_UPDATE;
00980 if ((resolved->mergeAbsolute == FALSE) && (tag == MERGE_ABSOLUTE))
00981 tag = MERGE_DUPLICATE;
00982 if ((resolved->mergeResult == MERGE_NEW) && (tag == MERGE_UPDATE))
00983 tag = MERGE_NEW;
00984 if (resolved->updated == FALSE)
00985 resolved->mergeResult = tag;
00986 resolved->updated = TRUE;
00987 if (tag >= MERGE_INVALID)
00988 {
00989 mergeData->abort = TRUE;
00990 mergeData->currentRule = resolved;
00991 return NULL;
00992 }
00993 mergeData->currentRule = resolved;
00994 return mergeData;
00995 }
00996
00997 gint
00998 qof_book_merge_commit (QofBookMergeData * mergeData)
00999 {
01000 QofBookMergeRule *currentRule;
01001 GList *check, *node;
01002
01003 g_return_val_if_fail (mergeData != NULL, -1);
01004 g_return_val_if_fail (mergeData->mergeList != NULL, -1);
01005 g_return_val_if_fail (mergeData->targetBook != NULL, -1);
01006 if (mergeData->abort == TRUE)
01007 return -1;
01008 check = g_list_copy (mergeData->mergeList);
01009 g_return_val_if_fail (check != NULL, -1);
01010 for (node = check; node != NULL; node = node->next)
01011 {
01012 currentRule = node->data;
01013 if (currentRule->mergeResult == MERGE_INVALID)
01014 {
01015 qof_book_merge_abort (mergeData);
01016 g_list_free (check);
01017 return (-2);
01018 }
01019 if (currentRule->mergeResult == MERGE_REPORT)
01020 {
01021 g_list_free (check);
01022 return 1;
01023 }
01024 }
01025 g_list_free (check);
01026 qof_book_merge_commit_foreach (qof_book_merge_commit_rule_loop,
01027 MERGE_NEW, mergeData);
01028 qof_book_merge_commit_foreach (qof_book_merge_commit_rule_loop,
01029 MERGE_UPDATE, mergeData);
01030
01031
01032 while (mergeData->mergeList != NULL)
01033 {
01034 currentRule = mergeData->mergeList->data;
01035 g_slist_free (currentRule->mergeParam);
01036 g_slist_free (currentRule->linkedEntList);
01037 mergeData->mergeList = g_list_next (mergeData->mergeList);
01038 }
01039 g_list_free (mergeData->mergeList);
01040 g_slist_free (mergeData->mergeObjectParams);
01041 g_slist_free (mergeData->targetList);
01042 if (mergeData->orphan_list != NULL)
01043 g_slist_free (mergeData->orphan_list);
01044 g_hash_table_destroy (mergeData->target_table);
01045 g_free (mergeData);
01046 return 0;
01047 }
01048
01049 void
01050 qof_book_merge_rule_foreach (QofBookMergeData * mergeData,
01051 QofBookMergeRuleForeachCB cb, QofBookMergeResult mergeResult)
01052 {
01053 struct QofBookMergeRuleIterate qiter;
01054 QofBookMergeRule *currentRule;
01055 GList *matching_rules, *node;
01056
01057 g_return_if_fail (cb != NULL);
01058 g_return_if_fail (mergeData != NULL);
01059 currentRule = mergeData->currentRule;
01060 g_return_if_fail (mergeResult > 0);
01061 g_return_if_fail (mergeResult != MERGE_INVALID);
01062 g_return_if_fail (mergeData->abort == FALSE);
01063 qiter.fcn = cb;
01064 qiter.data = mergeData;
01065 matching_rules = NULL;
01066 for (node = mergeData->mergeList; node != NULL; node = node->next)
01067 {
01068 currentRule = node->data;
01069 if (currentRule->mergeResult == mergeResult)
01070 matching_rules = g_list_prepend (matching_rules,
01071 currentRule);
01072 }
01073 qiter.remainder = g_list_length (matching_rules);
01074 g_list_foreach (matching_rules, qof_book_merge_rule_cb, &qiter);
01075 g_list_free (matching_rules);
01076 }
01077
01078