00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024
00025 #include <glib.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028
00029 #include <libpq-fe.h>
00030
00031 #include "AccountP.h"
00032 #include "qof.h"
00033 #include "gnc-commodity.h"
00034 #include "gnc-pricedb.h"
00035
00036 #include "account.h"
00037 #include "book.h"
00038 #include "base-autogen.h"
00039 #include "kvp-sql.h"
00040 #include "PostgresBackend.h"
00041 #include "price.h"
00042
00043 static QofLogModule log_module = GNC_MOD_BACKEND;
00044
00045 #include "putil.h"
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 static void
00077 pgendStoreAccountNoLock (PGBackend *be, Account *acct,
00078 gboolean do_mark,
00079 gboolean do_check_version)
00080 {
00081 const gnc_commodity *com;
00082 guint32 a_idata;
00083
00084 if (!be || !acct) return;
00085 if ((FALSE == do_mark) && (!qof_instance_get_dirty_flag(acct)))
00086 return;
00087
00088 ENTER ("acct=%p, mark=%d", acct, do_mark);
00089
00090 if (do_mark)
00091 {
00092
00093
00094
00095
00096
00097
00098 if (xaccAccountGetMark (acct)) return;
00099 xaccAccountSetMark (acct, 1);
00100 }
00101
00102 if (do_check_version)
00103 {
00104 if (0 < pgendAccountCompareVersion (be, acct)) return;
00105 }
00106
00107 qof_instance_increment_version(acct, be->version_check);
00108
00109 a_idata = qof_instance_get_idata(acct);
00110 if ((0 == a_idata) &&
00111 (FALSE == kvp_frame_is_empty (xaccAccountGetSlots(acct))))
00112 {
00113 a_idata = pgendNewGUIDidx(be);
00114 qof_instance_set_idata(acct, a_idata);
00115 }
00116
00117 pgendPutOneAccountOnly (be, acct);
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 com = xaccAccountGetCommodity (acct);
00130 pgendPutOneCommodityOnly (be, (gnc_commodity *) com);
00131
00132 if (a_idata)
00133 {
00134 pgendKVPDelete (be, a_idata);
00135 pgendKVPStore (be, a_idata, acct->inst.kvp_data);
00136 }
00137 LEAVE(" ");
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154 void
00155 pgendStoreAccountTreeNoLock (PGBackend *be, Account *root,
00156 gboolean do_mark, gboolean do_check_version)
00157 {
00158 GList *descendants, *node;
00159
00160 if (!be || !root) return;
00161 ENTER("root=%p mark=%d", root, do_mark);
00162
00163
00164 pgendStoreAccountNoLock (be, root, do_mark, do_check_version);
00165 descendants = gnc_account_get_descendants (root);
00166 for (node=descendants; node; node=node->next)
00167 pgendStoreAccountNoLock (be, node->data, do_mark, do_check_version);
00168 g_list_free(descendants);
00169 LEAVE(" ");
00170 }
00171
00172
00173 void
00174 pgendStoreAccountTree (PGBackend *be, Account *root)
00175 {
00176 char *p;
00177 ENTER ("be=%p, root=%p", be, root);
00178 if (!be || !root) return;
00179
00180
00181 p = "BEGIN;\n"
00182 "LOCK TABLE gncAccount IN EXCLUSIVE MODE;\n"
00183 "LOCK TABLE gncCommodity IN EXCLUSIVE MODE;\n";
00184 SEND_QUERY (be,p, );
00185 FINISH_QUERY(be->connection);
00186
00187
00188
00189 xaccClearMarkDown (root, 0);
00190
00191 pgendStoreAccountTreeNoLock (be, root, TRUE, TRUE);
00192
00193
00194 xaccClearMarkDown (root, 0);
00195
00196 p = "COMMIT;\n"
00197 "NOTIFY gncAccount;";
00198 SEND_QUERY (be,p, );
00199 FINISH_QUERY(be->connection);
00200 LEAVE(" ");
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210 static void
00211 restore_cb (Account *acc, void * cb_data)
00212 {
00213 PGBackend *be = (PGBackend *) cb_data;
00214 guint32 a_idata = qof_instance_get_idata(acc);
00215 if (0 == a_idata) return;
00216 acc->inst.kvp_data = pgendKVPFetch (be, a_idata, acc->inst.kvp_data);
00217 }
00218
00219 static void
00220 pgendGetAllAccountKVP (PGBackend *be, Account *root)
00221 {
00222 if (!root) return;
00223
00224 restore_cb(root, NULL);
00225 gnc_account_foreach_descendant(root, restore_cb, be);
00226 }
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 typedef struct
00238 {
00239 Account * account;
00240
00241 char * commodity_string;
00242 gboolean need_parent;
00243 GUID parent_guid;
00244 } AccountResolveInfo;
00245
00246 typedef struct
00247 {
00248 QofBook * book;
00249 GList * resolve_info;
00250 } GetAccountData;
00251
00252 static AccountResolveInfo *
00253 get_resolve_info (AccountResolveInfo * ri)
00254 {
00255 if (ri) return ri;
00256 return g_new0 (AccountResolveInfo, 1);
00257 }
00258
00259 static gpointer
00260 get_account_cb (PGBackend *be, PGresult *result, int j, gpointer data)
00261 {
00262 GetAccountData * gad = data;
00263 QofBook * book = gad->book;
00264 Account *parent;
00265 Account *acc;
00266 GUID acct_guid;
00267 char * commodity_string;
00268 gnc_commodity * commodity;
00269 AccountResolveInfo *ri = NULL;
00270
00271 PINFO ("account GUID=%s", DB_GET_VAL("accountGUID",j));
00272
00273 FIND_BOOK (book);
00274
00275
00276 acct_guid = nullguid;
00277 string_to_guid (DB_GET_VAL("accountGUID",j), &acct_guid);
00278
00279 acc = xaccAccountLookup (&acct_guid, book);
00280 if (!acc)
00281 {
00282 acc = xaccMallocAccount(book);
00283 xaccAccountBeginEdit(acc);
00284 xaccAccountSetGUID(acc, &acct_guid);
00285 }
00286 else
00287 {
00288 xaccAccountBeginEdit(acc);
00289 }
00290
00291 commodity_string = DB_GET_VAL("commodity",j);
00292 commodity = gnc_string_to_commodity (commodity_string, book);
00293 if (!commodity)
00294 {
00295 ri = get_resolve_info (ri);
00296
00297 ri->account = acc;
00298 ri->commodity_string = g_strdup (commodity_string);
00299 }
00300
00301 xaccAccountSetName(acc, DB_GET_VAL("accountName",j));
00302 xaccAccountSetDescription(acc, DB_GET_VAL("description",j));
00303 xaccAccountSetCode(acc, DB_GET_VAL("accountCode",j));
00304 xaccAccountSetType(acc, xaccAccountStringToEnum(DB_GET_VAL("type",j)));
00305 if (commodity)
00306 xaccAccountSetCommodity(acc, commodity);
00307 qof_instance_set_version(acc, atoi(DB_GET_VAL("version",j)));
00308 qof_instance_set_idata(acc, atoi(DB_GET_VAL("iguid",j)));
00309
00310
00311 PINFO ("parent GUID=%s", DB_GET_VAL("parentGUID",j));
00312 acct_guid = nullguid;
00313 string_to_guid (DB_GET_VAL("parentGUID",j), &acct_guid);
00314 if (guid_equal(guid_null(), &acct_guid))
00315 {
00316
00317
00318 gnc_account_append_child (gnc_book_get_root_account(book), acc);
00319 }
00320 else
00321 {
00322
00323
00324 parent = xaccAccountLookup (&acct_guid, book);
00325 if (!parent)
00326 {
00327 ri = get_resolve_info (ri);
00328
00329 ri->account = acc;
00330 ri->need_parent = TRUE;
00331 ri->parent_guid = acct_guid;
00332 }
00333 else
00334 {
00335 xaccAccountBeginEdit(parent);
00336 gnc_account_append_child(parent, acc);
00337 xaccAccountCommitEdit(parent);
00338 }
00339 }
00340
00341 xaccAccountCommitEdit(acc);
00342
00343 if (ri)
00344 gad->resolve_info = g_list_prepend (gad->resolve_info, ri);
00345
00346 return data;
00347 }
00348
00349 static void
00350 pgendGetAccounts (PGBackend *be, QofBook *book)
00351 {
00352 GetAccountData gad;
00353
00354 gad.book = book ? book : be->book;
00355 gad.resolve_info = NULL;
00356
00357 pgendGetResults (be, get_account_cb, &gad);
00358
00359 while (gad.resolve_info)
00360 {
00361 AccountResolveInfo *ri = gad.resolve_info->data;
00362
00363 gad.resolve_info = g_list_remove (gad.resolve_info, ri);
00364
00365 xaccAccountBeginEdit (ri->account);
00366
00367 if (ri->commodity_string)
00368 {
00369 gnc_commodity * commodity;
00370
00371 pgendGetCommodity (be, ri->commodity_string);
00372 commodity = gnc_string_to_commodity (ri->commodity_string,
00373 gnc_account_get_book(ri->account));
00374
00375 if (commodity)
00376 {
00377 xaccAccountSetCommodity (ri->account, commodity);
00378 }
00379 else
00380 {
00381 PERR ("Can't find commodity %s", ri->commodity_string);
00382 }
00383
00384 g_free (ri->commodity_string);
00385 ri->commodity_string = NULL;
00386 }
00387
00388 if (ri->need_parent)
00389 {
00390 Account * parent;
00391
00392
00393 parent = xaccAccountLookup (&ri->parent_guid, gad.book);
00394
00395 if (!parent)
00396 parent = pgendCopyAccountToEngine (be, &ri->parent_guid);
00397
00398 if (parent)
00399 {
00400 xaccAccountBeginEdit(parent);
00401 gnc_account_append_child(parent, ri->account);
00402 xaccAccountCommitEdit(parent);
00403 }
00404 else
00405 {
00406 PERR ("no such account: %s", guid_to_string (&ri->parent_guid));
00407 }
00408 }
00409
00410 xaccAccountCommitEdit (ri->account);
00411
00412 g_free (ri);
00413 }
00414 }
00415
00416 void
00417 pgendGetAllAccounts (PGBackend *be)
00418 {
00419 QofBookList *node;
00420 char * bufp;
00421
00422 ENTER ("be=%p", be);
00423 if (!be) return;
00424
00425
00426 pgendGetAllBooks (be, be->blist);
00427
00428
00429 pgendGetAllCommodities (be);
00430
00431
00432 bufp = "SELECT * FROM gncAccount;";
00433 SEND_QUERY (be, bufp, );
00434 pgendGetAccounts (be, NULL);
00435
00436 for (node=be->blist; node; node=node->next)
00437 {
00438 QofBook *book = node->data;
00439 Account *root = gnc_book_get_root_account(book);
00440 pgendGetAllAccountKVP (be, root);
00441 }
00442
00443 LEAVE (" ");
00444 }
00445
00446 void
00447 pgendGetAllAccountsInBook (PGBackend *be, QofBook *book)
00448 {
00449 char *p, buff[400];
00450 Account *root;
00451
00452 ENTER ("be=%p", be);
00453 if (!be || !book) return;
00454
00455
00456 pgendGetAllCommodities (be);
00457
00458
00459
00460 p = buff;
00461 p = stpcpy (p, "SELECT * FROM gncAccount WHERE bookGuid='");
00462 p = guid_to_string_buff (qof_book_get_guid(book), p);
00463 p = stpcpy (p, "';");
00464 SEND_QUERY (be, buff, );
00465 pgendGetAccounts (be, book);
00466
00467 root = gnc_book_get_root_account(book);
00468 pgendGetAllAccountKVP (be, root);
00469
00470 LEAVE (" ");
00471 }
00472
00473
00474
00475
00476 Account *
00477 pgendCopyAccountToEngine (PGBackend *be, const GUID *acct_guid)
00478 {
00479 char *pbuff;
00480 Account *acc = NULL;
00481 int engine_data_is_newer = 0;
00482 guint32 a_idata;
00483
00484 ENTER ("be=%p", be);
00485 if (!be || !acct_guid) return 0;
00486
00487
00488 qof_event_suspend();
00489 pgendDisable(be);
00490
00491
00492 acc = pgendAccountLookup (be, acct_guid);
00493
00494 if (!acc)
00495 {
00496 engine_data_is_newer = -1;
00497 }
00498 else
00499 {
00500
00501
00502 guint32 value = qof_instance_get_version_check(acc);
00503 if (MAX_VERSION_AGE >= be->version_check - value)
00504 {
00505 PINFO ("fresh data, skip check");
00506 engine_data_is_newer = 0;
00507 }
00508 else
00509 {
00510 engine_data_is_newer = - pgendAccountCompareVersion (be, acc);
00511 }
00512 }
00513
00514 if (0 > engine_data_is_newer)
00515 {
00516
00517 pbuff = be->buff;
00518 pbuff[0] = 0;
00519 pbuff = stpcpy (pbuff,
00520 "SELECT * FROM gncAccount WHERE accountGuid='");
00521 pbuff = guid_to_string_buff(acct_guid, pbuff);
00522 pbuff = stpcpy (pbuff, "';");
00523
00524 SEND_QUERY (be,be->buff, 0);
00525 pgendGetAccounts (be, NULL);
00526 acc = pgendAccountLookup (be, acct_guid);
00527
00528
00529 if (acc)
00530 {
00531 a_idata = qof_instance_get_idata(acc);
00532 if (a_idata)
00533 {
00534 acc->inst.kvp_data = pgendKVPFetch (be, a_idata, acc->inst.kvp_data);
00535 }
00536
00537 qof_instance_set_version_check(acc, be->version_check);
00538 }
00539 }
00540
00541
00542 pgendEnable(be);
00543 qof_event_resume();
00544
00545 LEAVE (" ");
00546 return acc;
00547 }
00548
00549
00550
00551
00552
00553
00554
00555 void
00556 pgend_account_commit_edit (QofBackend * bend,
00557 Account * acct)
00558 {
00559 char *p;
00560 QofBackendError err;
00561 PGBackend *be = (PGBackend *)bend;
00562
00563 ENTER ("be=%p, acct=%p", be, acct);
00564 if (!be || !acct) return;
00565
00566 if (!qof_instance_get_dirty_flag(acct))
00567 {
00568 LEAVE ("account not written because not dirty");
00569 return;
00570 }
00571
00572
00573
00574 p = "BEGIN;\n"
00575 "LOCK TABLE gncAccount IN EXCLUSIVE MODE;\n"
00576 "LOCK TABLE gncCommodity IN EXCLUSIVE MODE;\n";
00577
00578 SEND_QUERY (be,p,);
00579 FINISH_QUERY(be->connection);
00580
00581
00582
00583
00584 if (0 < pgendAccountCompareVersion (be, acct))
00585 {
00586 qof_instance_set_destroying(acct, FALSE);
00587 p = "ROLLBACK;";
00588 SEND_QUERY (be,p,);
00589 FINISH_QUERY(be->connection);
00590
00591
00592
00593 PWARN(" account data in engine is newer\n"
00594 " account must be rolled back. This function\n"
00595 " is not completely implemented !! \n");
00596 qof_backend_set_error (&be->be, ERR_BACKEND_MODIFIED);
00597 LEAVE ("rolled back");
00598 return;
00599 }
00600
00601 qof_instance_increment_version(acct, be->version_check);
00602
00603 if (qof_instance_get_destroying(acct))
00604 {
00605 const GUID *guid = xaccAccountGetGUID(acct);
00606 pgendKVPDelete (be, qof_instance_get_idata(acct));
00607
00608 p = be->buff; *p = 0;
00609 p = stpcpy (p, "DELETE FROM gncAccount WHERE accountGuid='");
00610 p = guid_to_string_buff (guid, p);
00611 p = stpcpy (p, "';");
00612 err = sendQuery (be,be->buff);
00613 if (err == ERR_BACKEND_NO_ERR) {
00614 err = finishQuery(be);
00615 if (err > 0)
00616 pgendStoreAuditAccount (be, acct, SQL_DELETE);
00617 }
00618 }
00619 else
00620 {
00621 pgendStoreAccountNoLock (be, acct, FALSE, FALSE);
00622 }
00623
00624 p = "COMMIT;\n"
00625 "NOTIFY gncAccount;";
00626 SEND_QUERY (be,p,);
00627 FINISH_QUERY(be->connection);
00628
00629 LEAVE ("commited");
00630 return;
00631 }
00632
00633