/*************************************************************************** shopDB.cpp - description ------------------- begin : Sun May 13 2001 copyright : (C) 2001 by Jes?s David D?az Leal email : address@hidden ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #define _GNU_SOURCE // This is for asprintf. It has an effect on stdio.h #include "shopDB.h" // This line need to be after _GNU_SOURCE due to it load stdio.h via #include #include #include #include #include #include #include #include #define TryRollback(db) \ if (!db->ExecCommandOk("ROLLBACK")) \ { error = "Fatal database error"; return SSERR_FATAL; } ShopDB::ShopDB() { this->error = NULL; this->state = STATE_NOT_LOGIN; this->current_transaction_id = -1; this->current_transform_id = -1; this->current_InventorySync_id = -1; this->appid = NULL; this->username = NULL; this->dbname = "shop"; this->dbhost = "localhost"; this->dbport = 0; this->magick_product = MAGICK_NONE; } enum ss_error ShopDB::open() { // parse("/etc/shopsuiterc"); char* tmp; asprintf(&tmp, "%s/.shopsuiterc", getenv("HOME")); parse(tmp); free(tmp); // parse("shopsuiterc"); if (this->appid == NULL) return SSERR_NOAPPID; return SSERR_OK; } enum ss_error ShopDB::login(const char* passwd) { char *dbstring; char *tmp = ""; if (dbport) asprintf(&tmp, " port=%d", this->dbport); asprintf (&dbstring, "dbname=%s password=%s%s%s%s%s%s", dbname, passwd, (dbhost?" host=":""), (dbhost?dbhost:""), (username?" user=":""), (username?username:""), tmp); if (dbport) free(tmp); this->db = new PgDatabase(dbstring); if (this->db->Status() == CONNECTION_BAD) { asprintf(&this->error, "Can't log in to the data base: %s", this->db->ErrorMessage()); delete this->db; return SSERR_ERROR; } this->state = STATE_LOGIN; return SSERR_OK; } enum ss_error ShopDB::parse(const char* filename) { char* buf1=NULL; char* buf2=NULL; int n1=0,n2=0; int i; int fd; int l0,l1; fd = ::open(filename, O_RDONLY); if (fd==-1) { fprintf(stderr,"\n %s \n", strerror(errno) ); return SSERR_CANTOPEN; } buf2 = (char*)malloc(4096); //XXX-Davi: XXX-Tomasz: Why this use of 4096? //XXX-Davi: User instead of while ((n2 = read(fd, buf2, 4096))) { buf1 = (char*)realloc(buf1, n1 + n2); memcpy(buf1 + n1, buf2, n2); n1 += n2; } free(buf2); ::close(fd); l0 = l1 = 0; for (i=0;idbname = (char*)malloc(i-l1); memcpy(this->dbname, buf1+l1+1, i-l1-1); this->dbname [i-l1-1] = 0; } else if (strncmp(buf1+l0, "dbhost", 6)==0) { this->dbhost = (char*)malloc(i-l1); memcpy(this->dbhost, buf1+l1+1, i-l1-1); this->dbhost [i-l1-1] = 0; } else if (strncmp(buf1+l0, "username", 8)==0) { this->username = (char*)malloc(i-l1); memcpy(this->username, buf1+l1+1, i-l1-1); this->username [i-l1-1] = 0; } else if (strncmp(buf1+l0, "appid", 5)==0) { this->appid = (char*)malloc(i-l1); memcpy(this->appid, buf1+l1+1, i-l1-1); this->appid [i-l1-1] = 0; } else if (strncmp(buf1+l0, "dbport", 6)==0) { this->dbport = atoi(buf1+l1+1); } else if (strncmp(buf1+l0, "font", 4) == 0) { this->font = (char*) malloc(i - l1); memcpy(this->font, buf1 + l1 + 1, i - l1 - 1); this->font[i - l1 - 1] = 0; } l0 = i + 1; } } return SSERR_OK; } // should have special error if unit already exists enum ss_error ShopDB::addMeasureUnit(const char* unit) { char* tmp; if (this->state != STATE_LOGIN) { this->error = "Wrong state, can't add unit"; return SSERR_STATE; } if (!unit) return SSERR_OK; asprintf(&tmp, "INSERT INTO measurementunits VALUES ('%s')", unit); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't add unit: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } // XXX: should have special error if unit doesn't exist enum ss_error ShopDB::delMeasureUnit(const char* unit) { char* tmp; if (this->state != STATE_LOGIN) { this->error = "Wrong state, can't delete unit"; return SSERR_STATE; } if (!unit) return SSERR_OK; asprintf(&tmp, "DELETE FROM measurementunits WHERE unit='%s'", unit); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't delete unit: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::keepTransform(const char* shortdsc) { // If there is current transform, then unactivate and keep it into the history char* tmp; asprintf(&tmp, "SELECT prodid_out,transformid FROM products,transform WHERE prodid=prodid_out AND shortdsc='%s' AND products.active=true AND transform.inactivation IS NULL", shortdsc); ExecStatusType status; status = this->db->Exec(tmp); free(tmp); switch(status) { case PGRES_TUPLES_OK: // if the query successfully returned tuples { int n=-1; n = this->db->Tuples(); switch(n) { case 0: // no previous transform break; case 1:{ int prodid_out =-1; int transformid=-1; prodid_out = atoi(db->GetValue (0,"prodid_out")); transformid= atoi(db->GetValue (0,"transformid")); char* tmp; asprintf(&tmp, "UPDATE transform SET inactivation='NOW' WHERE prodid_out=%d", prodid_out); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(this->db); asprintf(&this->error, "Can't change transform: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); break; } default: asprintf(&this->error, "Unexpected number of tuples: %d", n); return SSERR_ERROR; break; } } break; case PGRES_EMPTY_QUERY: case PGRES_COMMAND_OK: // if the query was a command case PGRES_COPY_OUT: case PGRES_COPY_IN: case PGRES_BAD_RESPONSE: // if an unexpected response was received case PGRES_NONFATAL_ERROR: case PGRES_FATAL_ERROR: default: asprintf(&this->error, "Unexpected condition"); return SSERR_ERROR; break; } return SSERR_OK; } enum ss_error ShopDB::startTransform(const char* shortdsc) { if (state != STATE_LOGIN) { this->error = "Wrong state, can't add transform"; return SSERR_STATE; } if (!this->db->ExecCommandOk("BEGIN")) { asprintf(&this->error, "Can't add transform: %s", this->db->ErrorMessage()); return SSERR_ERROR; } char* tmp; asprintf(&tmp, "INSERT INTO transform VALUES ((SELECT prodid FROM products WHERE shortdsc='%s'), NULL, NULL)", shortdsc); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(this->db); asprintf(&this->error, "Can't change transform: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); asprintf(&tmp, "SELECT transformid FROM transform WHERE oid = %s", this->db->OidStatus()); if (!this->db->ExecTuplesOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change transform: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); this->current_transform_id = atoi(this->db->GetValue(0, "transformid")); this->state = STATE_TRANSFORM; return SSERR_OK; } enum ss_error ShopDB::addIngredient(const char* shortdsc, const char* amount) { if (state != STATE_TRANSFORM) { this->error = "Wrong state, can't add transform ingredient"; return SSERR_STATE; } char* tmp; asprintf(&tmp, "INSERT INTO transform_ingredient VALUES (%d,(SELECT prodid FROM products WHERE shortdsc='%s'),'%s')", this->current_transform_id, shortdsc, amount); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change transform ingredient: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } void ShopDB::close() { switch (this->state) { case STATE_TRANSACTION: case STATE_TRANSFORM: case STATE_INVENTORYSYNC: // rollback case STATE_LOGIN: delete this->db; state = STATE_NOT_LOGIN; break; case STATE_NOT_LOGIN: break; } } enum ss_error ShopDB::newProd(const char* shortdsc, const char* longdsc, const char* unitPrice) { char* tmp; if (unitPrice!=NULL) { asprintf(&tmp, "INSERT INTO products VALUES ('%s', '%s', '%s', '0/1', 'NULL yet', TRUE)", shortdsc, longdsc, unitPrice); }else{ asprintf(&tmp, "INSERT INTO products VALUES ('%s', '%s', NULL, '0/1', 'NULL yet', TRUE)", shortdsc, longdsc); } if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't add product: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::updateProd(const char* shortdsc, const char* longdsc, const char* unitPrice) { char* tmp; if (unitPrice!=NULL) { asprintf(&tmp, "UPDATE products SET longdsc='%s', sellprice='%s' WHERE shortdsc='%s'", longdsc, unitPrice, shortdsc); }else{ asprintf(&tmp, "UPDATE products SET longdsc='%s', sellprice=NULL WHERE shortdsc='%s'", longdsc, shortdsc); } if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't update product: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::setStock(const char* prod, const char* stock) { char* tmp; asprintf(&tmp, "UPDATE products SET stock=%s WHERE shortdsc='%s'", stock, prod); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't set stock: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::setPrice(const char* prod, float price) { char* tmp; asprintf(&tmp, "UPDATE products SET sellprice=%f WHERE shortdsc='%s'", price, prod); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't change price: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::setProdActive(const char* prod, bool active) { //(XXX-Tomasz): Unactivate from the data base. (Notify postgres feature) char* tmp; asprintf(&tmp, "UPDATE products SET active=%s WHERE shortdsc='%s'", active?"TRUE":"FALSE", prod); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't change activity: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::endTransform() { if (this->state != STATE_TRANSFORM) { this->error = "Wrong state, can't finish adding transform"; return SSERR_STATE; } this->state = STATE_LOGIN; this->current_transform_id = -1; if (!this->db->ExecCommandOk("COMMIT")) return SSERR_ERROR; return SSERR_OK; } char** ShopDB::report_units() { char** units; int i,n; if (!this->db->ExecTuplesOk("SELECT unit FROM measurementunits")) { asprintf(&this->error, "Can't get units list: %s", this->db->ErrorMessage()); return NULL; } n = this->db->Tuples(); units = (char**) malloc(sizeof(char*) * (n+1)); for (i=0; idb->GetValue (i, "unit")); units[n] = NULL; return units; } //XXX-Davi Maybe the login window could ask for the login name, db name, etc, beside the password. // I do not know now if it could be good idea. I will think about it later. const ProdsToSell* ShopDB::createProdsToSell() { ProdsToSell* prods; int i,n; if (!this->db->ExecTuplesOk("SELECT shortdsc,longdsc,unit,sellprice,prodid FROM ProdsToSell ORDER BY shortdsc")) { asprintf(&this->error, "Can't get products to sell list: %s", this->db->ErrorMessage()); return NULL; } n = this->db->Tuples(); prods = new ProdsToSell[n+1]; for (i=0; iGetValue (i,"prodid")); prods[i].shortdsc = strdup (db->GetValue (i,"shortdsc")); //XXX-Davi: Warning: limit to 11 USE CONSTANT. What happens if the DB keeps a > 11 ? Is the chars not showed? Must the DB be 11 chars? prods[i].longdsc = strdup (db->GetValue (i,"longdsc")); prods[i].unit = strdup (db->GetValue (i,"unit")); prods[i].price = strdup (db->GetValue (i,"sellprice")); } prods[n].code = 0; prods[n].shortdsc = NULL; prods[n].longdsc = NULL; prods[n].unit = NULL; prods[n].price = NULL; return prods; } const ProdsToBuy* ShopDB::createProdsToBuy() { ProdsToBuy* prods; int i,n; if (!this->db->ExecTuplesOk("SELECT shortdsc,longdsc,unit,stock,prodid FROM ProdsToBuy ORDER BY shortdsc")) { asprintf(&this->error, "Can't get products to buy list: %s", this->db->ErrorMessage()); return NULL; } n = this->db->Tuples(); prods = new ProdsToBuy[n+1]; for (i=0; iGetValue (i,"prodid")); prods[i].shortdsc = strdup (db->GetValue (i,"shortdsc")); //XXX-Davi: Warning: limit to 11 USE CONSTANT. What happens if the DB keeps a > 11 ? Is the chars not showed? Must the DB be 11 chars? prods[i].longdsc = strdup (db->GetValue (i,"longdsc")); prods[i].unit = strdup (db->GetValue (i,"unit")); prods[i].stock = strdup (db->GetValue (i,"stock")); } prods[n].code = 0; prods[n].shortdsc = NULL; prods[n].longdsc = NULL; prods[n].unit = NULL; prods[n].stock = 0; return prods; } const Ingredients* ShopDB::createIngredients(const char* shortdsc) { char* tmp; asprintf(&tmp, "SELECT (SELECT shortdsc FROM products WHERE prodid=prodid_in) as shortdsc,amount FROM products,transform,transform_ingredient WHERE prodid=prodid_out AND transform.transformid=transform_ingredient.transformid AND products.active=true AND transform.inactivation=NULL AND shortdsc='%s'", shortdsc); if (!this->db->ExecTuplesOk(tmp)) { free(tmp); asprintf(&this->error, "Can't get products to buy list: %s", this->db->ErrorMessage()); return NULL; } free(tmp); int n; n = this->db->Tuples(); Ingredients* ingredients; ingredients = new Ingredients[n+1]; int i; for (i=0; iGetValue (i,"shortdsc")); //XXX-Davi: Warning: limit to 11 USE CONSTANT. What happens if the DB keeps a > 11 ? Is the chars not showed? Must the DB be 11 chars? ingredients[i].amount = strdup (db->GetValue (i,"amount")); } ingredients[n].shortdsc = NULL; ingredients[n].amount = NULL; return ingredients; } enum ss_error ShopDB::setNotes_currentTransform(const char* text) { if (state != STATE_TRANSFORM) { this->error = "Wrong state, can't add input to the transform"; return SSERR_STATE; } char* tmp; asprintf(&tmp, "UPDATE transform SET notes='%s' WHERE transformid=%d", text, this->current_transform_id); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't set transform notes: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::startTransaction() { if (state != STATE_LOGIN) { this->error = "Wrong state, can't add trading"; return SSERR_STATE; } if (!this->db->ExecCommandOk("BEGIN")) { asprintf(&this->error, "Can't add input to the trading: %s", this->db->ErrorMessage()); return SSERR_ERROR; } char* tmp; asprintf(&tmp, "INSERT INTO operations VALUES ('NOW', 'XXX-Davi empty yet', 'XXX-Davi empty yet')"); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(this->db); asprintf(&this->error, "Can't change operations: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); asprintf(&tmp, "SELECT opid FROM operations WHERE oid = %s", this->db->OidStatus()); if (!this->db->ExecTuplesOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change operations: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); this->current_transaction_id = atoi(this->db->GetValue(0, "opid")); this->state = STATE_TRANSACTION; return SSERR_OK; } enum ss_error ShopDB::setNotes_currentTransaction(const char* text) { if (state != STATE_TRANSACTION) { this->error = "Wrong state, can't add input to the trading"; return SSERR_STATE; } char* tmp; asprintf(&tmp, "UPDATE operations SET notes='%s' WHERE opid=%d", text, this->current_transaction_id); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't set operations notes: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::setUserID_currentTransaction(const char* userID) { if (state != STATE_TRANSACTION) { this->error = "Wrong state, can't add input to the trading"; return SSERR_STATE; } char* tmp; asprintf(&tmp, "UPDATE operations SET userid='%s' WHERE opid=%d", userID, this->current_transaction_id); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't set operations userID: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::endTransaction() { if (this->state != STATE_TRANSACTION) { this->error = "Wrong state, can't finish adding trade transaction"; return SSERR_STATE; } this->state = STATE_LOGIN; this->current_transaction_id = -1; if (!this->db->ExecCommandOk("COMMIT")) return SSERR_ERROR; return SSERR_OK; } enum ss_error ShopDB::purchase(const char* shortdsc, const char* amount, float cost) { if (state != STATE_TRANSACTION) { this->error = "Wrong state, can't add input to the trading"; return SSERR_STATE; } // The stock of the product which have been bought is updated char* tmp; asprintf(&tmp, "UPDATE products SET stock = (SELECT stock FROM products WHERE shortdsc='%s') + rational('%s') WHERE shortdsc='%s'", shortdsc, amount, shortdsc); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change product stock: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); // A new row is added to the tradehistory table asprintf(&tmp, "INSERT INTO TradeHistory VALUES (%d, (SELECT prodid FROM products WHERE shortdsc='%s'), '%s', %f)", this->current_transaction_id, shortdsc, amount, cost); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't add trade history: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::sell(const char* shortdsc, const char* amount, float price) { if (state != STATE_TRANSACTION) { this->error = "Wrong state, can't add input to the trading"; return SSERR_STATE; } //IIInfo: Although the Stock show 0 (or <0) units of all products // the application can be used to sell. This is to support the case in // which the application's inventory has not been fixed with the // real inventory. // Anyway, it is ridiculous the fact that the waiter want to sell and // the application does not permit it due this issue. // If the sold product is an elaborated one (with ingredients) then the // ingredients stock are updated, for example 'MENU'. If it is not an // elaborated product then the own product stock is subtracted, for // example 'WHISKY'. char* tmp; const Ingredients* ingredients; ingredients = this->createIngredients(shortdsc); if( ingredients!=NULL && ingredients[0].shortdsc != NULL ) { int i; for( i=0; ingredients[i].shortdsc != NULL; i++ ) { // The stock of the product which have been sell is updated asprintf(&tmp, "UPDATE products SET stock = (SELECT stock FROM products WHERE shortdsc='%s') - rational('%s')*rational('%s') WHERE shortdsc='%s'", ingredients[i].shortdsc, ingredients[i].amount, amount, ingredients[i].shortdsc); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change product stock: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); } delete ingredients; // We free the 'ingredients' array }else{ // The stock of the product which have been sell is updated asprintf(&tmp, "UPDATE products SET stock = (SELECT stock FROM products WHERE shortdsc='%s') - rational('%s') WHERE shortdsc='%s'", shortdsc, amount, shortdsc); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change product stock: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); } // A new row is added to the tradehistory table asprintf(&tmp, "INSERT INTO TradeHistory VALUES (%d, (SELECT prodid FROM products WHERE shortdsc='%s'), '-%s', %f)", this->current_transaction_id, shortdsc, amount, price); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't add trade history: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::startInventorySync() { if (state != STATE_LOGIN) { this->error = "Wrong state, can't add inventory deviation"; return SSERR_STATE; } if (!this->db->ExecCommandOk("BEGIN")) { asprintf(&this->error, "Can't add input to the inventory deviation: %s", this->db->ErrorMessage()); return SSERR_ERROR; } char* tmp; asprintf(&tmp, "INSERT INTO operations VALUES ('NOW', 'XXX-Davi empty yet', 'XXX-Davi empty yet')"); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(this->db); asprintf(&this->error, "Can't change operations: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); asprintf(&tmp, "SELECT opid FROM operations WHERE oid = %s", this->db->OidStatus()); if (!this->db->ExecTuplesOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change operations: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); this->current_InventorySync_id = atoi(this->db->GetValue(0, "opid")); this->state = STATE_INVENTORYSYNC; return SSERR_OK; } enum ss_error ShopDB::setNotes_currentInventory(const char* text) { if (state != STATE_INVENTORYSYNC) { this->error = "Wrong state, can't add input to the inventory deviation"; return SSERR_STATE; } char* tmp; asprintf(&tmp, "UPDATE operations SET notes='%s' WHERE opid=%d", text, this->current_InventorySync_id); if (!this->db->ExecCommandOk(tmp)) { free(tmp); asprintf(&this->error, "Can't set operations notes: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::addDeviation(const char* shortdsc, const char* devtype, const char* amount) { if (state != STATE_INVENTORYSYNC) { this->error = "Wrong state, can't add input to the inventory deviation"; return SSERR_STATE; } // The stock of the product which have been fixed is updated char* tmp; asprintf(&tmp, "UPDATE products SET stock = (SELECT stock FROM products WHERE shortdsc='%s') + rational('%s') WHERE shortdsc='%s'", shortdsc, amount, shortdsc); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't change product stock: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); // A new row is added to the InventoryDeviation table asprintf(&tmp, "INSERT INTO InventoryDeviation VALUES (%d, %d, (SELECT prodid FROM products WHERE shortdsc='%s'),'%s')", this->current_InventorySync_id, /* XXX-Davi: See DOC reference: devtype*/ 1, shortdsc, amount); if (!this->db->ExecCommandOk(tmp)) { free(tmp); TryRollback(db); asprintf(&this->error, "Can't add inventory deviation: %s", this->db->ErrorMessage()); return SSERR_ERROR; } free(tmp); return SSERR_OK; } enum ss_error ShopDB::endInventorySync() { if (this->state != STATE_INVENTORYSYNC) { this->error = "Wrong state, can't finish adding input to the inventory deviation"; return SSERR_STATE; } this->state = STATE_LOGIN; this->current_InventorySync_id = -1; if (!this->db->ExecCommandOk("COMMIT")) return SSERR_ERROR; return SSERR_OK; } const char* ShopDB::rationalCalculator(const char* operation) { char* tmp; asprintf(&tmp, "SELECT %s AS result", operation); ExecStatusType status; status = this->db->Exec(tmp); free(tmp); switch(status) { case PGRES_TUPLES_OK: // if the query successfully returned tuples tmp = strdup (db->GetValue (0,"result")); // n = this->db->Tuples(); Have to be always 1 return tmp; break; default: return NULL; break; } } ShopDB::~ShopDB() { }