mirror of https://github.com/Gnucash/gnucash
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
14 KiB
421 lines
14 KiB
|
|
divert(-1)
|
|
changecom(`/*', `*/')
|
|
|
|
/* data dictionary for the gnucash tables */
|
|
/* sql table description and manipulation macros */
|
|
|
|
define(`account', `gncAccount, Account, Account, a,
|
|
accountName, , char *, xaccAccountGetName(ptr),
|
|
accountCode, , char *, xaccAccountGetCode(ptr),
|
|
description, , char *, xaccAccountGetDescription(ptr),
|
|
type, , char *, xaccAccountTypeEnumAsString(xaccAccountGetType(ptr)),
|
|
commodity, , char *, gnc_commodity_get_unique_name(xaccAccountGetCommodity(ptr)),
|
|
version, , int32, xaccAccountGetVersion(ptr),
|
|
parentGUID, , GUID *, xaccAccountGetGUID(xaccAccountGetParentAccount(ptr)),
|
|
accountGUID, KEY, GUID *, xaccAccountGetGUID(ptr),
|
|
')
|
|
|
|
define(`split', `gncEntry, Split, Split, e,
|
|
accountGUID, , GUID *, xaccAccountGetGUID(xaccSplitGetAccount(ptr)),
|
|
transGUID, , GUID *, xaccTransGetGUID(xaccSplitGetParent(ptr)),
|
|
memo, , char *, xaccSplitGetMemo(ptr),
|
|
action, , char *, xaccSplitGetAction(ptr),
|
|
reconciled, , char, xaccSplitGetReconcile(ptr),
|
|
date_reconciled, , Timespec, xaccSplitRetDateReconciledTS(ptr),
|
|
amount, , int64, gnc_numeric_num(xaccSplitGetShareAmount(ptr)),
|
|
value, , int64, gnc_numeric_num(xaccSplitGetValue(ptr)),
|
|
entryGUID, KEY, GUID *, xaccSplitGetGUID(ptr),
|
|
')
|
|
|
|
/* note that for the date_entered, we use the sql database */
|
|
/* notion of 'current time'. This should help prevent clock */
|
|
/* skew problems between different simultaneous users */
|
|
/* Note also this means that the table entry is not */
|
|
/* date_entered, , Timespec, xaccTransRetDateEnteredTS(ptr), */
|
|
/* as one might have guessed */
|
|
|
|
define(`transaction', `gncTransaction, Transaction, Transaction, t,
|
|
num, , char *, xaccTransGetNum(ptr),
|
|
description, , char *, xaccTransGetDescription(ptr),
|
|
currency, , commod, gnc_commodity_get_unique_name(xaccTransGetCurrency(ptr)),
|
|
last_modified, , now, "NOW",
|
|
date_entered, , Timespec, xaccTransRetDateEnteredTS(ptr),
|
|
date_posted, , Timespec, xaccTransRetDatePostedTS(ptr),
|
|
version, , int32, xaccTransGetVersion(ptr),
|
|
transGUID, KEY, GUID *, xaccTransGetGUID(ptr),
|
|
')
|
|
|
|
|
|
define(`modity', `gncCommodity, Commodity, gnc_commodity, c,
|
|
namespace, , char *, gnc_commodity_get_namespace(ptr),
|
|
fullname, , char *, gnc_commodity_get_fullname(ptr),
|
|
mnemonic, , char *, gnc_commodity_get_mnemonic(ptr),
|
|
code, , char *, gnc_commodity_get_exchange_code(ptr),
|
|
fraction, , int32, gnc_commodity_get_fraction(ptr),
|
|
commodity, KEY, char *, gnc_commodity_get_unique_name(ptr),
|
|
')
|
|
|
|
|
|
define(`price', `gncPrice, Price, GNCPrice, p,
|
|
commodity, , commod, gnc_commodity_get_unique_name(gnc_price_get_commodity(ptr)),
|
|
currency, , commod, gnc_commodity_get_unique_name(gnc_price_get_currency(ptr)),
|
|
time, , Timespec, gnc_price_get_time(ptr),
|
|
source, , char *, gnc_price_get_source(ptr),
|
|
type, , char *, gnc_price_get_type(ptr),
|
|
valueNum, , int64, gnc_numeric_num(gnc_price_get_value(ptr)),
|
|
valueDenom, , int64, gnc_numeric_denom(gnc_price_get_value(ptr)),
|
|
version, , int32, gnc_price_get_version(ptr),
|
|
priceGUID, KEY, GUID *, gnc_price_get_guid(ptr),
|
|
')
|
|
|
|
|
|
define(`checkpoint', `gncCheckpoint, Checkpoint, Checkpoint, x,
|
|
balance, , int64, ptr->balance,
|
|
cleared_balance, , int64, ptr->cleared_balance,
|
|
reconciled_balance, , int64, ptr->reconciled_balance,
|
|
date_start, , Timespec, ptr->date_start,
|
|
date_end, , Timespec, ptr->date_end,
|
|
commodity, , char *, ptr->commodity,
|
|
accountGuid, , GUID *, ptr->account_guid,
|
|
')
|
|
|
|
|
|
define(`session', `gncSession, Session, void, x,
|
|
session_mode, , char *, pgendSessionGetMode(be),
|
|
hostname, , char *, pgendGetHostname(be),
|
|
login_name, , char *, pgendGetUsername(be),
|
|
gecos, , char *, pgendGetUserGecos(be),
|
|
time_on, , now, "NOW",
|
|
time_off, , now, "INFINITY",
|
|
sessionGUID, KEY, GUID *, be->sessionGuid,
|
|
')
|
|
|
|
define(`kvp_gint64', `gncKVPvalue_int64, KVPint64, store_data_t, k,
|
|
type, , char *, ptr->stype,
|
|
data, , int64, ptr->u.ival,
|
|
iguid, KEY, int32, ptr->iguid,
|
|
ipath, KEY, int32, ptr->ipath,
|
|
')
|
|
|
|
|
|
define(`kvp_double', `gncKVPvalue_dbl, KVPdouble, store_data_t, k,
|
|
type, , char *, ptr->stype,
|
|
data, , double, ptr->u.dbl,
|
|
iguid, KEY, int32, ptr->iguid,
|
|
ipath, KEY, int32, ptr->ipath,
|
|
')
|
|
|
|
define(`kvp_numeric', `gncKVPvalue_numeric, KVPnumeric, store_data_t, k,
|
|
type, , char *, ptr->stype,
|
|
num, , int64, ptr->u.numeric.num,
|
|
denom, , int64, ptr->u.numeric.denom,
|
|
iguid, KEY, int32, ptr->iguid,
|
|
ipath, KEY, int32, ptr->ipath,
|
|
')
|
|
|
|
define(`kvp_string', `gncKVPvalue_str, KVPstring, store_data_t, k,
|
|
type, , char *, ptr->stype,
|
|
data, , char *, ptr->u.str,
|
|
iguid, KEY, int32, ptr->iguid,
|
|
ipath, KEY, int32, ptr->ipath,
|
|
')
|
|
|
|
define(`kvp_guid', `gncKVPvalue_guid, KVPguid, store_data_t, k,
|
|
type, , char *, ptr->stype,
|
|
data, , char *, ptr->u.str,
|
|
iguid, KEY, int32, ptr->iguid,
|
|
ipath, KEY, int32, ptr->ipath,
|
|
')
|
|
|
|
/* ------------------------------------------------------- */
|
|
/* symbolic names for the table accessors */
|
|
define(`tablename', $1)
|
|
define(`func_name', $2)
|
|
define(`xacc_type', $3)
|
|
define(`obj_type', $4)
|
|
|
|
define(`firstrec', `shift(shift(shift(shift($@))))')
|
|
define(`nextrec', `shift(shift(shift(shift($@))))')
|
|
|
|
/* -------- */
|
|
/* macros that use the sql builder to build a query */
|
|
|
|
define(`sql_setter', `ifelse($2, `KEY',
|
|
`ifelse($1, `char *', sqlBuild_Where_Str,
|
|
$1, `int32', sqlBuild_Where_Int32,
|
|
$1, `GUID *', sqlBuild_Where_GUID)',
|
|
|
|
$2, ,
|
|
`ifelse($1, `char *', sqlBuild_Set_Str,
|
|
$1, `now', sqlBuild_Set_Str,
|
|
$1, `commod', sqlBuild_Set_Str,
|
|
$1, `double', sqlBuild_Set_Double,
|
|
$1, `int32', sqlBuild_Set_Int32,
|
|
$1, `int64', sqlBuild_Set_Int64,
|
|
$1, `GUID *', sqlBuild_Set_GUID,
|
|
$1, `Timespec', sqlBuild_Set_Date,
|
|
$1, `char', sqlBuild_Set_Char)')')
|
|
|
|
|
|
/* recursively walk the table, build the builders */
|
|
|
|
define(`set_fields_r', `ifelse($#, 1, ,
|
|
` sql_setter($3,$2) (be->builder, "$1", $4);
|
|
set_fields_r(nextrec($@))')')
|
|
|
|
define(`set_fields', `set_fields_r(firstrec($@))')
|
|
|
|
/* -------- */
|
|
/* macros to compare a query result */
|
|
/* the commod type behaves just like a string, except it
|
|
* has its one compre function. */
|
|
|
|
define(`cmp_value', `ifelse($1, `char *', COMP_STR,
|
|
$1, `now', COMP_NOW,
|
|
$1, `int32', COMP_INT32,
|
|
$1, `int64', COMP_INT64,
|
|
$1, `double', COMP_DOUBLE,
|
|
$1, `GUID *', COMP_GUID,
|
|
$1, `commod', COMP_COMMODITY,
|
|
$1, `Timespec', COMP_DATE,
|
|
$1, `char', COMP_CHAR)')
|
|
|
|
/* recursively walk the table, build compare functions,
|
|
* but only for non-primary-keys */
|
|
|
|
define(`cmp_fields_r', `ifelse($#, 1, ,
|
|
`ifelse($2, `KEY', ,
|
|
` cmp_value($3,$2) ("$1", $4, ndiffs);
|
|
cmp_fields_r(nextrec($@))')')')
|
|
|
|
define(`cmp_fields', `cmp_fields_r(firstrec($@))')
|
|
|
|
/* -------- */
|
|
/* return the name of the sql field associcate with the primary key */
|
|
|
|
define(`key_fieldname_r', `ifelse($#, 1, ,
|
|
`ifelse($2, `KEY', $1,
|
|
`key_fieldname_r(nextrec($@))')')')
|
|
|
|
define(`key_fieldname', `key_fieldname_r(firstrec($@))')
|
|
|
|
/* -------- */
|
|
/* return the getter function that deals with the version number */
|
|
define(`version_function_r', `ifelse($#, 1, ,
|
|
`ifelse($1, `version', $4,
|
|
`version_function_r(nextrec($@))')')')
|
|
|
|
define(`version_function', `version_function_r(firstrec($@))')
|
|
|
|
/* -------- */
|
|
|
|
define(`store_one_only',
|
|
`
|
|
/* ------------------------------------------------------ */
|
|
/* This routine stores/updates one record in the database.
|
|
* It does not do any traversals, it does not lock.
|
|
* It just pokes the data in.
|
|
*/
|
|
|
|
void
|
|
pgendStoreOne`'func_name($@)`'Only (PGBackend *be,
|
|
xacc_type($@) *ptr,
|
|
sqlBuild_QType update)
|
|
{
|
|
const char *buf;
|
|
ENTER ("be=%p, xacc_type($@)=%p", be, ptr);
|
|
if (!be || !ptr) return;
|
|
|
|
/* build the sql query */
|
|
sqlBuild_Table (be->builder, "tablename($@)", update);
|
|
set_fields($@)
|
|
|
|
buf = sqlBuild_Query (be->builder);
|
|
SEND_QUERY (be,buf, );
|
|
|
|
/* complete/commit the transaction, check the status */
|
|
FINISH_QUERY(be->connection);
|
|
LEAVE (" ");
|
|
}
|
|
|
|
')
|
|
|
|
define(`compare_one_only',
|
|
`
|
|
/* ------------------------------------------------------ */
|
|
/* This routine returns a positive int if the indicated object
|
|
* differs from that in the SQL database. It returns negative
|
|
* number if theres an error.
|
|
* It does not do any traversals, it does not lock.
|
|
*/
|
|
|
|
int
|
|
pgendCompareOne`'func_name($@)`'Only (PGBackend *be, xacc_type($@) *ptr)
|
|
{
|
|
const char *buf;
|
|
PGresult *result;
|
|
int i=0, nrows=0, ndiffs=0;
|
|
|
|
ENTER ("be=%p, xacc_type($@)=%p", be, ptr);
|
|
if (!be || !ptr) return -1;
|
|
|
|
/* build the sql query */
|
|
sqlBuild_Table (be->builder, "tablename($@)", SQL_SELECT);
|
|
set_fields($@)
|
|
|
|
buf = sqlBuild_Query (be->builder);
|
|
SEND_QUERY (be,buf, -1);
|
|
|
|
i=0; nrows=0;
|
|
do {
|
|
GET_RESULTS (be->connection, result);
|
|
IF_ONE_ROW (result, nrows, i) {
|
|
|
|
/* compared queried values to input values */
|
|
cmp_fields($@)
|
|
}
|
|
|
|
PQclear (result);
|
|
i++;
|
|
} while (result);
|
|
|
|
if (0 == nrows) ndiffs = -1;
|
|
LEAVE ("ndiffs=%d", ndiffs);
|
|
return ndiffs;
|
|
}
|
|
|
|
')
|
|
|
|
define(`put_one_only',
|
|
`
|
|
/* ------------------------------------------------------ */
|
|
/* This routine inserts or updates, as appropriate
|
|
* It does not do any traversals, it does not lock.
|
|
* It just updates.
|
|
*/
|
|
|
|
void
|
|
pgendPutOne`'func_name($@)`'Only (PGBackend *be, xacc_type($@) *ptr)
|
|
{
|
|
int ndiffs;
|
|
ndiffs = pgendCompareOne`'func_name($@)`'Only (be, ptr);
|
|
|
|
/* update the record if there are differences ... */
|
|
if (0<ndiffs)
|
|
{
|
|
pgendStoreOne`'func_name($@)`'Only (be, ptr, SQL_UPDATE);
|
|
pgendStoreAudit`'func_name($@)`' (be, ptr, SQL_UPDATE);
|
|
}
|
|
/* insert the record if it doesnt exist */
|
|
if (0>ndiffs)
|
|
{
|
|
pgendStoreOne`'func_name($@)`'Only (be, ptr, SQL_INSERT);
|
|
pgendStoreAudit`'func_name($@)`' (be, ptr, SQL_INSERT);
|
|
}
|
|
}
|
|
|
|
')
|
|
|
|
define(`compare_version',
|
|
`
|
|
/* ------------------------------------------------------ */
|
|
/* This routine compares the version number of the object in
|
|
* the engine and the sql database. It returns a negative
|
|
* number if the sql version is older (or the item is not
|
|
* present in the sql db). It returns a positive number
|
|
* if the sql version is newer. It returns zero if the
|
|
* two are equal.
|
|
*/
|
|
|
|
int
|
|
pgend`'func_name($@)`'CompareVersion (PGBackend *be, xacc_type($@) *ptr)
|
|
{
|
|
char *p;
|
|
int sql_version = 0;
|
|
|
|
p = be->buff; *p = 0;
|
|
p = stpcpy (p, "SELECT version FROM tablename($@) WHERE key_fieldname($@) = ''`");
|
|
p = guid_to_string_buff (&(ptr->guid), p);
|
|
p = stpcpy (p, "''`;");
|
|
SEND_QUERY (be,be->buff, -1);
|
|
sql_version = (int) pgendGetResults (be, get_version_cb, (gpointer) -1);
|
|
|
|
if (-1 == sql_version) return -1;
|
|
return (sql_version - version_function($@));
|
|
}
|
|
|
|
')
|
|
|
|
define(`is_deleted',
|
|
`
|
|
/* ------------------------------------------------------ */
|
|
/* This routine looks at the audit trail to see if the
|
|
* indicated object has been deleted. If it has been,
|
|
* it returns the version number of the deleted object;
|
|
* otherwise it returns -1.
|
|
*/
|
|
|
|
int
|
|
pgend`'func_name($@)`'GetDeletedVersion (PGBackend *be, xacc_type($@) *ptr)
|
|
{
|
|
char *p;
|
|
int sql_version = -1;
|
|
|
|
p = be->buff; *p = 0;
|
|
p = stpcpy (p, "SELECT version FROM tablename($@)" "Trail WHERE key_fieldname($@) = ''`");
|
|
p = guid_to_string_buff (&(ptr->guid), p);
|
|
p = stpcpy (p, "''` AND change = ''`d''`;");
|
|
SEND_QUERY (be,be->buff, -1);
|
|
sql_version = (int) pgendGetResults (be, get_version_cb, (gpointer) -1);
|
|
|
|
return sql_version;
|
|
}
|
|
|
|
')
|
|
|
|
define(`store_audit',
|
|
`
|
|
/* ------------------------------------------------------ */
|
|
/* This routine stores one autdit record in the database.
|
|
* It does not do any traversals, it does not lock.
|
|
* It just pokes the data in.
|
|
*/
|
|
|
|
void
|
|
pgendStoreAudit`'func_name($@)`' (PGBackend *be,
|
|
xacc_type($@) *ptr,
|
|
sqlBuild_QType update)
|
|
{
|
|
const char *buf;
|
|
ENTER ("be=%p, xacc_type($@)=%p", be, ptr);
|
|
if (!be || !ptr) return;
|
|
|
|
/* build the sql query */
|
|
sqlBuild_Table (be->builder, "tablename($@)" "Trail", SQL_INSERT);
|
|
#define sqlBuild_Where_Str sqlBuild_Set_Str
|
|
#define sqlBuild_Where_GUID sqlBuild_Set_GUID
|
|
#define sqlBuild_Where_Int32 sqlBuild_Set_Int32
|
|
set_fields($@)
|
|
#undef sqlBuild_Where_Str
|
|
#undef sqlBuild_Where_GUID
|
|
#undef sqlBuild_Where_Int32
|
|
sqlBuild_Set_Str (be->builder, "date_changed", "NOW");
|
|
/* sqlBuild_Set_GUID (be->builder, "sessionGUID", be->sessionGuid); */
|
|
sqlBuild_Set_Str (be->builder, "sessionGUID", be->session_guid_str);
|
|
sqlBuild_Set_Char (be->builder, "change", update);
|
|
sqlBuild_Set_Char (be->builder, "objtype", ''`obj_type($@)''`);
|
|
|
|
buf = sqlBuild_Query (be->builder);
|
|
SEND_QUERY (be,buf, );
|
|
|
|
/* complete/commit the transaction, check the status */
|
|
FINISH_QUERY(be->connection);
|
|
LEAVE (" ");
|
|
}
|
|
|
|
')
|
|
|
|
divert
|
|
/* DO NOT EDIT THIS FILE -- it is autogenerated -- edit table.m4 instead */
|