/**
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.
**/
/**
cmpr.cpp
Purpose: base comparion services
Author: Vijay Mathew Pandyalakal
Date: 16/11/2003
Copyright: logicmatrix
**/
#include <string>
#include <vector>
//#include <algorithm>
//#include <iostream>
using namespace std;
#include "db_cxx.h"
#include "mydate.h"
#include "mytime.h"
using namespace openutils;
#include "dsql_m_structs.h"
#include "bridge.h"
#include "bdb_index.h"
#include "text.h"
#include "cmpr.h"
#include "rec.h"
using namespace dsqlm;
Cmpr::Cmpr(Table *table,Database* db,vector<Column> vct_c,vector<ComparissonOperator> vct_co,
vector<string> vct_v,vector<LogicalOperator> vct_lo) {
if(vct_c.size() != vct_v.size()) {
throw DsqlMException("Not enough values");
}
if(db == 0) {
throw DsqlMException("Cmpr.cpp - database not inited");
}
m_db = db;
int csz = vct_co.size();
int lsz = vct_lo.size();
if(lsz != (csz-1)) {
throw DsqlMException("Invalid use of operators");
}
this->table = table;
for(int i=0;i<vct_c.size();i++) {
this->vct_cols.push_back(vct_c[i]);
}
for(i=0;i<vct_co.size();i++) {
this->vct_coprs.push_back(vct_co[i]);
}
for(i=0;i<vct_lo.size();i++) {
this->vct_loprs.push_back(vct_lo[i]);
}
for(i=0;i<vct_v.size();i++) {
this->vct_vals.push_back(vct_v[i]);
}
}
void Cmpr::run() {
vct_cur.clear();
int csz = vct_cols.size();
typedef vector<long> VCT_LONG;
vector<VCT_LONG> vct_pos;
int co_idx = 0;
for(int c=0;c<csz;c++) {
Column col = vct_cols[c];
string val = vct_vals[c];
DsqlType type = col.getType();
if(type == CHAR || type == VARCHAR || type == DATE
|| type == TIME) {
char *buff = new char[val.size() + 1];
strcpy(buff,val.c_str());
if(strcmpi(buff,"null") != 0) {
if(buff[0] != '\'') {
delete[] buff;
throw DsqlMException("Not a valid string");
}
int len = strlen(buff);
if(buff[len -1] != '\'') {
delete[] buff;
throw DsqlMException("Unterminated string");
}
val = "";
if(strcmpi(buff,"\'sysdate\'") == 0) {
if(type == DATE) {
openutils::MyDate date;
val = date.getDate();
}else {
throw DsqlMException("Not a date");
}
}else if(strcmpi(buff,"\'systime\'") == 0) {
if(type == TIME) {
openutils::MyTime time;
val = time.getTime();
}else {
throw DsqlMException("Not a time");
}
}else {
for(int i=1;i<(len-1);i++) {
val += buff[i];
}
}
}
delete[] buff;
}
ComparissonOperator copr = vct_coprs[co_idx];
co_idx++;
if(col.isIndexed() == TRUE || col.isUnique() == TRUE) {
bool uk = false;
//if(col.isUnique() == TRUE) uk = true;
char idxfil[80];
sprintf(idxfil,"%s\\%s_%s_x",m_db->getDBName().c_str(),
table->getName().c_str(),
col.getTitle().c_str());
BdbIndex index(idxfil,uk);
if(copr == EQUALS) {
vector<long> vct;
index.get(val.c_str());
long csz = index.getCursorSize();
for(long i=0;i<csz;i++) {
vct.push_back(index.getData(i));
}
//stable_sort(vct.begin(),vct.end());
vct_pos.push_back(vct);
}else {
vector<long> vct;
index.getAll();
long ilen = index.getCursorSize();
Text text;
for(long i=0;i<ilen;i++) {
string key = index.getKey(i);
if(compare(text.trim(key.c_str()).c_str(),text.trim(val.c_str()).c_str(),col.getType(),copr)){
long l = index.getData(i);
vct.push_back(l);
}
}
//stable_sort(vct.begin(),vct.end());
vct_pos.push_back(vct);
}
}else {
int col_num = table->getColumnNumber(col);
Rec rec(table,this->m_db);
rec.openCursor();
long pos = 0;
vector<long> vct;
Text text;
while(rec.next(&pos)) {
if(rec.isDeleted()) continue;
rec.read(pos);
string key = rec.getField(col_num);
if(compare(text.trim(key.c_str()).c_str(),text.trim(val.c_str()).c_str()
,col.getType(),copr)){
vct.push_back(pos);
}
}
//stable_sort(vct.begin(),vct.end());
vct_pos.push_back(vct);
}
}
int lidx = 0;
int lsz = vct_loprs.size();
if(lsz <= 0) {
for(int i=0;i<vct_pos.size();i++) {
VCT_LONG v = vct_pos[i];
for(long j=0;j<v.size();j++) {
vct_cur.push_back(v[j]);
}
}
}
bool first = true;
VCT_LONG v1;
VCT_LONG v2;
for(int i=0;i<lsz;i++) {
LogicalOperator lopr = vct_loprs[i];
if(first) {
v1 = vct_pos[lidx++];
first = false;
}else {
v1.clear();
for(int h=0;h<vct_cur.size();h++) {
v1.push_back(vct_cur[h]);
}
vct_cur.clear();
}
v2 = vct_pos[lidx++];
long s1 = v1.size();
long s2 = v2.size();
long idx = __max(s1,s2);
//cout << endl;
for(long u=0;u<idx;u++) {
for(long j=0;j<idx;j++) {
long p1 = 0;
long p2 = 0;
if(u < s1) {
p1 = v1[u];
}else {
p1 = -1;
}
if( j < s2) {
p2 = v2[j];
}else {
p2 = -1;
}
if(lopr == AND) {
if(p1 == p2) {
//cout << "p1 AND p2: " << p1 << " AND " << p2 << endl;
vct_cur.push_back(p1);
}
}else {
if(p1 != -1) {
//cout << "p1 OR p2: " << p1 << " OR " << p2 << endl;
vct_cur.push_back(p1);
}
if(p2 != -1) {
vct_cur.push_back(p2);
}
}
}
}
}
removeDuplicates();
}
bool Cmpr::compare(const char* val1,const char* val2,DsqlType type,
ComparissonOperator opr) {
if(strcmpi(val2,"null") == 0) {
if(opr != EQUALS && opr != NOT_EQUALS) {
throw DsqlMException("Only = and <> supported for NULLs");
}
}
if(opr == EQUALS) {
return equals(val1,val2,type);
}else if(opr == NOT_EQUALS) {
return notEquals(val1,val2,type);
}else if(opr == GREATER_THAN) {
return greaterThan(val1,val2,type);
}else if(opr == LESSER_THAN) {
return lesserThan(val1,val2,type);
}else if(opr == GREATER_THAN_OR_EQUAL_TO) {
return greaterThanOrEqualTo(val1,val2,type);
}else if(opr == LESSER_THAN_OR_EQUAL_TO) {
return lesserThanOrEqualTo(val1,val2,type);
}else if(opr == LIKE) {
return like(val1,val2,type);
}else {
throw DsqlMException("Invalid comparison operator");
}
}
// private section
// comparison functions
bool Cmpr::equals(const char* val1,const char* val2,DsqlType type) {
if(strcmpi(val2,"null") == 0) {
if(strcmpi(val1,val2) == 0) {
return true;
}else {
return false;
}
}
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
if(strcmp(val1,val2) == 0) {
return true;
}else {
return false;
}
}else if(type == SMALLINT || type == INT || type == BIGINT
|| type == UID || type == AUTOID) {
long v1 = atol(val1);
long v2 = atol(val2);
return (v1 == v2);
}else if(type ==FLOAT || type == DOUBLE) {
double v1 = (double)atof(val1);
double v2 = (double)atof(val2);
return (v1 == v2);
}else if(type == BOOL) {
int v1 = 0;
int v2 = 0;
if((strcmpi(val1,"true") == 0) || (strcmpi(val1,"1") == 0)) {
v1 = 1;
}else if((strcmpi(val1,"false") == 0) || (strcmpi(val1,"0") == 0)) {
v1 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
if((strcmpi(val2,"true") == 0) || (strcmpi(val2,"1") == 0)) {
v2 = 1;
}else if((strcmpi(val2,"false") == 0) || (strcmpi(val2,"0") == 0)) {
v2 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
return (v1 == v2);
}else if(type == DATE) {
try {
openutils::MyDate date1(val1);
openutils::MyDate date2(val2);
return date1 == date2;
}catch(openutils::MyDateException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else if(type == TIME) {
try {
openutils::MyTime time1(val1);
openutils::MyTime time2(val2);
return time1 == time2;
}catch(openutils::MyTimeException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else {
throw DsqlMException("Comparison not supported for this type");
}
}
bool Cmpr:: notEquals(const char* val1,const char* val2,DsqlType type) {
if(strcmpi(val2,"null") == 0) {
if(strcmpi(val1,val2) != 0) {
return true;
}else {
return false;
}
}
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
if(strcmpi(val1,val2) != 0) {
return true;
}else {
return false;
}
}else if(type == SMALLINT || type == INT || type == BIGINT
|| type == UID || type == AUTOID) {
long v1 = atol(val1);
long v2 = atol(val2);
return (v1 != v2);
}else if(type ==FLOAT || type == DOUBLE) {
double v1 = (double)atof(val1);
double v2 = (double)atof(val2);
return (v1 != v2);
}else if(type == BOOL) {
int v1 = 0;
int v2 = 0;
if((strcmpi(val1,"true") == 0) || (strcmpi(val1,"1") == 0)) {
v1 = 1;
}else if((strcmpi(val1,"false") == 0) || (strcmpi(val1,"0") == 0)) {
v1 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
if((strcmpi(val2,"true") == 0) || (strcmpi(val2,"1") == 0)) {
v2 = 1;
}else if((strcmpi(val2,"false") == 0) || (strcmpi(val2,"0") == 0)) {
v2 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
return (v1 != v2);
}else if(type == DATE) {
try {
openutils::MyDate date1(val1);
openutils::MyDate date2(val2);
return date1 != date2;
}catch(openutils::MyDateException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else if(type == TIME) {
try {
openutils::MyTime time1(val1);
openutils::MyTime time2(val2);
return time1 != time2;
}catch(openutils::MyTimeException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else {
throw DsqlMException("Comparison not supported for this type");
}
}
bool Cmpr:: greaterThan(const char* val1,const char* val2,DsqlType type){
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
if(strcmpi(val1,val2) > 0) {
return true;
}else {
return false;
}
}else if(type == DATE) {
try {
openutils::MyDate date1(val1);
openutils::MyDate date2(val2);
return (date1 > date2);
}catch(openutils::MyDateException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else if(type == SMALLINT || type == INT || type == BIGINT
|| type == UID || type == AUTOID) {
long v1 = atol(val1);
long v2 = atol(val2);
return (v1 > v2);
}else if(type ==FLOAT || type == DOUBLE) {
double v1 = (double)atof(val1);
double v2 = (double)atof(val2);
return (v1 > v2);
}else if(type == BOOL) {
int v1 = 0;
int v2 = 0;
if((strcmpi(val1,"true") == 0) || (strcmpi(val1,"1") == 0)) {
v1 = 1;
}else if((strcmpi(val1,"false") == 0) || (strcmpi(val1,"0") == 0)) {
v1 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
if((strcmpi(val2,"true") == 0) || (strcmpi(val2,"1") == 0)) {
v2 = 1;
}else if((strcmpi(val2,"false") == 0) || (strcmpi(val2,"0") == 0)) {
v2 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
return (v1 > v2);
}else if(type == TIME) {
try {
openutils::MyTime time1(val1);
openutils::MyTime time2(val2);
return time1 > time2;
}catch(openutils::MyTimeException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else {
throw DsqlMException("Comparison not supported for this type");
}
}
bool Cmpr:: lesserThan(const char* val1,const char* val2,DsqlType type){
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
if(strcmpi(val1,val2) < 0) {
return true;
}else {
return false;
}
}else if(type == DATE) {
try {
openutils::MyDate date1(val1);
openutils::MyDate date2(val2);
return (date1 < date2);
}catch(openutils::MyDateException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else if(type == SMALLINT || type == INT
|| type == BIGINT || type == UID || type == AUTOID) {
long v1 = atol(val1);
long v2 = atol(val2);
return (v1 < v2);
}else if(type ==FLOAT || type == DOUBLE) {
double v1 = (double)atof(val1);
double v2 = (double)atof(val2);
return (v1 < v2);
}else if(type == BOOL) {
int v1 = 0;
int v2 = 0;
if((strcmpi(val1,"true") == 0) || (strcmpi(val1,"1") == 0)) {
v1 = 1;
}else if((strcmpi(val1,"false") == 0) || (strcmpi(val1,"0") == 0)) {
v1 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
if((strcmpi(val2,"true") == 0) || (strcmpi(val2,"1") == 0)) {
v2 = 1;
}else if((strcmpi(val2,"false") == 0) || (strcmpi(val2,"0") == 0)) {
v2 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
return (v1 < v2);
}else if(type == TIME) {
try {
openutils::MyTime time1(val1);
openutils::MyTime time2(val2);
return time1 < time2;
}catch(openutils::MyTimeException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else {
throw DsqlMException("Comparison not supported for this type");
}
}
bool Cmpr:: greaterThanOrEqualTo(const char* val1,const char* val2,DsqlType type){
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
if(strcmpi(val1,val2) >= 0) {
return true;
}else {
return false;
}
}else if(type == DATE) {
try {
openutils::MyDate date1(val1);
openutils::MyDate date2(val2);
return (date1 > date2 || date1 == date2);
}catch(openutils::MyDateException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else if(type == SMALLINT || type == INT
|| type == BIGINT || type == UID || type == AUTOID) {
long v1 = atol(val1);
long v2 = atol(val2);
return (v1 >= v2);
}else if(type ==FLOAT || type == DOUBLE) {
double v1 = (double)atof(val1);
double v2 = (double)atof(val2);
return (v1 >= v2);
}else if(type == BOOL) {
int v1 = 0;
int v2 = 0;
if((strcmpi(val1,"true") == 0) || (strcmpi(val1,"1") == 0)) {
v1 = 1;
}else if((strcmpi(val1,"false") == 0) || (strcmpi(val1,"0") == 0)) {
v1 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
if((strcmpi(val2,"true") == 0) || (strcmpi(val2,"1") == 0)) {
v2 = 1;
}else if((strcmpi(val2,"false") == 0) || (strcmpi(val2,"0") == 0)) {
v2 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
return (v1 >= v2);
}else if(type == TIME) {
try {
openutils::MyTime time1(val1);
openutils::MyTime time2(val2);
return ((time1 > time2) || (time1 == time2));
}catch(openutils::MyTimeException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else {
throw DsqlMException("Comparison not supported for this type");
}
}
bool Cmpr:: lesserThanOrEqualTo(const char* val1,const char* val2,DsqlType type){
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
if(strcmpi(val1,val2) <= 0) {
return true;
}else {
return false;
}
}else if(type == DATE) {
try {
openutils::MyDate date1(val1);
openutils::MyDate date2(val2);
return (date1 < date2 || date1 == date2);
}catch(openutils::MyDateException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else if(type == SMALLINT || type == INT
|| type == BIGINT || type == UID || type == AUTOID) {
long v1 = atol(val1);
long v2 = atol(val2);
return (v1 <= v2);
}else if(type ==FLOAT || type == DOUBLE) {
double v1 = (double)atof(val1);
double v2 = (double)atof(val2);
return (v1 <= v2);
}else if(type == BOOL) {
int v1 = 0;
int v2 = 0;
if((strcmpi(val1,"true") == 0) || (strcmpi(val1,"1") == 0)) {
v1 = 1;
}else if((strcmpi(val1,"false") == 0) || (strcmpi(val1,"0") == 0)) {
v1 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
if((strcmpi(val2,"true") == 0) || (strcmpi(val2,"1") == 0)) {
v2 = 1;
}else if((strcmpi(val2,"false") == 0) || (strcmpi(val2,"0") == 0)) {
v2 = 0;
}else {
throw DsqlMException("Not a valid boolean value");
}
return (v1 <= v2);
}else if(type == TIME) {
try {
openutils::MyTime time1(val1);
openutils::MyTime time2(val2);
return ((time1 < time2) || (time1 == time2));
}catch(openutils::MyTimeException ex) {
throw DsqlMException(ex.getMessage().c_str());
}
}else {
throw DsqlMException("Comparison not supported for this type");
}
}
bool Cmpr::like(const char* val1,const char* val2,DsqlType type){
if(type == CHAR || type == VARCHAR || type == TIMESTAMP) {
int len1 = strlen(val1);
int len2 = strlen(val2);
if(len2 <= len1) {
for(int i=0;i<len2;i++) {
if(val1[i] != val2[i]) {
return false;
}
}
return true;
}else {
return false;
}
}else {
throw DsqlMException("LIKE not supported for this type");
}
}
long Cmpr::getCursorLength() {
return (long)vct_cur.size();
}
long Cmpr::getPos(long idx) {
if(idx < 0 || idx >= vct_cur.size()) {
throw DsqlMException("Invalid cursor position (Cmpr.obj)");
}
return vct_cur[idx];
}
void Cmpr::removeDuplicates() {
vector<long> tmp;
long csz = vct_cur.size();
for(long i=0;i<csz;i++) {
long l = vct_cur[i];
long tsz = tmp.size();
bool dup = false;
for(long j=0;j<tsz;j++) {
if(l == tmp[j]) {
dup = true;
break;
}
}
if(!dup) {
tmp.push_back(l);
}
}
vct_cur.clear();
for(i=0;i<tmp.size();i++) {
vct_cur.push_back(tmp[i]);
}
}