/**
Copyright 2000 - 2003 LogicMatrix. All rights reserved.
This software is distributed under the LogicMatrix Free Software License. This software may be used for any purpose, personal or commercial. Redistributions in binary /source code form are permitted. Commercial redistribution of larger works derived from, or works which bundle this software requires a "Commercial Redistribution License" which can be purchased from LogicMatrix. Contact LogicMatrix for details
Redistributions qualify as Free and non-commercial under one of the following terms:
1) Redistributions are made at no charge beyond the reasonable cost of materials and delivery.
2) Redistributions in binary/source code form must reproduce this Copyright Notice,these license terms, and the disclaimer/limitation of liability set forth as below, in the documentation and/or other materials
provided with the distribution.
Disclaimer
==========
The Software is provided on an "AS IS" basis. No warranty is
provided that the Software is free of defects, or fit for a
particular purpose.
Limitation of Liability
=======================
LogicMatrix shall not be liable for any damages suffered by the Licensee or any third party resulting from use of the Software.
**/
/**
update.cpp
Purpose: Defines classes to parse an UPDATE command
Author: Vijay Mathew Pandyalakal
Date: 21/11/2003
Copyright: logicmatrix
**/
#include <string>
#include <vector>
using namespace std;
#include "db_cxx.h"
#include "sql_lexer.h"
using namespace dsqlm;
#include "mydate.h"
using namespace openutils;
#include "dsql_m_structs.h"
#include "bridge.h"
#include "rec.h"
#include "cmpr.h"
#include "unique.h"
#include "update.h"
#include "sql_utils.h"
#include "bdb_index.h"
using namespace dsqlm;
Update::Update(const char* sql,Database* db) {
if(db == 0) {
throw DsqlMException("Update.cpp - database not inited");
}
m_db = db;
this->sql = sql;
}
void Update::setSql(const char* sql) {
this->sql = sql;
}
long Update::parse() {
SQLLexer lexer(sql.c_str());
vector<string> vct = lexer.tokenize();
int sz = vct.size();
if(sz < 6) {
throw DsqlMException("Not a valid UPDATE command");
}
string s = vct[0];
if((strcmpi(s.c_str(),"UPDATE")) != 0) {
throw DsqlMException("Not a valid UPDATE command");
}
s = vct[1];
Table table(s.c_str(),m_db);
table.open();
SQLUtils utils(m_db);
int wpos = utils.findPos(vct,"WHERE");
int end = wpos;
if(end < 0) {
end = sz;
}
char err_buff[151];
TokenType tt = KW_SET;
vector<Column> vct_update_cols;
vector<string> vct_new_vals;
for(int i=2;i<end;i++) {
s = vct[i];
if(tt == KW_SET) {
if(strcmpi(s.c_str(),"SET") != 0) {
sprintf(err_buff,"Expected SET at %d",(i+1));
throw DsqlMException(err_buff);
}
tt = ID;
}else if(tt == ID) {
Column col = table.getCol(s.c_str());
vct_update_cols.push_back(col);
tt = COPR;
}else if(tt == COPR) {
if(s != "=") {
sprintf(err_buff,"Expected = at %d",(i+1));
throw DsqlMException(err_buff);
}
tt = ANY;
}else if(tt == ANY) {
vct_new_vals.push_back(s);
tt = COMMA;
}else if(tt == COMMA) {
if(s != ",") {
sprintf(err_buff,"Expected , at %d",(i+1));
throw DsqlMException(err_buff);
}
tt = ID;
}
}
if(vct_update_cols.size() != vct_new_vals.size()) {
throw DsqlMException("Not enough values");
}
long ret = 0;
if(wpos < 0) { // no WHERE clause
Rec rec(&table,m_db);
rec.openCursor();
long pos = 0;
Unique uk(&table,m_db);
char pos_str[24];
while(rec.next(&pos)) {
if(rec.isDeleted()) continue;
sprintf(pos_str,"%d",pos);
for(i=0;i<vct_update_cols.size();i++) {
Column col = vct_update_cols[i];
string val = vct_new_vals[i];
string old_val = rec.getField(col.getId());
char *tmp_val = new char[col.getSize() + 1];
try {
rec.updateField(col.getId(),val.c_str(),tmp_val);
if(col.isUnique() == TRUE) {
if(uk.check(col,val.c_str(),pos)) {
sprintf(err_buff,"Duplicates not allowed for %s",col.getTitle().c_str());
delete[] tmp_val;
throw DsqlMException(err_buff);
}else {
char db_name[101];
sprintf(db_name,"%s\\%s_%s_x",m_db->getDBName().c_str(),
table.getName().c_str(),
col.getTitle().c_str());
BdbIndex bdb(db_name,false);
bdb.del(old_val.c_str());
bdb.put(tmp_val,pos_str);
}
}else if(col.isIndexed() == TRUE) {
char db_name[101];
sprintf(db_name,"%s\\%s_%s_x",m_db->getDBName().c_str(),
table.getName().c_str(),
col.getTitle().c_str());
BdbIndex bdb(db_name,false);
bdb.del(old_val.c_str(),pos_str);
bdb.put(tmp_val,pos_str);
}
}catch(DsqlMException ex) {
delete[] tmp_val;
throw DsqlMException(ex.getMessage().c_str());
}
delete[] tmp_val;
}
rec.write(pos);
ret++;
}
}else { // WHERE clause
vector<long> vct_pos;
/**
Copied from select.cpp
**/
TokenType tt = ID;
vector<Column> vct_cols;
vector<ComparissonOperator> vct_coprs;
vector<string> vct_vals;
vector<LogicalOperator> vct_loprs;
SQLUtils utils(m_db);
wpos++;
for(int i=wpos;i<sz;i++) {
s = vct[i];
if(tt == ID) {
Column col = table.getCol(s.c_str());
tt = COPR;
vct_cols.push_back(col);
}else if(tt == COPR) {
vct_coprs.push_back(utils.createComparissonOperator(s.c_str()));
tt = ANY;
}else if(tt == ANY) {
vct_vals.push_back(s);
tt = LOPR;
}else if(tt == LOPR) {
vct_loprs.push_back(utils.createLogicalOperator(s.c_str()));
tt = ID;
}else {
char err_buff[50];
sprintf(err_buff,"Unexpected token at %d",(i+1));
}
}
Cmpr cmpr(&table,m_db,vct_cols,vct_coprs,vct_vals,vct_loprs);
cmpr.run();
long csz = cmpr.getCursorLength();
for(long k=0;k<csz;k++) {
vct_pos.push_back(cmpr.getPos(k));
}
/**
**/
// updation
Rec rec(&table,m_db);
Unique uk(&table,m_db);
char pos_str[24];
for(k=0;k<vct_pos.size();k++) {
long pos = vct_pos[k];
rec.read(pos);
if(rec.isDeleted()) continue;
sprintf(pos_str,"%d",pos);
for(i=0;i<vct_update_cols.size();i++) {
Column col = vct_update_cols[i];
string val = vct_new_vals[i];
string old_val = rec.getField(col.getId());
char *tmp_val = new char[col.getSize() + 1];
try {
rec.updateField(col.getId(),val.c_str(),tmp_val);
if(col.isUnique() == TRUE) {
if(uk.check(col,tmp_val,pos)) {
sprintf(err_buff,"Duplicates not allowed for %s",col.getTitle().c_str());
//delete[] tmp_val;
throw DsqlMException(err_buff);
}else {
char db_name[101];
sprintf(db_name,"%s\\%s_%s_x",m_db->getDBName().c_str(),
table.getName().c_str(),
col.getTitle().c_str());
BdbIndex bdb(db_name,false);
bdb.del(old_val.c_str());
bdb.put(tmp_val,pos_str);
}
}else if(col.isIndexed() == TRUE) {
char db_name[101];
sprintf(db_name,"%s\\%s_%s_x",m_db->getDBName().c_str(),
table.getName().c_str(),
col.getTitle().c_str());
BdbIndex bdb(db_name,false);
bdb.del(old_val.c_str(),pos_str);
bdb.put(tmp_val,pos_str);
}
}catch(DsqlMException ex) {
delete[] tmp_val;
throw DsqlMException(ex.getMessage().c_str());
}
delete[] tmp_val;
}
rec.write(pos);
ret++;
}
}
return ret;
}