f65184802d
* NEW: Update copyright and license string in all source files. git-svn-id: svn://localhost/gambas/trunk@2241 867c0c6c-44f3-4631-809d-bfa615b0a4ec
701 lines
14 KiB
C++
701 lines
14 KiB
C++
/***************************************************************************
|
|
|
|
dataset.cpp
|
|
|
|
(c) 2000-2009 Benoît Minisini <gambas@users.sourceforge.net>
|
|
|
|
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
***************************************************************************/
|
|
/**********************************************************************
|
|
* Copyright (c) 2002, Leo Seib, Hannover
|
|
*
|
|
* Project: C++ Dynamic Library
|
|
* Module: Dataset abstraction later realisation file
|
|
* Author: Leo Seib E-Mail: lev@almaty.pointstrike.net
|
|
* Begin: 5/04/2002
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
**********************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <time.h>
|
|
#include <iostream>
|
|
#include <string.h>
|
|
|
|
#include "dataset.h"
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
//************* Database implementation ***************
|
|
|
|
Database::Database()
|
|
{
|
|
active = false; // No connection yet
|
|
error = ""; //S_NO_CONNECTION;
|
|
host = "";
|
|
port = "";
|
|
db = "";
|
|
login = "";
|
|
passwd = "";
|
|
sequence_table = "db_sequence";
|
|
}
|
|
|
|
Database::~Database()
|
|
{
|
|
disconnect(); // Disconnect if connected to database
|
|
}
|
|
|
|
int Database::connectFull(const char *newHost, const char *newPort,
|
|
const char *newDb, const char *newLogin,
|
|
const char *newPasswd)
|
|
{
|
|
host = newHost;
|
|
port = newPort;
|
|
db = newDb;
|
|
login = newLogin;
|
|
passwd = newPasswd;
|
|
return connect();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//************* Dataset implementation ***************
|
|
|
|
Dataset::Dataset()
|
|
{
|
|
|
|
db = NULL;
|
|
haveError = active = false;
|
|
frecno = 0;
|
|
fbof = feof = true;
|
|
autocommit = true;
|
|
|
|
select_sql = "";
|
|
|
|
fields_object = new Fields();
|
|
|
|
edit_object = new Fields();
|
|
}
|
|
|
|
|
|
|
|
Dataset::Dataset(Database * newDb)
|
|
{
|
|
|
|
db = newDb;
|
|
haveError = active = false;
|
|
frecno = 0;
|
|
fbof = feof = true;
|
|
autocommit = true;
|
|
|
|
select_sql = "";
|
|
|
|
fields_object = new Fields();
|
|
|
|
edit_object = new Fields();
|
|
|
|
}
|
|
|
|
|
|
Dataset::~Dataset()
|
|
{
|
|
update_sql.clear();
|
|
insert_sql.clear();
|
|
delete_sql.clear();
|
|
|
|
delete fields_object;
|
|
delete edit_object;
|
|
}
|
|
|
|
|
|
void Dataset::setSqlParams(const char *sqlFrmt, sqlType t, ...)
|
|
{
|
|
va_list ap;
|
|
char sqlCmd[DB_BUFF_MAX + 1];
|
|
|
|
va_start(ap, t);
|
|
vsnprintf(sqlCmd, DB_BUFF_MAX - 1, sqlFrmt, ap);
|
|
va_end(ap);
|
|
|
|
switch (t)
|
|
{
|
|
case sqlSelect:
|
|
set_select_sql(sqlCmd);
|
|
break;
|
|
case sqlUpdate:
|
|
add_update_sql(sqlCmd);
|
|
break;
|
|
case sqlInsert:
|
|
add_insert_sql(sqlCmd);
|
|
break;
|
|
case sqlDelete:
|
|
add_delete_sql(sqlCmd);
|
|
break;
|
|
case sqlExec:
|
|
sql = sqlCmd;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Dataset::set_select_sql(const char *sel_sql)
|
|
{
|
|
select_sql = sel_sql;
|
|
}
|
|
|
|
void Dataset::set_select_sql(const string & sel_sql)
|
|
{
|
|
select_sql = sel_sql;
|
|
}
|
|
|
|
|
|
void Dataset::parse_sql(string & sql)
|
|
{
|
|
string fpattern, by_what;
|
|
|
|
pars.set_str(sql.c_str());
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
{
|
|
fpattern = ":OLD_" + (*fields_object)[i].props.name;
|
|
by_what = "'" + (*fields_object)[i].val.get_asString() + "'";
|
|
//cout << "parsing " << fpattern <<by_what<<"\n\n";
|
|
sql = pars.replace(fpattern, by_what);
|
|
}
|
|
|
|
for (uint i = 0; i < edit_object->size(); i++)
|
|
{
|
|
fpattern = ":NEW_" + (*edit_object)[i].props.name;
|
|
by_what = "'" + (*edit_object)[i].val.get_asString() + "'";
|
|
sql = pars.replace(fpattern, by_what);
|
|
}
|
|
|
|
// StringList before_array, after_array;
|
|
// int tag = 0;
|
|
// bool eol_reached = false,
|
|
// was_changed = false,
|
|
// flag = false;
|
|
// ExtString which_before, which_after;
|
|
// ExtString bef, aft, prev_before, right_side, which_field, changed_field, f_value;
|
|
|
|
// before_array.add(":NEW_", tag);
|
|
// before_array.add(":OLD_", tag);
|
|
|
|
// after_array.add(")", tag);
|
|
// after_array.add(",", tag);
|
|
// after_array.add(" ", tag);
|
|
|
|
// sq.squish();
|
|
// bef = sq.before_arr(before_array, which_before);
|
|
|
|
// while (!(bef == prev_before)) {
|
|
// right_side = sq.after(which_before, flag);
|
|
// right_side.squish();
|
|
|
|
// aft = right_side.after_arr(after_array, which_after);
|
|
// aft.squish();
|
|
// which_field = right_side.before(which_after);
|
|
|
|
// // checking whather we reach end of line
|
|
// if ((which_field == "\0") && (which_before != "\0")) {
|
|
// which_field = right_side;
|
|
// eol_reached = true;
|
|
// }
|
|
|
|
// // If new field and is in insert or edit mode - looks in edit_object
|
|
// if ((which_before == ":NEW_") && (which_field != "\0")) {
|
|
// which_field.squish();
|
|
// f_value.assign(fv(which_field.getChars()));
|
|
// f_value.addslashes();
|
|
// changed_field.assign("'");
|
|
// changed_field + f_value + "'";
|
|
// }
|
|
// else
|
|
// // else looking old value in the current result set
|
|
// if ((which_before == ":OLD_") && (which_field != "\0")) {
|
|
// which_field.squish();
|
|
// f_value.assign(f_old(which_field.getChars()));
|
|
// f_value.addslashes();
|
|
// changed_field.assign("'");
|
|
// changed_field + f_value + "'";
|
|
// }
|
|
|
|
// if (!eol_reached) {
|
|
|
|
// sq.assign(bef + changed_field + which_after + aft);
|
|
// }
|
|
// else {
|
|
// if (!was_changed && (which_field != "\0")) {
|
|
|
|
// sq.assign(bef + changed_field + which_after + aft);
|
|
// was_changed = true;
|
|
// }
|
|
// }
|
|
|
|
|
|
// prev_before = bef;
|
|
// bef = sq.before_arr(before_array, which_before);
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
|
void Dataset::close(void)
|
|
{
|
|
haveError = false;
|
|
frecno = 0;
|
|
fbof = feof = true;
|
|
active = false;
|
|
}
|
|
|
|
|
|
//bool Dataset::seek(int pos=0) {
|
|
bool Dataset::seek(int pos)
|
|
{
|
|
frecno = (pos < num_rows() - 1) ? pos : num_rows() - 1;
|
|
frecno = (frecno < 0) ? 0 : frecno;
|
|
fbof = feof = (num_rows() == 0) ? true : false;
|
|
return frecno;
|
|
}
|
|
|
|
|
|
void Dataset::refresh()
|
|
{
|
|
int row = frecno;
|
|
|
|
if ((row != 0) && active)
|
|
{
|
|
close();
|
|
open();
|
|
seek(row);
|
|
}
|
|
else
|
|
open();
|
|
}
|
|
|
|
|
|
void Dataset::first()
|
|
{
|
|
if (ds_state == dsSelect)
|
|
{
|
|
frecno = 0;
|
|
feof = fbof = (num_rows() > 0) ? false : true;
|
|
}
|
|
}
|
|
|
|
void Dataset::next()
|
|
{
|
|
if (ds_state == dsSelect)
|
|
{
|
|
fbof = false;
|
|
if (frecno < num_rows() - 1)
|
|
{
|
|
frecno++;
|
|
feof = false;
|
|
}
|
|
else
|
|
feof = true;
|
|
if (num_rows() <= 0)
|
|
fbof = feof = true;
|
|
}
|
|
}
|
|
|
|
void Dataset::prev()
|
|
{
|
|
if (ds_state == dsSelect)
|
|
{
|
|
feof = false;
|
|
if (frecno)
|
|
{
|
|
frecno--;
|
|
fbof = false;
|
|
}
|
|
else
|
|
fbof = true;
|
|
if (num_rows() <= 0)
|
|
fbof = feof = true;
|
|
}
|
|
}
|
|
|
|
void Dataset::last()
|
|
{
|
|
if (ds_state == dsSelect)
|
|
{
|
|
frecno = (num_rows() > 0) ? num_rows() - 1 : 0;
|
|
feof = fbof = (num_rows() > 0) ? false : true;
|
|
}
|
|
}
|
|
|
|
//bool Dataset::goto_rec(int pos=1) {
|
|
bool Dataset::goto_rec(int pos)
|
|
{
|
|
if (ds_state == dsSelect)
|
|
{
|
|
return seek(pos - 1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
#if 0
|
|
void Dataset::insert()
|
|
{
|
|
//cout << "insert\n\n";
|
|
for (int i = 0; i < field_count(); i++)
|
|
{
|
|
(*fields_object)[i].val = "";
|
|
(*edit_object)[i].val = "";
|
|
//cout <<"Insert:"<<i<<"\n\n";
|
|
}
|
|
ds_state = dsInsert;
|
|
}
|
|
#endif
|
|
|
|
void Dataset::edit()
|
|
{
|
|
if (ds_state != dsSelect)
|
|
{
|
|
cerr << "Editing is possible only when query exists!";
|
|
return;
|
|
}
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
{
|
|
(*edit_object)[i].val = (*fields_object)[i].val;
|
|
}
|
|
ds_state = dsEdit;
|
|
}
|
|
|
|
|
|
void Dataset::post()
|
|
{
|
|
if (ds_state == dsInsert)
|
|
make_insert();
|
|
else if (ds_state == dsEdit)
|
|
make_edit();
|
|
}
|
|
|
|
|
|
void Dataset::deletion()
|
|
{
|
|
if (ds_state == dsSelect)
|
|
make_deletion();
|
|
}
|
|
|
|
|
|
bool Dataset::set_field_value(const char *f_name, const field_value & value)
|
|
{
|
|
bool found = false;
|
|
|
|
if ((ds_state == dsInsert) || (ds_state == dsEdit))
|
|
{
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
if ((*edit_object)[i].props.name == f_name)
|
|
{
|
|
(*edit_object)[i].val = value;
|
|
found = true;
|
|
}
|
|
if (!found)
|
|
{
|
|
GB.Error("Field not found: &1", f_name);
|
|
}
|
|
return found;
|
|
}
|
|
GB.Error("Not in Insert or Edit state");
|
|
return found;
|
|
}
|
|
|
|
|
|
const field_value & Dataset::get_field_value(const char *f_name)
|
|
{
|
|
static field_value fv;
|
|
|
|
if (ds_state != dsInactive)
|
|
{
|
|
if (ds_state == dsEdit || ds_state == dsInsert)
|
|
{
|
|
for (uint i = 0; i < edit_object->size(); i++)
|
|
if ((*edit_object)[i].props.name == f_name)
|
|
return (*edit_object)[i].val;
|
|
GB.Error("Field not found: %s", f_name);
|
|
}
|
|
else
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
if ((*fields_object)[i].props.name == f_name)
|
|
return (*fields_object)[i].val;
|
|
GB.Error("Field not found: %s", f_name);
|
|
}
|
|
|
|
GB.Error("Dataset state is Inactive");
|
|
return fv;
|
|
}
|
|
|
|
|
|
const field_value & Dataset::get_field_value(int index) //const char *f_name)
|
|
{
|
|
static field_value fv;
|
|
|
|
if (ds_state != dsInactive)
|
|
{
|
|
if (ds_state == dsEdit || ds_state == dsInsert)
|
|
return (*edit_object)[index].val;
|
|
else
|
|
return (*fields_object)[index].val;
|
|
}
|
|
|
|
GB.Error("Dataset state is Inactive");
|
|
return fv;
|
|
}
|
|
|
|
|
|
const field_value Dataset::f_old(const char *f_name)
|
|
{
|
|
if (ds_state != dsInactive)
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
if ((*fields_object)[i].props.name == f_name)
|
|
return (*fields_object)[i].val;
|
|
field_value fv;
|
|
|
|
return fv;
|
|
}
|
|
|
|
|
|
|
|
void Dataset::setParamList(const ParamList & params)
|
|
{
|
|
plist = params;
|
|
}
|
|
|
|
|
|
bool Dataset::locate()
|
|
{
|
|
bool result;
|
|
|
|
if (plist.empty())
|
|
return false;
|
|
|
|
std::map < string, field_value >::const_iterator i;
|
|
first();
|
|
while (!eof())
|
|
{
|
|
result = true;
|
|
for (i = plist.begin(); i != plist.end(); ++i)
|
|
if (fv(i->first.c_str()).get_asString() == i->second.get_asString())
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
break;
|
|
}
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
next();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Dataset::locate(const ParamList & params)
|
|
{
|
|
plist = params;
|
|
return locate();
|
|
}
|
|
|
|
bool Dataset::findNext(void)
|
|
{
|
|
bool result;
|
|
|
|
if (plist.empty())
|
|
return false;
|
|
|
|
std::map < string, field_value >::const_iterator i;
|
|
while (!eof())
|
|
{
|
|
result = true;
|
|
for (i = plist.begin(); i != plist.end(); ++i)
|
|
if (fv(i->first.c_str()).get_asString() == i->second.get_asString())
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
break;
|
|
}
|
|
if (result)
|
|
{
|
|
return result;
|
|
}
|
|
next();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void Dataset::add_update_sql(const char *upd_sql)
|
|
{
|
|
string s = upd_sql;
|
|
|
|
update_sql.push_back(s);
|
|
}
|
|
|
|
|
|
void Dataset::add_update_sql(const string & upd_sql)
|
|
{
|
|
update_sql.push_back(upd_sql);
|
|
}
|
|
|
|
void Dataset::add_insert_sql(const char *ins_sql)
|
|
{
|
|
string s = ins_sql;
|
|
|
|
insert_sql.push_back(s);
|
|
}
|
|
|
|
|
|
void Dataset::add_insert_sql(const string & ins_sql)
|
|
{
|
|
insert_sql.push_back(ins_sql);
|
|
}
|
|
|
|
void Dataset::add_delete_sql(const char *del_sql)
|
|
{
|
|
string s = del_sql;
|
|
|
|
delete_sql.push_back(s);
|
|
}
|
|
|
|
|
|
void Dataset::add_delete_sql(const string & del_sql)
|
|
{
|
|
delete_sql.push_back(del_sql);
|
|
}
|
|
|
|
void Dataset::clear_update_sql()
|
|
{
|
|
update_sql.clear();
|
|
}
|
|
|
|
void Dataset::clear_insert_sql()
|
|
{
|
|
insert_sql.clear();
|
|
}
|
|
|
|
void Dataset::clear_delete_sql()
|
|
{
|
|
delete_sql.clear();
|
|
}
|
|
|
|
int Dataset::field_count()
|
|
{
|
|
return fields_object->size();
|
|
}
|
|
|
|
int Dataset::fieldCount()
|
|
{
|
|
return fields_object->size();
|
|
}
|
|
|
|
const char *Dataset::fieldName(int n)
|
|
{
|
|
if (n < field_count() && n >= 0)
|
|
return (*fields_object)[n].props.name.c_str();
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
int Dataset::fieldSize(int n)
|
|
{
|
|
if (n < field_count() && n >= 0)
|
|
return (*fields_object)[n].props.field_len;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int Dataset::fieldIndex(const char *fn)
|
|
{
|
|
int index, length;
|
|
|
|
if (strchr(fn, (int) '.'))
|
|
{
|
|
/* table name has been supplied */
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
{
|
|
//if ((*fields_object)[i].props.name == fn)
|
|
if (strcmp((*fields_object)[i].props.name.c_str(), fn) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (uint i = 0; i < fields_object->size(); i++)
|
|
{
|
|
index = (*fields_object)[i].props.name.find('.') + 1;
|
|
length = (*fields_object)[i].props.name.length();
|
|
/*printf("Field name [%s] find [%s] fn [%s]\n",
|
|
(*fields_object)[i].props.name.c_str(),
|
|
(*fields_object)[i].props.name.substr(index, length).c_str(), fn); */
|
|
|
|
//if ((*fields_object)[i].props.name.substr(index, length) == fn){
|
|
if (strcmp
|
|
((*fields_object)[i].props.name.substr(index, length).c_str(),
|
|
fn) == 0)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int Dataset::fieldType(int n)
|
|
{
|
|
if (n < field_count() && n >= 0)
|
|
{
|
|
//cout << (*fields_object)[n].val.gft();
|
|
return (*fields_object)[n].val.get_fType();
|
|
//return (*fields_object)[n].props.type;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|