summaryrefslogtreecommitdiff
path: root/lib/db.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/db.c')
-rw-r--r--lib/db.c1086
1 files changed, 1086 insertions, 0 deletions
diff --git a/lib/db.c b/lib/db.c
new file mode 100644
index 0000000..17e679c
--- /dev/null
+++ b/lib/db.c
@@ -0,0 +1,1086 @@
+/*
+ * db.c
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#include <stdio.h>
+
+#include <mysql/errmsg.h>
+
+#include "db.h"
+
+// #define DEB_HANDLER
+
+//***************************************************************************
+// DB Statement
+//***************************************************************************
+
+cDbStatement::cDbStatement(cDbTable* aTable)
+{
+ table = aTable;
+ connection = table->getConnection();
+ stmtTxt = "";
+ stmt = 0;
+ inCount = 0;
+ outCount = 0;
+ inBind = 0;
+ outBind = 0;
+ affected = 0;
+ metaResult = 0;
+ bindPrefix = 0;
+}
+
+cDbStatement::cDbStatement(cDbConnection* aConnection, const char* stmt)
+{
+ table = 0;
+ connection = aConnection;
+ stmtTxt = stmt;
+ stmt = 0;
+ inCount = 0;
+ outCount = 0;
+ inBind = 0;
+ outBind = 0;
+ affected = 0;
+ metaResult = 0;
+ bindPrefix = 0;
+}
+
+//***************************************************************************
+// Execute
+//***************************************************************************
+
+int cDbStatement::execute(int noResult)
+{
+ affected = 0;
+
+ if (!connection || !connection->getMySql())
+ return fail;
+
+ if (!stmt)
+ return connection->errorSql(connection, "execute(missing statement)");
+
+ // tell(0, "execute %d [%s]", stmt, stmtTxt.c_str());
+
+ if (mysql_stmt_execute(stmt))
+ return connection->errorSql(connection, "execute(stmt_execute)", stmt, stmtTxt.c_str());
+
+ // out binding - if needed
+
+ if (outCount && !noResult)
+ {
+ if (mysql_stmt_store_result(stmt))
+ return connection->errorSql(connection, "execute(store_result)", stmt, stmtTxt.c_str());
+
+ // fetch the first result - if any
+
+ if (mysql_stmt_affected_rows(stmt) > 0)
+ mysql_stmt_fetch(stmt);
+ }
+ else if (outCount)
+ {
+ mysql_stmt_store_result(stmt);
+ }
+
+ // result was stored (above) only if output (outCound) is expected,
+ // therefore we don't need to call freeResult() after insert() or update()
+
+ affected = mysql_stmt_affected_rows(stmt);
+
+ return success;
+}
+
+int cDbStatement::getResultCount()
+{
+ mysql_stmt_store_result(stmt);
+
+ return mysql_stmt_affected_rows(stmt);
+}
+
+int cDbStatement::find()
+{
+ if (execute() != success)
+ return fail;
+
+ return getAffected() > 0 ? yes : no;
+}
+
+int cDbStatement::fetch()
+{
+ if (!mysql_stmt_fetch(stmt))
+ return yes;
+
+ return no;
+}
+
+int cDbStatement::freeResult()
+{
+ if (metaResult)
+ mysql_free_result(metaResult);
+
+ if (stmt)
+ mysql_stmt_free_result(stmt);
+
+ return success;
+}
+
+//***************************************************************************
+// Build Statements - new Interface
+//***************************************************************************
+
+int cDbStatement::build(const char* format, ...)
+{
+ if (format)
+ {
+ char* tmp;
+
+ va_list more;
+ va_start(more, format);
+ vasprintf(&tmp, format, more);
+
+ stmtTxt += tmp;
+ free(tmp);
+ }
+
+ return success;
+}
+
+int cDbStatement::bind(int field, int mode, const char* delim)
+{
+ return bind(table->getRow()->getValue(field), mode, delim);
+}
+
+int cDbStatement::bind(cDbValue* value, int mode, const char* delim)
+{
+ if (!value || !value->getField())
+ return fail;
+
+ if (delim)
+ stmtTxt += delim;
+
+ if (bindPrefix)
+ stmtTxt += bindPrefix;
+
+ if (mode & bndIn)
+ {
+ if (mode & bndSet)
+ stmtTxt += value->getName() + string(" =");
+
+ stmtTxt += " ?";
+ appendBinding(value, bndIn);
+ }
+ else if (mode & bndOut)
+ {
+ stmtTxt += value->getName();
+ appendBinding(value, bndOut);
+ }
+
+ return success;
+}
+
+int cDbStatement::bindCmp(const char* ctable, cDbValue* value,
+ const char* comp, const char* delim)
+{
+ if (ctable)
+ build("%s.", ctable);
+
+ build("%s%s %s ?", delim ? delim : "", value->getName(), comp);
+
+ appendBinding(value, bndIn);
+
+ return success;
+}
+
+int cDbStatement::bindCmp(const char* ctable, int field, cDbValue* value,
+ const char* comp, const char* delim)
+{
+ cDbValue* vf = table->getRow()->getValue(field);
+ cDbValue* vv = value ? value : vf;
+
+ if (ctable)
+ build("%s.", ctable);
+
+ build("%s%s %s ?", delim ? delim : "", vf->getName(), comp);
+
+ appendBinding(vv, bndIn);
+
+ return success;
+}
+
+//***************************************************************************
+// Clear
+//***************************************************************************
+
+void cDbStatement::clear()
+{
+ stmtTxt = "";
+ affected = 0;
+
+ if (inCount)
+ {
+ free(inBind);
+ inCount = 0;
+ inBind = 0;
+ }
+
+ if (outCount)
+ {
+ free(outBind);
+ outCount = 0;
+ outBind = 0;
+ }
+
+ if (stmt)
+ {
+ mysql_stmt_free_result(stmt);
+ mysql_stmt_close(stmt);
+ stmt = 0;
+ }
+}
+
+//***************************************************************************
+// Append Binding
+//***************************************************************************
+
+int cDbStatement::appendBinding(cDbValue* value, BindType bt)
+{
+ int count = 0;
+ MYSQL_BIND** bindings = 0;
+ MYSQL_BIND* newBinding;
+
+ if (bt & bndIn)
+ {
+ count = ++inCount;
+ bindings = &inBind;
+ }
+ else if (bt & bndOut)
+ {
+ count = ++outCount;
+ bindings = &outBind;
+ }
+ else
+ return 0;
+
+ if (!bindings)
+ *bindings = (MYSQL_BIND*)malloc(count * sizeof(MYSQL_BIND));
+ else
+ *bindings = (MYSQL_BIND*)realloc(*bindings, count * sizeof(MYSQL_BIND));
+
+ newBinding = &((*bindings)[count-1]);
+
+ if (value->getField()->format == ffAscii || value->getField()->format == ffText)
+ {
+ newBinding->buffer_type = MYSQL_TYPE_STRING;
+ newBinding->buffer = value->getStrValueRef();
+ newBinding->buffer_length = value->getField()->size;
+ newBinding->length = value->getStrValueSizeRef();
+
+ newBinding->is_null = value->getNullRef();
+ newBinding->error = 0; // #TODO
+ }
+ else if (value->getField()->format == ffMlob)
+ {
+ newBinding->buffer_type = MYSQL_TYPE_BLOB;
+ newBinding->buffer = value->getStrValueRef();
+ newBinding->buffer_length = value->getField()->size;
+ newBinding->length = value->getStrValueSizeRef();
+
+ newBinding->is_null = value->getNullRef();
+ newBinding->error = 0; // #TODO
+ }
+ else if (value->getField()->format == ffFloat)
+ {
+ newBinding->buffer_type = MYSQL_TYPE_FLOAT;
+ newBinding->buffer = value->getFloatValueRef();
+
+ newBinding->length = 0; // #TODO
+ newBinding->is_null = value->getNullRef();
+ newBinding->error = 0; // #TODO
+ }
+ else if (value->getField()->format == ffDateTime)
+ {
+ newBinding->buffer_type = MYSQL_TYPE_DATETIME;
+ newBinding->buffer = value->getTimeValueRef();
+
+ newBinding->length = 0; // #TODO
+ newBinding->is_null = value->getNullRef();
+ newBinding->error = 0; // #TODO
+ }
+ else
+ {
+ newBinding->buffer_type = MYSQL_TYPE_LONG;
+ newBinding->buffer = value->getIntValueRef();
+ newBinding->is_unsigned = (value->getField()->format == ffUInt);
+
+ newBinding->length = 0;
+ newBinding->is_null = value->getNullRef();
+ newBinding->error = 0; // #TODO
+ }
+
+ return success;
+}
+
+//***************************************************************************
+// Prepare Statement
+//***************************************************************************
+
+int cDbStatement::prepare()
+{
+ if (!stmtTxt.length() || !connection->getMySql())
+ return fail;
+
+ stmt = mysql_stmt_init(connection->getMySql());
+
+ // prepare statement
+
+ if (mysql_stmt_prepare(stmt, stmtTxt.c_str(), stmtTxt.length()))
+ return connection->errorSql(connection, "prepare(stmt_prepare)", stmt, stmtTxt.c_str());
+
+ if (outBind)
+ {
+ if (mysql_stmt_bind_result(stmt, outBind))
+ return connection->errorSql(connection, "execute(bind_result)", stmt);
+ }
+
+ if (inBind)
+ {
+ if (mysql_stmt_bind_param(stmt, inBind))
+ return connection->errorSql(connection, "buildPrimarySelect(bind_param)", stmt);
+ }
+
+ tell(2, "Statement '%s' with (%d) in parameters and (%d) out bindings prepared",
+ stmtTxt.c_str(), mysql_stmt_param_count(stmt), outCount);
+
+ return success;
+}
+
+//***************************************************************************
+// cDbService
+//***************************************************************************
+
+const char* cDbService::formats[] =
+{
+ "INT",
+ "INT",
+ "VARCHAR",
+ "TEXT",
+ "MEDIUMBLOB",
+ "FLOAT",
+ "DATETIME",
+
+ 0
+};
+
+const char* cDbService::toString(FieldFormat t)
+{
+ return formats[t];
+}
+
+//***************************************************************************
+// Class cDbTable
+//***************************************************************************
+
+char* cDbTable::confPath = 0;
+
+char* cDbConnection::encoding = 0;
+char* cDbConnection::dbHost = strdup("localhost");
+int cDbConnection::dbPort = 3306;
+char* cDbConnection::dbUser = 0;
+char* cDbConnection::dbPass = 0;
+char* cDbConnection::dbName = 0;
+
+//***************************************************************************
+// Object
+//***************************************************************************
+
+cDbTable::cDbTable(cDbConnection* aConnection, FieldDef* f, IndexDef* i)
+{
+ connection = aConnection;
+ row = new cDbRow(f);
+ holdInMemory = no;
+
+ stmtSelect = 0;
+ stmtInsert = 0;
+ stmtUpdate = 0;
+
+ indices = i;
+}
+
+cDbTable::~cDbTable()
+{
+ close();
+
+ delete row;
+}
+
+//***************************************************************************
+// Open / Close
+//***************************************************************************
+
+int cDbTable::open()
+{
+ if (connection->attachConnection() != success)
+ {
+ tell(0, "Could not access database '%s:%d' (tried to open %s)",
+ connection->getHost(), connection->getPort(), TableName());
+
+ return fail;
+ }
+
+ return init();
+}
+
+int cDbTable::close()
+{
+ if (stmtSelect) { delete stmtSelect; stmtSelect = 0; }
+ if (stmtInsert) { delete stmtInsert; stmtInsert = 0; }
+ if (stmtUpdate) { delete stmtUpdate; stmtUpdate = 0; }
+
+ connection->detachConnection();
+
+ return success;
+}
+
+//***************************************************************************
+// Init
+//***************************************************************************
+
+int cDbTable::init()
+{
+ string str;
+
+ if (!isConnected()) return fail;
+
+ // check/create table ...
+
+ if (createTable() != success)
+ return fail;
+
+ // ------------------------------
+ // prepare BASIC statements
+ // ------------------------------
+
+ // select by primary key ...
+
+ stmtSelect = new cDbStatement(this);
+
+ stmtSelect->build("select ");
+
+ for (int i = 0, n = 0; row->getField(i)->name; i++)
+ {
+ if (row->getField(i)->type & ftCalc)
+ continue;
+
+ stmtSelect->bind(i, bndOut, n++ ? ", " : "");
+ }
+
+ stmtSelect->build(" from %s where ", TableName());
+
+ for (int i = 0, n = 0; row->getField(i)->name; i++)
+ {
+ if (!(row->getField(i)->type & ftPrimary))
+ continue;
+
+ stmtSelect->bind(i, bndIn | bndSet, n++ ? " and " : "");
+ }
+
+ stmtSelect->build(";");
+
+ if (stmtSelect->prepare() != success)
+ return fail;
+
+ // -----------------------------------------
+ // insert
+
+ stmtInsert = new cDbStatement(this);
+
+ stmtInsert->build("insert into %s set ", TableName());
+
+ for (int i = 0, n = 0; row->getField(i)->name; i++)
+ {
+ // don't insert autoinc and calculated fields
+
+ if (row->getField(i)->type & ftCalc || row->getField(i)->type & ftAutoinc)
+ continue;
+
+ stmtInsert->bind(i, bndIn | bndSet, n++ ? ", " : "");
+ }
+
+ stmtInsert->build(";");
+
+ if (stmtInsert->prepare() != success)
+ return fail;
+
+ // -----------------------------------------
+ // update via primary key ...
+
+ stmtUpdate = new cDbStatement(this);
+
+ stmtUpdate->build("update %s set ", TableName());
+
+ for (int i = 0, n = 0; row->getField(i)->name; i++)
+ {
+ // don't update PKey, autoinc and calculated fields
+
+ if (row->getField(i)->type & ftPrimary ||
+ row->getField(i)->type & ftCalc ||
+ row->getField(i)->type & ftAutoinc)
+ continue;
+
+ if (strcmp(row->getField(i)->name, "inssp") == 0) // don't update the insert stamp
+ continue;
+
+ stmtUpdate->bind(i, bndIn | bndSet, n++ ? ", " : "");
+ }
+
+ stmtUpdate->build(" where ");
+
+ for (int i = 0, n = 0; row->getField(i)->name; i++)
+ {
+ if (!(row->getField(i)->type & ftPrimary))
+ continue;
+
+ stmtUpdate->bind(i, bndIn | bndSet, n++ ? " and " : "");
+ }
+
+ stmtUpdate->build(";");
+
+ if (stmtUpdate->prepare() != success)
+ return fail;
+
+ return success;
+}
+
+//***************************************************************************
+// Check Table
+//***************************************************************************
+
+int cDbTable::exist(const char* name)
+{
+ if (!name)
+ name = TableName();
+
+ MYSQL_RES* result = mysql_list_tables(connection->getMySql(), name);
+ MYSQL_ROW tabRow = mysql_fetch_row(result);
+ mysql_free_result(result);
+
+ return tabRow ? yes : no;
+}
+
+//***************************************************************************
+// Create Table
+//***************************************************************************
+
+int cDbTable::createTable()
+{
+ string statement;
+ string aKey;
+
+ if (!isConnected())
+ {
+ if (connection->attachConnection() != success)
+ {
+ tell(0, "Could not access database '%s:%d' (tried to create %s)",
+ connection->getHost(), connection->getPort(), TableName());
+
+ return fail;
+ }
+ }
+
+ // table exists -> nothing to do
+
+ if (exist())
+ return done;
+
+ tell(0, "Initialy creating table '%s'", TableName());
+
+ // build 'create' statement ...
+
+ statement = string("create table ") + TableName() + string("(");
+
+ for (int i = 0; getField(i)->name; i++)
+ {
+ int size = getField(i)->size;
+ char num[10];
+
+ if (getField(i)->type & ftCalc)
+ continue;
+
+ if (i) statement += string(", ");
+ statement += string(getField(i)->name) + " " + string(toString(getField(i)->format));
+
+ if (getField(i)->format != ffMlob)
+ {
+ if (!size) size = getField(i)->format == ffAscii || getField(i)->format == ffText ? 100 : 11;
+
+ if (getField(i)->format != ffFloat)
+ sprintf(num, "%d", size);
+ else
+ sprintf(num, "%d,%d", size/10, size%10);
+
+ statement += "(" + string(num) + ")";
+
+ if (getField(i)->format == ffUInt)
+ statement += " unsigned";
+
+ if (getField(i)->type & ftAutoinc)
+ statement += " not null auto_increment";
+ else if (getField(i)->type & ftDef0)
+ statement += " default '0'";
+ }
+ }
+
+ aKey = "";
+
+ for (int i = 0, n = 0; getField(i)->name; i++)
+ {
+ if (getField(i)->type & ftPrimary)
+ {
+ if (n++) aKey += string(", ");
+ aKey += string(getField(i)->name) + " DESC";
+ }
+ }
+
+ if (aKey.length())
+ {
+ statement += string(", PRIMARY KEY(");
+ statement += aKey;
+ statement += ")";
+ }
+
+ aKey = "";
+
+ for (int i = 0, n = 0; getField(i)->name; i++)
+ {
+ if (getField(i)->type & ftAutoinc && !(getField(i)->type & ftPrimary))
+ {
+ if (n++) aKey += string(", ");
+ aKey += string(getField(i)->name) + " DESC";
+ }
+ }
+
+ if (aKey.length())
+ {
+ statement += string(", KEY(");
+ statement += aKey;
+ statement += ")";
+ }
+
+ // statement += string(") ENGINE MYISAM;");
+ statement += string(") ENGINE InnoDB;");
+
+ tell(1, "%s", statement.c_str());
+
+ if (connection->query(statement.c_str()))
+ return connection->errorSql(getConnection(), "createTable()",
+ 0, statement.c_str());
+
+ // create indices
+
+ createIndices();
+
+ return success;
+}
+
+//***************************************************************************
+// Create Indices
+//***************************************************************************
+
+int cDbTable::createIndices()
+{
+ string statement;
+
+ tell(5, "Initialy checking indices for '%s'", TableName());
+
+ // check/create indexes
+
+ if (!indices)
+ return done;
+
+ for (int i = 0; getIndex(i)->name; i++)
+ {
+ IndexDef* index = getIndex(i);
+ int fCount;
+ string idxName;
+ int expectCount = 0;
+
+ for (; index->fields[expectCount] != na; expectCount++) ;
+
+ if (!expectCount)
+ continue;
+
+ // check
+
+ idxName = "idx" + string(index->name);
+
+ checkIndex(idxName.c_str(), fCount);
+
+ if (fCount != expectCount)
+ {
+ // create index
+
+ statement = "create index " + idxName;
+ statement += " on " + string(TableName()) + "(";
+
+ int n = 0;
+
+ for (int f = 0; index->fields[f] != na; f++)
+ {
+ FieldDef* fld = getField(index->fields[f]);
+
+ if (fld && !(fld->type & ftCalc))
+ {
+ if (n++) statement += string(", ");
+ statement += fld->name;
+ }
+ }
+
+ if (!n) continue;
+
+ statement += ");";
+ tell(1, "%s", statement.c_str());
+
+ if (connection->query(statement.c_str()))
+ return connection->errorSql(getConnection(), "createIndices()",
+ 0, statement.c_str());
+ }
+ }
+
+ return success;
+}
+
+//***************************************************************************
+// Check Index
+//***************************************************************************
+
+int cDbTable::checkIndex(const char* idxName, int& fieldCount)
+{
+ enum IndexQueryFields
+ {
+ idTable,
+ idNonUnique,
+ idKeyName,
+ idSeqInIndex,
+ idColumnName,
+ idCollation,
+ idCardinality,
+ idSubPart,
+ idPacked,
+ idNull,
+ idIndexType,
+ idComment,
+ idIndexComment,
+
+ idCount
+ };
+
+ MYSQL_RES* result;
+ MYSQL_ROW row;
+
+ fieldCount = 0;
+
+ if (connection->query("show index from %s", TableName()) != success)
+ {
+ connection->errorSql(getConnection(), "checkIndex()", 0);
+
+ return fail;
+ }
+
+ if ((result = mysql_store_result(connection->getMySql())))
+ {
+ while ((row = mysql_fetch_row(result)))
+ {
+ tell(5, "%s: %-20s %s %s",
+ row[idTable], row[idKeyName],
+ row[idSeqInIndex], row[idColumnName]);
+
+ if (strcasecmp(row[idKeyName], idxName) == 0)
+ fieldCount++;
+ }
+
+ mysql_free_result(result);
+
+ return success;
+ }
+
+ connection->errorSql(getConnection(), "checkIndex()");
+
+ return fail;
+}
+
+//***************************************************************************
+// Copy Values
+//***************************************************************************
+
+void cDbTable::copyValues(cDbRow* r)
+{
+ for (int i = 0; i < fieldCount(); i++)
+ {
+ if (getField(i)->format == ffAscii || getField(i)->format == ffText)
+ row->setValue(i, r->getStrValue(i));
+ else
+ row->setValue(i, r->getIntValue(i));
+ }
+}
+
+//***************************************************************************
+// SQL Error
+//***************************************************************************
+
+int cDbConnection::errorSql(cDbConnection* connection, const char* prefix, MYSQL_STMT* stmt, const char* stmtTxt)
+{
+ if (!connection || !connection->mysql)
+ {
+ tell(0, "SQL-Error in '%s'", prefix);
+ return fail;
+ }
+
+ int error = mysql_errno(connection->mysql);
+ char* conErr = 0;
+ char* stmtErr = 0;
+
+ if (error == CR_SERVER_LOST ||
+ error == CR_SERVER_GONE_ERROR ||
+ error == CR_INVALID_CONN_HANDLE ||
+ error == CR_SERVER_LOST_EXTENDED)
+ connectDropped = yes;
+
+ if (error)
+ asprintf(&conErr, "%s (%d) ", mysql_error(connection->mysql), error);
+
+ if (stmt || stmtTxt)
+ asprintf(&stmtErr, "'%s' [%s]",
+ stmt ? mysql_stmt_error(stmt) : "",
+ stmtTxt ? stmtTxt : "");
+
+ tell(0, "SQL-Error in '%s' - %s%s", prefix,
+ conErr ? conErr : "", stmtErr ? stmtErr : "");
+
+ free(conErr);
+ free(stmtErr);
+
+ if (connectDropped)
+ tell(0, "Fatal, lost connection to mysql server, aborting pending actions");
+
+ return fail;
+}
+
+//***************************************************************************
+// Delete Where
+//***************************************************************************
+
+int cDbTable::deleteWhere(const char* where)
+{
+ string tmp;
+
+ if (!connection || !connection->getMySql())
+ return fail;
+
+ tmp = "delete from " + string(TableName()) + " where " + string(where);
+
+ if (connection->query(tmp.c_str()))
+ return connection->errorSql(connection, "deleteWhere()", 0, tmp.c_str());
+
+ return success;
+}
+
+//***************************************************************************
+// Coiunt Where
+//***************************************************************************
+
+int cDbTable::countWhere(const char* where, int& count, const char* what)
+{
+ string tmp;
+ MYSQL_RES* res;
+ MYSQL_ROW data;
+
+ count = 0;
+
+ if (isEmpty(what))
+ what = "count(1)";
+
+ if (!isEmpty(where))
+ tmp = "select " + string(what) + " from " + string(TableName()) + " where " + string(where);
+ else
+ tmp = "select " + string(what) + " from " + string(TableName());
+
+ if (connection->query(tmp.c_str()))
+ return connection->errorSql(connection, "countWhere()", 0, tmp.c_str());
+
+ if (res = mysql_store_result(connection->getMySql()))
+ {
+ data = mysql_fetch_row(res);
+
+ if (data)
+ count = atoi(data[0]);
+
+ mysql_free_result(res);
+ }
+
+ return success;
+}
+
+//***************************************************************************
+// Truncate
+//***************************************************************************
+
+int cDbTable::truncate()
+{
+ string tmp;
+
+ tmp = "delete from " + string(TableName());
+
+ if (connection->query(tmp.c_str()))
+ return connection->errorSql(connection, "truncate()", 0, tmp.c_str());
+
+ return success;
+}
+
+
+//***************************************************************************
+// Store
+//***************************************************************************
+
+int cDbTable::store()
+{
+ int found;
+
+ // insert or just update ...
+
+ if (stmtSelect->execute(/*noResult =*/ yes) != success)
+ {
+ connection->errorSql(connection, "store()");
+ return no;
+ }
+
+ found = stmtSelect->getAffected() == 1;
+ stmtSelect->freeResult();
+
+ if (found)
+ return update();
+ else
+ return insert();
+}
+
+//***************************************************************************
+// Insert
+//***************************************************************************
+
+int cDbTable::insert()
+{
+ if (!stmtInsert)
+ {
+ tell(0, "Fatal missing insert statement\n");
+ return fail;
+ }
+
+ for (int i = 0; getField(i)->name; i++)
+ {
+ if (strcmp(getField(i)->name, "updsp") == 0 || strcmp(getField(i)->name, "inssp") == 0)
+ setValue(getField(i)->index, time(0));
+ }
+
+#ifdef DEB_HANDLER
+
+ if (strcmp(TableName(), "events") == 0)
+ tell(1, "inserting vdr event %d for '%s', starttime = %ld, updflg = '%s'",
+ getIntValue(0), getStrValue(1), getIntValue(15), getStrValue(6));
+#endif
+
+ if (stmtInsert->execute())
+ return fail;
+
+ return stmtInsert->getAffected() == 1 ? success : fail;
+}
+
+//***************************************************************************
+// Update
+//***************************************************************************
+
+int cDbTable::update()
+{
+ if (!stmtUpdate)
+ {
+ tell(0, "Fatal missing update statement\n");
+ return fail;
+ }
+
+ for (int i = 0; getField(i)->name; i++)
+ {
+ if (strcmp(getField(i)->name, "updsp") == 0)
+ {
+ setValue(getField(i)->index, time(0));
+ break;
+ }
+ }
+
+#ifdef DEB_HANDLER
+ if (strcmp(TableName(), "events") == 0)
+ tell(1, "updating vdr event %d for '%s', starttime = %ld, updflg = '%s'",
+ getIntValue(0), getStrValue(1), getIntValue(15), getStrValue(6));
+#endif
+
+ if (stmtUpdate->execute())
+ return fail;
+
+ return stmtUpdate->getAffected() == 1 ? success : fail;
+}
+
+//***************************************************************************
+// Find
+//***************************************************************************
+
+int cDbTable::find()
+{
+ if (!stmtSelect)
+ return no;
+
+ if (stmtSelect->execute() != success)
+ {
+ connection->errorSql(connection, "find()");
+ return no;
+ }
+
+ return stmtSelect->getAffected() == 1 ? yes : no;
+}
+
+//***************************************************************************
+// Find via Statement
+//***************************************************************************
+
+int cDbTable::find(cDbStatement* stmt)
+{
+ if (!stmt)
+ return no;
+
+ if (stmt->execute() != success)
+ {
+ connection->errorSql(connection, "find(stmt)");
+ return no;
+ }
+
+ return stmt->getAffected() > 0 ? yes : no;
+}
+
+//***************************************************************************
+// Fetch
+//***************************************************************************
+
+int cDbTable::fetch(cDbStatement* stmt)
+{
+ if (!stmt)
+ return no;
+
+ return stmt->fetch();
+}
+
+//***************************************************************************
+// Reset Fetch
+//***************************************************************************
+
+void cDbTable::reset(cDbStatement* stmt)
+{
+ if (stmt)
+ stmt->freeResult();
+}