mirror of
https://github.com/MariaDB/server.git
synced 2025-01-20 14:02:32 +01:00
602 lines
14 KiB
C++
602 lines
14 KiB
C++
/* Copyright (C) 2003 MySQL AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
#include "Bank.hpp"
|
|
#include <UtilTransactions.hpp>
|
|
|
|
/**
|
|
* Default account types
|
|
*
|
|
*/
|
|
struct AccountTypesStruct {
|
|
int id;
|
|
const char descr[64];
|
|
};
|
|
const AccountTypesStruct accountTypes[] = {
|
|
{ 0, "KASSA"},
|
|
{ 1, "BANKOMAT"},
|
|
{ 2, "POSTGIRO"},
|
|
{ 3, "LÖNEKONTO"},
|
|
{ 4, "SPARKONTO"}
|
|
};
|
|
|
|
const int
|
|
accountTypesSize = sizeof(accountTypes)/sizeof(AccountTypesStruct);
|
|
|
|
|
|
const char* tableNames[] = {
|
|
"GL",
|
|
"ACCOUNT",
|
|
"SYSTEM_VALUES",
|
|
"TRANSACTION",
|
|
"ACCOUNT_TYPE"
|
|
};
|
|
|
|
const int
|
|
tableNamesSize = sizeof(tableNames)/sizeof(const char*);
|
|
|
|
|
|
int Bank::getNumAccountTypes(){
|
|
return accountTypesSize;
|
|
}
|
|
|
|
int Bank::createAndLoadBank(bool ovrWrt, bool disk, int num_accounts){
|
|
|
|
m_ndb.init();
|
|
if (m_ndb.waitUntilReady() != 0)
|
|
return NDBT_FAILED;
|
|
|
|
const NdbDictionary::Table* pSysValTab =
|
|
m_ndb.getDictionary()->getTable("SYSTEM_VALUES");
|
|
if (pSysValTab != NULL){
|
|
// The table exists
|
|
if (ovrWrt == false){
|
|
ndbout << "Bank already exist and overwrite == false" << endl;
|
|
return NDBT_FAILED;
|
|
}
|
|
}
|
|
|
|
if (!m_skip_create && createTables(disk) != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
if (clearTables() != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
if (loadAccountType() != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
if (loadAccount(num_accounts) != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
if (loadSystemValues() != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
if (loadGl() != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
return NDBT_OK;
|
|
|
|
}
|
|
|
|
int Bank::dropBank(){
|
|
|
|
m_ndb.init();
|
|
if (m_ndb.waitUntilReady() != 0)
|
|
return NDBT_FAILED;
|
|
|
|
if (dropTables() != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
|
|
return NDBT_OK;
|
|
|
|
}
|
|
|
|
int Bank::createTables(bool disk){
|
|
for (int i = 0; i < tableNamesSize; i++){
|
|
if (createTable(tableNames[i], disk) != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
}
|
|
return NDBT_OK;
|
|
}
|
|
|
|
|
|
int Bank::dropTables(){
|
|
for (int i = 0; i < tableNamesSize; i++){
|
|
if (dropTable(tableNames[i]) != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
}
|
|
return NDBT_OK;
|
|
}
|
|
|
|
int Bank::clearTables(){
|
|
for (int i = 0; i < tableNamesSize; i++){
|
|
if (clearTable(tableNames[i]) != NDBT_OK)
|
|
return NDBT_FAILED;
|
|
}
|
|
return NDBT_OK;
|
|
}
|
|
|
|
int Bank::clearTable(const char* tabName){
|
|
UtilTransactions util(&m_ndb, tabName);
|
|
if(util.clearTable(&m_ndb, 64) != 0)
|
|
return NDBT_FAILED;
|
|
return NDBT_OK;
|
|
}
|
|
|
|
int Bank::createTable(const char* tabName, bool disk){
|
|
ndbout << "createTable " << tabName << endl;
|
|
|
|
const NdbDictionary::Table* pTab = NDBT_Tables::getTable(tabName);
|
|
if (pTab == NULL)
|
|
return NDBT_FAILED;
|
|
|
|
const NdbDictionary::Table* org =
|
|
m_ndb.getDictionary()->getTable(tabName);
|
|
|
|
if (org != 0 && (disk || pTab->equal(* org)))
|
|
{
|
|
return NDBT_OK;
|
|
}
|
|
|
|
if (org != 0){
|
|
ndbout << "Different table with same name exists" << endl;
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
if (disk)
|
|
{
|
|
if (NDBT_Tables::create_default_tablespace(&m_ndb))
|
|
{
|
|
ndbout << "Failed to create tablespaces" << endl;
|
|
return NDBT_FAILED;
|
|
}
|
|
NdbDictionary::Table copy(* pTab);
|
|
copy.setTablespace("DEFAULT-TS");
|
|
for (Uint32 i = 0; i<copy.getNoOfColumns(); i++)
|
|
copy.getColumn(i)->setStorageType(NdbDictionary::Column::StorageTypeDisk);
|
|
if(m_ndb.getDictionary()->createTable(copy) == -1){
|
|
ndbout << "Failed to create table: " <<
|
|
m_ndb.getNdbError() << endl;
|
|
return NDBT_FAILED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_ndb.getDictionary()->createTable(* pTab) == -1){
|
|
ndbout << "Failed to create table: " <<
|
|
m_ndb.getNdbError() << endl;
|
|
return NDBT_FAILED;
|
|
}
|
|
}
|
|
|
|
return NDBT_OK;
|
|
}
|
|
|
|
int Bank::dropTable(const char* tabName){
|
|
const NdbDictionary::Table* org =
|
|
m_ndb.getDictionary()->getTable(tabName);
|
|
|
|
if (org == NULL)
|
|
return NDBT_OK;
|
|
|
|
ndbout << "dropTable " <<tabName<<endl;
|
|
if (m_ndb.getDictionary()->dropTable(tabName) != 0){
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
return NDBT_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Load SYSTEM_VALUES table
|
|
* This table keeps track of system wide settings
|
|
* For example:
|
|
* - next transaction id
|
|
*
|
|
*/
|
|
int Bank::loadSystemValues (){
|
|
int result;
|
|
|
|
/**
|
|
* Insert start value for next transaction id
|
|
*
|
|
*/
|
|
result = writeSystemValue(LastTransactionId, 0);
|
|
|
|
/**
|
|
* Insert start value for current time
|
|
*
|
|
*/
|
|
result = writeSystemValue(CurrentTime, 1);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Load GL table
|
|
*
|
|
* Insert GL records for time = 0 with balance 0
|
|
*/
|
|
int Bank::loadGl(){
|
|
g_info << "loadGl" << endl;
|
|
int check;
|
|
|
|
NdbConnection* pTrans = m_ndb.startTransaction();
|
|
if (pTrans == NULL){
|
|
ERR(m_ndb.getNdbError());
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
for (int i = 0; i < getNumAccountTypes(); i++){
|
|
|
|
NdbOperation* pOp = pTrans->getNdbOperation("GL");
|
|
if (pOp == NULL) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->insertTuple();
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint64 time = 0;
|
|
check = pOp->equal("TIME", time);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->equal("ACCOUNT_TYPE", i);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint32 balance = 0;
|
|
if (getBalanceForAccountType(i, balance) != NDBT_OK){
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->setValue("BALANCE", balance);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint32 depositCount = 0;
|
|
check = pOp->setValue("DEPOSIT_COUNT", depositCount);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint32 depositSum = 0;
|
|
check = pOp->setValue("DEPOSIT_SUM", depositSum);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint32 withdrawalCount = 0;
|
|
check = pOp->setValue("WITHDRAWAL_COUNT", withdrawalCount);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint32 withdrawalSum = 0;
|
|
check = pOp->setValue("WITHDRAWAL_SUM", withdrawalSum);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
Uint32 purged = 1;
|
|
check = pOp->setValue("PURGED", purged);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
}
|
|
check = pTrans->execute(Commit);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_OK;
|
|
}
|
|
|
|
|
|
int Bank::getBalanceForAccountType(const Uint32 accountType,
|
|
Uint32& balance){
|
|
int check;
|
|
g_info << "getBalanceForAccountType: accountType="<<accountType<<endl;
|
|
|
|
NdbConnection* pScanTrans = m_ndb.startTransaction();
|
|
if (pScanTrans == NULL) {
|
|
ERR(m_ndb.getNdbError());
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
NdbScanOperation* pOp = pScanTrans->getNdbScanOperation("ACCOUNT");
|
|
if (pOp == NULL) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
if( pOp->readTuples() ) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->interpret_exit_ok();
|
|
if( check == -1 ) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
NdbRecAttr* accountTypeRec = pOp->getValue("ACCOUNT_TYPE");
|
|
if( accountTypeRec ==NULL ) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
NdbRecAttr* balanceRec = pOp->getValue("BALANCE");
|
|
if( balanceRec ==NULL ) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pScanTrans->execute(NoCommit);
|
|
if( check == -1 ) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
int eof;
|
|
int rows = 0;
|
|
eof = pOp->nextResult();
|
|
|
|
while(eof == 0){
|
|
rows++;
|
|
Uint32 a = accountTypeRec->u_32_value();
|
|
Uint32 b = balanceRec->u_32_value();
|
|
|
|
if (a == accountType){
|
|
// One record found
|
|
balance += b;
|
|
}
|
|
|
|
eof = pOp->nextResult();
|
|
}
|
|
if (eof == -1) {
|
|
ERR(pScanTrans->getNdbError());
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
m_ndb.closeTransaction(pScanTrans);
|
|
// ndbout << rows << " rows have been read" << endl;
|
|
|
|
return NDBT_OK;
|
|
|
|
}
|
|
|
|
/**
|
|
* Load ACCOUNT_TYPE table
|
|
*
|
|
*
|
|
*/
|
|
int Bank::loadAccountType(){
|
|
g_info << "loadAccountType" << endl;
|
|
int check;
|
|
|
|
NdbConnection* pTrans = m_ndb.startTransaction();
|
|
if (pTrans == NULL){
|
|
ERR(m_ndb.getNdbError());
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
for (int i = 0; i < getNumAccountTypes(); i++){
|
|
|
|
NdbOperation* pOp = pTrans->getNdbOperation("ACCOUNT_TYPE");
|
|
if (pOp == NULL) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->insertTuple();
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->equal("ACCOUNT_TYPE_ID", accountTypes[i].id);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->setValue("DESCRIPTION", accountTypes[i].descr);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
}
|
|
check = pTrans->execute(Commit);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_OK;
|
|
}
|
|
|
|
/**
|
|
* Load ACCOUNT table
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
int Bank::loadAccount (int numAccounts){
|
|
g_info << "loadAccount" << endl;
|
|
int check;
|
|
|
|
NdbConnection* pTrans = m_ndb.startTransaction();
|
|
if (pTrans == NULL){
|
|
ERR(m_ndb.getNdbError());
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
for (int i = 0; i < numAccounts; i++){
|
|
|
|
NdbOperation* pOp = pTrans->getNdbOperation("ACCOUNT");
|
|
if (pOp == NULL) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->insertTuple();
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
check = pOp->equal("ACCOUNT_ID", i);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
int owner;
|
|
if (i == 0)
|
|
owner = 0;
|
|
else
|
|
owner = i + 3000;
|
|
check = pOp->setValue("OWNER", owner);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
// Load balance so that the bank's account = 0 has 10 millions
|
|
// and all other accounts have 10000
|
|
// This set the total balance for the entire bank to
|
|
// 10000000 + (10000 * numAccounts-1)
|
|
// Since no money should dissapear from to the bank nor
|
|
// any money should be added this is a rule that can be checked when
|
|
// validating the db
|
|
int balance;
|
|
if (i == 0){
|
|
balance = 10000000;
|
|
} else {
|
|
balance = 10000;
|
|
}
|
|
check = pOp->setValue("BALANCE", balance);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
// TODO - This is how to set a value in a 16, 1 attribute, not so nice?
|
|
// NOTE - its not even possible to set the value 0 in this column
|
|
// since that is equal to NULL when casting to char*
|
|
// check = pOp->setValue("ACCOUNT_TYPE", (const char*)(Uint16)(i/accountTypesSize), 2);
|
|
// NOTE attribute now changed to be a 32 bit
|
|
|
|
|
|
int accountType;
|
|
if (i == 0)
|
|
accountType = 0; // KASSA
|
|
else
|
|
accountType = ((i%accountTypesSize) == 0 ? 1 : (i%getNumAccountTypes()));
|
|
check = pOp->setValue("ACCOUNT_TYPE", accountType);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
}
|
|
check = pTrans->execute(Commit);
|
|
if( check == -1 ) {
|
|
ERR(pTrans->getNdbError());
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_FAILED;
|
|
}
|
|
|
|
m_ndb.closeTransaction(pTrans);
|
|
return NDBT_OK;
|
|
}
|
|
|
|
|
|
int Bank::getNumAccounts(){
|
|
const NdbDictionary::Table* accountTab =
|
|
m_ndb.getDictionary()->getTable("ACCOUNT");
|
|
if (accountTab == NULL){
|
|
g_err << "Table ACCOUNT does not exist" << endl;
|
|
return NDBT_FAILED;
|
|
}
|
|
UtilTransactions util(*accountTab);
|
|
if(util.selectCount(&m_ndb, 64, &m_maxAccount) != 0)
|
|
return NDBT_FAILED;
|
|
return NDBT_OK;
|
|
}
|
|
|
|
int Bank::getMaxAmount(){
|
|
return 10000;
|
|
}
|