--- /dev/null
+mysqlclient
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <mysql/mysql.h>
+
+#define STRING_SIZE 50
+
+#define INSERT_SAMPLE "insert into anna_db_test (xx, yy, zz, tt) values (?,?,?,?)"
+
+
+#define MAXCOLUMN 4
+
+MYSQL* mysql;
+MYSQL_STMT *stmt;
+MYSQL_BIND bind[MAXCOLUMN];
+MYSQL_TIME ts;
+unsigned long length[MAXCOLUMN];
+int param_count, column_count, row_count;
+float float_data;
+int int_data;
+char str_data[STRING_SIZE];
+my_bool is_null[MAXCOLUMN];
+
+/*
+ * From http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
+ */
+int main (int argc, const char** argv)
+{
+ if ((mysql = mysql_init (NULL)) == NULL)
+ exit(-12);
+
+ if (mysql_real_connect (mysql, NULL, "sdp", "sdp", "test", 0, NULL, 0L) == NULL) {
+ fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Prepare a SELECT query to fetch data from test_table */
+ stmt = mysql_stmt_init(mysql);
+ if (!stmt)
+ {
+ fprintf(stderr, " mysql_stmt_init(), out of memory\n");
+ exit(0);
+ }
+
+ if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE)))
+ {
+ fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+ fprintf(stdout, " prepare, INSERT successful\n");
+
+ /* Get the parameter count from the statement */
+ param_count= mysql_stmt_param_count(stmt);
+ fprintf(stdout, " total parameters in INSERT: %d\n", param_count);
+
+ if (param_count != MAXCOLUMN) /* validate parameter count */
+ {
+ fprintf(stderr, " invalid parameter count returned by MySQL\n");
+ exit(0);
+ }
+
+ /* Bind the result buffers for all 3 columns before fetching them */
+
+ memset(bind, 0, sizeof(bind));
+
+ /* INTEGER COLUMN */
+ bind[0].buffer_type= MYSQL_TYPE_LONG;
+ bind[0].buffer= (char *)&int_data;
+ bind[0].is_null= &is_null[0];
+ bind[0].length= &length[0];
+
+ /* STRING COLUMN */
+ bind[1].buffer_type= MYSQL_TYPE_STRING;
+ bind[1].buffer= (char *)str_data;
+ bind[1].buffer_length= STRING_SIZE;
+ bind[1].is_null= &is_null[1];
+ bind[1].length= &length [1];
+
+ /* FLOAT COLUMN */
+ bind[2].buffer_type= MYSQL_TYPE_FLOAT;
+ bind[2].buffer= (char *)&float_data;
+ bind[2].is_null= &is_null[2];
+ bind[2].length= &length[2];
+
+ /* TIME COLUMN */
+ bind[3].buffer_type= MYSQL_TYPE_DATETIME;
+ bind[3].buffer= (char *)&ts;
+ bind[3].is_null= &is_null[2];
+ bind[3].length= &length[2];
+
+ /* Bind the result buffers */
+ if (mysql_stmt_bind_param (stmt, bind))
+ {
+ fprintf(stderr, " mysql_stmt_bind_param() failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ int_data = 99;
+ strcpy (str_data, "insert: 99");
+ length [1] = strlen (str_data);
+ float_data = 0.99;
+ ts.year = 1996; ts.month = 2; ts.day = 11;
+ ts.hour = 19; ts.minute = 22; ts.second = 0;
+
+ /* Execute the INSERT query */
+ if (mysql_stmt_execute(stmt))
+ {
+ fprintf(stderr, " mysql_stmt_execute(), failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ is_null [0] = 1;
+ strcpy (str_data, "insert: <null>");
+ length [1] = strlen (str_data);
+ float_data = 0.98;
+ ts.year = 1999; ts.month = 8; ts.day = 7;
+ ts.hour = 19; ts.minute = 18; ts.second = 17;
+
+ /* Execute the INSERT query */
+ if (mysql_stmt_execute(stmt))
+ {
+ fprintf(stderr, " mysql_stmt_execute(), failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Close the statement */
+ if (mysql_stmt_close(stmt))
+ {
+ fprintf(stderr, " failed while closing the statement\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ return 0;
+}
--- /dev/null
+mysqlclient
--- /dev/null
+#include <string.h>
+#include <stdio.h>
+
+#include <mysql/mysql.h>
+
+#define STRING_SIZE 50
+
+#define SELECT_SAMPLE "SELECT xx, yy, zz, tt FROM anna_db_test"
+
+#define MAXCOLUMN 4
+
+MYSQL* mysql;
+MYSQL_STMT *stmt;
+MYSQL_BIND bind[MAXCOLUMN];
+MYSQL_RES *prepare_meta_result;
+MYSQL_TIME ts;
+unsigned long length[MAXCOLUMN];
+int param_count, column_count, row_count;
+float float_data;
+int int_data;
+char str_data[STRING_SIZE];
+my_bool is_null[MAXCOLUMN];
+
+/*
+ * From http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
+ */
+int main (int argc, const char** argv)
+{
+ if ((mysql = mysql_init (NULL)) == NULL)
+ exit (-12);
+
+ if (mysql_real_connect (mysql, NULL, "sdp", "sdp", "test", 0, NULL, 0L) == NULL) {
+ fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Prepare a SELECT query to fetch data from test_table */
+ stmt = mysql_stmt_init(mysql);
+ if (!stmt)
+ {
+ fprintf(stderr, " mysql_stmt_init(), out of memory\n");
+ exit(0);
+ }
+
+ if (mysql_stmt_prepare(stmt, SELECT_SAMPLE, strlen(SELECT_SAMPLE)))
+ {
+ fprintf(stderr, " mysql_stmt_prepare(), SELECT failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+ fprintf(stdout, " prepare, SELECT successful\n");
+
+ /* Get the parameter count from the statement */
+ param_count= mysql_stmt_param_count(stmt);
+ fprintf(stdout, " total parameters in SELECT: %d\n", param_count);
+
+ if (param_count != 0) /* validate parameter count */
+ {
+ fprintf(stderr, " invalid parameter count returned by MySQL\n");
+ exit(0);
+ }
+
+ /* Fetch result set meta information */
+ prepare_meta_result = mysql_stmt_result_metadata(stmt);
+ if (!prepare_meta_result)
+ {
+ fprintf(stderr," mysql_stmt_result_metadata(), returned no meta information\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Get total columns in the query */
+ column_count= mysql_num_fields(prepare_meta_result);
+ fprintf(stdout, " total columns in SELECT statement: %d\n", column_count);
+
+ if (column_count != MAXCOLUMN) /* validate column count */
+ {
+ fprintf(stderr, " invalid column count returned by MySQL\n");
+ exit(0);
+ }
+
+ /* Execute the SELECT query */
+ if (mysql_stmt_execute(stmt))
+ {
+ fprintf(stderr, " mysql_stmt_execute(), failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Bind the result buffers for all 4 columns before fetching them */
+
+ memset(bind, 0, sizeof(bind));
+
+ /* INTEGER COLUMN */
+ bind[0].buffer_type= MYSQL_TYPE_LONG;
+ bind[0].buffer= (char *)&int_data;
+ bind[0].is_null= &is_null[0];
+ bind[0].length= &length[0];
+
+ /* STRING COLUMN */
+ bind[1].buffer_type= MYSQL_TYPE_STRING;
+ bind[1].buffer= (char *)str_data;
+ bind[1].buffer_length= STRING_SIZE;
+ bind[1].is_null= &is_null[1];
+ bind[1].length= &length[1];
+
+ /* SMALLINT COLUMN */
+ bind[2].buffer_type= MYSQL_TYPE_FLOAT;
+ bind[2].buffer= (char *)&float_data;
+ bind[2].is_null= &is_null[2];
+ bind[2].length= &length[2];
+
+ /* TIMESTAMP COLUMN */
+ bind[3].buffer_type= MYSQL_TYPE_TIMESTAMP;
+ bind[3].buffer= (char *)&ts;
+ bind[3].is_null= &is_null[3];
+ bind[3].length= &length[3];
+
+ /* Bind the result buffers */
+ if (mysql_stmt_bind_result(stmt, bind))
+ {
+ fprintf(stderr, " mysql_stmt_bind_result() failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Now buffer all results to client (optional step) */
+ if (mysql_stmt_store_result(stmt))
+ {
+ fprintf(stderr, " mysql_stmt_store_result() failed\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+ /* Fetch all rows */
+ row_count= 0;
+ fprintf(stdout, "Fetching results ...\n");
+ while (!mysql_stmt_fetch(stmt))
+ {
+ row_count++;
+ fprintf(stdout, " row %d\n", row_count);
+
+ /* column 1 */
+ fprintf(stdout, " column1 (integer) : ");
+ if (is_null[0])
+ fprintf(stdout, " NULL\n");
+ else
+ fprintf(stdout, " %d(%ld)\n", int_data, length[0]);
+
+ /* column 2 */
+ fprintf(stdout, " column2 (string) : ");
+ if (is_null[1])
+ fprintf(stdout, " NULL\n");
+ else
+ fprintf(stdout, " %s(%ld)\n", str_data, length[1]);
+
+ /* column 3 */
+ fprintf(stdout, " column3 (float) : ");
+ if (is_null[2])
+ fprintf(stdout, " NULL\n");
+ else
+ fprintf(stdout, " %f(%ld)\n", float_data, length[2]);
+
+ /* column 4 */
+ fprintf(stdout, " column4 (timestamp): ");
+ if (is_null[3])
+ fprintf(stdout, " NULL\n");
+ else
+ fprintf(stdout, " %04d-%02d-%02d %02d:%02d:%02d (%ld)\n",
+ ts.year, ts.month, ts.day,
+ ts.hour, ts.minute, ts.second,
+ length[3]);
+ fprintf(stdout, "\n");
+ }
+
+ /* Free the prepared result metadata */
+ mysql_free_result(prepare_meta_result);
+
+ /* Close the statement */
+ if (mysql_stmt_close(stmt))
+ {
+ fprintf(stderr, " failed while closing the statement\n");
+ fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
+ exit(0);
+ }
+
+}
--- /dev/null
+anna_dbms.mysql_static
+anna_dbms_static
+anna_comm_static
+anna_app_static
+anna_xml_static
+anna_io_static
+anna_core_static
+mysqlclient
+rt
+xml2
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <iostream>
+
+#include <anna/core/core.hpp>
+#include <anna/dbms/dbms.hpp>
+#include <anna/app/app.hpp>
+
+#include <anna/dbms.mysql/Database.hpp>
+#include <anna/dbms.mysql/OracleTranslator.hpp>
+
+class Insert : public Application {
+public:
+ Insert ();
+ ~Insert () { delete a_db; }
+
+private:
+ anna::dbms::Database* a_db;
+
+ void initialize () throw (RuntimeException);
+ void run () throw (RuntimeException);
+};
+
+using namespace std;
+
+int main (int argc, const char** argv)
+{
+ CommandLine& commandLine (CommandLine::instantiate ());
+ Insert testNull;
+
+ try {
+ commandLine.initialize (argv, argc);
+ commandLine.verify ();
+
+ Logger::setLevel (Logger::Debug);
+ Logger::initialize ("copy", new TraceWriter ("xinsert.trace", 1024 * 1024));
+
+ testNull.start ();
+ }
+ catch (Exception& ex) {
+ cout << ex.asString () << endl;
+ }
+
+ return 0;
+}
+
+Insert::Insert () :
+ Application ("xinsert", "Copiador de la tabla ad_funcionalidades", "1.0"),
+ a_db (NULL)
+{
+ CommandLine& cl (CommandLine::instantiate ());
+
+ cl.add ("user", CommandLine::Argument::Mandatory, "Nombre del usuario");
+ cl.add ("password", CommandLine::Argument::Mandatory, "Clave del usuario");
+ cl.add ("host", CommandLine::Argument::Optional, "Nombre de la maquina donde se ubica el MySQL");
+ cl.add ("db", CommandLine::Argument::Optional, "Nombre de la base de datos");
+}
+
+/*
+ * Las sentencias SQL usadas por este programana estaba originalmente escritas para Oracle,
+ * pero no hay que cambiar cada sentencia manualmente, s�lo hay que activar el traductor
+ * correspondiente y anna.dbms.mysql lo hace autom�ticamente.
+ */
+void Insert::initialize ()
+ throw (RuntimeException)
+{
+ CommandLine& ccll = CommandLine::instantiate ();
+ const char* host = ccll.exists ("host") ? ccll.getValue ("host"): NULL;
+
+ a_db = new anna::dbms::mysql::Database (ccll.getValue ("db"), host);
+ a_db->setStatementTranslator (dbms::mysql::OracleTranslator::instantiate ());
+}
+
+void Insert::run ()
+ throw (RuntimeException)
+{
+ LOGMETHOD (TraceMethod tm ("Insert", "run", ANNA_FILE_LOCATION));
+
+ CommandLine& cl (CommandLine::instantiate ());
+
+ Statement* create;
+ Statement* insert;
+
+ dbms::Integer n (true);
+ dbms::String name (15, true);
+ dbms::Float zz (true);
+ dbms::TimeStamp time (true);
+
+ dbms::ResultCode resultCode;
+
+ try {
+ Connection* connection = a_db->createConnection ("xinsert", cl.getValue ("user"), cl.getValue ("password"));
+
+ {
+ Guard guard (connection);
+
+ try {
+ create = a_db->createStatement (
+ "create", "create table anna_db_test (xx integer, yy varchar (15), zz float, tt datetime)"
+ );
+
+ resultCode = connection->execute (create);
+ }
+ catch (Exception& ex) {
+ ex.trace ();
+ }
+ cout << "Creando: " << resultCode.asString () << endl << endl;
+ }
+ Guard guard (connection);
+
+ /*
+ * Observar que la sentencia indica los parámetros tal y como se haría en Oracle.
+ */
+ insert = a_db->createStatement ("select", "insert into anna_db_test (xx, yy, zz, tt) values (:x,:y,:z, :t)");
+ insert->bindInput ("XX", n);
+ insert->bindInput ("YY", name);
+ insert->bindInput ("zz", zz);
+ insert->bindInput ("tt", time);
+
+ n = 88;
+ name = "El 88";
+ zz = 0.88;
+ time.setValue (anna::functions::second ());
+ cout << endl << " --- Insertando 1 ---" << endl;
+ resultCode = connection->execute (insert);
+ cout << resultCode.asString () << endl << endl;
+
+ n = 1010;
+ name = "El 1010";
+ zz = 0.1010;
+ time.setNull (true);
+ cout << endl << " --- Insertando 2 (date=null)---" << endl;
+ resultCode = connection->execute (insert);
+ cout << resultCode.asString () << endl << endl;
+
+ n = 89;
+ name.setNull (true);
+ zz = 0.89;
+ time.setValue ((Second)(anna::functions::second () + 100));
+ cout << endl << " --- Insertando 2 (name=null)---" << endl;
+ resultCode = connection->execute (insert);
+ cout << resultCode.asString () << endl << endl;
+ }
+ catch (dbms::DatabaseException& edb) {
+ throw RuntimeException (edb);
+ }
+}
+
+
+
--- /dev/null
+anna_dbms.mysql_static
+anna_dbms_static
+anna_comm_static
+anna_app_static
+anna_xml_static
+anna_io_static
+anna_core_static
+mysqlclient
+rt
+xml2
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <iostream>
+
+#include <anna/core/core.hpp>
+#include <anna/dbms/dbms.hpp>
+#include <anna/app/app.hpp>
+
+#include <anna/dbms.mysql/Database.hpp>
+#include <anna/dbms.mysql/OracleTranslator.hpp>
+
+class Select : public Application {
+public:
+ Select ();
+ ~Select () { delete a_db; }
+
+private:
+ anna::dbms::Database* a_db;
+
+ void initialize () throw (RuntimeException);
+ void run () throw (RuntimeException);
+};
+
+using namespace std;
+
+int main (int argc, const char** argv)
+{
+ CommandLine& commandLine (CommandLine::instantiate ());
+ Select testNull;
+
+ try {
+ commandLine.initialize (argv, argc);
+ commandLine.verify ();
+
+ Logger::setLevel (Logger::Debug);
+ Logger::initialize ("copy", new TraceWriter ("xselect.trace", 1024 * 1024));
+
+ testNull.start ();
+ }
+ catch (Exception& ex) {
+ cout << ex.asString () << endl;
+ }
+
+ return 0;
+}
+
+Select::Select () :
+ Application ("xselect", "Copiador de la tabla ad_funcionalidades", "1.0"),
+ a_db (NULL)
+{
+ CommandLine& cl (CommandLine::instantiate ());
+
+ cl.add ("user", CommandLine::Argument::Mandatory, "Nombre del usuario");
+ cl.add ("password", CommandLine::Argument::Mandatory, "Clave del usuario");
+ cl.add ("host", CommandLine::Argument::Optional, "Nombre de la maquina donde se ubica el MySQL");
+ cl.add ("db", CommandLine::Argument::Optional, "Nombre de la base de datos");
+}
+
+/*
+ * Las sentencias SQL usadas por este programana estaba originalmente escritas para Oracle,
+ * pero no hay que cambiar cada sentencia manualmente, s�lo hay que activar el traductor
+ * correspondiente y anna.dbms.mysql lo hace autom�ticamente.
+ */
+void Select::initialize ()
+ throw (RuntimeException)
+{
+ CommandLine& ccll = CommandLine::instantiate ();
+ const char* host = ccll.exists ("host") ? ccll.getValue ("host"): NULL;
+
+ a_db = new anna::dbms::mysql::Database (ccll.getValue ("db"), host);
+ a_db->setStatementTranslator (dbms::mysql::OracleTranslator::instantiate ());
+}
+
+void Select::run ()
+ throw (RuntimeException)
+{
+ LOGMETHOD (TraceMethod tm ("Select", "run", ANNA_FILE_LOCATION));
+
+ CommandLine& cl (CommandLine::instantiate ());
+
+ Statement* select;
+
+ dbms::Integer n (true);
+ dbms::String name (15, true);
+ dbms::Float zz (true);
+ dbms::TimeStamp tt (true);
+
+ dbms::ResultCode resultCode;
+
+ try {
+ Connection* connection = a_db->createConnection ("xselect", cl.getValue ("user"), cl.getValue ("password"));
+
+ Guard guard (connection);
+
+ select = a_db->createStatement ("select", "select xx,yy,zz, tt from anna_db_test");
+ select->bindOutput ("XX", n);
+ select->bindOutput ("YY", name);
+ select->bindOutput ("zz", zz);
+ select->bindOutput ("tt", tt);
+
+ cout << endl << " --- Leyendo ---" << endl;
+ resultCode = connection->execute (select);
+
+ if (resultCode.successful () == true) {
+ while (select->fetch () == true) {
+ if (n.isNull () == true)
+ cout << "<null>";
+ else
+ cout << n;
+
+ cout << " | YY: " << ((name.isNull () == true) ? "<null>": name);
+
+ cout << " | ZZ: ";
+ if (zz.isNull () == true)
+ cout << "<null>";
+ else
+ cout << zz.getValue ();
+
+ cout << " | TT: " << ((tt.isNull () == true) ? "<null>": tt.getCStringValue ());
+
+ cout << endl;
+ }
+ }
+ else
+ cout << resultCode.asString () << endl << endl;
+ }
+ catch (dbms::DatabaseException& edb) {
+ throw RuntimeException (edb);
+ }
+}
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include "Abstract.hpp"
+
+using namespace std;
+using namespace anna;
+using namespace workdir;
+
+filesystem::Abstract::Abstract (const Abstract::ClassType::_v classType, const std::string& name) :
+ a_classType (classType),
+ a_name (name), a_parent (NULL)
+{
+ a_path = name;
+}
+
+filesystem::Abstract::Abstract (const Abstract::ClassType::_v classType, filesystem::Abstract* parent, const std::string& name) :
+ a_classType (classType),
+ a_name (name),
+ a_parent (parent)
+{
+ a_parent->a_children.push_back (this);
+ a_path = calculePath (parent, name);
+}
+
+/*virtual*/
+filesystem::Abstract::~Abstract ()
+{
+ for (child_iterator ii = child_begin (), maxii = child_end (); ii != maxii; ii ++)
+ delete child (ii);
+
+ a_children.clear ();
+}
+
+/* static */
+string filesystem::Abstract::calculePath (const filesystem::Abstract* parent, const std::string& shortPath)
+ throw ()
+{
+ string result;
+
+ if (parent!= NULL) {
+ result = parent->a_path;
+ result += '/';
+ }
+
+ return result += shortPath;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef dbos_workdir_filesystem_Abstract_hpp
+#define dbos_workdir_filesystem_Abstract_hpp
+
+#include <vector>
+#include <string>
+
+#include <anna/core/util/ExclusiveHash.hpp>
+
+namespace workdir {
+
+namespace filesystem {
+
+using namespace anna;
+
+class Abstract {
+public:
+ struct ClassType { enum _v { Directory, File }; };
+
+ typedef std::vector <Abstract*> child_container;
+ typedef child_container::iterator child_iterator;
+ typedef child_container::const_iterator const_child_iterator;
+
+ virtual ~Abstract ();
+
+ Abstract* getParent () const throw () { return a_parent; }
+ ClassType::_v getClassType () const throw () { return a_classType; }
+ const std::string& getName () const throw () { return a_name; }
+ const std::string& getPath () const throw () { return a_path; }
+
+ int child_size () const throw () { return a_children.size (); }
+
+ child_iterator child_begin () throw () { return a_children.begin (); }
+ child_iterator child_end () throw () { return a_children.end (); }
+ static Abstract* child (child_iterator ii) throw () { return *ii; }
+
+ const_child_iterator child_begin () const throw () { return a_children.begin (); }
+ const_child_iterator child_end () const throw () { return a_children.end (); }
+ static const Abstract* child (const_child_iterator ii) throw () { return *ii; }
+
+ static std::string calculePath (const Abstract* parent, const std::string& shortPath) throw ();
+
+ virtual void print (const int level) const throw () = 0;
+
+protected:
+ Abstract (const ClassType::_v, const std::string& name);
+ Abstract (const ClassType::_v, Abstract* parent, const std::string& name);
+
+private:
+ const ClassType::_v a_classType;
+ Abstract* a_parent;
+ const std::string a_name;
+ std::string a_path;
+ child_container a_children;
+
+ Abstract (const Abstract&);
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <iostream>
+
+#include "Directory.hpp"
+#include "File.hpp"
+
+using namespace std;
+using namespace anna;
+using namespace workdir;
+
+void filesystem::Directory::print (const int level) const
+ throw ()
+{
+ filesystem::Directory::const_child_iterator ii;
+ filesystem::Directory::const_child_iterator maxii = child_end ();
+ const filesystem::Directory* auxd;
+ const filesystem::File* auxf;
+ int row = 0;
+ bool hasDirectories = false;
+
+ for (int space = 0; space < level; space ++)
+ cout << " ";
+
+ cout << getName () << "/ (" << child_size () << "): " << endl;
+
+ /*
+ * Recorre todas las dependencias y visualiza primero todos los ficheros
+ */
+ for (ii = child_begin (); ii != maxii; ii ++) {
+ auxf = filesystem::File::down_cast (filesystem::Directory::child (ii));
+
+ if (auxf == NULL) {
+ hasDirectories = true;
+ continue;
+ }
+
+ if (row == 0) {
+ for (int space = 0; space < level + 1; space ++)
+ cout << " ";
+ }
+
+ auxf->print (level + 1);
+
+ if (++ row == 5) {
+ cout << endl;
+ row = 0;
+ }
+ }
+
+ if (row > 0)
+ cout << endl;
+
+ /*
+ * Trata los directorios recursivamente
+ */
+ for (ii = child_begin (); hasDirectories == true && ii != maxii; ii ++) {
+ auxd = filesystem::Directory::down_cast (filesystem::Directory::child (ii));
+
+ if (auxd != NULL)
+ auxd->print (level + 1);
+ }
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef dbos_workdir_filesystem_Directory_hpp
+#define dbos_workdir_filesystem_Directory_hpp
+
+#include "Abstract.hpp"
+
+namespace workdir {
+
+namespace filesystem {
+
+using namespace anna;
+
+class Directory : public Abstract {
+public:
+ Directory (const std::string& name) : Abstract (ClassType::Directory, name) {;}
+ Directory (Directory* parent, const std::string& name) : Abstract (ClassType::Directory, parent, name) {;}
+
+ void print (const int level = 0) const throw ();
+
+ static Directory* down_cast (Abstract* abstract) throw () {
+ return (abstract->getClassType () == ClassType::Directory) ? static_cast <Directory*> (abstract): NULL;
+ }
+ static const Directory* down_cast (const Abstract* abstract) throw () {
+ return (abstract->getClassType () == ClassType::Directory) ? static_cast <const Directory*> (abstract): NULL;
+ }
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <iostream>
+
+#include "File.hpp"
+
+using namespace std;
+using namespace anna;
+using namespace workdir;
+
+void filesystem::File::print (const int) const
+ throw ()
+{
+ cout << getName () << " " << flush;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef dbos_workdir_filesystem_File_hpp
+#define dbos_workdir_filesystem_File_hpp
+
+#include "Abstract.hpp"
+#include "Directory.hpp"
+
+namespace workdir {
+
+namespace filesystem {
+
+using namespace anna;
+
+class File : public Abstract {
+public:
+ File (Directory* parent, const std::string& name) : Abstract (ClassType::File, parent, name) {;}
+
+ void print (const int level) const throw ();
+
+ static File* down_cast (Abstract* abstract) throw () {
+ return (abstract->getClassType () == ClassType::File) ? static_cast <File*> (abstract): NULL;
+ }
+ static const File* down_cast (const Abstract* abstract) throw () {
+ return (abstract->getClassType () == ClassType::File) ? static_cast <const File*> (abstract): NULL;
+ }
+};
+
+}
+}
+
+#endif
--- /dev/null
+anna_dbos_static
+anna_dbms_static
+anna_comm_static
+anna_app_static
+anna_xml_static
+anna_io_static
+anna_core_static
+rt
+xml2
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <iostream>
+
+#include <anna/core/core.hpp>
+#include <anna/app/app.hpp>
+
+#include <anna/io/Directory.hpp>
+#include <anna/io/functions.hpp>
+
+#include <anna/xml/Compiler.hpp>
+#include <anna/xml/Node.hpp>
+
+#include <anna/dbos/Repository.hpp>
+#include <anna/dbos/AutoObject.hpp>
+
+#include "filesystem/Directory.hpp"
+#include "filesystem/File.hpp"
+
+#include "storage/Directory.hpp"
+#include "storage/File.hpp"
+
+using namespace std;
+using namespace workdir;
+
+template <typename T> void message (const char* text, T* tt) throw () {
+ if (Logger::isActive (Logger::Debug) == false)
+ return;
+
+ cout << " " << text << " (";
+ cout << anna::functions::asHexString (anna_ptrnumber_cast (tt));
+ cout << "): ";
+
+ if (tt != NULL)
+ cout << tt->asString ();
+ else
+ cout << "<null>";
+
+ cout << endl;
+}
+
+class WorkDirectory : public Application {
+public:
+ struct Flags { enum _v { None = 0, Clear = 1 }; };
+
+ WorkDirectory ();
+
+ xml::Node* asXML (xml::Node* parent) const throw ();
+
+private:
+ typedef vector <storage::File*> file_container;
+ typedef file_container::iterator file_iterator;
+ typedef file_container::reverse_iterator file_reverse_iterator;
+
+ dbos::Repository a_repository;
+ filesystem::Directory* a_root;
+ file_container a_files;
+
+ void initialize () throw (RuntimeException);
+ void run () throw (RuntimeException);
+
+ void forward (filesystem::Directory*) throw (RuntimeException);
+ void instantiateOne (filesystem::Directory*) throw (RuntimeException);
+ void fullCache (filesystem::Directory*, file_container&, const int flags) throw (RuntimeException);
+ void reuseHoles (filesystem::Directory*, file_container&) throw (RuntimeException);
+ void destroyObjects (filesystem::Directory* dir, file_container&) throw (RuntimeException);
+ void clear (file_container&) throw ();
+
+ static void load (filesystem::Directory* parent, const int maxLevel, const int level = 0) throw (RuntimeException);
+};
+
+using namespace std;
+
+int main (int argc, const char** argv)
+{
+ CommandLine& commandLine (CommandLine::instantiate ());
+ WorkDirectory storageNull;
+
+ try {
+ commandLine.initialize (argv, argc);
+ commandLine.verify ();
+
+ Logger::setLevel (Logger::Local6);
+ Logger::initialize ("workdir", new TraceWriter ("file.trace", 4 * 1024 * 1024));
+
+ storageNull.start ();
+ }
+ catch (Exception& ex) {
+ cout << ex.asString () << endl;
+ }
+
+ return 0;
+}
+
+WorkDirectory::WorkDirectory () :
+ Application ("workdir", "Dbos workdir", "1.0.0"),
+ a_repository ("workdir")
+{
+ CommandLine& cl (CommandLine::instantiate ());
+
+ cl.add ("dir", CommandLine::Argument::Mandatory, "Nombre del directorio a procesar");
+ cl.add ("l", CommandLine::Argument::Optional, "Numero maximo de niveles de profundidad");
+ cl.add ("trace", CommandLine::Argument::Optional, "Nivel de trazado");
+ cl.add ("s", CommandLine::Argument::Mandatory, "Cache size");
+}
+
+void WorkDirectory::initialize ()
+ throw (RuntimeException)
+{
+}
+
+void WorkDirectory::run ()
+ throw (RuntimeException)
+{
+ LOGMETHOD (TraceMethod tm ("WorkDirectory", "run", ANNA_FILE_LOCATION));
+
+ CommandLine& cl (CommandLine::instantiate ());
+
+ const std::string& dir = cl.getValue ("dir");
+ const int maxLevel = cl.exists ("l") ? cl.getIntegerValue ("l"): -1;
+
+ if (cl.exists ("trace") == true)
+ Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
+
+ const int cacheSize = cl.getIntegerValue ("s");
+
+ storage::Directory::setup (a_repository, cacheSize);
+ storage::File::setup (a_repository, cacheSize);
+
+ a_root = new filesystem::Directory (dir);
+
+ load (a_root, maxLevel);
+
+ a_root->print ();
+ cout << endl;
+
+ forward (a_root);
+
+ writeContext ("file.context");
+}
+
+xml::Node* WorkDirectory::asXML (xml::Node* parent) const
+ throw ()
+{
+ xml::Node* result = app::Application::asXML (parent);
+ a_repository.asXML (result);
+ return result;
+}
+
+void WorkDirectory::forward (filesystem::Directory* dir)
+ throw (RuntimeException)
+{
+ cout << "forward: " << dir->getPath () << endl;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
+ dir = filesystem::Directory::down_cast (filesystem::Directory::child (ii));
+
+ if (dir == NULL)
+ continue;
+
+ try {
+ instantiateOne (dir);
+ fullCache (dir, a_files, Flags::Clear);
+ reuseHoles (dir, a_files);
+ destroyObjects (dir, a_files);
+ forward (dir);
+ }
+ catch (RuntimeException& ex) {
+ ex.trace ();
+ }
+ }
+}
+
+/*
+ * Crea una serie de instancia simultáneas sobre el mismo objeto para verificar que sólo lo carga
+ * de verdad sea necesario.
+ */
+void WorkDirectory::instantiateOne (filesystem::Directory* dir)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "instantiateOne", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::instantiateOne: Instancia varias veces la misma instancia para verificar el reuso" << endl;
+
+ storage::Directory* aux;
+
+ {
+ dbos::AutoObject <storage::Directory> root1;
+ aux = root1 = storage::Directory::instantiate (dir);
+ message ("Root1", aux);
+
+ dbos::AutoObject <storage::Directory> root2;
+ aux = root2 = storage::Directory::instantiate (dir);
+ message ("Root2", aux);
+ }
+
+ dbos::AutoObject <storage::Directory> root3;
+ aux = root3 = storage::Directory::instantiate (dir);
+ message ("Root3", aux);
+
+ message ("StorageArea", storage::File::getStorageArea ());
+
+ cout << endl;
+}
+
+void WorkDirectory::fullCache (filesystem::Directory* dir, WorkDirectory::file_container& files, const int flags)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "fullCache", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::fullCache: Llena la cache de objetos para verificar que crece tanto como sea necesario" << endl;
+
+ filesystem::File* file;
+
+ int maxSize = storage::File::getMaxSize ();
+
+ maxSize += rand () % maxSize;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
+ file = filesystem::File::down_cast (filesystem::Directory::child (ii));
+
+ if (file != NULL) {
+ storage::File* storageFile = storage::File::instantiate (file);
+ message ("File", storageFile);
+ files.push_back (storageFile);
+
+// if (files.size () >= maxSize)
+// break;
+ }
+ }
+
+ message ("StorageArea (full)", storage::File::getStorageArea ());
+
+ if (flags & Flags::Clear)
+ clear (files);
+
+ message ("StorageArea (empty)", storage::File::getStorageArea ());
+
+ cout << endl;
+}
+
+void WorkDirectory::reuseHoles (filesystem::Directory* dir, WorkDirectory::file_container& files)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "reuseHoles", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::reuseHoles: Invoca dos veces a fullCache para verificar que el tamano se mantiene la segunda vez" << endl;
+ fullCache (dir, files, Flags::Clear);
+ fullCache (dir, files, Flags::Clear);
+ cout << endl;
+}
+
+void WorkDirectory::destroyObjects (filesystem::Directory* dir, WorkDirectory::file_container& files)
+ throw (RuntimeException)
+{
+ TraceMethod tm ("WorkDirectory", "destroyObjects", ANNA_FILE_LOCATION);
+
+ cout << "WorkDirectory::destroyObjects: Carga un directorio distinto, para verificar que destruye los objetos segun se dejan de utilizar" << endl;
+ filesystem::File* file;
+ filesystem::Directory* other = NULL;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii && other == NULL; ii ++)
+ other = filesystem::Directory::down_cast (filesystem::Directory::child (ii));
+
+ if (other == NULL) {
+ cout << dir->getPath () << ": No se puede realizar esta prueba" << endl << endl;
+ return;
+ }
+
+ cout << "New Directory: " << other->getPath () << endl;
+ dir = other;
+
+ for (filesystem::Directory::child_iterator ii = dir->child_begin (), maxii = dir->child_end (); ii != maxii; ii ++) {
+ file = filesystem::File::down_cast (filesystem::Directory::child (ii));
+
+ if (file != NULL) {
+ storage::File* storageFile = storage::File::instantiate (file);
+ message ("File", storageFile);
+ storage::File::release (storageFile);
+ }
+ }
+
+ message ("StorageArea", storage::File::getStorageArea ());
+
+ cout << endl;
+}
+
+
+void WorkDirectory::clear (WorkDirectory::file_container& files)
+ throw ()
+{
+ storage::File* file;
+
+ /* Libera los objetos en distinto orden para empeorar el tratamiento huecos */
+
+ if ((anna::functions::millisecond () % 2) == 0) {
+ cout << "Clear directo" << endl;
+ for (file_iterator ii = files.begin (), maxii = files.end (); ii != maxii; ii ++) {
+ file = *ii;
+ storage::File::release (file);
+ }
+ }
+ else {
+ cout << "Clear inverso" << endl;
+ for (file_reverse_iterator ii = files.rbegin (), maxii = files.rend (); ii != maxii; ii ++) {
+ file = *ii;
+ storage::File::release (file);
+ }
+ }
+
+ files.clear ();
+}
+
+/*static*/
+void WorkDirectory::load (filesystem::Directory* parent, const int maxLevel, const int level)
+ throw (RuntimeException)
+{
+ if (level == maxLevel)
+ return;
+
+ io::Directory directory;
+ string fullPath;
+
+ directory.read (parent->getPath (), io::Directory::Mode::ShortPath);
+
+ for (io::Directory::const_iterator ii = directory.begin (), maxii = directory.end (); ii != maxii; ii ++) {
+ const std::string& name = io::Directory::data (ii);
+
+ fullPath = filesystem::Abstract::calculePath (parent, name);
+
+ if (io::functions::isADirectory (fullPath)) {
+ try {
+ filesystem::Directory* dd = new filesystem::Directory (parent, name);
+ load (dd, maxLevel, level + 1);
+ }
+ catch (RuntimeException& ex) {
+ ex.trace ();
+ }
+ }
+ else {
+ //Auto association to the parent:
+ new filesystem::File (parent, name);
+ }
+ }
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/io/functions.hpp>
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Statement.hpp>
+
+#include <anna/dbos/Repository.hpp>
+
+#include "../filesystem/Directory.hpp"
+
+#include "Directory.hpp"
+
+using namespace std;
+using namespace anna;
+using namespace workdir;
+
+/*static*/
+storage::Directory::Loader* storage::Directory::st_loader = NULL;
+
+/*static*/
+ExclusiveHash <std::string> storage::Directory::st_hash;
+
+/*static*/
+int storage::Directory::st_maxSize = 0;
+
+dbos_prepare_object (storage::Directory);
+
+void storage::Directory::setup (dbos::Repository& repository, const int maxSize)
+ throw (RuntimeException)
+{
+ st_loader = new Directory::Loader ();
+ st_maxSize = maxSize;
+
+ Directory::setStorageArea (
+ repository.createStorageArea ( // (1)
+ Directory::getStorageAreaId (), Directory::getStorageAreaName (), Directory::getMaxSize (),
+ Directory::allocator, 2
+ )
+ );
+}
+
+storage::Directory* storage::Directory::instantiate (const filesystem::Directory* directory)
+ throw (RuntimeException)
+{
+ if (st_loader == NULL)
+ throw RuntimeException ("storage::Directory::setup no ha sido invocado", ANNA_FILE_LOCATION);
+
+ Directory* result = NULL;
+
+ try {
+ Guard guard (st_loader, "storage::Directory::Loader");
+ result = dbos::ObjectFacade <Directory>::instance (st_loader->setKey (directory));
+ }
+ catch (dbms::DatabaseException& edb) {
+ throw RuntimeException (edb);
+ }
+
+ return result;
+}
+
+void storage::Directory::initialize (dbos::Loader& loader)
+ throw (RuntimeException, dbms::DatabaseException)
+{
+ Directory::Loader& dbLoader = static_cast <Directory::Loader&> (loader);
+
+ a_filesystemDirectory = dbLoader.getDirectory ();
+ a_inode = dbLoader.getINode ();
+
+ LOGINFORMATION (
+ string msg ("storage::Directory::initialize | ");
+ msg += asString ();
+ Logger::information (msg, ANNA_FILE_LOCATION);
+ );
+}
+
+void storage::Directory::destroy ()
+ throw ()
+{
+ LOGINFORMATION (
+ string msg ("storage::Directory::destroy | ");
+ msg += asString ();
+ Logger::information (msg, ANNA_FILE_LOCATION);
+ );
+}
+
+string storage::Directory::asString () const
+ throw ()
+{
+ std::string result ("storage::Directory { Name: ");
+ result += a_filesystemDirectory->getPath ();
+ result += functions::asHexText (" | I-Node: ", a_inode);
+ return result += " }";
+}
+
+/*
+ * Transfiere la información del medio físico al primer nivel de C++.
+ * Posteriormente será interpretada en storage::Directory::initialize
+ */
+bool storage::Directory::Loader::load (dbms::Connection*, const dbos::StorageArea* ssaa)
+ throw (RuntimeException)
+{
+ a_inode = io::functions::getINode (a_filesystemDirectory->getPath ());
+ return true;
+}
+
+dbos::Index storage::Directory::Loader::getIndex () const
+ throw ()
+{
+ return st_hash.calcule (a_filesystemDirectory->getPath ());
+}
+
+string storage::Directory::Loader::asString () const
+ throw ()
+{
+ std::string result ("storage::Loader::Directory { Name: ");
+ result += a_filesystemDirectory->getPath ();
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef dbos_workdir_storage_Directory_hpp
+#define dbos_workdir_storage_Directory_hpp
+
+#include <anna/dbos/Object.hpp>
+#include <anna/dbos/ObjectFacade.hpp>
+#include <anna/dbos/Loader.hpp>
+
+namespace anna {
+namespace dbms {
+class Database;
+class Connection;
+}
+namespace dbos {
+class Repository;
+}
+}
+
+namespace workdir {
+
+namespace filesystem {
+class Directory;
+}
+
+namespace storage {
+
+using namespace anna;
+
+class Directory : public dbos::Object, public dbos::ObjectFacade <Directory> {
+public:
+ const filesystem::Directory* getFilesystemDirectory() const throw() { return a_filesystemDirectory; }
+ int getINode() const throw() { return a_inode; }
+
+ std::string asString() const throw();
+
+ static void setup(dbos::Repository&, const int maxSize) throw(RuntimeException);
+ static Directory* instantiate(const filesystem::Directory*) throw(RuntimeException);
+
+ static const char* getStorageAreaName() throw() { return "storage::Directory"; }
+ static const dbos::Size getMaxSize() throw() { return st_maxSize; }
+
+private:
+ class Loader : public dbos::Loader {
+ public:
+ Loader() : dbos::Loader() {;}
+
+ Loader& setKey(const filesystem::Directory* directory) throw() {
+ a_filesystemDirectory = directory;
+ return *this;
+ }
+
+ const filesystem::Directory* getDirectory() const throw() { return a_filesystemDirectory; }
+ int getINode() const throw() { return a_inode; }
+
+ dbos::Index getIndex() const throw();
+ std::string asString() const throw();
+
+ private:
+ const filesystem::Directory* a_filesystemDirectory;
+ int a_inode;
+
+ // dbms::Statement is not required
+ dbms::Statement* initialize(dbms::Database&) throw(RuntimeException) { return NULL; }
+ bool load(dbms::Connection*, const dbos::StorageArea*) throw(RuntimeException);
+ };
+
+ const filesystem::Directory* a_filesystemDirectory;
+ int a_inode;
+
+ static Loader* st_loader;
+ static ExclusiveHash <std::string> st_hash;
+ static int st_maxSize;
+
+ Directory() { ; }
+ Directory(const Directory&);
+
+ void initialize(dbos::Loader& loader) throw(RuntimeException, dbms::DatabaseException);
+ void destroy() throw();
+
+ dbos_declare_object(Directory);
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/io/functions.hpp>
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Statement.hpp>
+
+#include <anna/dbos/Repository.hpp>
+
+#include "../filesystem/File.hpp"
+#include "../filesystem/Directory.hpp"
+
+#include "File.hpp"
+#include "Directory.hpp"
+
+using namespace std;
+using namespace anna;
+using namespace workdir;
+
+/*static*/
+storage::File::Loader* storage::File::st_loader = NULL;
+
+/*static*/
+ExclusiveHash <std::string> storage::File::st_hash;
+
+/*static*/
+int storage::File::st_maxSize = 0;
+
+dbos_prepare_object (storage::File);
+
+void storage::File::setup (dbos::Repository& repository, const int maxSize)
+ throw (RuntimeException)
+{
+ st_loader = new File::Loader ();
+ st_maxSize = maxSize;
+
+ File::setStorageArea (
+ repository.createStorageArea ( // (1)
+ File::getStorageAreaId (), File::getStorageAreaName (), File::getMaxSize (),
+ File::allocator, 2
+ )
+ );
+}
+
+storage::File* storage::File::instantiate (const filesystem::File* file)
+ throw (RuntimeException)
+{
+ if (st_loader == NULL)
+ throw RuntimeException ("storage::File::setup no ha sido invocado", ANNA_FILE_LOCATION);
+
+ File* result = NULL;
+
+ try {
+ Guard guard (st_loader, "storage::File::Loader");
+ result = dbos::ObjectFacade <File>::instance (st_loader->setKey (file));
+ }
+ catch (dbms::DatabaseException& edb) {
+ throw RuntimeException (edb);
+ }
+
+ return result;
+}
+
+void storage::File::initialize (dbos::Loader& loader)
+ throw (RuntimeException, dbms::DatabaseException)
+{
+ File::Loader& dbLoader = static_cast <File::Loader&> (loader);
+
+ a_filesystemFile = dbLoader.getFile ();
+ a_parent = Directory::instantiate (filesystem::Directory::down_cast (a_filesystemFile->getParent ()));
+ a_inode = dbLoader.getINode ();
+
+ LOGINFORMATION (
+ string msg ("storage::File::initialize | ");
+ msg += asString ();
+ Logger::information (msg, ANNA_FILE_LOCATION);
+ );
+}
+
+void storage::File::destroy ()
+ throw ()
+{
+ LOGINFORMATION (
+ string msg ("storage::File::destroy | ");
+ msg += asString ();
+ Logger::information (msg, ANNA_FILE_LOCATION);
+ );
+ Directory::release (a_parent);
+}
+
+string storage::File::asString () const
+ throw ()
+{
+ std::string result ("storage::File { Name: ");
+ result += a_filesystemFile->getPath ();
+ result += functions::asHexText (" | I-Node: ", a_inode);
+ return result += " }";
+}
+
+/*
+ * Transfiere la información del medio físico al primer nivel de C++.
+ * Posteriormente será interpretada en storage::File::initialize
+ */
+bool storage::File::Loader::load (dbms::Connection*, const dbos::StorageArea* ssaa)
+ throw (RuntimeException)
+{
+ a_inode = io::functions::getINode (a_filesystemFile->getPath ());
+ return true;
+}
+
+dbos::Index storage::File::Loader::getIndex () const
+ throw ()
+{
+ return st_hash.calcule (a_filesystemFile->getPath ());
+}
+
+string storage::File::Loader::asString () const
+ throw ()
+{
+ std::string result ("storage::Loader::File { Name: ");
+ result += a_filesystemFile->getPath ();
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef dbos_workdir_storage_File_hpp
+#define dbos_workdir_storage_File_hpp
+
+#include <anna/dbos/Object.hpp>
+#include <anna/dbos/ObjectFacade.hpp>
+#include <anna/dbos/Loader.hpp>
+
+namespace anna {
+namespace dbms {
+class Database;
+class Connection;
+}
+namespace dbos {
+class Repository;
+}
+}
+
+namespace workdir {
+
+namespace filesystem {
+class File;
+}
+
+namespace storage {
+
+class Directory;
+
+using namespace anna;
+
+class File : public dbos::Object, public dbos::ObjectFacade <File> {
+public:
+ const Directory* getParent() const throw() { return a_parent; }
+ const filesystem::File* getFilesystemFile() const throw() { return a_filesystemFile; }
+ int getINode() const throw() { return a_inode; }
+
+ std::string asString() const throw();
+
+ static void setup(dbos::Repository&, const int maxSize) throw(RuntimeException);
+ static File* instantiate(const filesystem::File*) throw(RuntimeException);
+
+ static const char* getStorageAreaName() throw() { return "storage::File"; }
+ static const dbos::Size getMaxSize() throw() { return st_maxSize; }
+
+private:
+ class Loader : public dbos::Loader {
+ public:
+ Loader() : dbos::Loader() {;}
+
+ Loader& setKey(const filesystem::File* file) throw() {
+ a_filesystemFile = file;
+ return *this;
+ }
+
+ const filesystem::File* getFile() const throw() { return a_filesystemFile; }
+ int getINode() const throw() { return a_inode; }
+
+ dbos::Index getIndex() const throw();
+ std::string asString() const throw();
+
+ private:
+ const filesystem::File* a_filesystemFile;
+ int a_inode;
+
+ // dbms::Statement is not required
+ dbms::Statement* initialize(dbms::Database&) throw(RuntimeException) { return NULL; }
+ bool load(dbms::Connection*, const dbos::StorageArea*) throw(RuntimeException);
+ };
+
+ Directory* a_parent;
+ const filesystem::File* a_filesystemFile;
+ int a_inode;
+
+ static Loader* st_loader;
+ static ExclusiveHash <std::string> st_hash;
+ static int st_maxSize;
+
+ File() : a_parent(NULL) { ; }
+ File(const File&);
+
+ void initialize(dbos::Loader& loader) throw(RuntimeException, dbms::DatabaseException);
+ void destroy() throw();
+
+ dbos_declare_object(File);
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_BaseBind_hpp
+#define anna_dbms_mysql_BaseBind_hpp
+
+#include <anna/dbms/Data.hpp>
+
+#include <anna/dbms.mysql/forward.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+namespace mysql {
+
+class BaseBind {
+public:
+ virtual ~BaseBind();
+
+protected:
+ /*
+ * mysql.h:typedef char my_bool;
+ */
+ char a_nullIndicator;
+
+ /**
+ * mysql_time.h: typedef st_mysql_time MYSQL_TIME
+ */
+ st_mysql_time* a_time;
+
+ unsigned long a_length;
+
+ BaseBind(const dbms::Data& data) ;
+ void setupBind(st_mysql_bind&, dbms::Data&) throw(RuntimeException);
+
+private:
+ static const int MaxBlobSize = 2 << 16;
+
+ const Data::Type::_v a_type;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_Connection_hpp
+#define anna_dbms_mysql_Connection_hpp
+
+
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbms.mysql/forward.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Database;
+
+namespace mysql {
+
+class Database;
+
+/**
+ Clase que modela la conexion con el RDBMS MySQL (tm).
+
+ Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones
+ se hagan atraves de una instancia anna::dbms::Connection.
+
+ Para obtener una conexion a una determinada base de datos habra que instanciar dicha base de datos
+ e invocar al metodo createConnection. Independientemente del tipo de conexion particular que la
+ base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Connection.
+*/
+class Connection : public dbms::Connection {
+public:
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ std::string asString() const throw();
+
+ /**
+ Operador de conversion.
+ \return El puntero al entorno asociado a esta base de datos.
+ */
+ operator st_mysql*() throw() { return a_mysql; }
+
+private:
+ Database& a_mysqlDatabase;
+ st_mysql* a_mysql;
+
+ Connection(Database& database, const std::string& name, const char* user, const char* password);
+
+ bool isAvailable() const throw(RuntimeException) { return a_mysql != NULL; }
+
+ void do_commit() throw(RuntimeException, DatabaseException);
+ void do_rollback() throw();
+ void open() throw(DatabaseException);
+ void close() throw();
+
+ friend class anna::dbms::mysql::Database;
+};
+
+}
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_Database_hpp
+#define anna_dbms_mysql_Database_hpp
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+namespace mysql {
+
+/**
+ Clase que modela la interaccion entre la RDMS MySQL (tm) y nuestra aplicacion.
+*/
+class Database : public dbms::Database {
+public:
+ /**
+ Contructor.
+ \param dbmsName Nombre de la base de datos.
+ \param host Identificador de la máquina anfitriona, que se usará para hacer las conexiones. Puede ser NULL.
+ \see http://dev.mysql.com/doc/refman/4.1/en/mysql-real-connect.html
+ */
+ Database(const char* dbmsName, const char* host);
+
+ /**
+ Contructor.
+ \param componentName Nombre logico de la base de datos por que el podemos buscar este componente.
+ \param dbmsName Nombre de la base de datos.
+ \param host Identificador de la máquina anfitriona, que se usará para hacer las conexiones. Puede ser NULL.
+ \see http://dev.mysql.com/doc/refman/4.1/en/mysql-real-connect.html
+ */
+ Database(const char* componentName, const char* dbmsName, const char* host);
+
+ /**
+ Destructor.
+ */
+ virtual ~Database();
+
+ /**
+ * Devuelve el nombre de la máquina anfitriona indicado en el constructor.
+ * \return El nombre de la máquina anfitriona indicado en el constructor.
+ */
+ const char* getHost() const throw() { return a_host; }
+
+ /**
+ Devuelve la cadena por la que podemos buscar el componente.
+ \return La cadena por la que podemos buscar el componente.
+ \see Application::find
+ */
+ static const char* getClassName() { return "anna::dbms::mysql::Database"; }
+
+private:
+ char* a_host;
+
+ void do_initialize() throw(RuntimeException);
+
+ dbms::Connection* allocateConnection(const std::string& name, const char* user, const char* password)
+ throw(RuntimeException);
+
+ dbms::Statement* allocateStatement(const char* name, const std::string& expression, const bool isCritical)
+ throw(RuntimeException);
+
+ dbms::InputBind* allocateInputBind(const char* name, Data&)
+ throw(RuntimeException);
+ void deallocate(dbms::InputBind* inputBind) throw();
+
+ dbms::OutputBind* allocateOutputBind(const char* name, Data&)
+ throw(RuntimeException);
+ void deallocate(dbms::OutputBind* outputBind) throw();
+};
+
+#ifdef ANNA_RDBMS_TRACE
+#define anna_dbms_mysql_check(a,_mysql) \
+ { \
+ Logger::write (Logger::Debug, (#a), __FILE__, __LINE__); \
+ const int status = (a); \
+ if (status != 0) { \
+ anna::dbms::mysql::ResultCode resultCode ((_mysql)); \
+ throw DatabaseException (resultCode, __FILE__, __LINE__); \
+ } \
+ }
+#else
+#define anna_dbms_mysql_check(a,_mysql) \
+ { \
+ const int status = (a); \
+ if (status != 0) { \
+ anna::dbms::mysql::ResultCode resultCode ((_mysql)); \
+ throw DatabaseException (resultCode, __FILE__, __LINE__); \
+ } \
+ }
+#endif
+}
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_InputBind_hpp
+#define anna_dbms_mysql_InputBind_hpp
+
+#include <anna/dbms/InputBind.hpp>
+
+#include <anna/dbms.mysql/BaseBind.hpp>
+
+namespace anna {
+
+class DataBlock;
+
+namespace dbms {
+
+class Data;
+class Statement;
+
+namespace mysql {
+
+class Statement;
+
+class InputBind : public dbms::InputBind, public BaseBind {
+public:
+ InputBind(const char* name, dbms::Data& data);
+ virtual ~InputBind();
+
+private:
+ void code() const throw(RuntimeException);
+
+ void codeShortBlock(dbms::Data&) throw();
+ void codeDate(dbms::Data&) throw();
+
+ static char asCharacter(const char byte)
+ throw() {
+ return (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'A');
+ }
+
+ /* Funciones virtuales puras */
+ void prepare(anna::dbms::Statement*, anna::dbms::Connection*, const int pos) throw(RuntimeException);
+ void release(anna::dbms::Statement*) throw() {;}
+
+ friend class mysql::Statement;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_OracleTranslator_hpp
+#define anna_dbms_mysql_OracleTranslator_hpp
+
+#include <anna/dbms/StatementTranslator.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+namespace mysql {
+
+/**
+ * Ésta clase permite que sentencias, escritas originalmente para ser ejecutadas sobre
+ * Oracle (tm) puedan ser ejecutadas desde MySQL (tm) sin ningún tipo de problemas.
+ *
+ * Si este traductor se aplica sobre una sentencia SQL escrita originalmente para
+ * funcionar sobre MySQL el resultado será la misma sentencia.
+ *
+ * \see anna::dbms::Database::setStatementTranslator
+ */
+class OracleTranslator : public StatementTranslator {
+public:
+ /**
+ * Obtiene la instancia de este traductor de sentencias SQL.
+ */
+ static StatementTranslator* instantiate() throw() { return &st_this; }
+
+private:
+ char* a_buffer;
+ int a_size;
+
+ static OracleTranslator st_this;
+
+ OracleTranslator() : StatementTranslator("dbms::mysql::OracleTranslator"),
+ a_buffer(NULL), a_size(-1)
+ {;}
+
+ const char* apply(const char* statement) throw(RuntimeException);
+ void allocate(const char* statement) throw();
+};
+
+}
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_OutputBind_hpp
+#define anna_dbms_mysql_OutputBind_hpp
+
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/OutputBind.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbms.mysql/BaseBind.hpp>
+
+namespace anna {
+
+class DataBlock;
+
+namespace dbms {
+
+class Statement;
+
+namespace mysql {
+
+class OutputBind : public dbms::OutputBind, public BaseBind {
+public:
+ OutputBind(const char* name, dbms::Data& data);
+ ~OutputBind();
+
+private:
+ struct Blob {
+ DataBlock buffer;
+ st_mysql_stmt* stmt;
+ st_mysql_bind* binds;
+ int pos;
+
+ Blob();
+ };
+
+ Blob* a_blob;
+
+ void decodeLongBlob(dbms::Data&) const throw(RuntimeException, dbms::DatabaseException);
+ void decodeDate(dbms::Data&) throw();
+
+ static unsigned char asByte(const char hex)
+ throw() {
+ return (hex >= '0' && hex <= '9') ? (hex - '0') : ((hex - 'A') + 0x0a);
+ }
+
+ /* Funciones virtuales puras */
+ void decode() const throw(RuntimeException);
+ void prepare(anna::dbms::Statement*, anna::dbms::Connection*, const int pos) throw(RuntimeException);
+ void release(anna::dbms::Statement*) throw() {;}
+ void do_write(const dbms::LongBlock&) const throw(RuntimeException, dbms::DatabaseException);
+
+ friend class Statement;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_ResultCode_hpp
+#define anna_dbms_mysql_ResultCode_hpp
+
+#include <anna/dbms/ResultCode.hpp>
+
+#include <anna/dbms.mysql/forward.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+namespace mysql {
+
+/**
+ Clase para acceder a la informacion devuelta por el gestor de base de datos
+ referente al ultimo comando realizado.
+ */
+class ResultCode : public dbms::ResultCode {
+public:
+ /**
+ Constructor.
+ \param mysql Instancia de la base de datos sobre la que aplicamos la sentencia SQL.
+ */
+ explicit ResultCode(st_mysql* mysql);
+
+ /**
+ Constructor.
+ \param stmt Instancia de la sentencia ejecutada.
+ */
+ explicit ResultCode(st_mysql_stmt* stmt);
+
+private:
+ class ErrorDecoder : public dbms::ResultCode::ErrorDecoder {
+ bool notFound(const int errorCode) const throw();
+ bool successful(const int errorCode) const throw();
+ bool locked(const int errorCode) const throw();
+ bool lostConnection(const int errorCode) const throw();
+ };
+
+ static ErrorDecoder st_errorDecoder;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_Statement_hpp
+#define anna_dbms_mysql_Statement_hpp
+
+#include <anna/dbms/Statement.hpp>
+
+#include <anna/dbms.mysql/forward.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Connection;
+
+namespace mysql {
+
+class Database;
+
+/**
+ Clase que facilita la ejecucion de sentencias SQL a traves del RDBMS MySQL (tm).
+
+ Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones
+ se hagan atraves de una instancia anna::dbms::Statement.
+
+ Para obtener la instancia de un comando para una determinada base de datos habra que instanciar
+ dicha base de datos e invocar al metodo createStatement. Independientemente del tipo de comando
+ particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement.
+ */
+class Statement : public dbms::Statement {
+public:
+ /**
+ Destructor.
+ */
+ virtual ~Statement();
+
+ /**
+ Operador de conversion.
+ \return El puntero MYSQL_STMT de esta sentencia.
+ */
+ operator st_mysql_stmt*() throw() { return a_mysqlStmt; }
+
+ /**
+ * Obtiene el array asociado a los valores de entrada.
+ * \return El array asociado a los valores de entrada.
+ * \warning Exclusivamente uso interno.
+ */
+ st_mysql_bind* getBindParams() throw() { return a_params; }
+
+ /**
+ * Obtiene el array asociado a los valores de salida.
+ * \return El array asociado a los valores de salida.
+ * \warning Exclusivamente uso interno.
+ */
+ st_mysql_bind* getBindResults() throw() { return a_results; }
+
+private:
+ st_mysql_stmt* a_mysqlStmt;
+
+ st_mysql_bind* a_params;
+ st_mysql_bind* a_results;
+
+ Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
+ dbms::Statement(database, name, expression, isCritical),
+ a_mysqlStmt(NULL),
+ a_params(NULL),
+ a_results(NULL) {}
+
+ Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
+ dbms::Statement(database, name, expression, isCritical),
+ a_mysqlStmt(NULL),
+ a_params(NULL),
+ a_results(NULL) {}
+
+ st_mysql_bind* create(const int size, const char* whatis) throw(RuntimeException);
+
+ void prepare(dbms::Connection* connection) throw(RuntimeException, DatabaseException);
+ dbms::ResultCode execute(dbms::Connection* connection) throw(RuntimeException, DatabaseException);
+ bool fetch() throw(RuntimeException, DatabaseException);
+
+ friend class Database;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_forward_hpp
+#define anna_dbms_mysql_forward_hpp
+
+/*
+ * el MYSQL es un typedef definido sobre la estructura st_mysql
+ */
+struct st_mysql;
+
+/* MYSQL_STMT */
+struct st_mysql_stmt;
+
+/* MYSQL_BIND */
+struct st_mysql_bind;
+
+/* MYSQL_TIME */
+struct st_mysql_time;
+
+#endif /*_anna_dbms_mysql_forward_h*/
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_internal_sccs_hpp
+#define anna_dbms_mysql_internal_sccs_hpp
+
+namespace anna {
+
+namespace dbms {
+
+namespace mysql {
+
+class sccs {
+public:
+ static void activate() throw();
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_mysql_mysql_hpp
+#define anna_dbms_mysql_mysql_hpp
+
+namespace anna {
+
+namespace dbms {
+/**
+Proporciona las clases necesarias para acceder a la ejecucion de sentencias SQL para
+MySQL (tm).
+
+El ejecutable debera enlazarse con las librerias:
+ \li anna.core.a
+ \li anna.xml.a
+ \li anna.app.a
+ \li anna.comm.a
+ \li anna.dbms.a
+ \li anna.dbms.mysql.a
+
+El <b>Packet Header</b> es anna.dbms.mysql.h
+*/
+namespace mysql {
+}
+}
+}
+
+#include <anna/dbms.mysql/Connection.hpp>
+#include <anna/dbms.mysql/Database.hpp>
+#include <anna/dbms.mysql/InputBind.hpp>
+#include <anna/dbms.mysql/OutputBind.hpp>
+#include <anna/dbms.mysql/ResultCode.hpp>
+#include <anna/dbms.mysql/Statement.hpp>
+
+using namespace anna::dbms::mysql;
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_BaseBind_hpp
+#define anna_dbms_oracle_BaseBind_hpp
+
+struct OCIEnv;
+struct OCIError;
+struct OCIBind;
+struct OCILobLocator;
+struct OCISvcCtx;
+struct OCIDateTime;
+
+#include <anna/dbms.oracle/Descriptor.hpp>
+
+namespace anna {
+
+class DataBlock;
+
+namespace dbms {
+
+class Statement;
+class Data;
+
+namespace oracle {
+
+class Statement;
+class Database;
+class Connection;
+
+class BaseBind {
+public:
+ virtual ~BaseBind();
+
+protected:
+ /**
+ * Número de bytes reservados para un Float cuando se trata como si fuera una cadena.
+ */
+ static const int FloatSize = 63;
+ struct oci_param {
+ int type;
+ int maxLength;
+ short unsigned int* length;
+ void* buffer;
+ };
+ struct Blob : public Descriptor {
+ OCILobLocator* handle;
+ Blob() : Descriptor((dvoid**) &handle) {;}
+ };
+ struct DateTime : public Descriptor {
+ OCIDateTime* handle;
+ DateTime() : Descriptor((dvoid**) &handle) {;}
+ };
+
+ short a_nullIndicator;
+ unsigned short a_length;
+ anna::DataBlock* a_ofb; // Oracle Formatted Buffer.
+ Blob a_blob;
+ DateTime a_datetime;
+
+ BaseBind(const dbms::Data& data) ;
+
+ oci_param getOCIParam(Database&, Connection*, dbms::Data&) throw(RuntimeException);
+
+private:
+ const Data::Type::_v a_type;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_Connection_hpp
+#define anna_dbms_oracle_Connection_hpp
+
+struct OCIServer;
+struct OCISession;
+struct OCISvcCtx;
+
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Database;
+
+namespace oracle {
+
+class Database;
+
+/**
+ Clase que modela la conexion con el RDBMS Oracle (tm).
+
+ Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones
+ se hagan atraves de una instancia anna::dbms::Connection.
+
+ Para obtener una conexion a una determinada base de datos habra que instanciar dicha base de datos
+ e invocar al metodo createConnection. Independientemente del tipo de conexion particular que la
+ base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Connection.
+*/
+class Connection : public dbms::Connection {
+public:
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ std::string asString() const throw();
+
+ /**
+ Operador de conversion.
+ \return El puntero al contexto asociado a este conexion.
+ */
+ operator OCISvcCtx*() throw() { return a_context; }
+
+private:
+ Database& a_oracleDatabase;
+ OCISvcCtx* a_context;
+ OCISession* a_session;
+ OCIServer* a_server;
+
+ Connection(Database& database, const std::string& name, const char* user, const char* password);
+ bool isAvailable() const throw(RuntimeException) { return a_context != NULL && a_session != NULL && a_server != NULL; }
+ void do_commit() throw(RuntimeException, DatabaseException);
+ void do_rollback() throw();
+ void open() throw(DatabaseException);
+ void close() throw();
+
+ friend class anna::dbms::oracle::Database;
+};
+
+}
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_Database_hpp
+#define anna_dbms_oracle_Database_hpp
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+
+struct OCIEnv;
+struct OCIError;
+
+namespace anna {
+
+namespace dbms {
+
+namespace oracle {
+
+/**
+ Clase que modela la interaccion entre la RDMS Oracle (tm) y nuestra aplicacion.
+
+ \warning La definicion conexiones y clusters debe hacerse antes de invocar al metodo Application::start,
+ o bien, en el metodo Application::initialize.
+*/
+class Database : public dbms::Database {
+public:
+ /**
+ Contructor.
+ \param dbmsName Nombre de la base de datos.
+ */
+ Database(const char* dbmsName);
+
+ /**
+ Contructor.
+ \param componentName Nombre logico de la base de datos por que el podemos buscar este compoenente.
+ \param dbmsName Nombre de la base de datos.
+ */
+ Database(const char* componentName, const char* dbmsName);
+
+ /**
+ Destructor.
+ */
+ virtual ~Database();
+
+ /**
+ Devuelve el manejador de error asociado a esta base de datos.
+ \return El manejador de error asociado a esta base de datos.
+ */
+ OCIError* getErrorHandler() throw() { return a_error; }
+
+ /**
+ Operador de conversion.
+ \return El puntero al entorno asociado a esta base de datos.
+ */
+ operator OCIEnv*() throw() { return a_env; }
+
+ /**
+ Devuelve la cadena por la que podemos buscar el componente.
+ \return La cadena por la que podemos buscar el componente.
+ \see Application::find
+ */
+ static const char* getClassName() { return "anna::dbms::oracle::Database"; }
+
+ /**
+ * Devuelve el caracter usado como punto decimal, obtenido a partir de la configuración establecida
+ * por la variables de entorno, LANG, LC_NUMERIC, etc, etc.
+ *
+ * \return El caracter usado como punto decimal.
+ *
+ * \warning Metodo exclusivamente de uso interno.
+ */
+ static char getDecimalPoint() throw() { return st_decimalPoint; }
+
+private:
+ OCIEnv* a_env;
+ OCIError* a_error;
+
+ static char st_decimalPoint;
+
+ void do_initialize() throw(RuntimeException);
+
+ dbms::Connection* allocateConnection(const std::string& name, const char* user, const char* password)
+ throw(RuntimeException);
+
+ dbms::Statement* allocateStatement(const char* name, const std::string& expression, const bool isCritical)
+ throw(RuntimeException);
+
+ dbms::InputBind* allocateInputBind(const char* name, Data&)
+ throw(RuntimeException);
+ void deallocate(dbms::InputBind* inputBind) throw();
+
+ dbms::OutputBind* allocateOutputBind(const char* name, Data&)
+ throw(RuntimeException);
+ void deallocate(dbms::OutputBind* outputBind) throw();
+
+ static void initializeDecimalPoint() throw(RuntimeException);
+};
+
+#ifdef ANNA_RDBMS_TRACE
+#define anna_dbms_oracle_check(a,error) \
+ { \
+ Logger::write (Logger::Debug, (#a), __FILE__, __LINE__); \
+ const sword status = (a); \
+ if (status != OCI_SUCCESS) { \
+ anna::dbms::oracle::ResultCode resultCode (status, (error)); \
+ throw DatabaseException (resultCode, __FILE__, __LINE__); \
+ } \
+ }
+#else
+#define anna_dbms_oracle_check(a,error) \
+ { \
+ const sword status = (a); \
+ if (status != OCI_SUCCESS) { \
+ anna::dbms::oracle::ResultCode resultCode (status, (error)); \
+ throw DatabaseException (resultCode, __FILE__, __LINE__); \
+ } \
+ }
+#endif
+}
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_Descriptor_hpp
+#define anna_dbms_oracle_Descriptor_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+struct OCIEnv;
+struct OCIError;
+struct OCIBind;
+struct OCILobLocator;
+struct OCISvcCtx;
+
+namespace anna {
+
+namespace dbms {
+
+namespace oracle {
+
+class Database;
+class Connection;
+
+struct Descriptor {
+ dvoid** reference;
+ OCIEnv* env;
+ OCIError* error;
+ OCISvcCtx* context;
+ int type;
+
+ Descriptor(dvoid** _handle) : reference(_handle) {
+ *reference = NULL; env = NULL; error = NULL; context = NULL; type = -1;
+ }
+ virtual ~Descriptor();
+
+ void allocate(Database&, Connection*, const int type) throw(RuntimeException);
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_InputBind_hpp
+#define anna_dbms_oracle_InputBind_hpp
+
+#include <anna/dbms/InputBind.hpp>
+
+#include <anna/dbms.oracle/BaseBind.hpp>
+
+struct OCIBind;
+
+namespace anna {
+
+class DataBlock;
+
+namespace dbms {
+
+class Data;
+class Statement;
+
+namespace oracle {
+
+class Statement;
+
+class InputBind : public dbms::InputBind, public BaseBind {
+public:
+ InputBind(const char* name, dbms::Data& data);
+ virtual ~InputBind();
+
+private:
+ OCIBind* a_ociBind;
+
+ void code() const throw(RuntimeException);
+ void prepare(dbms::Statement*, dbms::Connection*, const int pos) throw(RuntimeException, DatabaseException);
+ void release(dbms::Statement*) throw() { a_ociBind = NULL; }
+
+ void codeFloat(dbms::Data&) const throw();
+ void codeShortBlock(dbms::Data&) const throw();
+ void codeDate(dbms::Data&) const throw(RuntimeException, DatabaseException);
+
+ static char asCharacter(const char byte)
+ throw() {
+ return (byte >= 0 && byte <= 9) ? (byte + '0') : ((byte - 0xa) + 'A');
+ }
+
+ friend class oracle::Statement;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_OutputBind_hpp
+#define anna_dbms_oracle_OutputBind_hpp
+
+#include <anna/dbms/OutputBind.hpp>
+
+#include <anna/dbms.oracle/BaseBind.hpp>
+
+struct OCIDefine;
+
+namespace anna {
+
+namespace dbms {
+
+class Statement;
+
+namespace oracle {
+
+class OutputBind : public dbms::OutputBind, public BaseBind {
+public:
+ OutputBind(const char* name, dbms::Data& data);
+ ~OutputBind();
+
+private:
+ OCIDefine* a_ociDefine;
+
+ void decode() const throw(anna::RuntimeException);
+ void prepare(dbms::Statement*, dbms::Connection*, const int pos) throw(DatabaseException);
+ void release(dbms::Statement*) throw() { a_ociDefine = NULL; }
+
+ void decodeFloat(dbms::Data&) const throw(RuntimeException);
+ void decodeShortBlock(dbms::Data&) const throw(RuntimeException);
+ void decodeLongBlock(dbms::Data&) const throw(RuntimeException);
+ void decodeDate(dbms::Data&) const throw(RuntimeException, DatabaseException);
+
+ void do_write(const dbms::LongBlock&) const throw(RuntimeException, dbms::DatabaseException);
+
+ static unsigned char asByte(const char hex)
+ throw() {
+ return (hex >= '0' && hex <= '9') ? (hex - '0') : ((hex - 'A') + 0x0a);
+ }
+
+ friend class Statement;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_ResultCode_hpp
+#define anna_dbms_oracle_ResultCode_hpp
+
+#include <anna/dbms/ResultCode.hpp>
+
+struct OCIError;
+
+namespace anna {
+
+namespace dbms {
+
+namespace oracle {
+
+/**
+ Clase para acceder a la informacion devuelta por el gestor de base de datos
+ referente al ultimo comando realizado.
+ */
+class ResultCode : public dbms::ResultCode {
+public:
+ /**
+ Constructor.
+
+ \param status Codigo de resultado de la ultima operacion realizada.
+ \param error Estructura de datos que contiene la informacion adicional sobre el error.
+ */
+ explicit ResultCode(const int status, OCIError* error);
+
+private:
+ class ErrorDecoder : public dbms::ResultCode::ErrorDecoder {
+ bool notFound(const int errorCode) const throw();
+ bool successful(const int errorCode) const throw();
+ bool locked(const int errorCode) const throw() { return errorCode == 54; }
+ bool lostConnection(const int errorCode) const throw();
+ };
+
+ static ErrorDecoder st_errorDecoder;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_Statement_hpp
+#define anna_dbms_oracle_Statement_hpp
+
+#include <anna/dbms/Statement.hpp>
+
+struct OCIStmt;
+struct OCIError;
+
+namespace anna {
+
+namespace dbms {
+
+class Connection;
+
+namespace oracle {
+
+/**
+ Clase que facilita la ejecucion de sentencias SQL a traves del RDBMS Oracle (tm).
+
+ Esta clase no puede usarse directamente, ya que la capa ANNA.dbms obliga a que todas las peticiones
+ se hagan atraves de una instancia anna::dbms::Statement.
+
+ Para obtener la instancia de un comando para una determinada base de datos habra que instanciar
+ dicha base de datos e invocar al metodo createStatement. Independientemente del tipo de comando
+ particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement.
+ */
+class Statement : public dbms::Statement {
+public:
+ /**
+ Destructor.
+ */
+ virtual ~Statement();
+
+ /**
+ Operador de conversion.
+ \return El puntero OCI de esta sentencia.
+ */
+ operator OCIStmt*() throw() { return a_ociStmt; }
+
+private:
+ OCIStmt* a_ociStmt;
+ OCIError* a_ociError;
+ bool a_firstFetch;
+
+ Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
+ dbms::Statement(database, name, expression, isCritical),
+ a_ociStmt(NULL),
+ a_ociError(NULL) {}
+
+ Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
+ dbms::Statement(database, name, expression, isCritical),
+ a_ociStmt(NULL),
+ a_ociError(NULL) {}
+
+ void prepare(dbms::Connection* connection) throw(RuntimeException, DatabaseException);
+ dbms::ResultCode execute(dbms::Connection* connection) throw(RuntimeException, DatabaseException);
+ bool fetch() throw(RuntimeException, DatabaseException);
+
+ friend class Database;
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_internal_sccs_hpp
+#define anna_dbms_oracle_internal_sccs_hpp
+
+namespace anna {
+
+namespace dbms {
+
+namespace oracle {
+
+class sccs {
+public:
+ static void activate() throw();
+};
+
+}
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_oracle_oracle_hpp
+#define anna_dbms_oracle_oracle_hpp
+
+namespace anna {
+
+namespace dbms {
+/**
+Proporciona las clases necesarias para acceder a la ejecucion de sentencias SQL para
+Oracle (tm).
+
+El ejecutable debera enlazarse con las librerias:
+ \li anna.core.a
+ \li anna.xml.a
+ \li anna.app.a
+ \li anna.comm.a
+ \li anna.dbms.a
+ \li anna.dbms.oracle.a
+
+El <b>Packet Header</b> es anna.dbms.oracle.h
+*/
+namespace oracle {
+}
+}
+}
+
+#include <anna/dbms.oracle/Connection.hpp>
+#include <anna/dbms.oracle/Database.hpp>
+#include <anna/dbms.oracle/InputBind.hpp>
+#include <anna/dbms.oracle/OutputBind.hpp>
+#include <anna/dbms.oracle/ResultCode.hpp>
+#include <anna/dbms.oracle/Statement.hpp>
+
+using namespace anna::dbms::oracle;
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Bind_hpp
+#define anna_dbms_Bind_hpp
+
+#include <anna/core/functions.hpp>
+#include <anna/core/RuntimeException.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Connection;
+class Statement;
+class Data;
+
+class Bind {
+public:
+ dbms::Data& getData() throw() { return a_data; }
+ const dbms::Data& getData() const throw() { return a_data; }
+
+ virtual void prepare(Statement* statement, Connection* connection, const int pos)
+ throw(RuntimeException, DatabaseException) = 0;
+
+ virtual void release(Statement* statement) throw() = 0;
+ virtual void code() const throw(RuntimeException) = 0;
+ virtual void decode() const throw(RuntimeException) = 0;
+ virtual std::string asString() const throw();
+
+protected:
+ Bind(const char* name, dbms::Data& data) : a_name(name), a_data(data) {;}
+
+private:
+ const std::string a_name;
+ dbms::Data& a_data;
+
+ friend class Statement;
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Connection_hpp
+#define anna_dbms_Connection_hpp
+
+#include <anna/comm/Resource.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+#include <anna/dbms/ResultCode.hpp>
+
+namespace anna {
+
+namespace xml {
+class Node;
+}
+
+namespace dbms {
+
+class Database;
+class Statement;
+
+/**
+ Clase que modela la conexion con la base de datos.
+
+ Para crear una nueva conexion hay que invocar al Metodo Database::createConnection de la base de datos
+ contra la que deseamos establecer la conexion.
+
+ Para obtener una conexion a una determinada base de datos habria que instanciar dicha base de datos
+ e invocar al Metodo Database::createConnection. Independientemente del tipo de conexion particular que la base
+ de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Connection.
+*/
+class Connection : public comm::Resource {
+public:
+ /**
+ Devuelve la instancia de la base de datos asociada a esta conexion.
+ */
+ Database& getDatabase() const throw() { return a_database; }
+
+ /**
+ * Devuelve el usuario con el que fué realizada esta conexión.
+ * \return el usuario con el que fué realizada esta conexión.
+ */
+ const std::string& getUser() const throw() { return a_user; }
+
+ /**
+ * Devuelve el password del usuario con el que fué realizada esta conexión.
+ * \return el password del usuario con el que fué realizada esta conexión.
+ */
+ const std::string& getPassword() const throw() { return a_password; }
+
+ /**
+ * Establece el password del usuario de esta conexión
+ * \param password Codigo de acceso del usuario.
+ */
+ void setPassword(const char* password) throw() { a_password = password; }
+
+ /**
+ Establece el periodo de grabacion de esta conexion. Damos la posibilidad de que la conexion confirme
+ cambios realizados hasta el momento sin que termine la seccion critica que debemos establecer antes
+ de usar la conexion.
+ \param maxCommitPending Numero de transacciones que pueden estar pedientes de confirmacion antes
+ de invocar a #commit. Un valor 0, desactiva el periodo.
+ \return El periodo de grabacion que habia antes de invocar a este metodo.
+ \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la
+ esta conexion.
+ */
+ int setMaxCommitPending(const int maxCommitPending) throw() {
+ const int result = a_maxCommitPending;
+ a_maxCommitPending = maxCommitPending;
+ return result;
+ }
+
+ /**
+ Desactiva el indicador de que la conexion requiere una invocacion a #rollback.
+ \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la
+ esta conexion.
+ */
+ void resetRollbackPending() throw() { a_rollbackPending = false; }
+
+ /**
+ Activa de forma externa el indicador de que la conexion requiere una invocacion a #rollback.
+ \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la
+ esta conexion.
+ */
+ void activateRollbackPending() throw() { a_rollbackPending = true; }
+
+ /**
+ Ejecuta la sentencia recibida como parametro. Si la sentencia no tiene variables de salida consideraria
+ que es un comando \em update, \em insert o \em delete, lo cual, implica la invocacion automatica a los
+ #commit o #rollback cuando termine la seccion critica de esta conexion.
+
+ \param statement Sentencia que vamos a ejecuta
+
+ \return La estructura con el resultado de la ejecucion de la sentencia.
+
+ \warning La invocacion a este metodo debera hacerse con una seccion critica activada sobre la
+ esta conexion, por ejemplo:
+ \code
+ Guard guard (connection);
+ connection.execute (someStatement);
+ \endcode
+ */
+ ResultCode execute(Statement* statement) throw(RuntimeException, DatabaseException);
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+ /**
+ Devuelve un documento XML con la informacion referente a esta instancia.
+ \param parent Nodo XML del que debe colgar la informacion.
+ @return un documento XML con la informacion referente a esta instancia.
+ */
+ virtual xml::Node* asXML(xml::Node* parent) const throw();
+
+protected:
+ /**
+ Instancia de la base de datos asociada a esta conexion.
+ Coincidiria con la indicada en el constructor.
+ */
+ Database& a_database;
+ std::string a_user; /**< Nombre del usuario */
+ std::string a_password; /**< Clave de acceso del usuario. */
+
+ /**
+ Contructor.
+
+ @param database Instancia de la base de datos asociada a esta conexion.
+ @param name Nombre logico de la conexion.
+ @param user Nombre del usuario con el que realizamos la conexion.
+ @param password Codigo de acceso del usuario.
+ */
+ Connection(Database& database, const std::string& name, const char* user, const char* password) :
+ comm::Resource(name),
+ a_database(database),
+ a_user(user),
+ a_password(password),
+ a_lockingCounter(0),
+ a_commitPending(0),
+ a_rollbackPending(false),
+ a_maxCommitPending(0) {}
+
+ /**
+ Metodo que fija los cambios realizados en la ejecucion de los comandos SQL.
+ */
+ void commit() throw(RuntimeException, DatabaseException);
+
+ /**
+ Metodo que debemos re-escribir para descartar los cambios realizados sobre las tablas mediante
+ esta conexion.
+ */
+ void rollback() throw();
+
+ /**
+ Metodo que debemos re-escribir para hacer efectiva esta conexion.
+ */
+ virtual void open() throw(DatabaseException) = 0;
+
+ /**
+ Metodo que debemos re-escribir para cerrar la conexion.
+ */
+ virtual void close() throw() = 0;
+
+private:
+ int a_commitPending; // Numero de sentencias a las que no se han fijado cambios.
+ bool a_rollbackPending;
+ int a_maxCommitPending;
+ int a_lockingCounter;
+
+ Connection(const Connection&);
+
+ void initialize() throw(RuntimeException, DatabaseException);
+ void lock() throw(RuntimeException);
+ void unlock() throw();
+
+ virtual bool do_beginTransaction() throw(RuntimeException, DatabaseException) { return false;}
+ virtual void do_commit() throw(RuntimeException, DatabaseException) = 0;
+ virtual void do_rollback() throw() = 0;
+
+ friend class Database;
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Data_hpp
+#define anna_dbms_Data_hpp
+
+#include <string>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/functions.hpp>
+#include <anna/core/RuntimeException.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Bind;
+
+/**
+ Clase base para las variables de entrada/salida asociadas a las sentencias SQL.
+*/
+class Data {
+public:
+ struct Type {
+ enum _v {
+ Integer, /**< Numeros enteros */
+ String, /**< Cadenas de caracteres */
+ Float, /**< Número en coma flotante */
+ ShortBlock, /**< Tipos de dato RAW */
+ LongBlock, /**< Tipo de datos CLOB */
+ Date, /** Tipo de fecha (dependiendo del gestor de base de datos puede contener tambien la hora) */
+ TimeStamp /** Tipo para contener simultáneamente la fecha y la hora */
+ };
+ };
+
+ /**
+ Devuelve el tamano maximo de este dato que coincidiria con el indicado en el constructor.
+ \return El tamano maximo de este dato que coincidiria con el indicado en el constructor.
+ */
+ int getMaxSize() const throw() { return a_maxSize; }
+
+ /**
+ Devuelve el tipo de dato.
+ \return El tipo de datos.
+ */
+ Type::_v getType() const throw() { return a_type; }
+
+ /**
+ Devuelve el area de memoria asociada a esta variable.
+ */
+ void* getBuffer() throw() { return a_buffer; }
+
+ /**
+ Devuelve el indicador de nulo de esta instancia.
+ \return El indicador de nulo de esta instancia.
+ */
+ bool isNull() const throw() { return a_isNull; }
+
+ /**
+ Devuelve el valor que indica si este dato puede tomar valores nulos.
+ \return El valor que indica si este dato puede tomar valores nulos.
+ */
+ bool isNulleable() const throw() { return a_isNulleable; }
+
+ /**
+ Establece el indicador de nulo de esta instancia.
+ \param isNull Indicador de nulo de esta instancia.
+ \warning Slo tendr�efecto en caso de haber indicado en el constructor que
+ el dato puede tomar valores nulos.
+ */
+ void setNull(const bool isNull) throw() { if(a_isNulleable == true) a_isNull = isNull; }
+
+ /**
+ Incorpora el método clear para todos tipos de datos con lo que podemos obtener información
+ del medio físico.
+
+ Si el dato está definido como "nuleable" activará el indicador que indica que el dato está vacío,
+ en otro caso se asignará un valor adecuado dependiendo del tipo del dato, cero para los números,
+ "" para las cadenas, etc.
+ */
+ void clear() throw() {
+ setNull(true);
+ do_clear();
+ }
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+protected:
+ /**
+ Constructor.
+ \param type Tipo de dato de esta instancia.
+ \param maxSize Tamao maximo que puede tener este dato. Deberia coincidir con el indicado
+ por la columna con la que vaya a corresponder en la sentencia.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+
+ \warning los tipos de datos complejos deberia reimplementar los metodos #code and #decode.
+ */
+ explicit Data(const Type::_v type, const int maxSize, const bool isNulleable) :
+ a_type(type),
+ a_maxSize(maxSize),
+ a_isNulleable(isNulleable),
+ a_isNull(isNulleable),
+ a_buffer(NULL)
+ {;}
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ Data(const Data& other) :
+ a_type(other.a_type),
+ a_maxSize(other.a_maxSize),
+ a_isNulleable(other.a_isNulleable),
+ a_isNull(other.a_isNull),
+ a_buffer(other.a_buffer)
+ {;}
+
+ /**
+ Establece el area de memoria asociada a esta variable.
+ \param buffer Direccion de memoria donde comienza el contenido esta variable.
+ */
+ void setBuffer(void* buffer) throw() { a_buffer = buffer; }
+
+private:
+ const Type::_v a_type;
+ const int a_maxSize;
+ const bool a_isNulleable;
+ void* a_buffer;
+ bool a_isNull;
+
+ virtual void do_clear() throw() = 0;
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Database_hpp
+#define anna_dbms_Database_hpp
+
+#include <vector>
+
+#include <anna/app/Component.hpp>
+
+#include <anna/dbms/Connection.hpp>
+
+namespace anna {
+
+namespace comm {
+class INetAddress;
+class Delivery;
+}
+
+namespace dbms {
+
+class Statement;
+class InputBind;
+class OutputBind;
+class Data;
+class FailRecoveryHandler;
+class StatementTranslator;
+
+/**
+ Clase que modela la interaccion entre la base y nuestra aplicacion.
+*/
+class Database : public app::Component {
+public:
+ /**
+ Numero maximo de conexiones que podemos crear.
+ */
+ static const int MaxConnection = 32;
+
+ /**
+ Formas de conexion a la base de datos.
+ */
+ struct Type {
+ enum _v { Local, Remote } value;
+ Type() : value(Local) {;}
+ Type(const _v v) : value(v) {;}
+ Type(const Type& v) : value(v.value) {;}
+ operator int () const throw() { return value; }
+ };
+
+ typedef std::vector <Connection*>::const_iterator const_connection_iterator; /**<Iterador para acceder a las conexiones de esta base de datos */
+ typedef std::vector <Statement*>::const_iterator const_statement_iterator; /**<Iterador para acceder a las conexiones de esta base de datos */
+
+ /**
+ Destructor.
+ */
+ virtual ~Database();
+
+ /**
+ Devuelve el tipo de conexion de esta base de datos.
+ \return El tipo de conexion de esta base de datos.
+ */
+ const Type& getType() const throw() { return a_type; }
+
+ /**
+ Devuelve el nombre de la base de datos indicado en el constructor.
+ \return El nombre de la base de datos indicado en el constructor.
+ */
+ const std::string& getName() const throw() { return a_name; }
+
+ /**
+ Establece el manejador encargado de actuar cuando la recuperacion de la conexion falla.
+ El manejador por defecto no realiza ninguna activad.
+ \param failRecoveryHandler Manejador que seria invocado en caso de que no sea posible recuperar
+ una determina conexion.
+ */
+ void setFailRecoveryHandler(FailRecoveryHandler* failRecoveryHandler) throw() { a_failRecoveryHandler = failRecoveryHandler; }
+
+ /**
+ * Establece el traductor de sentencias SQL usado ajustar las sentencias SQL al
+ * motor de base de datos usados en la aplicación.
+ */
+ void setStatementTranslator(StatementTranslator* statementTranslator) throw() { a_statementTranslator = statementTranslator; }
+
+ /**
+ Crea y registra una nueva conexion con esta base de datos.
+ La clase usada para conectar con esta base de datos dependeria de la implementacion particular, que
+ seria definida por el metodo #allocateConnection.
+
+ \param name Nombre logico de la conexion a crear.
+ @param user Nombre del usuario con el que realizamos la conexion.
+ @param password Codigo de acceso del usuario.
+
+ @return La instancia de la nueva conexion a la base de datos.
+ */
+ Connection* createConnection(const char* name, const char* user, const char* password)
+ throw(RuntimeException, DatabaseException);
+
+ /**
+ Devuelve la conexion asociada al nombre logico recibido como parametro.
+ \param name Nombre logico de la conexion que queremos obtener.
+ \return La conexion asociada al nombre logico recibido como parametro.
+ \warning Si la conexion logica no existe no puede ser usada se lanzara una excepcion.
+ */
+ Connection& findConnection(const char* name) throw(RuntimeException);
+
+ /**
+ Devuelve un iterator al comienzo de la lista de conexiones establecidas con esta base de datos.
+ \return Un iterator al comienzo de la lista de conexiones establecidas con esta base de datos.
+ */
+ const_connection_iterator connection_begin() const throw() { return a_connections.begin(); }
+
+ /**
+ Devuelve un iterator al final de la lista de conexiones establecidas con esta base de datos.
+ \return Un iterator al final de la lista de conexiones establecidas con esta base de datos.
+ */
+ const_connection_iterator connection_end() const throw() { return a_connections.end(); }
+
+ /**
+ Crea y registra una nueva sentencia SQL asociada a esta base de datos.
+ La clase usada para interpretar la sentencia SQL dependera de la implementacion particular definida
+ mediante el metodo #allocateStatement.
+
+ \param name Nombre logico de esta sentencia.
+ \param expression Expresion asociada a la sentencia.
+ \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
+ la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
+ aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion.
+
+ \return Una nueva instancia de una conexion a base de datos. No puede ser NULL.
+ */
+ Statement* createStatement(const char* name, const char* expression, const bool isCritical = true)
+ throw(RuntimeException);
+
+ /**
+ Crea y registra una nueva sentencia SQL asociada a esta base de datos.
+ La clase usada para interpretar la sentencia SQL dependera de la implementacion particular definida
+ mediante el metodo #allocateStatement.
+
+ \param name Nombre logico de esta sentencia.
+ \param expression Expresion asociada a la sentencia.
+ \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
+ la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
+ aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion.
+
+ \return Una nueva instancia de una conexion a base de datos. No puede ser NULL.
+ */
+ Statement* createStatement(const char* name, const std::string& expression, const bool isCritical = true)
+ throw(RuntimeException) {
+ return createStatement(name, expression.c_str(), isCritical);
+ }
+
+ /**
+ Devuelve la instancia de la sentencia SQL asociada al nombre recibido como parametro.
+
+ @return La instancia de la sentencia SQL asociada al nombre recibido.
+ Puede ser NULL si el nombre no fue registrado previamente con #createStatement.
+ */
+ Statement* findStatement(const char* name) throw();
+
+ /**
+ Libera los recursos de la sentencia SQL recibida como parametro.
+ \param statement Instancia de la sentencia SQL a liberar. deberia haber sido obtenida mediante
+ el metodo #createStatement.
+ */
+ void releaseStatement(Statement* statement) throw();
+
+ /**
+ Devuelve un iterator al comienzo de la lista de sentencias SQL creadas en esta base de datos.
+ \return Un iterator al comienzo de la lista de sentencias SQL creadas en esta base de datos.
+ */
+ const_statement_iterator statement_begin() const throw() { return a_statements.begin(); }
+
+ /**
+ Devuelve un iterator al final de la lista de sentencias SQL creadas en esta base de datos.
+ \return Un iterator al final de la lista de sentencias SQL creadas en esta base de datos.
+ */
+ const_statement_iterator statement_end() const throw() { return a_statements.end(); }
+
+ /**
+ Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
+ \param ii Iterator que deberia estar comprendido entre #statement_begin y #statement_end.
+ \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
+ */
+ static Statement* statement(const_statement_iterator& ii) throw() { return *ii; }
+
+ /**
+ Devuelve una cadena con la informacion mas relevante de esta instancia.
+ \return Una cadena con la informacion mas relevante de esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+ /**
+ Devuelve un documento XML con la informacion mas relevante de esta instancia.
+ \param parent Nodo XML del que colgar la informacion referente a esta instancia.
+ \return Un documento XML con la informacion mas relevante de esta instancia.
+ */
+ virtual xml::Node* asXML(xml::Node* parent) const throw();
+
+ /**
+ Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
+ \param ii Iterator que deberia estar comprendido entre #connection_begin y #connection_end.
+ \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
+ */
+ static const Connection* connection(const_connection_iterator& ii) throw() { return *ii; }
+
+protected:
+ typedef std::vector <Connection*>::iterator connection_iterator; /**<Iterador para acceder a las conexiones de esta base de datos */
+
+ /**
+ Contructor.
+ \param rdbmsmsName Nombre del RDMS que gestiona esta base de datos.
+ \param dbmsName Nombre de la base de datos.
+ */
+ Database(const char* rdbmsmsName, const char* dbmsName);
+
+ /**
+ Recupera el estado de una conexion perdida.
+ \warning Este metodo se invoca automaticamente desde el nucleo de ANNA.dbms y nunca deberia
+ ser invocado por el programador.
+ \param connection Instancia de la conexion en la que hemos detectado el fallo.
+ \param tryCounter numero de intentos de recuperacion de la conexion.
+ */
+ void recover(Connection& connection, const int tryCounter) throw(RuntimeException);
+
+ /**
+ Inicializa las conexiones definidas sobre esta base de datos. Este metodo se invocaria
+ automaticamente desde el nucleo de ANNA.
+ Slo seria necesario invocarlo cuando nuestro programa no tenga asociada ninguna aplicacion
+ que se encarga de inicializar los componentes.
+ */
+ virtual void do_initialize() throw(RuntimeException);
+
+ /**
+ Elimina las conexiones definidas sobre esta base de datos. Este metodo se invocaria automaticamente
+ desde el nucleo de ANNA.
+ */
+ virtual void do_stop() throw();
+
+ /**
+ Devuelve un iterator al comienzo de la lista de conexiones establecidas con esta base de datos.
+ \return Un iterator al comienzo de la lista de conexiones establecidas con esta base de datos.
+ */
+ connection_iterator connection_begin() throw() { return a_connections.begin(); }
+
+ /**
+ Devuelve un iterator al final de la lista de conexiones establecidas con esta base de datos.
+ \return Un iterator al final de la lista de conexiones establecidas con esta base de datos.
+ */
+ connection_iterator connection_end() throw() { return a_connections.end(); }
+
+ /**
+ Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
+ \param ii Iterator que deberia estar comprendido entre #connection_begin y #connection_end.
+ \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
+ */
+ static Connection* connection(connection_iterator& ii) throw() { return *ii; }
+
+private:
+ const std::string a_name;
+ std::vector <Connection*> a_connections;
+ std::vector <Statement*> a_statements;
+ const Type a_type;
+ FailRecoveryHandler* a_failRecoveryHandler;
+ StatementTranslator* a_statementTranslator;
+
+ Database(const Database&);
+
+ void do_cloneChild() throw(RuntimeException);
+
+ virtual Connection* allocateConnection(const std::string& name, const char* user, const char* password)
+ throw(RuntimeException) = 0;
+
+ virtual Statement* allocateStatement(const char* name, const std::string& expression, const bool isCritical)
+ throw(RuntimeException) = 0;
+
+ virtual InputBind* allocateInputBind(const char* name, Data& data)
+ throw(RuntimeException) = 0;
+ virtual void deallocate(InputBind* inputBind) throw() = 0;
+
+ virtual OutputBind* allocateOutputBind(const char* name, Data& data)
+ throw(RuntimeException) = 0;
+ virtual void deallocate(OutputBind* outputBind) throw() = 0;
+
+ friend class Statement;
+ friend ResultCode Connection::execute(Statement*) throw(RuntimeException, DatabaseException);
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_DatabaseException_hpp
+#define anna_dbms_DatabaseException_hpp
+
+#include <anna/core/Exception.hpp>
+
+#include <anna/dbms/ResultCode.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Exception ocurrida al acceder a algun servicio de la base de datos.
+*/
+class DatabaseException : public Exception {
+public:
+ /**
+ Constructor.
+
+ @param resultCode Clase utilizada para transferir codigo de error entre el gestor de base de datos
+ y nuestro programa. Entre otra informacion contiene el error ocurrido en la ultima operacion realizada.
+ @param fromFile Fichero en el que se provoco la situacion de error.
+ @param fromLine Linea del fichero en la que se provoco la situacion de error.
+ */
+ DatabaseException(const ResultCode& resultCode, const char* fromFile, const int fromLine) :
+ Exception(resultCode.getErrorText(), "DatabaseException", fromFile, fromLine),
+ a_resultCode(resultCode) {}
+
+ /**
+ Constructor.
+
+ @param logicalName Nombre logico del elemento que genera la excepcion.
+ @param resultCode Clase utilizada para transferir codigo de error entre el gestor de base de datos
+ y nuestro programa. Entre otra informacion contiene el error ocurrido en la ultima operacion realizada.
+ @param fromFile Fichero en el que se provoco la situacion de error.
+ @param fromLine Linea del fichero en la que se provoco la situacion de error.
+ */
+ DatabaseException(const std::string& logicalName, const ResultCode& resultCode, const char* fromFile, const int fromLine) :
+ Exception("", "DatabaseException", fromFile, fromLine),
+ a_resultCode(resultCode) {
+ std::string aux(logicalName);
+ aux += ": ";
+ aux += resultCode.getErrorText();
+ setText(aux.c_str());
+ }
+
+ /**
+ Destructor.
+ */
+ virtual ~DatabaseException() throw() {;}
+
+ /**
+ Devuelve el resultado de base de datos asociado a la excepcion
+
+ @return El resultado de base de datos asociado a la excepcion
+ */
+ const ResultCode& getResultCode() const throw() { return a_resultCode; }
+
+private:
+ const ResultCode a_resultCode;
+};
+
+}
+}
+
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Date_hpp
+#define anna_dbms_Date_hpp
+
+#include <time.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/RuntimeException.hpp>
+
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Tipo de datos que permite trabajar con el tipo de dato 'Date' de un gestor de base de
+ datos generico.
+
+ Dependiendo el gestor de base de datos usado el tipo \em date puede contener informacion que incluya
+ la hora del día, en Oracle (tm) la incluye, mientras que en mysql, por ejemplo, no la incluye.
+
+ Internamente trabaja con una estructura de tipo 'tm' que habitualmente tendrá los campos:
+ \code
+ struct tm {
+ int tm_sec; // Seconds. [0-60] (1 leap second)
+ int tm_min; // Minutes. [0-59]
+ int tm_hour; // Hours. [0-23]
+ int tm_mday; // Day. [1-31]
+ int tm_mon; // Month. [0-11]
+ int tm_year; // Year - 1900.
+ int tm_wday; // Day of week. [0-6]
+ int tm_yday; // Days in year.[0-365]
+ int tm_isdst; // DST. [-1/0/1]
+ };
+ \endcode
+*/
+class Date : public Data {
+public:
+ /**
+ * Espacio maximo reservado para representar lo datos de una fecha sobre una cadena.
+ */
+ static const int MaxDateSize = 48;
+
+ /**
+ Constructor.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ \param format Formato usado para interpretar los datos de esta fecha, en los metodos Date::getCStringValue y
+ Date::setValue (const char*) y Date::setValue (const std::string&). Sigue la especificacion:
+
+ \code
+ %a Replaced by the localeâs abbreviated weekday name. [ tm_wday]
+
+ %A Replaced by the localeâs full weekday name. [ tm_wday]
+
+ %b Replaced by the localeâs abbreviated month name. [ tm_mon]
+
+ %B Replaced by the localeâs full month name. [ tm_mon]
+
+ %c Replaced by the localeâs appropriate date and time representation. (See the Base Definitions volume of
+ IEEE Std 1003.1-2001, <time.h>.)
+
+ %C Replaced by the year divided by 100 and truncated to an integer, as a decimal number [00,99]. [ tm_year]
+
+ %d Replaced by the day of the month as a decimal number [01,31]. [ tm_mday]
+
+ %D Equivalent to %m / %d / %y . [ tm_mon, tm_mday, tm_year]
+
+ %e Replaced by the day of the month as a decimal number [1,31]; a single digit is preceded by a space. [
+ tm_mday]
+
+ %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard date format). [ tm_year, tm_mon, tm_mday]
+
+ %g Replaced by the last 2 digits of the week-based year (see below) as a decimal number [00,99]. [ tm_year,
+ tm_wday, tm_yday]
+
+ %G Replaced by the week-based year (see below) as a decimal number (for example, 1977). [ tm_year, tm_wday,
+ tm_yday]
+
+ %h Equivalent to %b . [ tm_mon]
+
+ %H Replaced by the hour (24-hour clock) as a decimal number [00,23]. [ tm_hour]
+
+ %I Replaced by the hour (12-hour clock) as a decimal number [01,12]. [ tm_hour]
+
+ %j Replaced by the day of the year as a decimal number [001,366]. [ tm_yday]
+
+ %m Replaced by the month as a decimal number [01,12]. [ tm_mon]
+
+ %M Replaced by the minute as a decimal number [00,59]. [ tm_min]
+
+ %n Replaced by a <newline>.
+
+ %p Replaced by the localeâs equivalent of either a.m. or p.m. [ tm_hour]
+
+ %r Replaced by the time in a.m. and p.m. notation; in the POSIX locale this shall be equivalent to %I : %M
+ : %S %p . [ tm_hour, tm_min, tm_sec]
+
+ %R Replaced by the time in 24-hour notation ( %H : %M ). [ tm_hour, tm_min]
+
+ %S Replaced by the second as a decimal number [00,60]. [ tm_sec]
+
+ %t Replaced by a <tab>.
+
+ %T Replaced by the time ( %H : %M : %S ). [ tm_hour, tm_min, tm_sec]
+
+ %u Replaced by the weekday as a decimal number [1,7], with 1 representing Monday. [ tm_wday]
+
+ %U Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the
+ first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+
+ %V Replaced by the week number of the year (Monday as the first day of the week) as a decimal number [01,53].
+ If the week containing 1 January has four or more days in the new year, then it is considered week 1. Oth-
+ erwise, it is the last week of the previous year, and the next week is week 1. Both January 4th and the
+ first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
+
+ %w Replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. [ tm_wday]
+
+ %W Replaced by the week number of the year as a decimal number [00,53]. The first Monday of January is the
+ first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+
+ %x Replaced by the localeâs appropriate date representation. (See the Base Definitions volume of
+ IEEE Std 1003.1-2001, <time.h>.)
+
+ %X Replaced by the localeâs appropriate time representation. (See the Base Definitions volume of
+ IEEE Std 1003.1-2001, <time.h>.)
+
+ %y Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
+
+ %Y Replaced by the year as a decimal number (for example, 1997). [ tm_year]
+
+ %z Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no charac-
+ ters if no timezone is determinable. For example, "-0430" means 4 hours 30 minutes behind UTC (west of
+ Greenwich). If tm_isdst is zero, the standard time offset is used. If tm_isdst is greater than zero, the
+ daylight savings time offset is used. If tm_isdst is negative, no characters are returned. [ tm_isdst]
+
+ %Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [
+ tm_isdst]
+
+ %% Replaced by % .
+ \endcode
+
+ Para obtener más informacion sobre la espeficacion de formato \em man \em strftime (p.e.).
+ */
+ explicit Date(const bool isNulleable = false, const char* format = NULL) ;
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ Date(const Date& other);
+
+ /**
+ Destructor.
+ */
+ virtual ~Date();
+
+ /**
+ Devuelve el contenido de esta fecha.
+ \return El contenido de esta fecha.
+ \warning Si el metodo Data::isNull devolvio \em true el contenido de la estructura no esta definido.
+ */
+ const tm& getValue() const throw() { return a_value; }
+
+ /**
+ Devuelve el contenido de esta fecha.
+ \return El contenido de esta fecha.
+ \warning Si el metodo Data::isNull devolvio \em true el contenido de la estructura no esta definido.
+ */
+ tm& getValue() throw() { return a_value; }
+
+ /**
+ * Interpreta el contenido de la fecha y lo transfiere al buffer.
+ * \return El buffer que contiene esta fecha interpretada con el formato indicado en el contructor.
+ * \warning El resultado sera NULL en caso de no poder interpretar correctamente la fecha.
+ */
+ virtual const char* getCStringValue() const throw();
+
+ /**
+ * Interpreta el contenido de esta fecha como el numero de segundos transcurridos desde el 1 de Enero de 1970.
+ * Si el contenido de la columna sociada es nulo este metodo devolvera 0. Si la conversion a segundos no puede
+ * ser realizada devolvera -1.
+ * \return Interpreta el contenido de esta fecha como el numero de segundos transcurridos desde el 1 de Enero de 1970.
+ * Si el contenido de la columna sociada es nulo este metodo devolvera 0. Si la conversion a
+ * segundos no puede ser realizada devolvera -1.
+ */
+ Second getSecondValue() const throw() { return Second((Data::isNull() == true) ? 0 : mktime(&const_cast <Date*>(this)->a_value)); }
+
+ /**
+ * Devuelve el formato indicado en el constructor de la clase.
+ * \return El formato indicado en el constructor de la clase.
+ */
+ const char* getFormat() const throw() { return a_format; }
+
+ /**
+ * Devuelve el año contenido por esta fecha.
+ * \return El año contenido por esta fecha.
+ */
+ int getYear() const throw() { return a_value.tm_year + 1900; }
+
+ /**
+ * Devuelve el mes contenido por esta fecha.
+ * \return El mes contenido por esta fecha.
+ */
+ int getMonth() const throw() { return a_value.tm_mon + 1; }
+
+ /**
+ * Devuelve el dia del mes contenido por esta fecha.
+ * \return El dia del mes contenido por esta fecha.
+ */
+ int getDay() const throw() { return a_value.tm_mday; }
+
+ /**
+ * Devuelve la hora del dia contenida en la fecha.
+ * \return La hora del dia contenida en la fecha.
+ * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos.
+ */
+ int getHour() const throw() { return a_value.tm_hour; }
+
+ /**
+ * Devuelve el minuto de la hora contenida en la fecha.
+ * \return El minuto de la hora contenida en la fecha.
+ * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos.
+ */
+ int getMinute() const throw() { return a_value.tm_min; }
+
+ /**
+ * Devuelve el segundo de la hora contenida en la fecha.
+ * \return El segundo de la hora contenida en la fecha.
+ * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos.
+ */
+ int getSecond() const throw() { return a_value.tm_sec; }
+
+ /**
+ * Establece el año de esta fecha
+ * \param year Año de la fecha. Debe ser mayor de 1900.
+ */
+ void setYear(const int year) throw(RuntimeException) { set("Year", a_value.tm_year, year - 1900, 0, -1); }
+
+ /**
+ * Establece mes de esta fecha.
+ * \param month Mes de la fecha. Debe estar comprendido entre 1 y 12.
+ */
+ void setMonth(const int month) throw(RuntimeException) { set("Month", a_value.tm_mon, month - 1, 0, 11); }
+
+ /**
+ * Establece el dia del mes de esta fecha.
+ * \param day Dia del mes. Debe estar comprendido entre 1 y 31.
+ */
+ void setDay(const int day) throw(RuntimeException) { set("Day", a_value.tm_mday, day, 1, 31); }
+
+ /**
+ * Establece la hora de esta fecha.
+ * \param hour Hora del dia. Debe estar comprendida entre 0 y 23.
+ * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos.
+ */
+ void setHour(const int hour) throw(RuntimeException) { set("Hour", a_value.tm_hour, hour, 0, 23); }
+
+ /**
+ * Establece el minuto de esta fecha.
+ * \param minute Minuto de la hora del dia. Debe estar comprendida entre 0 y 59.
+ * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos.
+ */
+ void setMinute(const int minute) throw(RuntimeException) { set("Minute", a_value.tm_min, minute, 0, 59); }
+
+ /**
+ * Establece el segundo de esta fecha.
+ * \param second Segungo de la hora del dia. Debe estar comprendida entre 0 y 60.
+ * \warning Verifique que el tipo 'Date' de su RDBMS es capaz de contener horas, minutos y segundos.
+ */
+ void setSecond(const int second) throw(RuntimeException) { set("Second", a_value.tm_sec, second, 0, 60); }
+
+ /**
+ Interpreta la cadena recibida segun el formato indicado en el constructor y la asigna a esta instancia, pero requiere que al
+ invocar al constructor de esta fecha se indique el formato usado para traducir.
+ \param str Cadena de la que copiar.
+ */
+ void setValue(const char* str) throw(RuntimeException);
+
+ /**
+ Interpreta la cadena recibida segun el formato indicado en el constructor y la asigna a esta instancia, pero requiere que al
+ invocar al constructor de esta fecha se indique el formato usado para traducir.
+ \param str Cadena de la que copiar.
+ */
+ void setValue(const std::string& str) throw(RuntimeException) { setValue(str.c_str()); }
+
+ /**
+ * Establece esta fecha con los segundos transcurridos desde el 1/1/1970.
+ * \param second Numeros de segundos transcurridos desde el 1 de Enero de 1970.
+ * \see anna::functions::second
+ */
+ void setValue(const Second &second) throw(RuntimeException);
+
+ /**
+ Operador de copia.
+ \param date Fecha de la que copiar.
+ \return La instancia de esta fecha.
+ \warning Solo copia el contenido de la fecha recibida, no cambia el formato de interpretacion de la fecha origen.
+ */
+ Date& operator = (const Date& date) throw(RuntimeException);
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ \return Una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+protected:
+ char* a_format;
+ tm a_value;
+ char a_buffer [MaxDateSize + 1];
+
+ /**
+ * Constructor invocado desde el constructor de TimeStamp.
+ \param type Sera Data::Type::TimeStamp.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ \param format Formato usado para representar los datos de esta fecha.
+ */
+ explicit Date(const Type::_v type, const bool isNulleable, const char* format);
+
+private:
+ void set(const char* what, int& variable, const int value, const int min, const int max) throw(RuntimeException);
+ void do_clear() throw() { anna_memset(&a_value, 0, sizeof(a_value)); }
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Delivery_hpp
+#define anna_dbms_Delivery_hpp
+
+#include <anna/comm/Delivery.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Connection;
+
+/**
+ Agrupacion logica de conexiones con la base de datos. Reparte la carga de las transacciones contra
+ la base de datos entre las distintas conexiones que contenga esta instancia. Ademas en caso de estar
+ en una ejecucion con soporte para multithread (ver anna::functions::supportMultithread) asegura
+ que cada uno de los threads siempre utiliza la misma conexion lo cual asegura el mantinimiento de la
+ integridad de cada una de las transacciones de los threads.
+*/
+class Delivery : comm::Delivery {
+public:
+ /**
+ Constructor.
+ @param name Nombre logico de este grupo de conexiones.
+ */
+ Delivery(const char *name) : comm::Delivery(name) {;}
+
+ /**
+ Crea automaticamente las conexiones a la base de datos recibida como parametro con el usuario/password
+ indicado.
+ \param database Instancia de la base de datos contra la que realizamos la conexion.
+ \param prefixName Prefijo del nombre logico de la conexiones que vamos a crear. El resto del nombre vendra
+ dado por el numero secuencial de la conexion.
+ \param user Nombre del usuario con el que realizamos la conexion.
+ \param password Codigo de acceso del usuario.
+ \param n Numero de conexion a crear.
+ \warning Recordar que el numero maximo de conexiones a una base de datos esta limitado por Database::maxConnection.
+ */
+ void createConnections(Database& database, const char* prefixName, const char* user, const char* password, const int n)
+ throw(RuntimeException, DatabaseException);
+
+ /**
+ Incorpora al conexion recibida como parametro a la agrupacion logica.
+ \param connection Conexion que vamos a incorporar a la agrupacion logica.
+ */
+ void addConnection(Connection* connection) throw(RuntimeException) {
+ this->add(connection);
+ a_iiConnection = this->begin();
+ }
+
+ /**
+ Devuelve la instancia de la conexion a base de datos con la que debemos trabajar.
+ @return la instancia de la conexion a base de datos con la que debemos trabajar.
+ \warning La conexion debe ser bloqueada por el Thread que la recibe (ver anna::Guard) para asegurar que
+ cualquier otro thread que intente acceder a ella queda bloqueado a la espera de que terminemos de
+ trabajar sobre ella.
+ */
+ Connection& getConnection() throw(RuntimeException);
+
+private:
+ iterator a_iiConnection;
+
+ void do_initialize() throw() { a_iiConnection = begin(); }
+ comm::Resource* do_apply() throw(RuntimeException);
+ static Connection* connection(iterator& ii) { return (Connection*) comm::Delivery::resource(ii); }
+
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_FailRecoveryHandler_hpp
+#define anna_dbms_FailRecoveryHandler_hpp
+
+namespace anna {
+
+namespace dbms {
+
+class Database;
+class Connection;
+
+/**
+ Interfaz que deben cumplir los manejadores que reciben la notificacion de que no ha sido posible
+ restaurar una determina conexion con la base de datos.
+*/
+class FailRecoveryHandler {
+protected:
+ /**
+ Este metodo debe ser reimplementado para describir las operaciones que vamos a realizar en caso
+ de no poder recuperar la conexion recibida como parametro.
+ \param connection Instancia de la conexion en la que hemos detectado el fallo.
+ \param tryCounter Numero de intentos de recuperacion de la conexion.
+
+ \warning Este metodo se invocara automaticamente desde anna::dbms::Database::recover.
+ */
+ virtual void apply(Connection& connection, const int tryCounter) throw(RuntimeException) = 0;
+
+ friend class Database;
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Float_hpp
+#define anna_dbms_Float_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Numero en coma flotante usado como entrada y/o salida de las sentencias SQL.
+*/
+class Float : public Data {
+public:
+ /**
+ Constructor.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ \para format Indica el indicador de formato para pasar de cadena a numero. Usa la misma nomenclatura
+ que printf, scanf, etc. Su uso dependerá del gestor de base de datos usado.
+ */
+ explicit Float(const bool isNulleable = false, const char* format = "%f") :
+ Data(Type::Float, sizeof(float), isNulleable),
+ a_format(format),
+ a_value(0.0) {
+ Data::setBuffer(&a_value);
+ }
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ Float(const Float& other) : Data(other), a_value(other.a_value), a_format(other.a_format) {
+ Data::setBuffer(&a_value);
+ }
+
+ /**
+ * Metodo obsoleto, debería usar #getValue.
+ Devuelve el contenido del campo de tipo Float.
+ \return el contenido del campo de tipo Float.
+ \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido.
+ */
+ //float getFloatValue () const throw () { return getValue (); }
+
+ /**
+ * Devuelve el valor asociado a este campo.
+ * \return Devuelve el valor asociado a este campo.
+ */
+ float getValue() const throw() { return a_value; }
+
+ /**
+ * Devuelve el formato que indica la forma en la que el número será representado sobre
+ * una cadena, en caso de que fuera necesario.
+ */
+ const char* getFormat() const throw() { return a_format; }
+
+ /**
+ Operador de copia.
+ \param other Float del que copiar.
+ \return La instancia de esta cadena.
+ */
+ Float& operator = (const Float& other) throw(RuntimeException) {
+ if(this != &other) {
+ setNull(other.isNull());
+ a_value = other.a_value;
+ }
+
+ return *this;
+ }
+
+ /**
+ Operador de asignacion.
+ \param value Float del que copiar.
+ \return La instancia de esta cadena.
+ */
+ Float& operator = (const float value) throw(RuntimeException) {
+ a_value = value;
+ setNull(false);
+ return *this;
+ }
+
+ /**
+ Operador de conversion.
+ \warning Si la columna asociada tiene un valor NULL, devolvera 0.0.
+ \return El contenido de esta cadena.
+ */
+ operator float() const throw() { return getValue(); }
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ \return Una cadena con la informacion referente a esta instancia.
+ */
+ std::string asString() const throw();
+
+private:
+ float a_value;
+ const char* a_format;
+
+ void do_clear() throw() { a_value = 0.0; }
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_InputBind_hpp
+#define anna_dbms_InputBind_hpp
+
+#include <anna/dbms/Bind.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class InputBind : public Bind {
+protected:
+ InputBind(const char* name, dbms::Data& value) : Bind(name, value) {;}
+
+private:
+ // Éste metodo no sera invocado nunca. A partir de un Input nunca hay que
+ // convertir de C++ -> RDBMS
+ void decode() const throw(RuntimeException) {;}
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Integer_hpp
+#define anna_dbms_Integer_hpp
+
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Cadena usada como entrada y/o salida de las sentencias SQL.
+*/
+class Integer : public Data {
+public:
+ /**
+ Constructor.
+ \param isNulleable Indica si el dato puede tomar valores nulos
+ */
+ explicit Integer(const bool isNulleable = false) :
+ Data(Type::Integer, sizeof(int), isNulleable),
+ a_value(0) {
+ Data::setBuffer(&a_value);
+ }
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ Integer(const Integer& other) :
+ Data(other),
+ a_value(other.a_value) {
+ Data::setBuffer(&a_value);
+ }
+
+ /**
+ Devuelve el valor entero asociado a esta instancia.
+ \return El valor entero asociado a esta instancia.
+ */
+ int getValue() const throw() { return a_value; }
+
+ /**
+ Operador de asignacin entero.
+ \param i Valor entero a asignar.
+ \return La referencia a esta instancia.
+ */
+ Integer& operator = (const int i)
+ throw() {
+ a_value = i;
+ Data::setNull(false);
+ return *this;
+ }
+
+ /**
+ Operador copia.
+ \param other Instancia de la que copiar.
+ \return La referencia a esta instancia.
+ */
+ Integer& operator = (const Integer& other)
+ throw() {
+ if(this != &other) {
+ setNull(other.isNull());
+ a_value = other.a_value;
+ }
+
+ return *this;
+ }
+
+ /**
+ Operador de conversion.
+ \return El valor entero asociado a esta instancia.
+ */
+ operator int () const throw() { return a_value; }
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ std::string asString() const throw();
+
+private:
+ int a_value;
+
+ void do_clear() throw() { a_value = 0; }
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_LongBlock_hpp
+#define anna_dbms_LongBlock_hpp
+
+#include <string>
+
+#include <anna/core/RuntimeException.hpp>
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Bloque de datos usado como entrada y/o salida de las sentencias SQL.
+
+ A diferencia del tipo de datos ShortBlock, en principio, no tiene ninguna limitacion
+ en cuanto a la longitud del campo que vamos a tratar. Por contra, dependiendo del motor
+ de base de datos que vayamos a usar puede tener un tratamiento especial a la hora de
+ grabarlo en la base de datos.
+
+ \see ShortBlock
+*/
+class LongBlock : public Data {
+public:
+ /**
+ Constructor.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ */
+ explicit LongBlock(const bool isNulleable = false) :
+ Data(Type::LongBlock, 0, isNulleable),
+ a_value(true) {
+ Data::setBuffer((void*) NULL);
+ }
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ LongBlock(const LongBlock& other) :
+ Data(other),
+ a_value(true) {
+ a_value = other.a_value;
+ }
+
+ /**
+ Destructor.
+ */
+ virtual ~LongBlock() {;}
+
+ /**
+ Devuelve el tamao actual de este dato.
+ \return El tamao actual de este dato.
+ */
+ int getSize() const throw() { return a_value.getSize(); }
+
+ /**
+ Devuelve el contenido de la este bloque de memoria.
+ \return Devuelve el contenido de la este bloque de memoria.
+ \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido.
+ */
+ const anna::DataBlock& getValue() const throw() { return a_value; }
+
+ /**
+ Devuelve el contenido de la este bloque de memoria.
+ \return Devuelve el contenido de la este bloque de memoria.
+ \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido.
+ */
+ anna::DataBlock& getValue() throw() { return a_value; }
+
+ /**
+ Operador de asignacin.
+ \param other Bloque del que copiar.
+ \return La instancia de este bloque de memoria.
+ */
+ LongBlock& operator = (const LongBlock& other) throw(RuntimeException);
+
+ /**
+ Operador de asignacin.
+ \param value Valor que queremos a asignar.
+ \return La instancia de esta cadena.
+ */
+ LongBlock& operator = (const anna::DataBlock& value) throw(RuntimeException);
+
+ /**
+ Operador de conversion.
+ \return El anna::DataBlock asociado a esta instancia.
+ */
+ operator anna::DataBlock& () throw() { return a_value; }
+
+ /**
+ Operador de conversion.
+ \return El anna::DataBlock asociado a esta instancia.
+ */
+ operator const anna::DataBlock& () const throw() { return a_value; }
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ \return Una cadena con la informacion referente a esta instancia.
+ */
+ std::string asString() const throw();
+
+protected:
+ anna::DataBlock a_value;
+
+ void do_clear() throw() { a_value.clear(); }
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_OutputBind_hpp
+#define anna_dbms_OutputBind_hpp
+
+#include <anna/dbms/Bind.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class LongBlock;
+
+/**
+ Clase que facilita la interconexion entre las variables del ambito C++ y el ambito RDBMS.
+
+ A continuacion presentamos un ejemplo de uso detallado.
+ \include db_blob.p/main.cc
+*/
+class OutputBind : public Bind {
+public:
+ /**
+ Graba el valor de la variable anna::dbms::LongBlock asociada a esta OutputBind. Cualquier
+ modificacion que necesitemos aplicar sobre la columnna de tipo se debera hacer mediante los
+ metodos ofrecidos por la clase anna::dbms::LongBlock.
+
+ \warning Este metodo solo puede ser usado para variables de tipo dbms::Data::Type::LongBlock y
+ siempre y cuando hayamos abierto el BLOB con una sentencia SQL de seleccion.
+ */
+ void write() const throw(RuntimeException, dbms::DatabaseException);
+
+protected:
+ OutputBind(const char* name, dbms::Data& value) : Bind(name, value) {;}
+
+private:
+ // este metodo no sera invocado nunca. A partir de un Output nunca hay que
+ // convertir de C++ -> RDBMS
+ void code() const throw(RuntimeException) {;}
+
+ virtual void do_write(const dbms::LongBlock&) const throw(RuntimeException, dbms::DatabaseException) = 0;
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_ResultCode_hpp
+#define anna_dbms_ResultCode_hpp
+
+#include <string>
+
+#include <string.h>
+
+#include <stdlib.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/RuntimeException.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Clase para acceder a la informacion devuelta por el gestor de base de datos
+ referente al ultimo comando realizado.
+ */
+class ResultCode {
+public:
+ /**
+ Constructor vacio.
+ \warning Antes de usarse debe asignarse a algun otro ResultCode obtenido mediante la invocacion
+ a anna::dbms::Connection::execute.
+ */
+ ResultCode() : a_errorText(NULL), a_errorDecoder(NULL), a_errorCode(0) {;}
+
+ /**
+ Constructor copia.
+ @param other Instancia de la que copiar los datos.
+ */
+ ResultCode(const ResultCode& other) :
+ a_errorText(NULL),
+ a_errorDecoder(other.a_errorDecoder) {
+ set(other.a_errorCode, other.a_errorText);
+ }
+
+ /**
+ Destructor.
+ */
+ virtual ~ResultCode() { if(a_errorText != NULL) free(a_errorText); }
+
+ /**
+ Devuelve el codigo de error del ultimo comando ejecutado contra la base de datos.
+ @return El codigo de error del ultimo comando ejecutado contra la base de datos.
+ */
+ int getErrorCode() const throw() { return a_errorCode; }
+
+ /**
+ Devuelve el texto del error del ultimo comando ejecutado contra la base de datos.
+ @return El texto del error del ultimo comando ejecutado contra la base de datos.
+ */
+ const char* getErrorText() const throw() { return (a_errorText != NULL) ? a_errorText : ""; }
+
+ // Operadores
+ /**
+ Operador copia.
+ @param resultCode Instancia a copiar.
+ @return Una instancia de si mismo.
+ */
+ ResultCode& operator = (const ResultCode& resultCode)
+ throw() {
+ if(this != &resultCode) {
+ a_errorDecoder = resultCode.a_errorDecoder;
+ set(resultCode.a_errorCode, resultCode.a_errorText);
+ }
+
+ return *this;
+ }
+
+ /**
+ Devuelve \em true si las condiciones de busqueda de la ultimo operacion
+ no han sido satisfechas por ningun registro o \em false en otro caso.
+ @return \em true si las condiciones de busqueda de la ultimo operacion
+ no han sido satisfechas por ningun registro o \em false en otro caso.
+ */
+ bool notFound() const throw(anna::RuntimeException);
+
+ /**
+ Devuelve \em true si la ultima operacion solicitada fue realizada correctamente
+ o \em false en otro caso.
+ @return \em true si la ultima operacion solicitada fue realizada correctamente
+ o \em false en otro caso.
+ */
+ bool successful() const throw(anna::RuntimeException);
+
+ /**
+ Devuelve \em true Si el registro obtenenido en una sentencia de seleccion con indicador
+ de modo exclusivo ha sido bloqueada previamente por otro proceso y/o contexto de base de
+ datos o \em false en otro caso.
+ @return \em true Si el registro obtenenido en una sentencia de seleccion con indicador
+ de modo exclusivo ha sido bloqueada previamente por otro proceso y/o contexto de base de
+ datos o \em false en otro caso.
+ */
+ bool locked() const throw(anna::RuntimeException);
+
+ /**
+ Devuelve \em true si se perdio la conexion la base de datos o \em false en otro caso.
+ @return \em true si se perdio la conexion la base de datos o \em false en otro caso.
+ */
+ bool lostConnection() const throw(anna::RuntimeException);
+
+ /**
+ Devuelve una cadena con la informacion sobre esta clase.
+ \return Una cadena con la informacion sobre esta clase.
+ */
+ std::string asString() const throw();
+
+protected:
+ static const int MaxErrorLen = 512;
+
+ /**
+ Decodificador del error devuelto por el RDBMS concreto que estemos usando.
+ \warning Exclusivamente uso interno.
+ */
+ class ErrorDecoder {
+ public:
+ virtual bool notFound(const int errorCode) const throw() = 0;
+ virtual bool successful(const int errorCode) const throw() = 0;
+ virtual bool locked(const int errorCode) const throw() = 0;
+ virtual bool lostConnection(const int errorCode) const throw() = 0;
+ };
+
+ /**
+ Constructor.
+
+ \param errorCode Codigo de error asociado a la ultima operacion realizada contra la base de datos.
+ \param errorText Texto asociado al error de ultima operacion realizada contra la base de datos. Puede ser
+ NULL si no hay ningun texto de error asociado al codigo recibido.
+ \param errorDecoder Decofidicador de errores.
+ */
+ ResultCode(const int errorCode, const char* errorText, const ErrorDecoder* errorDecoder) :
+ a_errorText(NULL),
+ a_errorDecoder(errorDecoder) {
+ set(errorCode, errorText);
+ }
+
+ /**
+ Establece el contenido de esta clase.
+
+ \param errorCode Codigo de error asociado a la ultima operacion realizada contra la base de datos.
+ \param errorText Texto asociado al error de ultima operacion realizada contra la base de datos.
+ */
+ void set(const int errorCode, const char* errorText)
+ throw() {
+ a_errorCode = errorCode;
+ copy(errorText);
+ }
+
+private:
+ int a_errorCode;
+ char* a_errorText;
+ const ErrorDecoder* a_errorDecoder;
+
+ void copy(const char* text) throw();
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Sentence_hpp
+#define anna_dbms_Sentence_hpp
+
+#include <anna/core/mt/Mutex.hpp>
+
+#include <anna/dbms/ResultCode.hpp>
+
+namespace anna {
+
+namespace xml {
+class Node;
+}
+
+namespace dbms {
+
+class Database;
+class Connection;
+class Statement;
+
+/**
+ Clase que facilita la ejecucion de sentencias SQL compuestas y la comprobacion de errores ya que
+ solo devuelve excepciones de tipo anna::RuntimeException.
+*/
+class Sentence : public Mutex {
+public:
+ /**
+ Modos de actuar cuando se detecta un error en la ejecucion de las sentencias SQL.
+ \see Sentence
+ */
+ struct Mode { enum _v { ExceptionWhenNotFound, SilentWhenNotFound }; };
+
+ /**
+ Ejecuta la sentencia SQL asociada a este instancia. Antes de invocar a este metodo debemos
+ activar una seccion critica sobre esta instancia.
+ \param connection Conexion usada para ejecutar la sentencia. Debe tener activa una seccion critica.
+ */
+ virtual dbms::ResultCode execute(dbms::Connection& connection) throw(RuntimeException) {
+ return execute(connection, a_dbStatement);
+ }
+
+ /**
+ Devuelve el nombre de la sentencia SQL asociada a esta instancia.
+ \return El nombre de la sentencia SQL asociada a esta instancia.
+ \warning Si todavia no tiene nombre asociado devolvera una cadena vacia.
+ */
+ const std::string& getName() const throw();
+
+ /**
+ Inicializa el estado de esta instancia
+ \param database Instancia de la base de datos usada para definir las sentencias SQL que componen esta
+ instancia.
+ */
+ void initialize(dbms::Database& database) throw(RuntimeException);
+
+ /**
+ Transfiere un registro desde la base de datos a las variables del entorno C++.
+ \return \em false si no hay mas registros o \em true en caso contrario.
+ */
+ bool fetch() throw(RuntimeException);
+
+ /**
+ Transfiere un registro desde la base de datos a las variables del entorno C++.
+ \param resultCode Variable que contiene el resultado de invocar a anna::dbms::Sentence::execute
+ \return \em false si no hay mas registros o \em true en caso contrario.
+ */
+ bool fetch(const ResultCode& resultCode) throw(RuntimeException) {
+ return (resultCode.successful() == true) ? fetch() : false;
+ }
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ \return una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+ /**
+ Devuelve un documento XML con la informacion referente a esta instancia.
+ \param parent Nodo XML del que dependerá la información referente a esta instancia.
+ \return un documento XML con la informacion referente a esta instancia.
+ */
+ virtual xml::Node* asXML(xml::Node* parent) const throw();
+
+protected:
+ /**
+ Constructor.
+ \param mode Modo de actuacion en caso de detectar errores.
+ */
+ Sentence(const Mode::_v mode = Mode::ExceptionWhenNotFound) :
+ a_mode(mode), a_dbStatement(NULL)
+ {;}
+
+ /**
+ Ejecuta la sentencia SQL asociada a este instancia.
+ \param connection Conexion usada para ejecutar la sentencia. Debe tener activa una seccion critica.
+ \param statement Sentencia a ejecutar.
+ */
+ dbms::ResultCode execute(dbms::Connection& connection, dbms::Statement* statement) throw(RuntimeException);
+
+ /**
+ Metodo que debe inicializar las sentencias asociadas a esta instancia (valores de entrada y salida).
+ \return Retorna la instancia de la sentencia asociada a esta instancia debidamente inicializada.
+ */
+ virtual dbms::Statement* do_initialize(dbms::Database&) throw(RuntimeException) = 0;
+
+private:
+ const Mode::_v a_mode;
+ dbms::Statement* a_dbStatement;
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_ShortBlock_hpp
+#define anna_dbms_ShortBlock_hpp
+
+#include <string>
+
+#include <anna/core/RuntimeException.hpp>
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Bloque de datos usado como entrada y/o salida de las sentencias SQL.
+
+ La longitud del dato a tratar estara en 2048 y 4096 bytes, dependiendo
+ del RDBMS concreto con el que estemos trabajando.
+
+ \see LongBlock
+*/
+class ShortBlock : public Data {
+public:
+ /**
+
+ Constructor.
+ \param maxSize Tamao maximo que puede tener este bloque.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ */
+ explicit ShortBlock(const int maxSize, const bool isNulleable = false) :
+ Data(Type::ShortBlock, maxSize, isNulleable),
+ a_value(true) {
+ a_value.allocate(maxSize);
+ Data::setBuffer((void*) a_value.getData());
+ }
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ ShortBlock(const ShortBlock& other) :
+ Data(other),
+ a_value(true) {
+ a_value = other.a_value;
+ Data::setBuffer((void*) a_value.getData());
+ }
+
+ /**
+ Destructor.
+ */
+ virtual ~ShortBlock() {;}
+
+ /**
+ Devuelve el tamao actual de este dato.
+ \return El tamao actual de este dato.
+ */
+ int getSize() const throw() { return a_value.getSize(); }
+
+ /**
+ Devuelve el contenido de la este bloque de memoria.
+ \return Devuelve el contenido de la este bloque de memoria.
+ \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido.
+ */
+ const anna::DataBlock& getValue() const throw() { return a_value; }
+
+ /**
+ Operador de asignacin.
+ \param other Bloque del que copiar.
+ \return La instancia de este bloque de memoria.
+ */
+ ShortBlock& operator = (const ShortBlock& other) throw(RuntimeException);
+
+ /**
+ Operador de asignacin.
+ \param value Valor que queremos a asignar.
+ \return La instancia de esta cadena.
+ */
+ ShortBlock& operator = (const anna::DataBlock& value) throw(RuntimeException);
+
+ /**
+ Operador de conversion.
+ \return El anna::DataBlock asociado a esta instancia.
+ */
+ operator anna::DataBlock& () throw() { return a_value; }
+
+ /**
+ Operador de conversion.
+ \return El anna::DataBlock asociado a esta instancia.
+ */
+ operator const anna::DataBlock& () const throw() { return a_value; }
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ \return Una cadena con la informacion referente a esta instancia.
+ */
+ std::string asString() const throw();
+
+protected:
+ anna::DataBlock a_value;
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_Statement_hpp
+#define anna_dbms_Statement_hpp
+
+#include <vector>
+
+#include <anna/core/RuntimeException.hpp>
+#include <anna/core/mt/Mutex.hpp>
+#include <anna/core/util/Average.hpp>
+#include <anna/core/util/Microsecond.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+#include <anna/dbms/ResultCode.hpp>
+
+namespace anna {
+
+namespace xml {
+class Node;
+}
+
+namespace dbms {
+
+class Database;
+class Connection;
+class InputBind;
+class OutputBind;
+class Data;
+
+/**
+ Clase que facilita la ejecucion de sentencias SQL.
+
+ Para obtener la instancia de un comando para una determinada base de datos habra que instanciar
+ dicha base de datos e invocar al metodo Database::createStatement. Independientemente del tipo de comando
+ particular que la base de datos retorne, debemos asignarlo a un puntero de tipo anna::dbms::Statement.
+*/
+class Statement : public Mutex {
+public:
+ typedef std::vector <InputBind*>::iterator input_iterator;
+ typedef std::vector <OutputBind*>::iterator output_iterator;
+
+ /**
+ Destructor.
+ */
+ virtual ~Statement();
+
+ /**
+ Devuelve el nombre logico de esta sentencia.
+ \return El nombre logico de esta sentencia.
+ */
+ const std::string& getName() const throw() { return a_name; }
+
+ /**
+ Devuelve la expresion SQL recibida en el constructor.
+ \return La expresion SQL recibida en el constructor.
+ */
+ const std::string& getExpression() const throw() { return a_expression; }
+
+ /**
+ Devuelve el indicador de criticidad, si vale \em true indica que si la ejecucion de esta sentencia
+ falla al desbloquear la conexion con la que ejecutamos esta sentencia se invocara a
+ Connection::rollback, en otro caso aunque falle se invocara a Connection::commit.
+ Solo aplicara en sentencias que no sean de seleccion.
+ \return El indicador de criticidad de esta sentencia.
+ */
+ bool isCritical() const throw() { return a_isCritical; }
+
+ /**
+ Devuelve la instancia de la base de datos asociada a esta sentencia.
+ \return La instancia de la base de datos asociada a la sentencia.
+ */
+ Database& getDatabase() const throw() { return a_database; }
+
+ /**
+ Establece el parametro de entrada de la sentencia SQL.Cada una de las variables de entrada indicadas
+ en esta sentencia SQL deberia tener un parametro de entrada asociado. La correspondencia entre esta
+ variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
+ de definicion del parametro.
+
+ Por ejemplo la sentencia:
+
+ \code
+ update tabla1 set xx = :unavariable where yy = :otravariable;
+ \endcode
+
+ Cada una de las variables \em unavariable y \em otravariable debera tener asociado una variable de entrada.
+ Primero debemos indicaremos la correspondiente a \em unavariable y luego la correspondiente a \em otravariable.
+
+ \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
+ de la columna.
+ \param data Variable que deseamos asociar como variable de entrada. La correspondencia entre esta
+ y la sentencia SQL vendra dada por el orden de declaracion.
+ */
+ void bindInput(const char* name, Data& data) throw();
+
+ /**
+ Establece el parametro de salida de la sentencia SQL.Cada una de las variables de salida indicadas
+ en esta sentencia SQL deberia tener un parametro de salida asociado. La correspondencia entre esta
+ variable y la sentencia SQL vendra dada por el orden de aparacion en la sentencia SQL y por el orden
+ de definicion del parametro.
+
+ Por ejemplo la sentencia:
+
+ \code
+ select xx, yy from tabla1 where zz = :unavariable;
+ \endcode
+
+ Cada una de las variables \em xx e \em yy debera tener asociado una variable de salida.
+ Ademas la variable \em unavaraible debera tener asociada una variable de entrada.
+
+ \param name Nombre logico de esta variable. No tiene porque tener ninguna correspondencia con el nombre
+ de la columna.
+ \param data Variable que deseamos asociar como variable de salida. La correspondencia entre esta
+ y la sentencia SQL vendra dada por el orden de declaracion.
+
+ \return La instancia del dbms::OutputBind asociado al dato. nos permite
+ grabar el contenido de los tipos de datos BLOB.
+
+ \warning Solo las sentencias SQL del tipo \em select usan las variables de salida.
+ */
+ const dbms::OutputBind* bindOutput(const char* name, Data& data) throw();
+
+ /**
+ Establece el valor del indicador que activa/desactiva la necesidad de invocar al
+ \em commit y/o \em rollback despues de ejecutar esta sentencia.
+ */
+ void setRequiresCommit(const bool requiresCommit) throw() { a_requiresCommit = requiresCommit; }
+
+ /**
+ Devuelve \em true si la sentencia requiere la invocacion a \em commit o \em rollback
+ tras su ejecucion. Puede devolver \em true por tratarse de una sentencia que no tiene variables
+ de salida (insert, update o delete) o bien porque se haya activado el indicador correspondiente
+ mediante la llamada #setRequiresCommit
+ */
+ bool requiresCommit() const throw() { return (a_requiresCommit == true) || (a_outputBinds.empty() == true); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de entrada.
+ \return el iterador que apunta a la primera variable de entrada.
+ */
+ input_iterator input_begin() throw() { return a_inputBinds.begin(); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de entrada.
+ \return el iterador que apunta a la primera variable de entrada.
+ */
+ input_iterator input_end() throw() { return a_inputBinds.end(); }
+
+ /**
+ Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
+ \return el numero de variables de entrada asociado a esta sentencia SQL.
+ */
+ int input_size() const throw() { return a_inputBinds.size(); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de salida.
+ \return el iterador que apunta a la primera variable de salida.
+ */
+ output_iterator output_begin() throw() { return a_outputBinds.begin(); }
+
+ /**
+ Devuelve el iterador que apunta a la primera variable de salida.
+ \return el iterador que apunta a la primera variable de salida.
+ */
+ output_iterator output_end() throw() { return a_outputBinds.end(); }
+
+ /**
+ Devuelve el numero de variables de entrada asociado a esta sentencia SQL.
+ \return el numero de variables de entrada asociado a esta sentencia SQL.
+ */
+ int output_size() const throw() { return a_outputBinds.size(); }
+
+ /**
+ Devuelve un documento XML con la informacion referente a esta instancia.
+ \param parent Nodo XML del que debe colgar la informacion.
+ @return un documento XML con la informacion referente a esta instancia.
+ */
+ virtual xml::Node* asXML(xml::Node* parent) const throw();
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ @return Una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+ /**
+ Transfiere la informacion de una fila de la sentencia SQL de seleccion a las
+ variables de salida asociadas a la sentencia.
+
+ \return \em true si el registro ha sido transferido a las variables de salida o \em false si habiamos llegado
+ al ultimo registro de la seleccion.
+ */
+ virtual bool fetch() throw(RuntimeException, DatabaseException) = 0;
+
+ /**
+ Devuelve la variable de entrada apuntada por el iterador recibido como parametro.
+ \return la variable de entrada apuntada por el iterador recibido como parametro.
+ */
+ static Data& input(input_iterator& ii) throw();
+
+ /**
+ Devuelve la variable de salida apuntada por el iterador recibido como parametro.
+ \return la variable de salida apuntada por el iterador recibido como parametro.
+ */
+ static Data& output(output_iterator& ii) throw();
+
+protected:
+ /**
+ Contructor.
+
+ \param database Base de datos sobre la que se define la sentencia.
+ \param name Nombre logico de la sentencia.
+ \param expression Sentencia SQL asociada a esta clase.
+ \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
+ la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
+ aunque falle se invocara a Connection::commit. Solo aplicara en sentencias que no sean de seleccion.
+ */
+ Statement(Database& database, const char* name, const char* expression, const bool isCritical) :
+ a_database(database),
+ a_name(name),
+ a_expression(expression),
+ a_prepared(false),
+ a_isCritical(isCritical),
+ a_measureTiming("Timing", "us"),
+ a_requiresCommit(false) {
+ }
+
+ /**
+ Contructor.
+
+ \param database Base de datos sobre la que se define la sentencia.
+ \param name Nombre logico de la sentencia.
+ \param expression Sentencia SQL asociada a esta clase.
+ \param isCritical Si vale \em true indica que si la ejecucion de esta sentencia falla al desbloquear
+ la conexion con la que ejecutamos esta sentencia se invocara a Connection::rollback, en otro caso
+ aunque falle se invocara a Connection::commit. Solo aplicara en cuenta en sentencias que no
+ sean de seleccion.
+ */
+ Statement(Database& database, const char* name, const std::string& expression, const bool isCritical) :
+ a_database(database),
+ a_name(name),
+ a_expression(expression),
+ a_prepared(false),
+ a_isCritical(isCritical),
+ a_measureTiming("Timing", "us"),
+ a_requiresCommit(false) {
+ }
+
+ /**
+ Devuelve la referencia de entrada apuntada por el iterador recibido como parametro.
+ \return la referencia de entrada apuntada por el iterador recibido como parametro.
+ */
+ static InputBind* inputBind(input_iterator& ii) throw() { return *ii; }
+
+ /**
+ Devuelve la referencia de salida apuntada por el iterador recibido como parametro.
+ \return la referencia de salida apuntada por el iterador recibido como parametro.
+ */
+ static OutputBind* outputBind(output_iterator& ii) throw() { return *ii; }
+
+private:
+ Database& a_database;
+ const std::string a_name;
+ std::string a_expression;
+ std::vector <InputBind*> a_inputBinds; /**< Lista de variables de entrada */
+ std::vector <OutputBind*> a_outputBinds; /**< Lista de variables de salida */
+ bool a_prepared;
+ const bool a_isCritical;
+ Average <Microsecond> a_measureTiming;
+ bool a_requiresCommit;
+
+ Statement(const Statement&);
+ void measureTiming(const Microsecond & init, const Microsecond & end) throw() { a_measureTiming += (end - init); }
+
+ virtual void prepare(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
+ virtual ResultCode execute(Connection* connection) throw(RuntimeException, DatabaseException) = 0;
+
+ friend class Connection;
+ friend class Database;
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_StatementTranslator_hpp
+#define anna_dbms_StatementTranslator_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+class Database;
+
+/**
+ * Clase que ajustar de forma transparente las diferencias de tratamiento que tiene las
+ * sentencias SQL en los distintos motores de base de datos. De esta forma una aplicación
+ * originariamente escrita para un determinado RDBMS no tendrá que hacer ningún cambio
+ * en las sentencias SQL al cambiar a otro RDBMS.
+ *
+ * Por ejemplo para indicar los parámetros de entrada en Oracle se indica con un
+ * literal precedido de ':' o '&'. Con lo que la sentencia podría quedar como:
+ * \code
+ * insert into foo (field1, field2) values (:f1, :f2)
+ * \endcode
+ *
+ * En PosgreSQL (tambien sorpotado en Oracle) quedaría algo así:
+ * \code
+ * insert into foo (field1, field2) values (&f1, &f2)
+ * \endcode
+ *
+ * Mientras que en MySQL la expresión debería ser como:
+ * \code
+ * insert into foo (field1, field2) values (?, ?);
+ * \endcode
+ *
+ * \see anna::dbms::Database::setStatementTranslator
+ */
+class StatementTranslator {
+ /**
+ * Devuelve el nombre lógico de este traductor.
+ * \return el nombre lógico de este traductor.
+ */
+ const char* getName() const throw() { return a_name; }
+
+protected:
+ /**
+ * Constructor.
+ * \param name Nombre lógico del traductor.
+ */
+ explicit StatementTranslator(const char* name) : a_name(name) {;}
+
+ /**
+ * Se invoca automáticamente desde anna::dbms::Database::createStatement si la
+ * instancia de la base de datos tiene asociada alguna instancia heredada de esta clase.
+ *
+ * Ã\89ste metodo sólo se invoca una vez para cada una de las sentencias definidas sobre
+ * la base de datos, por lo que la traducción de sentencias SQL tiene un consumo despreciable
+ * con respecto al tiempo total del proceso.
+ *
+ * \param statement Sentencia SQL original.
+ * \return La sentencia SQL correspondiente con la original, pero tratada para que
+ * pueda ser interpretada correctamente por el motor de base de datos sobre el que
+ * se va a ejecutar.
+ */
+ virtual const char* apply(const char* statement) throw(RuntimeException) = 0;
+
+private:
+ const char* a_name;
+
+ StatementTranslator(const StatementTranslator&);
+
+ friend class Database;
+};
+
+}
+}
+
+#endif
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_String_hpp
+#define anna_dbms_String_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+#include <anna/dbms/Data.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Cadena usada como entrada y/o salida de las sentencias SQL.
+*/
+class String : public Data {
+public:
+ /**
+ Constructor.
+ \param maxSize Tamao maximo que puede tener esta cadena. Deberia coincidir con el indicado
+ por la columna con la que vaya a corresponder en la sentencia.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ */
+ explicit String(const int maxSize, const bool isNulleable = false) :
+ Data(Type::String, maxSize, isNulleable) {
+ Data::setBuffer(a_value = new char [maxSize + 1]);
+ anna_memset(a_value, 0, maxSize + 1);
+ }
+
+ /**
+ Constructor copia.
+ \param other Instancia de la que copiar.
+ */
+ String(const String& other) :
+ Data(other),
+ a_value(other.a_value) {
+ const int maxSize = getMaxSize();
+ Data::setBuffer(a_value = new char [maxSize + 1]);
+ anna_memset(a_value, 0, maxSize + 1);
+ }
+
+ /**
+ Destructor.
+ */
+ virtual ~String() { delete [] a_value; }
+
+ /**
+ Devuelve el contenido de la cadena.
+ \return El contenido de la cadena.
+ \warning Si el metodo Data::isNull devolvio \em true el resultado de este metodo no esta definido.
+ */
+ const char* getValue() const throw() { return a_value; }
+
+ /**
+ Operador de copia.
+ \param str Cadena de la que copiar. Si la longitud de la cadena sobrepasa el tamao maximo
+ indicado en el constructor obtendremos una excepcin.
+ \return La instancia de esta cadena.
+ */
+ String& operator = (const String& str) throw(RuntimeException);
+
+ /**
+ Operador de asignacin.
+ \param str Cadena de la que copiar. Si la longitud de la cadena sobrepasa el tamao maximo
+ indicado en el constructor obtendremos una excepcin.
+ \return La instancia de esta cadena.
+ */
+ String& operator = (const char* str) throw(RuntimeException);
+
+ /**
+ Operador de asignacin.
+ \param str Cadena de la que copiar. Si la longitud de la cadena sobrepasa el tamao maximo
+ indicado en el constructor obtendremos una excepcin.
+ \return La instancia de esta cadena.
+ */
+ String& operator = (const std::string& str) throw(RuntimeException) { return operator= (str.c_str()); }
+
+ /**
+ Operador de conversion. si el contenido de la columna sociada
+ fue nulo este metodo devolvera NULL.
+ \return El contenido de esta cadena.
+ */
+ operator const char*() const throw() { return (Data::isNull() == true) ? NULL : a_value; }
+
+ /**
+ Elimina los espacios a la derecha de la cadena recibida.
+ \return La misma cadena recibida pero con los espacios eliminados.
+ */
+ static char* strip(char *str) throw();
+
+ /**
+ Devuelve una cadena con la informacion referente a esta instancia.
+ \return Una cadena con la informacion referente a esta instancia.
+ */
+ virtual std::string asString() const throw();
+
+private:
+ char* a_value;
+
+ void do_clear() throw() { a_value [0] = 0; }
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_TimeStamp_hpp
+#define anna_dbms_TimeStamp_hpp
+
+#include <anna/dbms/Date.hpp>
+
+namespace anna {
+
+namespace dbms {
+
+/**
+ Tipo de datos que permite trabajar con el tipo de dato 'TimeStamp' de un gestor de base de
+ datos generico.
+
+ El tipo de dato TimeStamp contiene la información suficiente para representar una fecha
+ incluyendo la hora del día.
+*/
+class TimeStamp : public Date {
+public:
+ /**
+ Constructor.
+ \param isNulleable Indica si el dato puede tomar valores nulos.
+ \param format Formato usado para interpretar los datos de esta fecha, en los metodos Date::getCStringValue y
+ Date::setValue (const char*) y Date::setValue (const std::string&). Sigue la especificacion:
+
+ \code
+ %a Replaced by the localeâs abbreviated weekday name. [ tm_wday]
+
+ %A Replaced by the localeâs full weekday name. [ tm_wday]
+
+ %b Replaced by the localeâs abbreviated month name. [ tm_mon]
+
+ %B Replaced by the localeâs full month name. [ tm_mon]
+
+ %c Replaced by the locale's appropriate date and time representation. (See the Base Definitions volume of
+ IEEE Std 1003.1-2001, <time.h>.)
+
+ %C Replaced by the year divided by 100 and truncated to an integer, as a decimal number [00,99]. [ tm_year]
+
+ %d Replaced by the day of the month as a decimal number [01,31]. [ tm_mday]
+
+ %D Equivalent to %m / %d / %y . [ tm_mon, tm_mday, tm_year]
+
+ %e Replaced by the day of the month as a decimal number [1,31]; a single digit is preceded by a space. [
+ tm_mday]
+
+ %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard date format). [ tm_year, tm_mon, tm_mday]
+
+ %g Replaced by the last 2 digits of the week-based year (see below) as a decimal number [00,99]. [ tm_year,
+ tm_wday, tm_yday]
+
+ %G Replaced by the week-based year (see below) as a decimal number (for example, 1977). [ tm_year, tm_wday,
+ tm_yday]
+
+ %h Equivalent to %b . [ tm_mon]
+
+ %H Replaced by the hour (24-hour clock) as a decimal number [00,23]. [ tm_hour]
+
+ %I Replaced by the hour (12-hour clock) as a decimal number [01,12]. [ tm_hour]
+
+ %j Replaced by the day of the year as a decimal number [001,366]. [ tm_yday]
+
+ %m Replaced by the month as a decimal number [01,12]. [ tm_mon]
+
+ %M Replaced by the minute as a decimal number [00,59]. [ tm_min]
+
+ %n Replaced by a <newline>.
+
+ %p Replaced by the locale's equivalent of either a.m. or p.m. [ tm_hour]
+
+ %r Replaced by the time in a.m. and p.m. notation; in the POSIX locale this shall be equivalent to %I : %M
+ : %S %p . [ tm_hour, tm_min, tm_sec]
+
+ %R Replaced by the time in 24-hour notation ( %H : %M ). [ tm_hour, tm_min]
+
+ %S Replaced by the second as a decimal number [00,60]. [ tm_sec]
+
+ %t Replaced by a <tab>.
+
+ %T Replaced by the time ( %H : %M : %S ). [ tm_hour, tm_min, tm_sec]
+
+ %u Replaced by the weekday as a decimal number [1,7], with 1 representing Monday. [ tm_wday]
+
+ %U Replaced by the week number of the year as a decimal number [00,53]. The first Sunday of January is the
+ first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+
+ %V Replaced by the week number of the year (Monday as the first day of the week) as a decimal number [01,53].
+ If the week containing 1 January has four or more days in the new year, then it is considered week 1. Oth-
+ erwise, it is the last week of the previous year, and the next week is week 1. Both January 4th and the
+ first Thursday of January are always in week 1. [ tm_year, tm_wday, tm_yday]
+
+ %w Replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. [ tm_wday]
+
+ %W Replaced by the week number of the year as a decimal number [00,53]. The first Monday of January is the
+ first day of week 1; days in the new year before this are in week 0. [ tm_year, tm_wday, tm_yday]
+
+ %x Replaced by the locale's appropriate date representation. (See the Base Definitions volume of
+ IEEE Std 1003.1-2001, <time.h>.)
+
+ %X Replaced by the locale's appropriate time representation. (See the Base Definitions volume of
+ IEEE Std 1003.1-2001, <time.h>.)
+
+ %y Replaced by the last two digits of the year as a decimal number [00,99]. [ tm_year]
+
+ %Y Replaced by the year as a decimal number (for example, 1997). [ tm_year]
+
+ %z Replaced by the offset from UTC in the ISO 8601:2000 standard format ( +hhmm or -hhmm ), or by no charac-
+ ters if no timezone is determinable. For example, "-0430" means 4 hours 30 minutes behind UTC (west of
+ Greenwich). If tm_isdst is zero, the standard time offset is used. If tm_isdst is greater than zero, the
+ daylight savings time offset is used. If tm_isdst is negative, no characters are returned. [ tm_isdst]
+
+ %Z Replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. [
+ tm_isdst]
+
+ %% Replaced by % .
+ \endcode
+
+ Para obtener más informacion sobre la espeficacion de formato \em man \em strftime (p.e.).
+
+ Para poder obtener la parte fraccionaria en la salida del metodo #getCStringValue hay que indicar el literal \em %%d. Por ejemplo:
+
+ \code
+ TimeStamp oneTime (false, "%T.%%d")
+ \endcode
+ */
+ explicit TimeStamp(const bool isNulleable = false, const char* format = NULL) :
+ Date(Data::Type::TimeStamp, isNulleable, format),
+ a_fractionalSecond(0)
+ {;}
+
+ /**
+ * Devuelve la parte fraccionaria de los segundos asociados a este objeto.
+ * \return La parte fraccionaria de los segundos asociados a este objeto.
+ */
+ int getFractionalSecond() const throw() { return a_fractionalSecond; }
+
+ /**
+ * Establece la parte fraccionaria de los segundos de este objeto.
+ * \param fsec Parte fraccionaria de los segundos.
+ */
+ void setFractionalSecond(const int fsec) throw() { a_fractionalSecond = fsec; }
+
+ /**
+ * Interpreta el contenido de la fecha y lo transfiere al buffer.
+ * \return El buffer que contiene esta fecha interpretada con el formato indicado en el contructor.
+ * \warning El resultado sera NULL en caso de no poder interpretar correctamente la fecha.
+ */
+ virtual const char* getCStringValue() const throw();
+
+ /**
+ Operador de copia.
+ \param timeStamp Fecha de la que copiar.
+ \return La instancia de esta fecha.
+ \warning Solo copia el contenido de la fecha recibida, no cambia el formato de interpretacion de la fecha origen.
+ */
+ TimeStamp& operator = (const TimeStamp& timeStamp) throw(RuntimeException) {
+ Date::operator= (timeStamp);
+ a_fractionalSecond = timeStamp.a_fractionalSecond;
+ return *this;
+ }
+
+ /**
+ Operador de copia.
+ \param date Fecha de la que copiar.
+ \return La instancia de esta fecha.
+ \warning Solo copia el contenido de la fecha recibida, no cambia el formato de interpretacion de la fecha origen.
+ */
+ TimeStamp& operator = (const Date& date) throw(RuntimeException) { Date::operator= (date); a_fractionalSecond = 0; return *this; }
+
+private:
+ char a_anotherBuffer [MaxDateSize + 1];
+ int a_fractionalSecond;
+
+ void do_clear() throw() { a_fractionalSecond = 0; a_anotherBuffer [0] = 0; }
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_dbms_hpp
+#define anna_dbms_dbms_hpp
+
+namespace anna {
+/**
+Define de forma generica el protocolo de acceso a los datos guardados en un DBMS.
+
+El ejecutable debera enlazarse con las librerias:
+ \li anna.core.a
+ \li anna.xml.a
+ \li anna.app.a
+ \li anna.comm.a
+ \li anna.dbms.a
+
+El <b>Packet Header</b> es anna.dbms.h
+*/
+namespace dbms {
+}
+}
+
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/Data.hpp>
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+#include <anna/dbms/Delivery.hpp>
+#include <anna/dbms/FailRecoveryHandler.hpp>
+#include <anna/dbms/Integer.hpp>
+#include <anna/dbms/LongBlock.hpp>
+#include <anna/dbms/OutputBind.hpp>
+#include <anna/dbms/ResultCode.hpp>
+#include <anna/dbms/ShortBlock.hpp>
+#include <anna/dbms/Statement.hpp>
+#include <anna/dbms/StatementTranslator.hpp>
+#include <anna/dbms/Sentence.hpp>
+#include <anna/dbms/String.hpp>
+#include <anna/dbms/Float.hpp>
+#include <anna/dbms/Date.hpp>
+#include <anna/dbms/TimeStamp.hpp>
+
+using namespace anna::dbms;
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_functions_hpp
+#define anna_dbms_functions_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+namespace anna {
+namespace dbms {
+class Connection;
+}
+}
+
+namespace anna {
+namespace dbms {
+
+using namespace anna;
+
+
+/**
+ Métodos usados habitualmente para trabajar contra la base de datos.
+*/
+struct functions {
+public:
+ /**
+ * Este metodo asegura la integridad entre el esquema de tablas instalado y el esperado por los procesos de un proyecto.
+ * Para ello cada uno de los proyectos debe invocar a este método indicado los parámetro requeridos. Es imprescindible
+ * que la versión esperada del esquema de base de datos esté definida en una única variable centralizada.
+ *
+ * La idea es que cada vez que hagamos un cambio en la estructura de tablas de una cierta entidad cambiemos la versión
+ * del esquema, y ese cambio deberá reflejarse en la invocación a este nuevo método.
+ *
+ * Este método lanzará una excepción si el último parche instalado en el esquema de base de datos no coincide
+ * con el valor de la variable \em requiredPatch.
+ *
+ * Cada proceso debe invocar la comprobación de esquema en cuanto la base de datos tenga una conexión disponible, de forma
+ * que si el esquema de base de datos no coincide con el esperado el proceso mostrará un error indicado el esquema de base
+ * de datos esperado y el esquema de base datos instalado.
+ *
+ * Para usar este método el esquema de base de nuestro proyecto debe disponer de una tabla que debe contener, al menos,
+ * la siguiente estructura:
+ *
+ * \code
+ * -- Ejemplo de creación para Oracle(tm)
+ * create table axe_dataScheme (
+ * id varchar(8) not null,
+ * installation_date date default sysdate not null
+ * );
+ *
+ * alter table axe_dataScheme add constraint axe_dataScheme_pk primary key (id);
+ *
+ * \endcode
+ *
+ * \code
+ * -- Ejemplo de creación para PostgreSQL
+ * create table data_scheme (
+ * id varchar(8) not null,
+ * installation_date timestamp default now (),
+ * primary key (id)
+ * );
+ * \endcode
+ *
+ * El nombre de la tabla y los campos de las columnas podrían ser distintos ya que este método los recibe como parámetros.
+ *
+ * Un ejemplo de implementación podría ser:
+ *
+ * \code
+ * //static
+ * void axe::storage::functions::verifyDataScheme (dbms::Connection& connection)
+ * throw (RuntimeException)
+ * {
+ * anna::dbms::functions::verifyDataScheme (connection, "axe_dataScheme", "v1.3");
+ * }
+ * \endcode
+ *
+ * \param connection Conexión usada para acceder a los datos.
+ * \param tableName Nombre de la tabla que contiene las versiones instaladas.
+ * \param requiredPatch Identificador de parche de base de base de datos requerido por los procesos de nuestro proyecto.
+ * Este indicador debería estar definido en un único punto para todo nuestro proyecto.
+ * \param columnID Nombre de la columna que contiene el identificador de cada uno de los parches instalados.
+ * \param columnDate Nombre de la columna que contiene la fecha de instalación de cada parche.
+ */
+ static void verifyDataScheme(dbms::Connection& connection, const char* tableName, const char* requiredPatch, const char* columnID = "id", const char* columnDate = "installation_date")
+ throw(RuntimeException);
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbms_internal_sccs_hpp
+#define anna_dbms_internal_sccs_hpp
+
+namespace anna {
+
+namespace dbms {
+
+class sccs {
+public:
+ static void activate() throw();
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Accesor_hpp
+#define anna_dbos_Accesor_hpp
+
+#include <anna/core/RuntimeException.hpp>
+#include <anna/core/mt/Mutex.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbos/defines.hpp>
+
+namespace anna {
+
+namespace dbms {
+class Database;
+class Connection;
+class Statement;
+}
+
+namespace dbos {
+
+class StorageArea;
+
+/**
+ Interfaz que deben cumplir los objetos encargados de acceder al objeto del medio fisico,
+ que normalmente sera alguna base de datos.
+*/
+class Accesor : public Mutex {
+public:
+ typedef short Id; /**< Permite identificar el tipo de accesor. */
+
+ /**
+ Destructor.
+ */
+ virtual ~Accesor();
+
+ /**
+ Devuelve el identificador de este accesor.
+ \return El identificador de este accesor.
+ */
+ Id getId() const throw() { return a_id; }
+
+ /**
+ Devuelve la instancia de la sentencia \em statement asociada a este cargador.
+ \return La instancia de la sentencia \em statement asociada a este cargador. Puede ser NULL.
+ */
+ dbms::Statement* getStatement()
+ throw(RuntimeException) {
+ return (a_statement == NULL && a_database != NULL) ? (a_statement = initialize(*a_database)) : a_statement;
+ }
+
+ /**
+ * Devuelve \em true si el accesor fue inicializado con base de datos o \em false en otro caso.
+ * \return \em true si el accesor fue inicializado con base de datos o \em false en otro caso.
+ */
+ bool hasDataBase() const throw() { return a_database != NULL; }
+
+ /**
+ Devuelve la instancia de la base de datos asociada a este cargador.
+ \return La instancia de la base de datos asociada a este cargador.
+
+ \warning Si el accesor fue inicializado sin base de datos lo resultados no están definidos.
+ */
+ dbms::Database& getDatabase() throw() { return *a_database; }
+
+ /**
+ Devuelve la conexion que esta usando actualmente este cargador.
+ \return la conexion que esta usando actualmente este cargador.
+ */
+ dbms::Connection& getConnection() throw(RuntimeException) {
+ if(a_connection == NULL) {
+ std::string msg(asString());
+ msg += " | No available database connection";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return *a_connection;
+ }
+
+ /**
+ Devuelve la representacion en forma de cadena de la clave primaria establecida.
+ @return La representacion en forma de cadena de la clave primaria establecida.
+ */
+ virtual std::string asString() const throw() = 0;
+
+ /**
+ Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos.
+ Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces
+ a la que pertenece la clase.
+ \return Una cadena con el nombre de este selector.
+ */
+ virtual const char* getClassName() const throw() = 0;
+
+protected:
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ */
+ Accesor(dbms::Database& database, const Id id) :
+ a_database(&database),
+ a_id(id),
+ a_statement(NULL),
+ a_connection(NULL),
+ a_emodeIsNull(true)
+ {;}
+
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ \param emode Modo de actuar en caso de no encontrar el dato buscado.
+ */
+ Accesor(dbms::Database& database, const Id id, const Exception::Mode::_v emode) :
+ a_database(&database),
+ a_id(id),
+ a_statement(NULL),
+ a_connection(NULL),
+ a_emodeIsNull(false),
+ a_exceptionMode(emode)
+ {;}
+
+ /**
+ Constructor.
+ \param id Identificador de este accesor.
+ */
+ Accesor(const Id id) :
+ a_database(NULL),
+ a_id(id),
+ a_statement(NULL),
+ a_connection(NULL),
+ a_emodeIsNull(true)
+ {;}
+
+ /**
+ Metodo que deben implementar todos los accesores para definir la sentencia
+ SQL que los definira.
+ Se invocara automaticamente desde el nucleo de anna.dbos la primera vez que
+ se use este accesor, de forma que el programador solo debe preocuparse por
+ definir este metodo.
+ \param database Instancia de la base de datos indicada en el constructor.
+ */
+ virtual dbms::Statement* initialize(dbms::Database& database) throw(RuntimeException) = 0;
+
+private:
+ dbms::Database* a_database;
+ const Id a_id;
+ dbms::Statement* a_statement;
+ dbms::Connection* a_connection;
+ bool a_emodeIsNull;
+ Exception::Mode::_v a_exceptionMode;
+
+ void setStatement(dbms::Statement* statement) throw() { a_statement = statement; }
+
+ virtual bool load(dbms::Connection*, const StorageArea*) throw(RuntimeException, dbms::DatabaseException);
+
+ friend class StorageArea;
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_AutoObject_hpp
+#define anna_dbos_AutoObject_hpp
+
+#include <anna/dbos/Object.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+
+/**
+ Facilita el uso de los punteros a objectos obtenidos a partir de los datos guardados en un medio fisico.
+
+ La idea de esta clase es que el constructor y el destructor de esta clase cooperan para reservar y/o
+ liberar correctamente la instancia de T asociada a esta instancia.
+
+ \param T Clase que vamos a gestionar.
+
+ En el siguiente ejemplo podemos ver la forma habitual de trabajar con un objeto persistente tiene
+ el incoveniente de que tenemos que tener en cuenta cada una de las situaciones en las que la
+ referencia obtenida mediante el metodo \em instantiate debe ser liberada.
+
+ \code
+ void Application::getServerSocketsData (vector <SocketData>& serverSocketsData) const
+ throw (RuntimeException)
+ {
+ LOGMETHOD (TraceMethod ("anna::Application", "getServerSocketsData", ANNA_FILE_LOCATION));
+
+ Facility* facility (NULL);
+ FacilityLoader facilityLoader;
+
+ try {
+ facility = Facility::instantiate (facilityLoader.setKey (a_thisFacility)); // (1)
+ LOGDEBUG (Logger::write (Logger::Debug, facility->asString (), ANNA_FILE_LOCATION));
+
+ getSocketsData (getThisHostName (), facility->getName (), a_thisCell, a_thisInstance, serverSocketsData);
+
+ Facility::release (facility);
+ }
+ catch (dbos::DatabaseException& edbos) {
+ Facility::release (facility);
+ throw RuntimeException (edbos.getText (), ANNA_FILE_LOCATION);
+ }
+ catch (RuntimeException&) { // Tenemos que capturar esta excepcion para liberar el recurso.
+ Facility::release (facility);
+ throw;
+ }
+ }
+ \endcode
+
+ Como podemos ver a continuacion el siguiente metodo es mucho mas sencillo y aporta la gran ventaja de que
+ el sistema trabaja por nosotros para liberar correctamente los recursos.
+
+ \code
+ void Application::getServerSocketsData (vector <SocketData>& serverSocketsData) const
+ throw (RuntimeException)
+ {
+ LOGMETHOD (TraceMethod ("anna::Application", "getServerSocketsData", ANNA_FILE_LOCATION));
+
+ AutoObject <Facility> facility;
+ FacilityLoader facilityLoader;
+
+ try {
+ facility = Facility::instantiate (facilityLoader.setKey (a_thisFacility)); // (1)
+
+ LOGDEBUG (Logger::write (Logger::Debug, facility->asString (), ANNA_FILE_LOCATION));
+
+ getSocketsData (getThisHostName (), facility->getName (), a_thisCell, a_thisInstance, serverSocketsData);
+ }
+ catch (dbos::DatabaseException& edbos) {
+ throw RuntimeException (edbos.getText (), ANNA_FILE_LOCATION);
+ }
+ }
+ \endcode
+*/
+template <typename T> class AutoObject {
+public:
+ /**
+ Constructor.
+ \param t Instancia del objeto asociado a esta instancia.
+ \warning La instancia deberia haber sido obtenida mediate la invocacion a \em T::instantiate de la
+ clase persistente.
+ */
+ explicit AutoObject(T* t) : a_t(t) {;}
+
+ /**
+ Constructor.
+ */
+ AutoObject() : a_t(NULL) {;}
+
+ /**
+ Destructor. Invoca al metodo \em T::release
+ */
+ ~AutoObject() { if(a_t != NULL) T::release(a_t); }
+
+ /**
+ Operador ->
+ Permite invocar a metodos de la clase T.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ T* operator -> () const throw() { return a_t; }
+
+ /**
+ Operador copia.
+ \param t Referencia al objeto que vamos a tratar.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ T* operator = (T* t) throw() {
+ if(a_t != t) {
+ T::release(a_t);
+ a_t = t;
+ }
+
+ return a_t;
+ }
+
+ /**
+ Operador copia.
+ \param other Referencia al objeto que vamos a tratar.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ T* operator = (const AutoObject <T>& other) throw(RuntimeException) {
+ return (this != &other) ? (*this = T::duplicate(other.a_t)) : a_t;
+ }
+
+ /**
+ Operador de conversion.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ operator T*() const throw() { return a_t; }
+
+private:
+ T* a_t;
+};
+
+
+}
+}
+
+
+
+#endif
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_AutoSet_hpp
+#define anna_dbos_AutoSet_hpp
+
+#include <anna/dbos/Set.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+
+/**
+ Facilita el uso de los punteros a objectos obtenidos a partir de los datos guardados en un medio fisico.
+
+ La idea de esta clase es que el constructor y el destructor de esta clase cooperan para reservar y/o
+ liberar correctamente la instancia de T asociada a esta instancia.
+
+ \param T Clase que vamos a gestionar.
+
+ En el siguiente ejemplo podemos ver la forma habitual de trabajar con un objeto persistente tiene
+ el incoveniente de que tenemos que tener en cuenta cada una de las situaciones en las que la
+ referencia obtenida mediante el metodo \em instantiate debe ser liberada.
+
+ \code
+ Server::Set <Server>* servers (NULL);
+ ServerLoader serverLoader; // ServerLoader hereda de anna::dbos::Loader.
+ Server* server;
+
+ try {
+ serverLoader.setKey (..........); // Establece los parametros de busqueda
+
+ servers = Server::instantiate (serverLoader);
+
+ if (servers->size () == 0) {
+ ....
+ .... Si fuera necesario trataria la condicion de no encontrar ningun registro
+ ....
+ }
+
+ Server::iterator ii, maxii;
+
+ for (ii = servers->begin (), maxii = servers->end (); ii != maxii; ii ++) {
+ server = *ii;
+
+ .... Trataria cada uno de los Server encontrados ....
+ }
+
+ Server::release (servers);
+ }
+ catch (Exception& ex) {
+ Server::release (servers);
+
+ ...
+ ... Si fuera necesario trataria la condificion de error.
+ }
+ \endcode
+
+ Como podemos ver a continuacion el siguiente metodo es mucho mas sencillo y aporta la gran ventaja de que
+ el sistema trabaja por nosotros para liberar correctamente los recursos.
+
+ \code
+ AutoSet <Server> servers;
+ ServerLoader serverLoader; // ServerLoader hereda de anna::dbos::Loader.
+ Server* server;
+
+ try {
+ serverLoader.setKey (..........); // Establece los parametros de busqueda
+
+ servers = Server::instantiate (serverLoader);
+
+ if (servers->size () == 0) {
+ ....
+ .... Si fuera necesario trataria la condicion de no encontrar ningun registro
+ ....
+ }
+
+ Server::iterator ii, maxii;
+
+ for (ii = servers->begin (), maxii = servers->end (); ii != maxii; ii ++) {
+ server = *ii;
+
+ .... Trataria cada uno de los Server encontrados ....
+ }
+ }
+ catch (Exception& ex) {
+ ...
+ ... Si fuera necesario trataria la condificion de error.
+ }
+ \endcode
+*/
+template <typename T> class AutoSet {
+public:
+ /**
+ Constructor.
+ \param t Instancia del objeto asociado a esta instancia.
+ \warning La instancia deberia haber sido obtenida mediate la invocacion a \em T::instantiate de la
+ clase persistente.
+ */
+ explicit AutoSet(Set <T>* t) : a_t(t) {;}
+
+ /**
+ Constructor.
+ */
+ AutoSet() : a_t(NULL) {;}
+
+ /**
+ Destructor. Invoca al metodo \em T::release
+ */
+ ~AutoSet() { if(a_t != NULL) T::release(a_t); }
+
+ /**
+ Operador ->
+ Permite invocar a metodos de la clase T.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ Set <T>* operator -> () const throw() { return a_t; }
+
+ /**
+ Operador copia.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ Set <T>* operator = (Set<T>* t)
+ throw() {
+ if(a_t == t)
+ return t;
+
+ if(a_t != NULL)
+ T::release(a_t);
+
+ return a_t = t;
+ }
+
+ /**
+ Operador de conversion.
+ \return La instancia de la clase T asociada a esta instancia.
+ */
+ operator Set <T>*() const throw() { return a_t; }
+
+private:
+ Set <T>* a_t;
+};
+
+
+}
+}
+
+
+
+#endif
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Creator_hpp
+#define anna_dbos_Creator_hpp
+
+#include <anna/dbos/Accesor.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+/**
+ Interfaz que deben cumplir los objetos encargados de crear un nuevo objeto que sera ubicado
+ en el area de almacenamiento asociado a un medio fisico.
+*/
+class Creator : public Accesor {
+public:
+ /**
+ Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos.
+ Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces
+ a la que pertenece la clase.
+ \return Una cadena con el nombre de este selector.
+ */
+ virtual const char* getClassName() const throw() { return "anna::dbos::Creator"; }
+
+protected:
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ */
+ Creator(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;}
+
+ /**
+ Constructor.
+ \param id Identificador de este accesor.
+ */
+ Creator(const Id id = 0) : Accesor(id) {;}
+
+ /**
+ Devuelve el indice usado para ubicar en memoria el objeto que vamos a cargar.
+ @return El indice usado para ubicar en memoria el objeto que vamos a cargar.
+ */
+ virtual Index getIndex() const throw(RuntimeException) = 0;
+
+private:
+ dbms::Statement* initialize(dbms::Database&) throw(RuntimeException) { return NULL;}
+
+ friend class StorageArea;
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_CrossedLoader_hpp
+#define anna_dbos_CrossedLoader_hpp
+
+#include <anna/dbos/Accesor.hpp>
+
+namespace anna {
+
+namespace dbms {
+class Database;
+}
+
+namespace dbos {
+
+class Loader;
+
+/**
+ * Interfaz que deben cumplir los cargadores cruzados. Un cargador cruzado facilita que una
+ * misma clase pueda ser cargada usando varios criterios de búsqueda.
+ *
+ * El criterio de búsqueda más usado y que debería ser más óptimo será desarrollado
+ * mediante la definición del anna::dbos::Loader específico. El resto de criterios de búsqueda,
+ * los cargadores cruzados, deberían ser capaces obtener los datos usados como clave en el criterio
+ * principal, para a partir de ahí poder aplicar el criterio de búsqueda principal.
+ *
+ * Cada cargador cruzado podría tener una lista de pares (clave_alternativa, clave_principal) que permitirá
+ * acelerar las búsquedas de la clave principal, en base a la clave alternativa usada en este cargador.
+ *
+ * Para obtener los datos de la clave principal en base a los datos de la clave alternativa habrá que
+ * acceder al medio físico.
+ *
+ * Para optimizar el acceso a los pares (Clave alternativa, Clave Principal) se podría usar una
+ * instancia del tipo anna::LRUMap.
+*/
+class CrossedLoader : public Accesor {
+public:
+ /**
+ Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos.
+ Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces
+ a la que pertenece la clase.
+ \return Una cadena con el nombre de este selector.
+ */
+ virtual const char* getClassName() const throw() { return "anna::dbos::CrossedLoader"; }
+
+protected:
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ */
+ CrossedLoader(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;}
+
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ \param emode Modo de actuar en caso de no encontrar el dato buscado.
+ */
+ CrossedLoader(dbms::Database& database, const Id id, const Exception::Mode::_v emode) : Accesor(database, id, emode) {;}
+
+ /**
+ Este método debe ser reescrito para que permita localizar la información del objeto, que posiblemente
+ esté ubicado en la lista de objetos de este cargador cruzado.
+
+ @return \em true si se ha localizado la información la clave primaria del objeto en su lista de pares
+ o \em false en otro caso.
+ */
+ virtual bool seek() const throw() { return false; }
+
+ /**
+ * Este método debe ser reescrito para que se pueda actualizar la lista de pares (clave_alternativa, clave_principal)
+ * que permitirá acelear las posteriores búsquedas.
+ *
+ * \param loader Instancia del cargador principal que habrá compuesto la clave principal con los suministrados por
+ * esta instancia.
+ */
+ virtual void download(Loader& loader) throw() {;}
+
+ friend class StorageArea;
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Eraser_hpp
+#define anna_dbos_Eraser_hpp
+
+#include <anna/dbos/Accesor.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+class Object;
+
+/**
+ Interfaz que deben cumplir los objetos encargados de borrar el objeto del medio fisico,
+ que normalmente sera alguna base de datos.
+*/
+class Eraser : public Accesor {
+public:
+ /**
+ Devuelve la instancia establecida por #setObject.
+ \return La instancia establecida por #setObject. Puede ser NULL.
+ */
+ Object* getObject() throw() { return a_object; }
+
+ /**
+ Establece la instancia del objeto sobre el que vamos a actuar.
+ \param object Instancia del objeto sobre el que vamos a actuar.
+ */
+ void setObject(Object* object) throw() { a_object = object; }
+
+ /**
+ Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos.
+ Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces
+ a la que pertenece la clase.
+ \return Una cadena con el nombre de este selector.
+ */
+ virtual const char* getClassName() const throw() { return "anna::dbos::Eraser"; }
+
+protected:
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ */
+ Eraser(dbms::Database& database, const Id id = 0) :
+ Accesor(database, id),
+ a_object(NULL)
+ {;}
+
+private:
+ Object* a_object;
+
+ Index getIndex() const throw() { return 0; } // No se usa
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Loader_hpp
+#define anna_dbos_Loader_hpp
+
+#include <anna/dbos/Accesor.hpp>
+
+namespace anna {
+
+namespace dbms {
+class Database;
+}
+
+namespace dbos {
+
+class CrossedLoader;
+
+/**
+ Interfaz que deben cumplir los objetos encargados de cargar el objeto desde el medio fisico,
+ que normalmente sera alguna base de datos, y pasarlo un ambito de objetos en C++.
+*/
+class Loader : public Accesor {
+public:
+ /**
+ Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos.
+ Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces
+ a la que pertenece la clase.
+ \return Una cadena con el nombre de este selector.
+ */
+ virtual const char* getClassName() const throw() { return "anna::dbos::Loader"; }
+
+protected:
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ */
+ Loader(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;}
+
+ /**
+ Constructor.
+ \param id Identificador de este accesor.
+ */
+ Loader(const Id id = 0) : Accesor(id) {;}
+
+ /**
+ Devuelve el indice usado para ubicar en memoria el objeto que vamos a cargar.
+ @return El indice usado para ubicar en memoria el objeto que vamos a cargar.
+ */
+ virtual Index getIndex() const throw(RuntimeException) = 0;
+
+ /**
+ * Este método debe ser reescrito para poder obtener los datos de la clave principal usada para localizar
+ * los objetos en un área del almacenamiento.
+ *
+ * \param crossedLoader Instancia del cargador alternativo que habrá calculado la clave principal en
+ * a lo clave alternativa contenida en él.
+ */
+ virtual void upload(CrossedLoader& crossedLoader) throw(RuntimeException) {;}
+
+ friend class StorageArea;
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Object_hpp
+#define anna_dbos_Object_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbos/Loader.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+class Creator;
+
+/**
+ Interfaz que deben cumplir los objetos persistentes.
+
+ Ejemplo de definicion de una clase usando esta interfaz:
+
+ \include dbos_demo.p/oodb.d/hdrs/dbos_demo.oodb.Table01.h
+
+ Ejemplo de implementacion de la clase correspondiente a la definicion:
+
+ \include dbos_demo.p/oodb.d/oodb.Table01.cc
+*/
+class Object {
+public:
+ /**
+ Devuelve el indice asociado a este objeto
+ \return el indice asociado a este objeto
+ */
+ Index getIndex() const throw() { return a_index; }
+
+ /**
+ * Devuelve \em true si este objeto ya existe en el medio físico (fué cargado desde allí o fue creado y grabado posteriormente) o
+ * \em false si este objeto sólo existe en la memoria intermedia.
+ * \return \em true si este objeto ya existe en el medio físico (fué cargado desde allí o fue creado y grabado posteriormente) o
+ * \em false si este objeto sólo existe en la memoria intermedia.
+ */
+ bool isStored() const throw() { return a_isStored; }
+
+protected:
+ /**
+ Constructor.
+ */
+ Object() : a_index(0), a_isStored(false) {;}
+
+ /**
+ Inicializa este objeto con la informacion obtenida desde el medio fisico donde
+ esta grabado el objeto. Normalmente este medio fisico correspondera con una base de datos.
+
+ \param loader Cargador que contiene la informacion con la que debemos inicializar este objeto.
+
+ */
+ virtual void initialize(Loader& loader) throw(RuntimeException, dbms::DatabaseException) = 0;
+
+ /**
+ Actualiza la informacion de este objeto con la nueva informacion obtenida del medio
+ fisico.
+ \param creator Creador que contiene la informacion con la que debemos inicializar este objeto.
+ */
+ virtual void create(Creator& creator) throw(RuntimeException, dbms::DatabaseException) {;}
+
+ /**
+ Libera los recursos reservados por este objeto. Este metodo solo se invocara cuando el objeto
+ vaya a ser sacado definitivamente del area de almacenamiento.
+ */
+ virtual void destroy() throw() {;}
+
+ /**
+ Devuelve \em true si el registro del medio fisico ha cambiado respecto al registro
+ cargado en memoria o \em false en otro caso.
+
+ \param loader Cargador que contiene la informacion con la que deberiamos re-inicializar
+ este objeto.
+
+ \return \em true si el registro del medio fisico ha cambiado respecto al registro
+ cargado en memoria o \em false en otro caso.
+ */
+ virtual bool hasChanges(Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
+ return true;
+ }
+
+ /**
+ Devuelve \em true si el objeto requiere comenzar el proceso de comprobacion de recarga
+ de datos \em false en otro caso.
+ */
+ virtual bool enableUpdate() const throw() { return true; }
+
+private:
+ Index a_index;
+ bool a_isStored;
+
+ void setIndex(const Index index) throw() { a_index = index; }
+
+ friend class StorageArea;
+};
+
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_ObjectAllocator_hpp
+#define anna_dbos_ObjectAllocator_hpp
+
+namespace anna {
+
+namespace dbos {
+
+class Object;
+
+typedef Object*(*ObjectAllocator)();
+
+}
+
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_ObjectFacade_hpp
+#define anna_dbos_ObjectFacade_hpp
+
+#include <anna/core/RuntimeException.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbos/StorageArea.hpp>
+#include <anna/dbos/Creator.hpp>
+#include <anna/dbos/Loader.hpp>
+#include <anna/dbos/Recorder.hpp>
+#include <anna/dbos/Eraser.hpp>
+
+namespace anna {
+
+namespace dbms {
+class Connection;
+}
+
+namespace dbos {
+
+class Object;
+
+/**
+ Clase que facilita el acceso y uso de las clases encargadas de la instanciacion de objetos a partir de los datos
+ contenidos en un medio fisico, que normalmente seria la tabla de una base de datos.
+
+ \param T clase debe ser heredada de anna::dbos::Object.
+
+ Ejemplo de definicion de una clase usando esta interfaz:
+
+ \include dbos_demo.p/oodb.d/hdrs/dbos_demo.oodb.Table01.h
+
+ Ejemplo de implementacion de la clase correspondiente a la definicion:
+
+ \include dbos_demo.p/oodb.d/oodb.Table01.cc
+
+ \see dbos_declare_object
+ \see dbos_prepare_object
+*/
+template <typename T> class ObjectFacade {
+public:
+ /**
+ Devuelve un numerico que puede ser usado en la definicion del area de almacenamiento.
+
+ \return Un numerico que puede ser usado en la definicion del area de almacenamiento.
+ \see Database::createStorageArea
+ */
+ static StorageId getStorageAreaId() throw() { return (StorageId) anna_ptrnumber_cast(&st_storageArea); }
+
+ /**
+ Devuelve el area de almacenamiento asociado a esta clase.
+ \return Devuelve el area de almacenamiento asociado a esta clase.
+ */
+ static StorageArea* getStorageArea() throw() { return st_storageArea; }
+
+ /**
+ Establece el area de almacenamiento asociado a esta clase, que deberiaser creado mediante la invocacin al metodo
+ Database::createStorageArea.
+
+ \param storageArea area de almacenamiento asociada esta clase.
+
+ \warning El area de almacenamiento debe establecerse antes de invocar a cualquier otro metodo de esta clase.
+ */
+ static void setStorageArea(StorageArea* storageArea) throw() {
+ (st_storageArea = storageArea)->setSizeof(sizeof(T));
+ }
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar el area de almacenamiento asociado a esta clase se halla indicado un \em errorCode
+ igual a -1 en otro caso si no encuentra el objeto que cumpla el patron devolveria una
+ excepcion.
+
+ \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ static T* instance(dbms::Connection& connection, Loader& loader)
+ throw(RuntimeException, dbms::DatabaseException) {
+ if(st_storageArea == NULL) {
+ std::string msg(loader.asString());
+ msg += " | ObjectFacade uninitialized ";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return static_cast <T*>(st_storageArea->instance(connection, loader));
+ }
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar.
+
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar el area de almacenamiento asociado a esta clase se halla indicado un \em errorCode
+ igual a -1 en otro caso si no encuentra el objeto que cumpla el patron devolveria una
+ excepcion.
+
+ \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ static T* instance(Loader& loader)
+ throw(RuntimeException, dbms::DatabaseException) {
+ if(st_storageArea == NULL) {
+ std::string msg(loader.asString());
+ msg += " | ObjectFacade uninitialized ";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return static_cast <T*>(st_storageArea->instance(loader));
+ }
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
+ recibido como parámetro en base a una clave alternativa contenida en el mismo.
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
+ caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ static T* instance(dbms::Connection& connection, CrossedLoader& crossedLoader, Loader& loader)
+ throw(RuntimeException, dbms::DatabaseException) {
+ if(st_storageArea == NULL) {
+ std::string msg(loader.asString());
+ msg += " | ObjectFacade uninitialized ";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return static_cast <T*>(st_storageArea->instance(connection, crossedLoader, loader));
+ }
+
+ /**
+ Crea un objeto en el area de almacenamiento un y lo prepara para ser transferido al medio fisico
+ si fuera necesario.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario acceder al medio fisico.
+ \param creator Creador encargado de generar el objeto de forma que sea facil de localizar posteriormente
+ en el area de almacenamiento.
+
+ \return La nueva instancia que cumple el patron establecido por el creador.
+
+ \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ static T* create(dbms::Connection& connection, Creator& creator)
+ throw(RuntimeException, dbms::DatabaseException) {
+ if(st_storageArea == NULL) {
+ std::string msg(creator.asString());
+ msg += " | ObjectFacade uninitialized ";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return static_cast <T*>(st_storageArea->create(connection, creator));
+ }
+
+ /**
+ Devuelve la informacion de un objeto cargado desde el medio fisico.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el
+ objeto no fue cargado en el area de almacenamiento.
+
+ \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ static T* find(Loader& loader)
+ throw(RuntimeException) {
+ if(st_storageArea == NULL) {
+ std::string msg(loader.asString());
+ msg += " | ObjectFacade uninitialized ";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return static_cast <T*>(st_storageArea->find(loader));
+ }
+
+ /**
+ Habilita la reutilizacion del espacio de memoria ocupado por un objeto alojado en el area de almacenamiento.
+
+ Este metodo no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria
+ como subceptible de ser reutilizado. De esta forma, si el numero de objetos cargados en memoria se
+ acerca al tamao maximo indicado en la inicializacion, se intentara reusar espacios libres en vez
+ de continuar ampliando la memoria reservada.
+
+ \param t Instancia del tipo T que vamos a liberar.
+
+ \warning Si el objeto recibido como parametro no fue reservado mediate alguno de los metodos de reserva de
+ objetos ofrecidos por esta clase no tendra ningun efecto.
+ */
+ static void release(T*& t)
+ throw() {
+ if(st_storageArea == NULL)
+ return;
+
+ try {
+ st_storageArea->release(reinterpret_cast <Object**>(&t));
+ } catch(RuntimeException& ex) {
+ ex.trace();
+ }
+ }
+
+ /**
+ Descarga todos los objetos contenidos en el area de almacenamiento.
+ */
+ static void clear()
+ throw(RuntimeException) {
+ if(st_storageArea == NULL)
+ throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION);
+
+ st_storageArea->clear();
+ }
+
+ /**
+ Devuelve de una copia del objeto recibido como parametro e incrementa la cuenta de utilizacion
+ asociada a la instancia.
+
+ \param t Instancia del tipo T obtenida mediate el metodo #instance.
+
+ \return Una copia del objeto recibido como parametro. Si el parametro recibido es NULL devolveria NULL.
+
+ \warning Cada llamada a este metodo deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ static T* duplicate(const T* t)
+ throw(RuntimeException) {
+ if(st_storageArea == NULL)
+ throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION);
+
+ return static_cast <T*>(st_storageArea->duplicate(t));
+ }
+
+ /**
+ Permite conocer si un determinado objeto esta alojado en el area de almacenamiento.
+
+ \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
+
+ \return \em true Si el objeto identificado por el Loader esta en el area de almacenamiento o
+ \em false en otro caso.
+ */
+ static bool isLoaded(const Loader& loader)
+ throw(RuntimeException) {
+ if(st_storageArea == NULL)
+ throw RuntimeException("ObjectFacade uninitialized ", ANNA_FILE_LOCATION);
+
+ return st_storageArea->isLoaded(loader);
+ }
+
+ /**
+ Transfiere la informacion del objeto recibido como parametro al medio fisico usando el Recorder
+ recibido como parametro.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param recorder Grabador usado para transferir los datos al medio fisico.
+ */
+ static void apply(dbms::Connection& connection, Recorder& recorder)
+ throw(RuntimeException, dbms::DatabaseException) {
+ if(st_storageArea == NULL) {
+ std::string msg(recorder.asString());
+ msg += " | ObjectFacade uninitialized";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ st_storageArea->apply(connection, recorder);
+ }
+
+ /**
+ Elimina la informacion del objeto recibido como parametro del medio fisico usando el Eraser
+ recibido como parametro.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param eraser Objecto usado para eliminar los datos al medio fisico.
+
+ \warning Si la cuanta de utilizacion de T es 1 se liberaria en otro caso se devolveria una excepcion.
+ */
+ static void apply(dbms::Connection& connection, Eraser& eraser)
+ throw(RuntimeException, dbms::DatabaseException) {
+ if(st_storageArea == NULL) {
+ std::string msg(eraser.asString());
+ msg += " | ObjectFacade uninitialized";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ st_storageArea->apply(connection, eraser);
+ }
+
+ /**
+ Elimina toda la informacion referente al objeto recibido como parametro, siempre y cuando
+ solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento,
+
+ \param t Instancia del tipo T que vamos a descargar de la memoria de almacenamiento.
+
+ \warning \li Si el objeto recibido como parametro no fue reservado mediate #instance no tiene
+ ningun efecto. \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion.
+ \li La memoria asignada a la instancia recibida es liberada, por lo que podemos evitar la invocacion
+ al metodo #release para esta instancia.
+ */
+ static void erase(T*& t)
+ throw(RuntimeException) {
+ if(st_storageArea == NULL)
+ return;
+
+ st_storageArea->erase(reinterpret_cast <Object**>(&t));
+ }
+
+ /**
+ Devuelve el puntero sobre el que estaria posicionado el iterador recibido como parametro.
+ \return El puntero sobre el que estaria posicionado el iterador recibido como parametro.
+ */
+ static T* data(StorageArea::iterator& ii) throw() { return static_cast <T*>(StorageArea::data(ii)); }
+
+ /**
+ Devuelve el puntero sobre el que estaria posicionado el iterador recibido como parametro.
+ \return El puntero sobre el que estaria posicionado el iterador recibido como parametro.
+ */
+ static const T* data(StorageArea::const_iterator& ii) throw() { return static_cast <const T*>(StorageArea::data(ii)); }
+
+ /**
+ Metodo creador de nuevas instancias de la clase T.
+ \return Una nueva instancia del tipo de objeto T.
+ \warning Solo deberia ser llamado desde anna::comm::StorageArea cuando sea preciso crear
+ nuevas instancias de objetos.
+ */
+ static Object* allocator() throw() { return new T; }
+
+protected:
+ static StorageArea* st_storageArea;
+
+ /**
+ Constructor.
+ */
+ ObjectFacade() {}
+};
+
+}
+}
+
+/**
+ Definicion a la que hay que invocar en la implementacion de la clase que hereda
+ de anna::dbos::ObjectFacade.
+
+ \param T Nombre de la clase que vamos a tratar en el ambito de C++.
+*/
+#define dbos_prepare_object(T) \
+ template <> anna::dbos::StorageArea* anna::dbos::ObjectFacade< T >::st_storageArea = NULL
+
+/**
+ Definicion a la que hay que invocar dentro de la definicion de la clase que hereda
+ de anna::dbos::ObjectFacade.
+
+ \param T Nombre de la clase que vamos a tratar en el ambito de C++.
+*/
+#define dbos_declare_object(T) \
+ friend class anna::dbos::ObjectFacade <T>
+
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Recorder_hpp
+#define anna_dbos_Recorder_hpp
+
+#include <anna/dbos/Accesor.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+/**
+ Interfaz que deben cumplir los objetos encargados de grabar el objeto en el medio fisico,
+ que normalmente sera alguna base de datos.
+*/
+class Recorder : public Accesor {
+public:
+ /**
+ Metodo de debemos re-escribir para devolver el nombre completo del selector de recursos.
+ Para evitar ambigüedades este nombre deberia incluir la lista completa de \em namespaces
+ a la que pertenece la clase.
+ \return Una cadena con el nombre de este selector.
+ */
+ virtual const char* getClassName() const throw() { return "anna::dbos::Recorder"; }
+
+protected:
+ /**
+ Constructor.
+ \param database Base de datos asociada a este cargador y que deberia servir para
+ obtener los datos de un objeto. Debe tener la misma disponibilidad que este cargador.
+ \param id Identificador de este accesor.
+ */
+ Recorder(dbms::Database& database, const Id id = 0) : Accesor(database, id) {;}
+
+private:
+ Index getIndex() const throw() { return 0; } // No se usa
+};
+
+}
+}
+
+#endif
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Repository_hpp
+#define anna_dbos_Repository_hpp
+
+#include <vector>
+
+#include <anna/core/mt/Mutex.hpp>
+
+#include <anna/dbos/StorageArea.hpp>
+#include <anna/dbos/defines.hpp>
+
+namespace anna {
+
+namespace xml {
+class Node;
+}
+
+namespace comm {
+class INetAddress;
+class Delivery;
+}
+
+namespace dbms {
+class Connection;
+}
+
+namespace dbos {
+
+/**
+ Clase que modela la interaccion entre la base y nuestra aplicacion.
+*/
+class Repository : public Mutex {
+public:
+ typedef std::map <StorageId, StorageArea*> container;
+ typedef container::const_iterator const_storage_iterator; /**<Iterador para acceder a las areas de almacenamiento de esta base de datos */
+ typedef container::iterator storage_iterator; /**<Iterador para acceder a las areas de almacenamiento de esta base de datos */
+
+ /**
+ Constructor.
+ \param name Nombre logico del repositorio de areas de almacenamiento.
+ */
+ explicit Repository(const char* name);
+
+ /**
+ Constructor.
+ \param name Nombre logico del repositorio de areas de almacenamiento.
+ */
+ explicit Repository(const std::string& name);
+
+ /**
+ Crea una nueva area de almacenamiento para objetos cargados a partir de un medio fisico, normalmente
+ la base de datos.
+
+ El tipo de dato de esta nueva area vendria definida implicitamente por el tipo de factoria empleadas
+ para instanciar y/o liberar los objetos y sus respectivos registros.
+
+ \param index Clave que seria usada para localizar el area de almacenamiento.
+ \param name Nombre logico de la nueva area de almacenamiento.
+ \param maxSize Limita el numero maximo de objetos que pueden estar cargados simultanemante en memoria.
+ Si se alcanza este limite pero no hay ningun objeto susceptible de ser sacado de la memoria de almacenamiento
+ se ampliaria automaticamente la reserva de memoria necesaria para cargar nuevos objetos, en tanto en cuanto
+ no se libere alguno de los objetos cargados. Ver StorageArea::StandardSize.
+ \param objectAllocator actoria de objetos usada para crear las nuevas instancias en este area de
+ almacenamiento.
+ \param errorCode Cdigo de error asociado a la excepcin lanzada por el metodo StorageArea::instantiate
+ en caso de que no se encuentre el objeto buscado. Si vale StorageArea::NoExceptionWhenNotFound en
+ caso de no encontrar el objeto no se devolveriaexcepcin y el valor retornado seria NULL.
+ \param aamm Modo de acceso de este area de almacenamiento.
+
+ \warning Las dos actorias deben estar disponibles desde el momento de invocar a este metodo hasta la
+ finalizacin de esta instancia de base de datos.
+ */
+ StorageArea* createStorageArea(const StorageId index, const char* name, const Size maxSize, ObjectAllocator objectAllocator, const int errorCode, const StorageArea::AccessMode::_v aamm = StorageArea::AccessMode::ReadOnly)
+ throw(RuntimeException);
+
+ /**
+ Devuelve la instancia del area de almacenamiento asociada al indice recibido.
+
+ \param index Indice del area de almacenamiento.
+
+ \return La instancia del area de almacenamiento asociada al indice recibido. Puede ser NULL si el
+ indice no fue usado para crear un area mediate #createStorageArea.
+ */
+ StorageArea* findStorageArea(const StorageId index) throw();
+
+ /**
+ Elimina todos los objetos cargados en las areas de almacenamiento definidas.
+ */
+ void clear() throw(RuntimeException);
+
+ /**
+ Devuelve un iterator al comienzo de la lista de areas de almacenamiento de esta base de datos.
+ \return Un iterator al comienzo de la lista de areas de almacenamiento de esta base de datos.
+ */
+ const_storage_iterator storage_begin() const throw() { return a_storageAreas.begin(); }
+
+ /**
+ Devuelve un iterator al final de la lista de areas de almacenamiento de esta base de datos.
+ \return Un iterator al final de la lista de areas de almacenamiento de esta base de datos.
+ */
+ const_storage_iterator storage_end() const throw() { return a_storageAreas.end(); }
+
+ /**
+ Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
+ \param ii Iterator que deberia estar comprendido entre #const_storage_begin y #const_storage_end.
+ \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
+ */
+ static const StorageArea* storageArea(const_storage_iterator& ii) throw() { return ii->second; }
+
+ /**
+ Devuelve un documento XML con la informacion referente a esta instancia.
+ \param parent Nodo XML del que dependende la informacion.
+ @return un documento XML con la informacion referente a esta instancia.
+ */
+ xml::Node* asXML(xml::Node* parent) const throw();
+
+protected:
+ /**
+ Devuelve un iterator al comienzo de la lista de areas de almacenamiento de esta base de datos.
+ \return Un iterator al comienzo de la lista de areas de almacenamiento de esta base de datos.
+ */
+ storage_iterator storage_begin() throw() { return a_storageAreas.begin(); }
+
+ /**
+ Devuelve un iterator al final de la lista de areas de almacenamiento de esta base de datos.
+ \return Un iterator al final de la lista de areas de almacenamiento de esta base de datos.
+ */
+ storage_iterator storage_end() throw() { return a_storageAreas.end(); }
+
+ /**
+ Devuelve el objeto sobre el que esta posicionado el iterator recibido como parametro.
+ \param ii Iterator que deberia estar comprendido entre #const_storage_begin y #const_storage_end.
+ \return El objeto sobre el que esta posicionado el iterator recibido como parametro.
+ */
+ static StorageArea* storageArea(storage_iterator& ii) throw() { return ii->second; }
+
+private:
+ std::string a_name;
+ container a_storageAreas;
+
+ Repository(const Repository&);
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_Set_hpp
+#define anna_dbos_Set_hpp
+
+#include <anna/core/mt/SafeRecycler.hpp>
+#include <anna/core/mt/Guard.hpp>
+#include <anna/core/Allocator.hpp>
+
+#include <anna/dbms/Statement.hpp>
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbos/Object.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+/**
+ Template para acceder a los elementos de un conjunto de objetos inicializados a partir
+ de los datos contenidos en un medio fisico.
+
+ A continuacion presentamos un ejemplo de uso:
+
+ \code
+ Server::Set <Server>* servers (NULL); // Server hereda de esta clase.
+ ServerLoader serverLoader; // ServerLoader hereda de dbos::Loader.
+ Server* server;
+
+ try {
+ serverLoader.setKey (..........); // Establece los parametros de busqueda
+
+ servers = Server::instantiate (serverLoader);
+
+ if (servers->size () == 0) {
+ ....
+ .... Si fuera necesario Trataria la condicion de no encontrar ningun registro
+ ....
+ }
+
+ Server::iterator ii, maxii;
+
+ for (ii = servers->begin (), maxii = servers->end (); ii != maxii; ii ++) {
+ server = *ii;
+
+ .... Trataria cada uno de los Server encontrados ....
+ }
+
+ Server::release (servers);
+ }
+ catch (Exception& ex) {
+ Server::release (servers);
+
+ ...
+ ... Si fuera necesario Trataria la condicion de error.
+ }
+ \endcode
+ */
+template <typename T> class Set : public Object {
+public:
+ /**
+ Sinonimo usado para definir la clase contenedora de objetos del conjunto.
+ */
+ typedef typename anna::SafeRecycler <T, anna::Allocator<T> > Container;
+
+ /**
+ Sinonimo usado para acceder a los elementos del conjunto atraves de un iterador
+ de objetos no modificables.
+ */
+ typedef typename Container::const_iterator const_iterator;
+
+ /**
+ Sinonimo usado para acceder a los elementos del conjunto atraves de un iterador
+ de objetos modificables.
+ */
+ typedef typename Container::iterator iterator;
+
+ /**
+ Devuelve el inicio del vector de objetos contenidos en el conjunto.
+ \return El inicio del vector de objetos contenidos en el conjunto.
+ */
+ const_iterator begin() const throw() { return a_objects.begin(); }
+
+ /**
+ Devuelve el inicio del vector de objetos contenidos en el conjunto.
+ \return El inicio del vector de objetos contenidos en el conjunto.
+ */
+ iterator begin() throw() { return a_objects.begin(); }
+
+ /**
+ Devuelve el final del vector de objetos contenidos en el conjunto.
+ \return El final del vector de objetos contenidos en el conjunto.
+ */
+ const_iterator end() const throw() { return a_objects.end(); }
+
+ /**
+ Devuelve el final del vector de objetos contenidos en el conjunto.
+ \return El final del vector de objetos contenidos en el conjunto.
+ */
+ iterator end() throw() { return a_objects.end(); }
+
+ /**
+ Crea un nuevo puntero de la clase T dentro de este conjunto.
+ */
+ T* append() throw(RuntimeException) { return a_objects.create(); }
+
+ /**
+ Saca de este conjunto la instancia recibida como parametro y libera su memoria asociada.
+ La operacion se ignoraria si el puntero recibido como parametro es nulo o no pertenece al conjunto.
+ \param t Instancia que del objeto a eliminar.
+ */
+ void remove(T*& t) throw(RuntimeException) { a_objects.release(t); t = NULL; }
+
+ /**
+ Devuelve el nmero de elementos contenidos en el conjunto.
+ \return El nmero de elementos contenidos en el conjunto.
+ */
+ int size() const throw() { return a_objects.size(); }
+
+ /**
+ Devuelve el puntero sobre el que esta posicionado el iterador recibido como parametro.
+ \return El puntero sobre el que esta posicionado el iterador recibido como parametro.
+ */
+ static T* data(iterator& ii) throw() { return Container::data(ii); }
+
+ /**
+ Devuelve el puntero sobre el que esta posicionado el iterador recibido como parametro.
+ \return El puntero sobre el que esta posicionado el iterador recibido como parametro.
+ */
+ static const T* data(const_iterator& ii) throw() { return Container::data(ii); }
+
+private:
+ Container a_objects;
+
+ void initialize(Loader& loader)
+ throw(RuntimeException, dbms::DatabaseException) {
+ T* object;
+ dbms::Statement* statement = loader.getStatement();
+
+ try {
+ do {
+ a_objects.create()->initialize(loader);
+ } while(statement->fetch() == true);
+ } catch(RuntimeException&) {
+ destroy();
+ throw;
+ } catch(dbms::DatabaseException&) {
+ destroy();
+ throw;
+ }
+ }
+
+ void destroy()
+ throw() {
+ for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++)
+ data(ii)->destroy();
+
+ a_objects.clear();
+ }
+};
+
+}
+}
+
+#endif
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_SetFacade_hpp
+#define anna_dbos_SetFacade_hpp
+
+#include <vector>
+
+#include <anna/dbos/Set.hpp>
+#include <anna/dbos/ObjectFacade.hpp>
+
+namespace anna {
+
+namespace dbos {
+
+/**
+ Clase que facilita el acceso y uso de las clases encargadas de la instanciacion de multiples objetos a partir de los
+ datos contenidos en un medio fisico, que normalmente seria la tabla de una base de datos.
+
+ Esta nos facilita el manejo de instancias multiples, es decir, para una condicion de carga dada hay varios registros
+ o elementos del medio fisico que la cumplen.
+
+ La clase \em T debe tener definidos los siquientes metodos:
+ \li anna::dbos::Object::instantiate: Interpreta la informacin la del medio fisico para adecuarla a
+ la clase C++.
+ \li void destroy () throw (): Libera los recursos reservados por este objeto
+
+ \see dbos_declare_set
+ \see dbos_prepare_set
+*/
+template <typename T> class SetFacade : public ObjectFacade < Set <T> > {
+public:
+ typedef typename Set<T>::iterator iterator;
+ typedef typename Set<T>::const_iterator const_iterator;
+
+ /**
+ Devuelve el numero de elementos contenidos en el conjunto recibido como parametro.
+ Se puede usar sin tener que preocuparse por
+ el valor de la instancia del conjunto, ya que si este es NULL devolveria 0.
+ \param t Instancia del conjunto.
+ \return El numero de elementos que contiene el conjunto.
+ */
+ static int size(Set<T>* t) throw() { return (t == NULL) ? 0 : t->size(); }
+
+ /**
+ Iterator al primer elemento del conjunto. Se puede usar sin tener que preocuparse por
+ el valor de la instancia del conjunto, ya que si este es NULL devolveria 0.
+ \return Un iterador del primer elemento del conjunto.
+ */
+ static iterator begin(Set<T>* t) throw() {
+ return (t == NULL) ? iterator(0) : t->begin();
+ }
+
+ /**
+ Iterator al ultimo elemento del conjunto. Se puede usar sin tener que preocuparse por
+ el valor de la instancia del conjunto, ya que si este es NULL devolveria 0.
+ \return Un iterador del primer elemento del conjunto.
+ */
+ static iterator end(Set<T>* t) throw() {
+ return (t == NULL) ? iterator(0) : t->end();
+ }
+
+ /**
+ Iterator al primer elemento del conjunto. Se puede usar sin tener que preocuparse por
+ el valor de la instancia del conjunto, ya que si este es NULL devolveria 0.
+ \return Un iterador del primer elemento del conjunto.
+ */
+ static const_iterator begin(const Set<T>* t) throw() {
+ return (t == NULL) ? const_iterator(0) : t->begin();
+ }
+
+ /**
+ Iterator al ultimo elemento del conjunto. Se puede usar sin tener que preocuparse por
+ el valor de la instancia del conjunto, ya que si este es NULL devolveria 0.
+ \return Un iterador del primer elemento del conjunto.
+ */
+ static const_iterator end(const Set<T>* t) throw() {
+ return (t == NULL) ? const_iterator(0) : t->end();
+ }
+ /**
+ Devuelve el objeto referenciado por el iterator recibido como parametro.
+ \return El objeto referenciado por el iterator recibido como parametro.
+ */
+ static T* data(iterator ii) throw() { return Set<T>::data(ii); }
+
+ /**
+ Devuelve el objeto referenciado por el iterator recibido como parametro.
+ \return El objeto referenciado por el iterator recibido como parametro.
+ */
+ static const T* data(const_iterator ii) throw() { return Set<T>::data(ii); }
+
+protected:
+ /**
+ Contructor.
+ */
+ SetFacade() {}
+};
+
+/**
+ Definicion a la que hay que invocar en la implementacion de la clase que hereda
+ de anna::dbos::SetFacade.
+
+ \param T Nombre de la clase que vamos a tratar en el ambito de C++.
+*/
+#define dbos_prepare_set(T) \
+ template <> anna::dbos::StorageArea* anna::dbos::ObjectFacade < anna::dbos::Set <T> >::st_storageArea = NULL
+
+/**
+ Definicion a la que hay que invocar dentro de la definicion de la clase que hereda
+ de anna::dbos::SetFacade.
+
+ \param T Nombre de la clase que vamos a tratar en el ambito de C++.
+*/
+#define dbos_declare_set(T) \
+ friend class anna::Allocator<T>; \
+ friend class anna::dbos::Set <T>
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_StorageArea_hpp
+#define anna_dbos_StorageArea_hpp
+
+#include <vector>
+#include <map>
+#include <list>
+#include <deque>
+
+#include <algorithm>
+
+#include <anna/core/mt/Mutex.hpp>
+#include <anna/config/defines.hpp>
+#include <anna/core/util/SortedVector.hpp>
+
+#include <anna/dbms/DatabaseException.hpp>
+
+#include <anna/dbos/defines.hpp>
+#include <anna/dbos/ObjectAllocator.hpp>
+
+namespace anna {
+
+namespace xml {
+class Node;
+}
+
+namespace dbms {
+class Connection;
+}
+
+namespace dbos {
+
+class Accesor;
+class Object;
+class Creator;
+class Loader;
+class Recorder;
+class Eraser;
+class Repository;
+class CrossedLoader;
+
+/**
+ Area de almacenamiento de los objetos obtenidos a partir de los datos guardados en un medio
+ fisico, que normalmente seria una base de datos.
+
+ La creacion de cualquier área de almacenamiento debe hacerse mediante el método
+ anna::dbos::Repository::createStorageArea.
+
+ \warning Exclusivamente para uso interno de anna.dbos
+*/
+class StorageArea : public Mutex {
+ struct Instance;
+ class Block;
+ class Holes;
+
+public:
+ /**
+ Modo de acceso al área de almacenamiento.
+ */
+ struct AccessMode {
+ enum _v {
+ /**
+ Carga el objeto una vez y no lo vuelve a comprobar mientras tena un estado valido.
+ No permite la creacion de nuevos objetos.
+ */
+ ReadOnly,
+ /**
+ Carga el objeto una vez e intenta recargarlo cada vez que su cuenta de utilizacion
+ sea cero. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de
+ realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la
+ informacion mediante el dbos::Loader correspondiente y se invocaria al
+ método dbos::Object::hasChange (dbos::Loader&).
+ */
+ ReadWrite,
+ /**
+ Comprueba la recarga del objeto cada vez que se accede a el. Se invocara al método dbos::Object::needUpdate () que se ejecuta antes de
+ realizar ninguna operacion sobre el medio fisico, si devuelve 'true' cargaria la
+ informacion mediante el dbos::Loader correspondiente y se invocaria al
+ método dbos::Object::hasChange (dbos::Loader&).
+ */
+ ReadEver
+ };
+
+ /*
+ Devuelve el literal correspondiente al codigo recibido.
+ \param v Codigo a traducir a literal.
+ \return el literal correspondiente al codigo recibido.
+ */
+ static const char* asString(const _v v) throw();
+ };
+
+ /**
+ Flags usados para marcar los registros cargados en memoria.
+ \warning Exclusivamente uso interno.
+ */
+ struct Flag {
+ enum _v {
+ None = 0, Dirty = 1, Incoherent = 2, Empty = 4, HasHole = 8, Ready = 16, InProgress = 32,
+ NoDirty = ~Dirty, NoIncoherent = ~Incoherent, NoEmpty = ~Empty, NoHasHole = ~HasHole, NoReady = ~Ready, Done = ~InProgress
+ };
+ };
+
+ /**
+ Tamaños normalizados del área de almacenamiento.
+
+ @see StorageArea
+ */
+ struct StandardSize {
+ enum Value {
+ Tiny = 16, /**< Intenta que el número de registros cargados no supere los 16 registros. */
+ Little = 64, /**< Intenta que el número de registros cargados no supere los 64 registros. */
+ Small = 256, /**<Intenta que el número de registros cargados no supere los 256 registros.*/
+ Medium = 2048, /**<Intenta que el número de registros cargados no supere los 2048 registros.*/
+ Large = 8192, /**<Intenta que el número de registros cargados no supere los 8192 registros.*/
+ Huge = 32768, /**<Intenta que el número de registros cargados no supere los 32768 registros.*/
+ LargeHuge = 65536, /**<Intenta que el número de registros cargados no supere los 65536 registros.*/
+ Biggest = 131072 /**<Intenta que el número de registros cargados no supere los 131072 registros.*/
+ };
+ };
+
+ /**
+ Valor que hay que indicar al crear el área de almacenamiento (ver anna::dbos::Repository::createStorageArea)
+ para que el método #instance no devuelva excepcion de ejecucion en caso de no encontrar el
+ registro buscado.
+ */
+ static const int NoExceptionWhenNotFound = -1;
+
+ typedef std::vector <Block*> Blocks; /**< Estructura para mantener los bloques de objetos */
+ typedef std::map <Index, Instance*>::iterator iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */
+ typedef std::map <Index, Instance*>::const_iterator const_iterator; /**< Definicion para recorrer los objetos del área de almacenamiento */
+
+ /**
+ Destructor.
+ */
+ virtual ~StorageArea();
+
+ /**
+ * Devuelve el código de error asociado a la excepción cuando no se encuentra un registro buscado.
+ * \return el código de error asociado a la excepción cuando no se encuentra un registro buscado.
+ */
+ int getErrorCode() const throw() { return a_errorCode; }
+
+ /*
+ * Devuelve el nombre de la este área de almacenamiento.
+ * \return el nombre de la este área de almacenamiento.
+ */
+ const std::string& getName() const throw() { return a_name; }
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
+ caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ Object* instance(dbms::Connection& connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
+ return instance(&connection, loader);
+ }
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
+ caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ Object* instance(dbms::Connection* connection, Loader& loader) throw(RuntimeException, dbms::DatabaseException);
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
+ recibido como parámetro en base a una clave alternativa contenida en el mismo.
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
+ caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ Object* instance(dbms::Connection& connection, CrossedLoader& crossedLoader, Loader& loader)
+ throw(RuntimeException, dbms::DatabaseException) {
+ return instance(&connection, crossedLoader, loader);
+ }
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario extraer los datos del medio fisico.
+ \param crossedLoader Cargador encargado de encontrar la clave principal a aplicar con el #Loader
+ recibido como parámetro en base a una clave alternativa contenida en el mismo.
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
+ caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ Object* instance(dbms::Connection* connection, CrossedLoader& crossedLoader, Loader& loader)
+ throw(RuntimeException, dbms::DatabaseException);
+
+ /**
+ Carga la informacion de un objeto contenida en un medio fisico y la interpreta para adecuarla a
+ una clase C++.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar.
+
+ \param loader Cargador de clase encargado de localizar y obtener la informacion referente al objeto
+ que deseamos cargar en memoria.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL en caso de
+ que al inicializar esta clase \em errorCode se halla indicado un #NoExceptionWhenNotFound en otro
+ caso si no encuentra el objeto que cumpla el patron devolveria una excepcion de ejecucion.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ \warning Para usar este método se requiere haber re-escrito el método virtual Loader::load para que no intente
+ obtener los datos desde la base de datos.
+ */
+ Object* instance(Loader& loader) throw(RuntimeException, dbms::DatabaseException) {
+ return instance(NULL, loader);
+ }
+
+ /**
+ Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico
+ si fuera necesario.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario acceder al medio fisico.
+ \param creator Creador encargado de generar el objeto en el área de almacenamiento.
+
+ \return La nueva instancia que cumple el patron establecido por el creador.
+
+ \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
+ */
+ Object* create(dbms::Connection& connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException) {
+ return create(&connection, creator);
+ }
+
+ /**
+ Crea un objeto en el área de almacenamiento un y lo prepara para ser transferido al medio fisico
+ si fuera necesario.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param connection Conexion usada si fuera necesario acceder al medio fisico.
+ \param creator Creador encargado de generar el objeto en el área de almacenamiento.
+
+ \return La nueva instancia que cumple el patron establecido por el creador.
+
+ \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
+ */
+ Object* create(dbms::Connection* connection, Creator& creator) throw(RuntimeException, dbms::DatabaseException);
+
+ /**
+ Crea un objeto en el área de almacenamiento y lo prepara para ser transferido al medio fisico
+ si fuera necesario.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe cargar.
+
+ \param creator Creador encargado de generar el objeto en el área de almacenamiento.
+
+ \return La nueva instancia que cumple el patron establecido por el creador.
+
+ \warning \li Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ \li No puede usarse en las áreas de almacenamiento definidas como AccessMode::ReadOnly.
+ */
+ Object* create(Creator& creator) throw(RuntimeException, dbms::DatabaseException) { return create(NULL, creator); }
+
+ /**
+ Devuelve la informacion de un objeto cargado desde el medio fisico.
+
+ Este cargador deberia tener todos los datos necesarios para localizar la informacion del objeto que
+ debe buscar. Por ejemplo, en caso de tener que obtener el objeto a partir de los datos contenidos
+ en una tabla de una base de datos deberia conocer la clave primaria del objeto a cargar, o alguna
+ otra combinacion de columnas que lo identifiquen univocamente.
+
+ \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
+
+ \return Una instancia que cumple el patron establecido por el cargador. Puede ser NULL si el
+ objeto no fue cargado en el área de almacenamiento.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ Object* find(Loader& loader) throw(RuntimeException);
+
+ /**
+ Devuelve de una copia del objeto recibido como parámetro e incrementa la cuenta de utilizacion
+ asociada a la instancia.
+
+ \param object Instancia obtenida mediate el método #instance.
+
+ \return Una copia del objeto recibido como parámetro. Si el parámetro recibido es NULL devolveria NULL.
+
+ \warning Cada llamada a este método deberia tener su correspondiente liberacion invocando a #release
+ cuando dejemos de usar la instancia.
+ */
+ Object* duplicate(const Object* object) throw(RuntimeException);
+
+ /**
+ Permite conocer si un determinado objeto esta alojado en el área de almacenamiento. No
+ cambia la cuenta de utilizacion de los objetos ni provoca cambios en las estadisticas
+ de aciertos.
+
+ \param loader Cargador de clase encargado de localizar la informacion referente al objeto buscado.
+
+ \return \em true Si el objeto identificado por el Loader esta en el área de almacenamiento o
+ \em false en otro caso.
+ */
+ bool isLoaded(const Loader& loader) throw(RuntimeException);
+
+ /**
+ Transfiere la informacion del objeto recibido como parámetro al medio fisico usando el Recorder
+ recibido como parámetro.
+
+ \param connection Conexion usada si fuera necesario acceder al medio fisico.
+ \param recorder Grabador usado para transferir los datos al medio fisico.
+ */
+ void apply(dbms::Connection& connection, Recorder& recorder) throw(RuntimeException, dbms::DatabaseException);
+
+ /**
+ Elimina la informacion del objeto recibido como parámetro del medio fisico usando el Eraser
+ recibido como parámetro.
+
+ \param connection Conexion usada si fuera necesario acceder al medio fisico.
+ \param eraser Objecto usado para eliminar los datos al medio fisico.
+
+ \warning Si la cuenta de utilizacion del objeto es 1 se liberaría en otro caso se devolvería una excepción.
+ */
+ void apply(dbms::Connection& connection, Eraser& eraser) throw(RuntimeException, dbms::DatabaseException);
+
+ /**
+ Habilita la reutilizacion del espacio de memoria ocupado por un objeto instanciado mediate #instance.
+
+ Este método no saca al objeto de la memoria de almacenamiento, sino que marca su espacio de memoria
+ como subceptible de ser reutilizado. De esta forma, si el número de objetos cargados en memoria se
+ acerca al tamaño maximo indicado en la inicializacin, cuando halla que cargar un nuevo registro se
+ reusaria el espacio libre en vez de seguir aumentando el tamaño de la memoria de almacenamiento.
+
+ \param object Instancia del objeto que vamos a liberar.
+
+ \warning Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
+ ningun efecto.
+ */
+ void release(Object** object) throw(RuntimeException);
+
+ /**
+ Elimina toda la informacion referente al objeto recibido como parámetro, siempre y cuando
+ solo tenga un unica referencia activa. Descarga el objeto de la memoria de almacenamiento,
+
+ \param object Instancia que vamos a descargar de la memoria de almacenamiento.
+
+ \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
+ ningun efecto.
+ \li La instancia a liberar solo puede tener 1 en su cuenta de utilizacion.
+ */
+ void erase(Object** object) throw(RuntimeException);
+
+ /**
+ Marca el objeto recibido como pendiente de recarga de datos.
+
+ \param object Instancia que vamos a marcar como pendiente de recarga.
+
+ \warning \li Si el objeto recibido como parámetro no fue reservado mediate #instance no tiene
+ ningun efecto.
+ \li La instancia a marcar solo deberia tener una unica instancia en uso.
+ */
+ void dirty(Object* object) throw(RuntimeException);
+
+ /**
+ Establece el tamanho de las instancias de los objetos contenidos en este área de almacenamiento.
+ \param _sizeof Numero de bytes ocupado por cada una de las instancias.
+ */
+ void setSizeof(const Size _sizeof) throw() { a_sizeof = _sizeof + sizeof(Instance); }
+
+ /**
+ Devuelve el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento.
+ \return el numero maximo de bytes teorico que puede llegar a reservar este área de almacenamiento.
+ */
+ Size getMaxSizeOf() const throw() { return a_maxSize * a_sizeof; }
+
+ /**
+ Devuelve el numero de bytes teorico que puede llegar a reservar este área de almacenamiento.
+ \return el numero de bytes teorico que puede llegar a reservar este área de almacenamiento.
+ */
+ Size getSizeOf() const throw() { return a_directory.size() * a_sizeof; }
+
+ /**
+ Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento.
+ \return Un iterator al primero de los objetos contenido en el área del almacenamiento.
+ */
+ iterator begin() throw() { return a_directory.begin(); }
+
+ /**
+ Devuelve un iterator al primero de los objetos contenido en el área del almacenamiento.
+ \return Un iterator al primero de los objetos contenido en el área del almacenamiento.
+ */
+ const_iterator begin() const throw() { return a_directory.begin(); }
+
+ /**
+ Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento.
+ \return Un iterator al fin de los objetos contenidos en el área del almacenamiento.
+ */
+ iterator end() throw() { return a_directory.end(); }
+
+ /**
+ Devuelve un iterator al fin de los objetos contenidos en el área del almacenamiento.
+ \return Un iterator al fin de los objetos contenidos en el área del almacenamiento.
+ */
+ const_iterator end() const throw() { return a_directory.end(); }
+
+ /**
+ Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro.
+ \return El puntero sobre el que esta posicionado el iterador recibido como parámetro.
+ */
+ static Object* data(iterator ii) throw() { return ii->second->object; }
+
+ /**
+ Devuelve el puntero sobre el que esta posicionado el iterador recibido como parámetro.
+ \return El puntero sobre el que esta posicionado el iterador recibido como parámetro.
+ */
+ static const Object* data(const_iterator ii) throw() { return ii->second->object; }
+
+ /**
+ Devuelve una cadena con la informacion referente a este área de almacenamiento.
+ \return Una cadena con la informacion referente a este área de almacenamiento.
+ */
+ std::string asString() const throw();
+
+ /**
+ Devuelve un documento XML con la informacion referente a esta instancia.
+ \param parent Nodo XML del que dependende la informacion.
+ @return un documento XML con la informacion referente a esta instancia.
+ */
+ xml::Node* asXML(xml::Node* parent) const throw();
+
+protected:
+ /**
+ Descarga del área de almacenamiento todos los objetos que estuviera cargados.
+ Este método se invoca desde anna::dbos::Repository::clear
+ */
+ void clear() throw(RuntimeException);
+
+ /**
+ Devuelve un literal con el entero recibido tratado como una cantidad en bytes.
+ \return un literal con el entero recibido tratado como un cantidad en bytes
+ */
+ static std::string asMemorySize(const Size size) throw();
+
+private:
+ typedef std::map <Index, Instance*>::value_type value_type;
+
+ friend class Holes;
+
+ class Holes {
+ public:
+ struct Mode { enum _v { ReadyToReuse, TimeWait }; };
+
+ typedef std::list <Instance*> hole_container;
+ typedef hole_container::iterator hole_iterator;
+
+ Holes() : a_size(0) {;}
+
+ bool insert(Instance* instance, const Mode::_v mode) throw();
+ void erase(Instance* instance) throw();
+ Instance* front() throw() { return a_holes.front(); }
+ int size() const throw() { return a_size; }
+ int empty() const throw() { return a_holes.empty(); }
+ void pop_front() throw() { a_holes.pop_front(); a_size --; }
+ void clear() throw() { a_holes.clear(); a_size = 0; }
+
+ private:
+ hole_container a_holes;
+ int a_size;
+ };
+
+ //------------------------------------------------------------------------
+ // - object: Puntero a la instancia con el objeto cacheado.
+ // - msHoleTime: Millisecond en el que entra en la lista de huecos.
+ // - copyCounter: Numero de copias del objeto.
+ // - flags: Flags (Dirty, Incoherent, Empty).
+ //------------------------------------------------------------------------
+ friend struct Instance;
+
+ struct Instance {
+ Object* object;
+ Counter copyCounter;
+ int flags;
+ Holes::hole_iterator holeIterator;
+
+ Instance() : copyCounter(0), object(NULL), flags(Flag::None) {;}
+ };
+
+ friend class Block;
+
+ class Block {
+ public:
+ Block(ObjectAllocator objectAllocator, const Size maxSize);
+ Instance* getInstance() throw() { return (a_size < a_maxSize) ? &a_instances [a_size ++] : NULL; }
+ void reset() throw() { a_size = 0; }
+
+ private:
+ Instance* a_instances;
+ Size a_maxSize;
+ Size a_size;
+ };
+
+ const std::string a_name;
+ const Size a_maxSize;
+ ObjectAllocator a_objectAllocator;
+ const AccessMode::_v a_accessMode;
+ int a_errorCode;
+ Size a_sizeof;
+
+ Blocks a_blocks;
+ std::map <Index, Instance*> a_directory;
+ Holes a_holes;
+ Block* a_currentBlock;
+ int a_indexBlock;
+ Counter a_hit;
+ Counter a_fault;
+ Counter a_doneReuse;
+
+ /*
+ typedef std::deque <std::pair <DBIndex> inprogress_container;
+ typedef inprogress_container::iterator inprogress_iterator;
+ inprogress_container a_inprogress;
+
+ inprogress_iterator inprogress_begin () const throw () { return a_inprogress.begin (); }
+ inprogress_iterator inprogress_end () const throw () { return a_inprogress.end (); }
+ static DBIndex index (inprogress_iterator ii) throw () { return *ii; }
+ bool isInProgress (const DBIndex index) const throw ();
+ */
+
+ /*
+ * Constructor.
+ * \warning Este método sólo debería usarse desde el método dbos::Repository::allocateStorageArea.
+ */
+ StorageArea(const char* name, const Size maxSize, ObjectAllocator, const AccessMode::_v, const int errorCode);
+ StorageArea(const StorageArea&);
+
+ Object* reload(dbms::Connection*, Loader&, Instance*) throw(RuntimeException, dbms::DatabaseException);
+ void checkIncoherence(Instance*) throw();
+ bool quickReusing(Instance*) throw();
+ void verifyStatus(StorageArea::Instance*, const bool ignoreDirty = false) throw(RuntimeException);
+ Instance* allocate() throw();
+ Instance* reuse() throw();
+
+ static Instance* instance(iterator& ii) throw() { return ii->second; }
+ static std::string asString(const Instance*) throw();
+
+ friend class Repository;
+};
+
+}
+}
+
+#endif
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_dbos_hpp
+#define anna_dbos_dbos_hpp
+
+namespace anna {
+/**
+Define las clases y templates necesarias para convertir datos guardados en un medio fisico en
+clases totalmente funcionalines en C++.
+
+El ejecutable debera enlazarse con las librerias:
+ \li anna.core.a
+ \li anna.xml.a
+ \li anna.app.a
+ \li anna.comm.a
+ \li anna.dbms.a
+ \li anna.dbos.a
+
+El <b>Packet Header</b> es anna.dbos.h
+*/
+namespace dbos {
+}
+}
+
+#include <anna/dbos/Accesor.hpp>
+#include <anna/dbos/AutoObject.hpp>
+#include <anna/dbos/AutoSet.hpp>
+#include <anna/dbos/Creator.hpp>
+#include <anna/dbos/Eraser.hpp>
+#include <anna/dbos/Loader.hpp>
+#include <anna/dbos/Repository.hpp>
+#include <anna/dbos/Object.hpp>
+#include <anna/dbos/ObjectAllocator.hpp>
+#include <anna/dbos/ObjectFacade.hpp>
+#include <anna/dbos/Recorder.hpp>
+#include <anna/dbos/Set.hpp>
+#include <anna/dbos/SetFacade.hpp>
+#include <anna/dbos/StorageArea.hpp>
+#include <anna/dbos/CrossedLoader.hpp>
+
+using namespace anna::dbos;
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_defines_hpp
+#define anna_dbos_defines_hpp
+
+#include <anna/config/defines.hpp>
+
+namespace anna {
+
+namespace dbos {
+typedef unsigned int Size;
+typedef U64 Index;
+typedef ptrnumber StorageId;
+typedef unsigned int Counter;
+}
+
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#ifndef anna_dbos_internal_sccs_hpp
+#define anna_dbos_internal_sccs_hpp
+
+namespace anna {
+
+namespace dbos {
+
+class sccs {
+public:
+ static void activate() throw();
+};
+
+}
+}
+
+#endif
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <mysql/mysql.h>
+
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/Data.hpp>
+#include <anna/dbms/LongBlock.hpp>
+
+#include <anna/dbms.mysql/BaseBind.hpp>
+
+using namespace std;
+using namespace anna;
+
+//----------------------------------------------------------------------------
+// (1) Reserva 2 Kbytes para trabajar con el LOB.
+//----------------------------------------------------------------------------
+dbms::mysql::BaseBind::BaseBind(const dbms::Data& data) :
+ a_type(data.getType()),
+ a_time(NULL) {
+ switch(a_type) {
+ case Data::Type::ShortBlock:
+ case Data::Type::LongBlock:
+ break;
+ case Data::Type::Date: // (1)
+ case Data::Type::TimeStamp:
+ a_time = new MYSQL_TIME;
+ break;
+ default: break;
+ }
+}
+
+dbms::mysql::BaseBind::~BaseBind() {
+ delete a_time;
+}
+
+/**
+ * Según http://dev.mysql.com/doc/refman/4.1/en/c-api-prepared-statement-datatypes.html
+ * y el truco para recoger BLOB's http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html.
+ */
+void dbms::mysql::BaseBind::setupBind(st_mysql_bind& bind, dbms::Data& data)
+throw(RuntimeException) {
+ anna_memset(&bind, 0, sizeof(bind));
+ bind.is_null = &a_nullIndicator;
+ a_length = 0;
+
+ switch(a_type) {
+ case Data::Type::Integer:
+ bind.buffer_type = MYSQL_TYPE_LONG;
+ bind.buffer_length = data.getMaxSize();
+ bind.length = &a_length;
+ bind.buffer = const_cast <dbms::Data&>(data).getBuffer();
+ bind.is_unsigned = false;
+ break;
+ case Data::Type::String:
+ bind.buffer_type = MYSQL_TYPE_STRING;
+ bind.buffer_length = data.getMaxSize();
+ bind.length = &a_length;
+ bind.buffer = const_cast <dbms::Data&>(data).getBuffer();
+ break;
+ case Data::Type::Float:
+ bind.buffer_type = MYSQL_TYPE_FLOAT;
+ bind.buffer_length = data.getMaxSize();
+ bind.length = &a_length;
+ bind.buffer = const_cast <dbms::Data&>(data).getBuffer();
+ break;
+ case Data::Type::Date: // (1)
+ bind.buffer_type = MYSQL_TYPE_DATE;
+ bind.buffer_length = sizeof(MYSQL_TIME);
+ bind.length = &a_length;
+ bind.buffer = (char*) a_time;
+ break;
+ case Data::Type::TimeStamp:
+ bind.buffer_type = MYSQL_TYPE_DATETIME;
+ bind.buffer_length = sizeof(MYSQL_TIME);
+ bind.length = &a_length;
+ bind.buffer = (char*) a_time;
+ break;
+ case Data::Type::ShortBlock:
+
+ if((bind.buffer_length = data.getMaxSize()) < MaxBlobSize) {
+ bind.buffer_type = MYSQL_TYPE_BLOB;
+ bind.length = &a_length;
+ bind.buffer = const_cast <dbms::Data&>(data).getBuffer();
+ } else {
+ string msg(data.asString());
+ msg += functions::asString(" | Over maximum size: %d/%d", data.getMaxSize(), MaxBlobSize);
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ break;
+ case Data::Type::LongBlock:
+ /**
+ * El tratamiento particular se realiza en las clases InputBind y OutputBind.
+ */
+ break;
+ default:
+ throw RuntimeException(functions::asString("Unsupported data type %d", (int) a_type), ANNA_FILE_LOCATION);
+ }
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <mysql/mysql.h>
+
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms.mysql/Database.hpp>
+#include <anna/dbms.mysql/Connection.hpp>
+#include <anna/dbms.mysql/ResultCode.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+mysql::Connection::Connection(Database& database, const std::string& name, const char* user, const char* password) :
+ dbms::Connection(database, name, user, password),
+ a_mysqlDatabase(database),
+ a_mysql(NULL) {
+}
+
+void mysql::Connection::open()
+throw(dbms::DatabaseException) {
+ if(a_mysql != NULL) {
+ LOGWARNING(
+ string msg = asString();
+ msg += " | Has already been established";
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ );
+ return;
+ }
+
+ if((a_mysql = mysql_init(NULL)) == NULL)
+ RuntimeException("Cannot initiate MySQL", ANNA_FILE_LOCATION);
+
+ const char* dbmsName = (a_mysqlDatabase.getType() == Database::Type::Remote) ? a_mysqlDatabase.getName().c_str() : NULL;
+
+ try {
+ if(mysql_real_connect(a_mysql, a_mysqlDatabase.getHost(), a_user.c_str(), a_password.c_str(), dbmsName, 0, NULL, 0L) == NULL) {
+ ResultCode resultCode(a_mysql);
+ throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
+ }
+
+ LOGINFORMATION(
+ string msg("anna::dbms::mysql::Connection::open | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ } catch(DatabaseException& edbms) {
+ close();
+ throw;
+ }
+}
+
+void mysql::Connection::close()
+throw() {
+ LOGINFORMATION(
+ string msg("anna::dbms::mysql::Connection::close | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+
+ if(a_mysql != NULL) {
+ mysql_close(a_mysql);
+ a_mysql = NULL;
+ LOGINFORMATION(
+ string msg("anna::dbms::mysql::Connection::close | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ }
+}
+
+void mysql::Connection::do_commit()
+throw(RuntimeException, dbms::DatabaseException) {
+ anna_dbms_mysql_check(mysql_commit(a_mysql), a_mysql);
+}
+
+void mysql::Connection::do_rollback()
+throw() {
+ try {
+ anna_dbms_mysql_check(mysql_rollback(a_mysql), a_mysql);
+ } catch(Exception& ex) {
+ ex.trace();
+ }
+}
+
+string mysql::Connection::asString() const
+throw() {
+ string result("dbms::mysql::Connection { ");
+ result += dbms::Connection::asString();
+ result += " | Context: ";
+ result += (a_mysql == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_mysql));
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <string.h>
+
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/dbms.mysql/mysql.hpp>
+#include <anna/dbms.mysql/internal/sccs.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+mysql::Database::Database(const char* dbmsName, const char* host) :
+ dbms::Database(getClassName(), dbmsName) {
+ a_host = (host == NULL) ? NULL : strdup(host);
+ mysql::sccs::activate();
+}
+
+mysql::Database::Database(const char* componentName, const char* dbmsName, const char* host) :
+ dbms::Database(componentName, dbmsName) {
+ a_host = (host == NULL) ? NULL : strdup(host);
+ mysql::sccs::activate();
+}
+
+void mysql::Database::do_initialize()
+throw(RuntimeException) {
+ LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Database", "do_initialize", ANNA_FILE_LOCATION));
+ dbms::Database::do_initialize();
+}
+
+//----------------------------------------------------------------------------------
+// Libera todos los manejadores asociados a este entorno.
+//----------------------------------------------------------------------------------
+mysql::Database::~Database() {
+ LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Database", "~Database", ANNA_FILE_LOCATION));
+
+ if(a_host != NULL)
+ free(a_host);
+}
+
+dbms::Connection* mysql::Database::allocateConnection(const std::string& name, const char* user, const char* password)
+throw(RuntimeException) {
+ return new Connection(*this, name, user, password);
+}
+
+dbms::Statement* mysql::Database::allocateStatement(const char* name, const std::string& expression, const bool isCritical)
+throw(RuntimeException) {
+ return new Statement(*this, name, expression, isCritical);
+}
+
+dbms::InputBind* mysql::Database::allocateInputBind(const char* name, Data& data)
+throw(RuntimeException) {
+ return new InputBind(name, data);
+}
+
+void mysql::Database::deallocate(dbms::InputBind* inputBind)
+throw() {
+ delete(InputBind*) inputBind;
+}
+
+dbms::OutputBind* mysql::Database::allocateOutputBind(const char* name, Data& data)
+throw(RuntimeException) {
+ return new OutputBind(name, data);
+}
+
+void mysql::Database::deallocate(dbms::OutputBind* outputBind)
+throw() {
+ delete(OutputBind*) outputBind;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <time.h>
+
+#include <mysql/mysql.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/functions.hpp>
+#include <anna/core/DataBlock.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms/String.hpp>
+#include <anna/dbms/ShortBlock.hpp>
+#include <anna/dbms/Date.hpp>
+#include <anna/dbms/TimeStamp.hpp>
+#include <anna/dbms/LongBlock.hpp>
+
+#include <anna/dbms.mysql/mysql.hpp>
+
+using namespace std;
+using namespace anna;
+
+InputBind::InputBind(const char* name, dbms::Data& data) :
+ dbms::InputBind(name, data),
+ BaseBind(data) {
+}
+
+InputBind::~InputBind() {
+}
+
+/*
+ * Completa la informacion establececida por el setupBind.
+ */
+void InputBind::prepare(anna::dbms::Statement* dbmsStmt, anna::dbms::Connection*, const int pos)
+throw(RuntimeException) {
+ st_mysql_bind* bind = static_cast <dbms::mysql::Statement*>(dbmsStmt)->getBindParams() + pos;
+ Data& data = anna::dbms::Bind::getData();
+ BaseBind::setupBind(*bind, data);
+
+ if(data.getType() == Data::Type::LongBlock) {
+ DataBlock& dataBlock = static_cast <dbms::LongBlock&>(data).getValue();
+ bind->buffer_type = MYSQL_TYPE_BLOB;
+ bind->buffer_length = dataBlock.getSize();
+ bind->buffer = (char*) dataBlock.getData();
+ bind->length = &a_length;
+ }
+}
+
+/*
+ * Se invoca desde anna::dbms::mysql::Statement::execute.
+ * Codificar� la informaci�n C++ de forma que encaje en las estructuras requeridas por el API de MySQL.
+ */
+void InputBind::code() const
+throw(RuntimeException) {
+ InputBind* _this = const_cast <InputBind*>(this);
+ Data& data = _this->getData();
+
+ if((_this->a_nullIndicator = data.isNull() ? true : false) == true)
+ return;
+
+ switch(data.getType()) {
+ case Data::Type::String:
+ _this->a_length = anna_strlen((char*)(static_cast <dbms::String&>(data).getBuffer()));
+ break;
+ case Data::Type::Date:
+ case Data::Type::TimeStamp:
+ _this->codeDate(data);
+ break;
+ case Data::Type::Integer:
+ throw RuntimeException("anna::dbms::mysql::InputBind::code not implemented for Data::Type::Integer", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::Float:
+ throw RuntimeException("anna::dbms::mysql::InputBind::code not implemented for Data::Type::Float", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::ShortBlock:
+ throw RuntimeException("anna::dbms::mysql::InputBind::code not implemented for Data::Type::ShortBlock", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::LongBlock:
+ throw RuntimeException("anna::dbms::mysql::InputBind::code not implemented for Data::Type::LongBlock", ANNA_FILE_LOCATION);
+ break;
+
+ }
+}
+
+/**
+ * El bind.buffer ha sido asociado a una estructura de tipo MYSQL_TIME (a_time), cuyos valores vamos
+ * a establecer en �ste m�todo.
+ */
+void InputBind::codeDate(dbms::Data& data)
+throw() {
+ dbms::Date& date = static_cast <dbms::Date&>(data);
+
+ if(data.getType() == Data::Type::TimeStamp) {
+ a_time->second_part = static_cast <dbms::TimeStamp&>(data).getFractionalSecond();
+ }
+
+ a_time->year = date.getYear();
+ a_time->month = date.getMonth();
+ a_time->day = date.getDay();
+ a_time->hour = date.getHour();
+ a_time->minute = date.getMinute();
+ a_time->second = date.getSecond();
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <ctype.h>
+
+#include <anna/config/defines.hpp>
+
+#include <anna/dbms.mysql/OracleTranslator.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+mysql::OracleTranslator mysql::OracleTranslator::st_this;
+
+/*
+ * Pone las sentencias SQL escritas para Oracle en el formato que necesita el
+ * MySQL.
+ *
+ * La sentencia Oracle podría ser algo así como:
+ * insert into foo (a, b, c) values (:x, :y, :zzzz)
+ * update goo set xx=&value where yy=:zzz
+ *
+ * Y Debería quedar algo así:
+ * insert into foo (a, b, c) values (?,?,?)
+ * update goo set xx=? where yy=?
+ */
+const char* mysql::OracleTranslator::apply(const char* statement)
+throw(RuntimeException) {
+ bool makeit = false;
+
+ if(anna_strchr(statement, ':') != NULL)
+ makeit = true;
+ else if(anna_strchr(statement, '&') != NULL)
+ makeit = true;
+
+ if(makeit == false)
+ return statement;
+
+ allocate(statement);
+ enum { Copying, Filtering };
+ int mode(Copying);
+ char* w = a_buffer;
+ char character;
+
+ while((character = *statement) != 0) {
+ switch(mode) {
+ case Copying:
+
+ if(character == ':' || character == '&') {
+ *w ++ = '?';
+ mode = Filtering;
+ } else
+ *w ++ = character;
+
+ break;
+ case Filtering:
+
+ if(character == ',' || character == ')' || isspace(character) || iscntrl(character)) {
+ *w ++ = character;
+ mode = Copying;
+ }
+
+ break;
+ }
+
+ statement ++;
+ }
+
+ *w = 0;
+ return a_buffer;
+}
+
+void mysql::OracleTranslator::allocate(const char* statement)
+throw() {
+ const int size = anna_strlen(statement);
+
+ if(size > a_size) {
+ if(a_size > 0) {
+ delete a_buffer;
+ a_buffer = NULL;
+ }
+
+ a_buffer = new char [a_size = size + 1];
+ }
+
+ a_buffer [0] = 0;
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <mysql/mysql.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/Float.hpp>
+#include <anna/dbms/ShortBlock.hpp>
+#include <anna/dbms/LongBlock.hpp>
+#include <anna/dbms/String.hpp>
+#include <anna/dbms/Date.hpp>
+#include <anna/dbms/TimeStamp.hpp>
+
+#include <anna/dbms.mysql/mysql.hpp>
+
+using namespace anna;
+using namespace std;
+
+OutputBind::OutputBind(const char* name, dbms::Data& data) :
+ dbms::OutputBind(name, data),
+ BaseBind(data) {
+ a_blob = (data.getType() == Data::Type::LongBlock) ? new Blob : NULL;
+}
+
+OutputBind::~OutputBind() {
+ delete a_blob;
+}
+
+/*
+ * El dato de LONG BLOB se recoge según cuenta:
+ * http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html.
+ */
+void OutputBind::prepare(anna::dbms::Statement* dbmsStmt, anna::dbms::Connection*, const int pos)
+throw(RuntimeException) {
+ st_mysql_bind* bind = static_cast <dbms::mysql::Statement*>(dbmsStmt)->getBindResults() + pos;
+ Data& data = anna::dbms::Bind::getData();
+ BaseBind::setupBind(*bind, data);
+
+ if(data.getType() == Data::Type::LongBlock) {
+ dbms::mysql::Statement* myStmt = static_cast <dbms::mysql::Statement*>(dbmsStmt);
+ a_blob->stmt = *myStmt;
+ a_blob->binds = myStmt->getBindResults();
+ a_blob->pos = pos;
+ bind->buffer_type = MYSQL_TYPE_BLOB;
+ bind->buffer = NULL;
+ bind->buffer_length = 0;
+ bind->length = &a_length;
+ }
+}
+
+/*
+ * Transfiere la información del los MYSQL_BIND del API C de MySQL a las
+ * estructuras dbms::Data de nuestro programa C++.
+ */
+void OutputBind::decode() const
+throw(RuntimeException) {
+ OutputBind* _this = const_cast <OutputBind*>(this);
+ char* str;
+ Data& data = _this->getData();
+ data.setNull(a_nullIndicator == true);
+
+ switch(data.getType()) {
+ case Data::Type::String:
+ str = (char*) data.getBuffer();
+
+ if(data.isNull() == true)
+ *str = 0;
+ else
+ dbms::String::strip(str);
+
+ break;
+ case Data::Type::Float:
+
+ if(data.isNull() == true)
+ static_cast <dbms::Float&>(data) = 0.0;
+
+ break;
+ case Data::Type::Date:
+ case Data::Type::TimeStamp:
+ _this->decodeDate(data);
+ break;
+ case Data::Type::Integer:
+ throw RuntimeException("anna::dbms::mysql::OutputBind::decode not implemented for Data::Type::Integer", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::ShortBlock:
+ throw RuntimeException("anna::dbms::mysql::OutputBind::decode not implemented for Data::Type::ShortBlock", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::LongBlock:
+
+ try {
+ _this->decodeLongBlob(data);
+ } catch(dbms::DatabaseException& edb) {
+ throw RuntimeException(edb);
+ }
+
+ break;
+ }
+}
+
+void OutputBind::do_write(const dbms::LongBlock&) const
+throw(RuntimeException, dbms::DatabaseException) {
+}
+
+/*
+ * El m�todo BaseBind::setupBind asocia� el contenido de la variable
+ * a_time al buffer de salida de la sentencia SQL, as� que el contenido
+ * de la columna est� contenido ah�. S�lo tendremos que copiar dichos
+ * contenidos en la variable C++ de nuestro entorno.
+ */
+void OutputBind::decodeDate(dbms::Data& data)
+throw() {
+ if(data.isNull() == true)
+ return;
+
+ Date& date = static_cast <Date&>(data);
+ date.setYear(a_time->year);
+ date.setMonth(a_time->month);
+ date.setDay(a_time->day);
+ date.setHour(a_time->hour);
+ date.setMinute(a_time->minute);
+ date.setSecond(a_time->second);
+
+ if(data.getType() == Data::Type::TimeStamp)
+ static_cast <dbms::TimeStamp&>(data).setFractionalSecond(a_time->second_part);
+}
+
+/*
+ * Según http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
+ *
+ * Recoge el contenido total de BLOB en partes que va componiendo sobre el
+ * DataBlock final asociado al anna::dbms::LongBlock sobre el que trabaja el
+ * programador final.
+ */
+void OutputBind::decodeLongBlob(dbms::Data& data) const
+throw(RuntimeException, dbms::DatabaseException) {
+ const int bufferSize = a_blob->buffer.getMaxSize();
+ st_mysql_bind& bind = a_blob->binds [a_blob->pos];
+ DataBlock& target = static_cast <dbms::LongBlock&>(data).getValue();
+ const int maxloop = *bind.length / bufferSize;
+ const int remainder = *bind.length % bufferSize;
+ int offset = 0;
+ target.clear();
+ bind.buffer = (void*) a_blob->buffer.getData();
+
+ for(int iloop = 0; iloop < maxloop; iloop ++) {
+ bind.buffer_length = bufferSize;
+ anna_dbms_mysql_check(
+ mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt
+ );
+ target += DataBlock((const char*) bind.buffer, bind.buffer_length, false);
+ offset += bufferSize;
+ }
+
+ if(remainder) {
+ bind.buffer_length = remainder;
+ anna_dbms_mysql_check(
+ mysql_stmt_fetch_column(a_blob->stmt, a_blob->binds, a_blob->pos, offset), a_blob->stmt
+ );
+ target += DataBlock((const char*) bind.buffer, remainder, false);
+ }
+}
+
+OutputBind::Blob::Blob() :
+ buffer(true) {
+ buffer.allocate(64 * 1024);
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <mysql/mysql.h>
+#include <mysql/mysqld_error.h>
+#include <mysql/errmsg.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms.mysql/ResultCode.hpp>
+
+using namespace anna;
+using namespace anna::dbms;
+
+mysql::ResultCode::ErrorDecoder mysql::ResultCode::st_errorDecoder;
+
+mysql::ResultCode::ResultCode(st_mysql* _mysql) :
+ dbms::ResultCode(0, NULL, &st_errorDecoder) {
+ int errorCode = mysql_errno(_mysql);
+
+ if(errorCode != 0)
+ dbms::ResultCode::set(errorCode, mysql_error(_mysql));
+}
+
+mysql::ResultCode::ResultCode(st_mysql_stmt* stmt) :
+ dbms::ResultCode(0, NULL, &st_errorDecoder) {
+ int errorCode = mysql_stmt_errno(stmt);
+
+ if(errorCode != 0)
+ dbms::ResultCode::set(errorCode, mysql_stmt_error(stmt));
+}
+
+/*
+ * Códigos de error obtenidos de:
+ * http://dev.mysql.com/doc/refman/4.1/en/error-messages-client.html
+ */
+
+bool mysql::ResultCode::ErrorDecoder::notFound(const int errorCode) const
+throw() {
+ return errorCode == CR_NO_DATA;
+}
+
+bool mysql::ResultCode::ErrorDecoder::successful(const int errorCode) const
+throw() {
+ return errorCode == 0;
+}
+
+bool mysql::ResultCode::ErrorDecoder::locked(const int errorCode) const
+throw() {
+ return false; // No parece que haya un código de error en MySQL para identificar esta situación ¿?¿?
+}
+
+bool mysql::ResultCode::ErrorDecoder::lostConnection(const int errorCode) const
+throw() {
+ return errorCode == CR_INVALID_CONN_HANDLE || errorCode == CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR || errorCode == CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR ||
+ errorCode == CR_SHARED_MEMORY_CONNECT_MAP_ERROR || errorCode == CR_SHARED_MEMORY_CONNECT_SET_ERROR;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <mysql/mysql.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/dbms.mysql/mysql.hpp>
+
+using namespace std;
+using namespace anna;
+
+dbms::mysql::Statement::~Statement() {
+ if(a_mysqlStmt) {
+ try {
+ anna_dbms_mysql_check(mysql_stmt_close(a_mysqlStmt), a_mysqlStmt);
+ } catch(DatabaseException& edb) {
+ edb.trace();
+ }
+ }
+
+ delete [] a_params;
+ delete [] a_results;
+}
+
+/**
+ * Según el ejemplo de: http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
+ *
+ */
+void dbms::mysql::Statement::prepare(dbms::Connection* dbmsConnection)
+throw(RuntimeException, dbms::DatabaseException) {
+ LOGMETHOD(TraceMethod tm("anna::dbms::mysql::Statement", "prepare", ANNA_FILE_LOCATION));
+ Connection* connection(static_cast <Connection*>(dbmsConnection));
+ //Database& dbms(static_cast <Database&>(connection->getDatabase()));
+ LOGDEBUG(
+ string msg("anna::dbms::mysql::Statement::prepare | ");
+ msg += asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+
+ /*
+ * Libera la información establecida anteriormente. Las sentencias se pueden reusar.
+ */
+ if(a_mysqlStmt != NULL) {
+ anna_dbms_mysql_check(mysql_stmt_reset(a_mysqlStmt), a_mysqlStmt);
+ delete [] a_params;
+ delete [] a_results;
+ a_params = a_results = NULL;
+ } else if((a_mysqlStmt = mysql_stmt_init(*connection)) == NULL) {
+ string msg(asString());
+ msg += " | Insufficient memory";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ const char* expression = dbms::Statement::getExpression().c_str();
+
+ anna_dbms_mysql_check(mysql_stmt_prepare(a_mysqlStmt, expression, anna_strlen(expression)), a_mysqlStmt);
+
+ const int paramCount = mysql_stmt_param_count(a_mysqlStmt);
+
+ const int inputSize = dbms::Statement::input_size();
+
+ const int outputSize = dbms::Statement::output_size();
+
+ /*
+ * Verifica que el número de parámetros de entrada de la sentencia coincida con el número de parámetros
+ * indicados por el programador.
+ */
+ if(paramCount != inputSize) {
+ string msg(asString());
+ msg += " | Wrong input parameters";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ /*
+ * Verifica que el número de parámetros de salida de la sentencia coincida con el número de parámetros
+ * indicados por el programador. Si no tiene parámetros de salida (INSERT) => no debe tener parámetros
+ * indicados por el programador.
+ */
+ MYSQL_RES* metaResult = mysql_stmt_result_metadata(a_mysqlStmt);
+
+ try {
+ if(metaResult == NULL) {
+ if(outputSize != 0) {
+ string msg(asString());
+ msg += " | Wrong output parameters";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+ } else if(mysql_num_fields(metaResult) != outputSize) {
+ string msg(asString());
+ msg += " | Wrong output parameters";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+ } catch(RuntimeException&) {
+ mysql_free_result(metaResult);
+ throw;
+ }
+
+ /*
+ * Define las estructuras requeridas para asociar las columasn MySQL con las áreas de memoria C++
+ */
+ int pos;
+
+ if((a_params = create(inputSize, "input")) != NULL) {
+ pos = 0;
+
+ for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++)
+ inputBind(ii)->prepare(this, dbmsConnection, pos ++);
+
+ anna_dbms_mysql_check(mysql_stmt_bind_param(a_mysqlStmt, a_params), a_mysqlStmt);
+ }
+
+ if((a_results = create(outputSize, "output")) != NULL) {
+ pos = 0;
+
+ for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++)
+ outputBind(oo)->prepare(this, dbmsConnection, pos ++);
+
+ anna_dbms_mysql_check(mysql_stmt_bind_result(a_mysqlStmt, a_results), a_mysqlStmt);
+ }
+}
+
+dbms::ResultCode dbms::mysql::Statement::execute(dbms::Connection* dbmsConnection)
+throw(RuntimeException, dbms::DatabaseException) {
+ //Connection* connection(static_cast <Connection*>(dbmsConnection));
+
+ for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) {
+ inputBind(ii)->code();
+ LOGDEBUG(
+ string msg("anna::dbms::mysql::Statement::InputBind: ");
+ msg += inputBind(ii)->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ }
+
+ anna_dbms_mysql_check(mysql_stmt_execute(a_mysqlStmt), a_mysqlStmt)
+ ResultCode result(a_mysqlStmt);
+ return result;
+}
+
+/*
+ * Según la información de http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-fetch.html
+ */
+bool dbms::mysql::Statement::fetch()
+throw(RuntimeException, dbms::DatabaseException) {
+ bool result = false;
+
+ switch(mysql_stmt_fetch(a_mysqlStmt)) {
+ case 0:
+ result = true;
+
+ for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) {
+ outputBind(oo)->decode();
+ LOGDEBUG(Logger::write(Logger::Debug, outputBind(oo)->asString(), ANNA_FILE_LOCATION));
+ }
+
+ break;
+ case 1:
+ throw DatabaseException(ResultCode(a_mysqlStmt), ANNA_FILE_LOCATION);
+ default:
+ result = false;
+ break;
+ }
+
+ LOGDEBUG(
+ string msg("anna::dbms::mysql::Statement::fetch | Result: ");
+ msg += functions::asString(result);
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ return result;
+}
+
+st_mysql_bind* dbms::mysql::Statement::create(const int size, const char* whatis)
+throw(RuntimeException) {
+ st_mysql_bind* result = NULL;
+
+ if(size > 0) {
+ if((result = new st_mysql_bind [size]) == NULL) {
+ string msg(asString());
+ msg += anna::functions::asString("Insufficient memory to create %d parameters of %s", size, whatis);
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+ }
+
+ return result;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/internal/sccs.hpp>
+#include <anna/dbms/internal/sccs.hpp>
+#include <anna/dbms.mysql/internal/sccs.hpp>
+
+#include <anna/core/internal/ModuleManager.hpp>
+
+anna_define_sccs_tag_ex(dbms_mysql, dbms.mysql, 0);
+
+void anna::dbms::mysql::sccs::activate()
+throw() {
+ dbms::sccs::activate();
+ ModuleManager::instantiate().insert(anna_use_sccs_tag(dbms_mysql), "00");
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <oci.h>
+
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/Data.hpp>
+#include <anna/dbms/LongBlock.hpp>
+
+#include <anna/dbms.oracle/BaseBind.hpp>
+#include <anna/dbms.oracle/Database.hpp>
+#include <anna/dbms.oracle/Connection.hpp>
+#include <anna/dbms.oracle/ResultCode.hpp>
+
+using namespace anna;
+
+//----------------------------------------------------------------------------
+// (1) Reserva 2 Kbytes para trabajar con el LOB.
+//----------------------------------------------------------------------------
+dbms::oracle::BaseBind::BaseBind(const dbms::Data& data) :
+ a_type(data.getType()),
+ a_ofb(NULL) {
+ switch(a_type) {
+ case Data::Type::Float:
+ a_ofb = new anna::DataBlock(true);
+ a_ofb->allocate(FloatSize + 1);
+ break;
+ case Data::Type::ShortBlock:
+ a_ofb = new anna::DataBlock(true);
+ a_ofb->allocate(data.getMaxSize() * 2 + 1);
+ break;
+ case Data::Type::LongBlock:
+ a_ofb = new anna::DataBlock(true);
+ a_ofb->allocate(2048); // (1)
+ break;
+ default: break;
+ }
+}
+
+dbms::oracle::BaseBind::~BaseBind() {
+ delete a_ofb;
+}
+
+//
+// (1) Aunque sea un objeto de tipo Date lo define/trata como un tipo TimeStamp, porque de otro modo no se grabaria la
+// informacion referente a la hora.
+// (2) El Float hasta ahora se trataba como un tipo especial de cadena, pero no es un tratamiento indicado
+// para todos los gestores de base de datos, as� que vamos a resumir en estas clases todos los detalles de
+// tratamiento.
+//
+dbms::oracle::BaseBind::oci_param dbms::oracle::BaseBind::getOCIParam(dbms::oracle::Database& database, dbms::oracle::Connection* connection, dbms::Data& data)
+throw(RuntimeException) {
+ oci_param ociparam;
+
+ switch(a_type) {
+ case Data::Type::Integer:
+ ociparam.type = SQLT_INT;
+ ociparam.maxLength = data.getMaxSize();
+ ociparam.length = NULL;
+ ociparam.buffer = const_cast <dbms::Data&>(data).getBuffer();
+ break;
+ case Data::Type::String:
+ ociparam.type = SQLT_STR;
+ ociparam.maxLength = data.getMaxSize() + 1;
+ ociparam.length = NULL;
+ ociparam.buffer = const_cast <dbms::Data&>(data).getBuffer();
+ break;
+ case Data::Type::Float: // (2)
+ ociparam.type = SQLT_STR;
+ ociparam.maxLength = FloatSize + 1;
+ ociparam.length = NULL;
+ ociparam.buffer = const_cast <char*>(a_ofb->getData());
+ break;
+ case Data::Type::ShortBlock:
+ ociparam.type = SQLT_STR;
+ ociparam.maxLength = data.getMaxSize() * 2 + 1;
+ ociparam.length = &a_length;
+ ociparam.buffer = const_cast <char*>(a_ofb->getData());
+ break;
+ case Data::Type::LongBlock:
+ a_blob.allocate(database, connection, OCI_DTYPE_LOB);
+ ociparam.type = SQLT_BLOB;
+ ociparam.buffer = &a_blob.handle;
+ ociparam.length = NULL;
+ ociparam.maxLength = 0;
+ break;
+ case Data::Type::Date: // (1)
+ case Data::Type::TimeStamp:
+ a_datetime.allocate(database, connection, OCI_DTYPE_TIMESTAMP);
+ ociparam.type = SQLT_TIMESTAMP;
+ ociparam.buffer = &a_datetime.handle;
+ ociparam.length = NULL;
+ ociparam.maxLength = 0;
+ break;
+ default:
+ throw RuntimeException(functions::asString("Unsupported data type %d", (int) a_type), ANNA_FILE_LOCATION);
+ }
+
+ return ociparam;
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <oci.h>
+
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms.oracle/Database.hpp>
+#include <anna/dbms.oracle/Connection.hpp>
+#include <anna/dbms.oracle/ResultCode.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+oracle::Connection::Connection(Database& database, const std::string& name, const char* user, const char* password) :
+ dbms::Connection(database, name, user, password),
+ a_context(NULL),
+ a_session(NULL),
+ a_server(NULL),
+ a_oracleDatabase(database) {
+}
+
+void oracle::Connection::open()
+throw(dbms::DatabaseException) {
+ OCIError* error = a_oracleDatabase.getErrorHandler();
+
+ if(a_context != NULL) {
+ LOGWARNING(
+ string msg = asString();
+ msg += " | Already established";
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ );
+ return;
+ }
+
+ try {
+ anna_dbms_oracle_check(OCIHandleAlloc(a_oracleDatabase, (void**) &a_context, OCI_HTYPE_SVCCTX, 0, 0), error);
+ anna_dbms_oracle_check(OCIHandleAlloc(a_oracleDatabase, (void**) &a_session, OCI_HTYPE_SESSION, 0, 0), error);
+ anna_dbms_oracle_check(OCIHandleAlloc(a_oracleDatabase, (void**) &a_server, OCI_HTYPE_SERVER, 0, 0), error);
+ const char* dbmsName = NULL;
+ int lenDBName = 0;
+
+ if(a_oracleDatabase.getType() == Database::Type::Remote) {
+ dbmsName = a_oracleDatabase.getName().c_str();
+ lenDBName = anna_strlen(dbmsName);
+ }
+
+ anna_dbms_oracle_check(
+ OCIServerAttach(a_server, error, (unsigned char*) dbmsName, lenDBName, OCI_DEFAULT),
+ error
+ );
+ anna_dbms_oracle_check(OCIAttrSet(a_context, OCI_HTYPE_SVCCTX, a_server, 0, OCI_ATTR_SERVER, error), error);
+ anna_dbms_oracle_check(
+ OCIAttrSet(a_session, OCI_HTYPE_SESSION, (void*) a_user.c_str(), a_user.size(), OCI_ATTR_USERNAME, error),
+ error
+ );
+ anna_dbms_oracle_check(
+ OCIAttrSet(a_session, OCI_HTYPE_SESSION, (void*) a_password.c_str(), a_password.size(), OCI_ATTR_PASSWORD, error),
+ error
+ );
+ anna_dbms_oracle_check(OCISessionBegin(a_context, error, a_session, OCI_CRED_RDBMS, OCI_DEFAULT), error);
+ anna_dbms_oracle_check(OCIAttrSet(a_context, OCI_HTYPE_SVCCTX, a_session, 0, OCI_ATTR_SESSION, error), error);
+ LOGINFORMATION(
+ string msg("anna::dbms::oracle::Connection::open | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ } catch(DatabaseException& edbms) {
+ close();
+ throw;
+ }
+}
+
+void oracle::Connection::close()
+throw() {
+ OCIError* error = a_oracleDatabase.getErrorHandler();
+
+ try {
+ LOGINFORMATION(
+ string msg("anna::dbms::oracle::Connection::close | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+
+ if(a_session != NULL && a_context != NULL) {
+ OCISessionEnd(a_context, error, a_session, OCI_DEFAULT);
+ a_session = NULL;
+ }
+
+ if(a_server != NULL) {
+ OCIServerDetach(a_server, error, OCI_DEFAULT);
+ OCIHandleFree(a_server, OCI_HTYPE_SERVER);
+ a_server = NULL;
+ }
+
+ if(a_context != NULL) {
+ OCIHandleFree(a_context, OCI_HTYPE_SVCCTX);
+ a_context = NULL;
+ }
+
+ LOGINFORMATION(
+ string msg("anna::dbms::oracle::Connection::close | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ } catch(DatabaseException& ex) {
+ ex.trace();
+ }
+}
+
+void oracle::Connection::do_commit()
+throw(RuntimeException, dbms::DatabaseException) {
+ OCIError* error = a_oracleDatabase.getErrorHandler();
+ anna_dbms_oracle_check(OCITransCommit(a_context, error, 0), error);
+}
+
+void oracle::Connection::do_rollback()
+throw() {
+ try {
+ OCIError* error = a_oracleDatabase.getErrorHandler();
+ anna_dbms_oracle_check(OCITransRollback(a_context, error, 0), error);
+ } catch(Exception& ex) {
+ ex.trace();
+ }
+}
+
+string oracle::Connection::asString() const
+throw() {
+ string result("dbms::oracle::Connection { ");
+ result += dbms::Connection::asString();
+ result += " | Context: ";
+ result += (a_context == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_context));
+ result += " | Session: ";
+ result += (a_session == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_session));
+ result += " | Server: ";
+ result += (a_server == NULL) ? "(null)" : functions::asHexString(anna_ptrnumber_cast(a_server));
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <locale.h>
+
+#include <oci.h>
+
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/dbms.oracle/oracle.hpp>
+#include <anna/dbms.oracle/internal/sccs.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+char oracle::Database::st_decimalPoint = 0;
+
+oracle::Database::Database(const char* dbmsName) :
+ dbms::Database(getClassName(), dbmsName),
+ a_env(NULL),
+ a_error(NULL) {
+ oracle::sccs::activate();
+}
+
+oracle::Database::Database(const char* componentName, const char* dbmsName) :
+ dbms::Database(componentName, dbmsName),
+ a_env(NULL),
+ a_error(NULL) {
+ oracle::sccs::activate();
+}
+
+void oracle::Database::do_initialize()
+throw(RuntimeException) {
+ LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Database", "do_initialize", ANNA_FILE_LOCATION));
+
+ if(a_env != NULL) {
+ Logger::write(Logger::Warning, asString(), "Already initialized", ANNA_FILE_LOCATION);
+ return;
+ }
+
+ if(OCIInitialize(OCI_DEFAULT, 0, 0, 0, 0) != OCI_SUCCESS) {
+ string msg(asString());
+ msg += " | Cannot initialize Oracle access system";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(OCIEnvInit(&a_env, OCI_DEFAULT, 0, 0) != OCI_SUCCESS) {
+ string msg(asString());
+ msg += " | Cannot create database environment";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(OCIHandleAlloc(a_env, (void**) &a_error, OCI_HTYPE_ERROR, 0, 0) != OCI_SUCCESS) {
+ string msg(asString());
+ msg += " | Cannot create database error handler";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ WHEN_MULTITHREAD(
+ OCIThreadProcessInit();
+ anna_dbms_oracle_check(OCIThreadInit(a_env, a_error), a_error);
+ );
+ initializeDecimalPoint();
+ dbms::Database::do_initialize();
+}
+
+//----------------------------------------------------------------------------------
+// Libera todos los manejadores asociados a �te entorno.
+//----------------------------------------------------------------------------------
+oracle::Database::~Database() {
+ LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Database", "~Database", ANNA_FILE_LOCATION));
+
+ if(a_error) {
+ OCIHandleFree(a_env, OCI_HTYPE_ERROR);
+ a_env = NULL;
+ }
+
+ if(a_env) {
+ OCIHandleFree(a_env, OCI_HTYPE_ENV);
+ a_env = NULL;
+ }
+}
+
+dbms::Connection* oracle::Database::allocateConnection(const std::string& name, const char* user, const char* password)
+throw(RuntimeException) {
+ return new Connection(*this, name, user, password);
+}
+
+dbms::Statement* oracle::Database::allocateStatement(const char* name, const std::string& expression, const bool isCritical)
+throw(RuntimeException) {
+ return new Statement(*this, name, expression, isCritical);
+}
+
+dbms::InputBind* oracle::Database::allocateInputBind(const char* name, Data& data)
+throw(RuntimeException) {
+ return new InputBind(name, data);
+}
+
+void oracle::Database::deallocate(dbms::InputBind* inputBind)
+throw() {
+ delete(InputBind*) inputBind;
+}
+
+dbms::OutputBind* oracle::Database::allocateOutputBind(const char* name, Data& data)
+throw(RuntimeException) {
+ return new OutputBind(name, data);
+}
+
+void oracle::Database::deallocate(dbms::OutputBind* outputBind)
+throw() {
+ delete(OutputBind*) outputBind;
+}
+
+/**
+ * Ojo no se activa el uso de forma definitiva porque afectaría a todo el programa, cualquier
+ * conversion texto -> float/double que se hiciera se vería afectado por este cambio, que sólo debería
+ * aplicar a temas relaciones con la base de datos.
+ *
+ * Carga el valor del LC_NUMERIC de la correspondiente variable del entorno y luego repone el
+ * usado por defecto en las librerias del core de C.
+ */
+/*static*/
+void oracle::Database::initializeDecimalPoint()
+throw(RuntimeException) {
+ setlocale(LC_NUMERIC, "");
+ struct lconv *locale = localeconv();
+
+ if(*locale->decimal_point != '.')
+ st_decimalPoint = *locale->decimal_point;
+
+ setlocale(LC_NUMERIC, "C");
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <oci.h>
+
+#include <anna/dbms.oracle/Descriptor.hpp>
+#include <anna/dbms.oracle/Database.hpp>
+#include <anna/dbms.oracle/Connection.hpp>
+#include <anna/dbms.oracle/ResultCode.hpp>
+
+using namespace anna;
+
+dbms::oracle::Descriptor::~Descriptor() {
+ if(*reference != NULL) {
+ OCIDescriptorFree(*reference, type);
+ *reference = NULL;
+ }
+}
+
+void dbms::oracle::Descriptor::allocate(dbms::oracle::Database& database, dbms::oracle::Connection* connection, const int _type)
+throw(RuntimeException) {
+ if(*reference != NULL)
+ return;
+
+ env = database;
+ error = database.getErrorHandler();
+ context = *connection; // Invoca al operador de conversion
+
+ try {
+ anna_dbms_oracle_check(OCIDescriptorAlloc(env, reference, type = _type, 0, 0), error);
+ } catch(DatabaseException& edb) {
+ throw RuntimeException(edb);
+ }
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <oci.h>
+
+#include <time.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/functions.hpp>
+#include <anna/core/DataBlock.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms/Float.hpp>
+#include <anna/dbms/ShortBlock.hpp>
+#include <anna/dbms/Date.hpp>
+#include <anna/dbms/TimeStamp.hpp>
+#include <anna/dbms/Database.hpp>
+
+#include <anna/dbms.oracle/oracle.hpp>
+
+using namespace std;
+using namespace anna;
+
+InputBind::InputBind(const char* name, dbms::Data& data) :
+ dbms::InputBind(name, data),
+ BaseBind(data),
+ a_ociBind(NULL) {
+}
+
+InputBind::~InputBind() {
+}
+
+// Slo se invoca una vez. Establece las variables atrav� de las que nos vamos a poder
+// comunicar con Oracle, para indicar la longitud de una variable, o su estado de nulo o
+// no nulo.
+void InputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos)
+throw(RuntimeException, dbms::DatabaseException) {
+ if(a_ociBind != NULL)
+ return;
+
+ Data& data = anna::dbms::Bind::getData();
+
+ if(data.getType() == Data::Type::LongBlock) {
+ string msg("anna::dbms::oracle::InputBind::prepare | ");
+ msg += data.asString();
+ msg += " | This RDBMS doesn't support BLOB type as BindInput (see anna::dbms::OutputBind::write)";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ Database& database = static_cast <Database&>(dbmsStatement->getDatabase());
+ OCIError* error = database.getErrorHandler();
+ Statement* statement(static_cast <Statement*>(dbmsStatement));
+ oci_param ociparam = getOCIParam(database, static_cast <oracle::Connection*>(connection), data);
+
+ if(data.isNulleable() == false) {
+ anna_dbms_oracle_check(
+ OCIBindByPos(
+ *statement, &a_ociBind, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type,
+ 0, ociparam.length, 0, 0, 0, OCI_DEFAULT
+ ),
+ error
+ );
+ } else {
+ anna_dbms_oracle_check(
+ OCIBindByPos(
+ *statement, &a_ociBind, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type,
+ &a_nullIndicator, ociparam.length, 0, 0, 0, OCI_DEFAULT
+ ),
+ error
+ );
+ }
+
+ LOGDEBUG(
+ std::string msg("anna::dbms::oracle::InputBind::prepare | ");
+ msg += asString();
+ msg += " | Sentence: ";
+ msg += statement->getName();
+ msg += " | Position: ";
+ msg += functions::asString(pos);
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+}
+
+//-------------------------------------------------------------------------------
+// Establece la informacin mediante la que conectamos con Oracle. Todos los
+// par�etros que modificamos en �te m�odo tienen efecto en la llamada a Oracle
+// debido cmo hemos invocamo al m�odo OCIBindByPos.
+//
+// Todo esto se podr� haber hecho en la anna::dbms::DataBlock pero exigir�
+// definir una clase distinta para cada RDBMS. Creo que los Binds particulares de
+// cada base de datos se ocupen toda la complejidad de convertir los datos.
+//-------------------------------------------------------------------------------
+void InputBind::code() const
+throw(RuntimeException) {
+ InputBind* _this = const_cast <InputBind*>(this);
+ Data& data = _this->getData();
+
+ if((_this->a_nullIndicator = data.isNull() ? -1 : 0) == -1)
+ return;
+
+ switch(data.getType()) {
+ case Data::Type::String:
+ throw RuntimeException("anna::dbms::oracle::InputBind::code not implemented for Data::Type::String", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::Integer:
+ throw RuntimeException("anna::dbms::oracle::InputBind::code not implemented for Data::Type::Integer", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::Float:
+ codeFloat(data);
+ break;
+ case Data::Type::ShortBlock:
+ codeShortBlock(data);
+ break;
+ case Data::Type::LongBlock:
+ throw RuntimeException("anna::dbms::oracle::InputBind::code not implemented for Data::Type::LongBlock", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::Date:
+ case Data::Type::TimeStamp:
+
+ try {
+ codeDate(data);
+ } catch(DatabaseException& edb) {
+ throw RuntimeException(edb);
+ }
+
+ break;
+ }
+}
+
+/**
+ * Transfiere el valor numerico del float, al buffer reservado para
+ * ubiucarlo como una cadena. Ã\89ste buffer es el que está "conectado" con
+ * Oracle (tm).
+ */
+void InputBind::codeFloat(dbms::Data& data) const
+throw() {
+ dbms::Float& _float = static_cast <dbms::Float&>(data);
+ InputBind* _this = const_cast <InputBind*>(this);
+ char* buffer = (char*) _this->a_ofb->getData();
+ snprintf(buffer, FloatSize, _float.getFormat(), _float.getValue());
+ const char decimalPoint = oracle::Database::getDecimalPoint();
+
+ if(decimalPoint != 0) {
+ char* point = anna_strchr(buffer, '.');
+
+ if(point != NULL)
+ *point = decimalPoint;
+ }
+}
+
+void InputBind::codeShortBlock(dbms::Data& data) const
+throw() {
+ const int length = static_cast <dbms::ShortBlock&>(data).getSize();
+ InputBind* _this = const_cast <InputBind*>(this);
+
+ if(length == 0) {
+ _this->a_ofb->clear();
+ _this->a_length = 0;
+ return;
+ }
+
+ const char* src = (const char*) data.getBuffer();
+
+ char* dest = const_cast <char*>(a_ofb->getData());
+
+ int j = 0;
+
+ for(int i = 0; i < length; i ++) {
+ dest [j ++] = asCharacter((src [i] & 0xf0) >> 4);
+ dest [j ++] = asCharacter(src [i] & 0x0f);
+ }
+
+ dest [j ++] = 0;
+ _this->a_length = j;
+}
+
+void InputBind::codeDate(dbms::Data& data) const
+throw(RuntimeException, dbms::DatabaseException) {
+ dbms::Date& date = static_cast <dbms::Date&>(data);
+ ub4 fsec(0);
+
+ if(data.getType() == Data::Type::TimeStamp)
+ fsec = static_cast <dbms::TimeStamp&>(data).getFractionalSecond() * 1000;
+
+ anna_dbms_oracle_check(
+ OCIDateTimeConstruct(
+ a_datetime.env, a_datetime.error, a_datetime.handle,
+ date.getYear(), date.getMonth(), date.getDay(), date.getHour(), date.getMinute(), date.getSecond(), fsec, NULL, 0
+ ),
+ a_datetime.error
+ );
+ ub4 errorMask(0);
+ anna_dbms_oracle_check(
+ OCIDateTimeCheck(a_datetime.env, a_datetime.error, a_datetime.handle, &errorMask),
+ a_datetime.error
+ );
+
+ if(errorMask != 0) {
+ string msg(data.asString());
+ msg += anna::functions::asHexText(" | Invalid date | ErrorCode: ", (int) errorMask);
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <oci.h>
+#include <orl.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/DataBlock.hpp>
+
+#include <anna/dbms/Float.hpp>
+#include <anna/dbms/ShortBlock.hpp>
+#include <anna/dbms/LongBlock.hpp>
+#include <anna/dbms/String.hpp>
+#include <anna/dbms/Date.hpp>
+#include <anna/dbms/TimeStamp.hpp>
+
+#include <anna/dbms.oracle/oracle.hpp>
+
+using namespace anna;
+using namespace std;
+
+OutputBind::OutputBind(const char* name, dbms::Data& data) :
+ dbms::OutputBind(name, data),
+ BaseBind(data),
+ a_ociDefine(NULL) {
+}
+
+OutputBind::~OutputBind() {
+}
+
+void OutputBind::prepare(dbms::Statement* dbmsStatement, dbms::Connection* connection, const int pos)
+throw(dbms::DatabaseException) {
+ if(a_ociDefine != NULL)
+ return;
+
+ Database& database(static_cast <Database&>(dbmsStatement->getDatabase()));
+ OCIError* error = database.getErrorHandler();
+ Statement* statement(static_cast <Statement*>(dbmsStatement));
+ dbms::Data& data = anna::dbms::Bind::getData();
+ oci_param ociparam = getOCIParam(database, static_cast <oracle::Connection*>(connection), data);
+
+ if(data.isNulleable() == false) {
+ anna_dbms_oracle_check(
+ OCIDefineByPos(
+ *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type,
+ 0, ociparam.length, 0, OCI_DEFAULT
+ ),
+ error
+ );
+ } else {
+ anna_dbms_oracle_check(
+ OCIDefineByPos(
+ *statement, &a_ociDefine, error, pos, ociparam.buffer, ociparam.maxLength, ociparam.type,
+ &a_nullIndicator, ociparam.length, 0, OCI_DEFAULT
+ ),
+ error
+ );
+ }
+
+ LOGDEBUG(
+ std::string msg("anna::dbms::oracle::OutputBind::prepare | ");
+ msg += asString();
+ msg += " | Sentence: ";
+ msg += statement->getName();
+ msg += " | Position: ";
+ msg += functions::asString(pos);
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+}
+
+//-------------------------------------------------------------------------------
+// Transfiere la informacin obtenida desde Oracle. Todos los comprobados en �te
+// m�odo son parametros que modificados al ejecuta la sentencia Oracle debido cmo
+// hemos invocamo al m�odo OCIDefineByPos
+//
+// Todo esto se podr� haber hecho en la anna::dbms::DataBlock pero exigir�
+// definir una clase distinta para cada RDBMS. Creo que los Binds particulares de
+// cada base de datos se ocupen toda la complejidad de convertir los datos.
+//
+// (1) Truco para fijar el contenido y la longitud actual.
+//-------------------------------------------------------------------------------
+void OutputBind::decode() const
+throw(RuntimeException) {
+ OutputBind* _this = const_cast <OutputBind*>(this);
+ char* str;
+ Data& data = _this->getData();
+ data.setNull(a_nullIndicator < 0);
+
+ switch(data.getType()) {
+ case Data::Type::String:
+ str = (char*) data.getBuffer();
+
+ if(data.isNull() == true)
+ *str = 0;
+ else
+ dbms::String::strip(str);
+
+ break;
+ case Data::Type::Integer:
+ throw RuntimeException("anna::dbms::oracle::OutputBind::decode not implemented for Data::Type::Integer", ANNA_FILE_LOCATION);
+ break;
+ case Data::Type::Float:
+ decodeFloat(data);
+ break;
+ case Data::Type::ShortBlock:
+ decodeShortBlock(data);
+ break;
+ case Data::Type::LongBlock:
+ decodeLongBlock(data);
+ break;
+ case Data::Type::Date:
+ case Data::Type::TimeStamp:
+
+ try {
+ decodeDate(data);
+ } catch(DatabaseException& edb) {
+ throw RuntimeException(edb);
+ }
+
+ break;
+ }
+}
+
+void OutputBind::decodeFloat(dbms::Data& data) const
+throw(RuntimeException) {
+ dbms::Float& _float = static_cast <dbms::Float&>(data);
+
+ if(data.isNull() == true) {
+ _float = 0.0;
+ return;
+ }
+
+ char* _data = (char*) a_ofb->getData();
+ const char decimalPoint = oracle::Database::getDecimalPoint();
+
+ if(decimalPoint != 0) {
+ char* point = anna_strchr(_data, decimalPoint);
+
+ if(point != NULL)
+ *point = '.';
+ }
+
+ sscanf(_data, _float.getFormat(), (float*) _float.getBuffer());
+}
+
+void OutputBind::decodeShortBlock(dbms::Data& data) const
+throw(RuntimeException) {
+ const anna::DataBlock& constdbms(static_cast <dbms::ShortBlock&>(data).getValue());
+ anna::DataBlock& dataBlock(const_cast <anna::DataBlock&>(constdbms));
+
+ if(data.isNull() == true) {
+ dataBlock.clear();
+ return;
+ }
+
+ const char* src = a_ofb->getData();
+
+ char* dest = (char*) dataBlock.getData();
+
+ unsigned char hex;
+
+ int j = 0;
+
+ for(int i = 1; i < a_length; i += 2, j ++) {
+ hex = asByte(src [i - 1]) << 4;
+ hex |= asByte(src [i]);
+ dest [j] = hex;
+ }
+
+ dataBlock.clear();
+ dataBlock.allocate(j); // (1)
+}
+
+//--------------------------------------------------------------------------------------------
+// (1) Offset = 1 => primer caracter.
+//--------------------------------------------------------------------------------------------
+void OutputBind::decodeLongBlock(dbms::Data& data) const
+throw(RuntimeException) {
+ const anna::DataBlock& constdbms(static_cast <dbms::LongBlock&>(data).getValue());
+ anna::DataBlock& dataBlock(const_cast <anna::DataBlock&>(constdbms));
+ dataBlock.clear();
+
+ if(data.isNull() == true)
+ return;
+
+ ub1* buffer;
+ ub4 maxLength;
+ ub4 length;
+ sword ret;
+ bool stop = false;
+ ub4 offset = 1; // (1)
+
+ try {
+ buffer = (ub1*) a_ofb->getData();
+ maxLength = a_ofb->getSize();
+ length = 0;
+
+ do {
+ ret = OCILobRead(a_blob.context, a_blob.error, a_blob.handle, &length, offset, buffer, maxLength, 0, 0, 0, SQLCS_IMPLICIT);
+
+ switch(ret) {
+ case OCI_SUCCESS:
+ dataBlock += anna::DataBlock((const char*) buffer, length, false);
+ stop = true;
+ break;
+ case OCI_NEED_DATA:
+ dataBlock += anna::DataBlock((const char*) buffer, length, false);
+ offset += length;
+ break;
+ default:
+ throw dbms::DatabaseException(oracle::ResultCode(ret, a_blob.error), ANNA_FILE_LOCATION);
+ }
+ } while(stop == false);
+ } catch(dbms::DatabaseException& edbms) {
+ throw RuntimeException(edbms);
+ }
+}
+
+void OutputBind::do_write(const dbms::LongBlock& data) const
+throw(RuntimeException, dbms::DatabaseException) {
+ const anna::DataBlock& dataBlock = data.getValue();
+
+ if(a_blob.handle == NULL) {
+ string msg("anna::dbms::oracle::OutputBind::do_write | ");
+ msg += data.asString();
+ msg += " | BLOB must be loaded before modification";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ ub1* buffer = (ub1*) dataBlock.getData();
+ ub4 length = dataBlock.getSize();
+ anna_dbms_oracle_check(
+ OCILobWrite(a_blob.context, a_blob.error, a_blob.handle, &length, (ub4) 1, buffer, length, OCI_ONE_PIECE, 0, 0, 0, SQLCS_IMPLICIT),
+ a_blob.error
+ );
+}
+
+void OutputBind::decodeDate(dbms::Data& data) const
+throw(RuntimeException, dbms::DatabaseException) {
+ if(data.isNull() == true)
+ return;
+
+ Date& date = static_cast <Date&>(data);
+ sb2 year;
+ ub1 month, day;
+ anna_dbms_oracle_check(
+ OCIDateTimeGetDate(a_datetime.env, a_datetime.error, a_datetime.handle, &year, &month, &day),
+ a_datetime.error
+ );
+ date.setYear(year);
+ date.setMonth(month);
+ date.setDay(day);
+ ub1 hour, min, sec;
+ ub4 fsec;
+ sword status = OCIDateTimeGetTime(a_datetime.env, a_datetime.error, a_datetime.handle, &hour, &min, &sec, &fsec);
+
+ if(status == OCI_SUCCESS) {
+ date.setHour(hour);
+ date.setMinute(min);
+ date.setSecond(sec);
+
+ if(data.getType() == Data::Type::TimeStamp)
+ static_cast <dbms::TimeStamp&>(data).setFractionalSecond(fsec / 1000);
+ } else {
+ date.setHour(0);
+ date.setMinute(0);
+ date.setSecond(0);
+
+ if(data.getType() == Data::Type::TimeStamp)
+ static_cast <dbms::TimeStamp&>(data).setFractionalSecond(0);
+ }
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <oci.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms.oracle/ResultCode.hpp>
+
+using namespace anna;
+using namespace anna::dbms;
+
+oracle::ResultCode::ErrorDecoder oracle::ResultCode::st_errorDecoder;
+
+oracle::ResultCode::ResultCode(const int status, OCIError* error) :
+ dbms::ResultCode(0, NULL, &st_errorDecoder) {
+ char errorText [dbms::ResultCode::MaxErrorLen];
+ int errorCode = status;
+
+ if(status == OCI_SUCCESS) {
+ dbms::ResultCode::set(OCI_SUCCESS, NULL);
+ return;
+ } else if(status == OCI_SUCCESS_WITH_INFO) {
+ OCIErrorGet(error, (ub4) 1, (text*) 0, &errorCode, (unsigned char*) errorText, (ub4) sizeof(errorText), OCI_HTYPE_ERROR);
+ dbms::ResultCode::set(OCI_SUCCESS, errorText);
+ LOGINFORMATION(Logger::information(asString(), ANNA_FILE_LOCATION));
+ return;
+ }
+
+ switch(status) {
+ case OCI_ERROR:
+ OCIErrorGet(error, (ub4) 1, (text*) 0, &errorCode, (unsigned char*) errorText, (ub4) sizeof(errorText), OCI_HTYPE_ERROR);
+ break;
+ case OCI_NEED_DATA: anna_strcpy(errorText, "OCI | Need data"); break;
+ case OCI_NO_DATA: anna_strcpy(errorText, "OCI | Data not found"); break;
+ case OCI_INVALID_HANDLE: anna_strcpy(errorText, "OCI | Invalid handle"); break;
+ default: sprintf(errorText, "OCI | Error code: %d", status); break;
+ }
+
+ dbms::ResultCode::set(errorCode, errorText);
+}
+
+bool oracle::ResultCode::ErrorDecoder::notFound(const int errorCode) const
+throw() {
+ return errorCode == OCI_NO_DATA;
+}
+
+bool oracle::ResultCode::ErrorDecoder::successful(const int errorCode) const
+throw() {
+ return errorCode == OCI_SUCCESS;
+}
+
+bool oracle::ResultCode::ErrorDecoder::lostConnection(const int errorCode) const
+throw() {
+ return errorCode == 28 || errorCode == 3113 || errorCode == 3114 || errorCode == 1012 || errorCode == 12570 || errorCode == 12571;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <oci.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/dbms.oracle/oracle.hpp>
+
+using namespace std;
+using namespace anna;
+
+dbms::oracle::Statement::~Statement() {
+ if(a_ociStmt)
+ OCIHandleFree(a_ociStmt, OCI_HTYPE_STMT);
+}
+
+void dbms::oracle::Statement::prepare(dbms::Connection* dbmsConnection)
+throw(RuntimeException, dbms::DatabaseException) {
+ LOGMETHOD(TraceMethod tm("anna::dbms::oracle::Statement", "prepare", ANNA_FILE_LOCATION));
+ Connection* connection(static_cast <Connection*>(dbmsConnection));
+ Database& dbms(static_cast <Database&>(connection->getDatabase()));
+ a_ociError = dbms.getErrorHandler();
+
+ if(a_ociStmt != NULL) {
+ anna_dbms_oracle_check(OCIHandleFree(a_ociStmt, OCI_HTYPE_STMT), a_ociError);
+ a_ociStmt = NULL;
+ }
+
+ const char* expression = dbms::oracle::Statement::getExpression().c_str();
+
+ anna_dbms_oracle_check(OCIHandleAlloc(dbms, (void**) &a_ociStmt, OCI_HTYPE_STMT, 0, 0), a_ociError);
+
+ anna_dbms_oracle_check(
+ OCIStmtPrepare(a_ociStmt, a_ociError, (text*) expression, anna_strlen(expression), OCI_NTV_SYNTAX, OCI_DEFAULT),
+ a_ociError
+ );
+
+ int pos = 1;
+
+ for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++)
+ inputBind(ii)->prepare(this, dbmsConnection, pos ++);
+
+ pos = 1;
+
+ for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++)
+ outputBind(oo)->prepare(this, dbmsConnection, pos ++);
+}
+
+dbms::ResultCode dbms::oracle::Statement::execute(dbms::Connection* dbmsConnection)
+throw(RuntimeException, dbms::DatabaseException) {
+ Connection* connection(static_cast <Connection*>(dbmsConnection));
+
+ for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) {
+ inputBind(ii)->code();
+ LOGDEBUG(
+ string msg("anna::dbms::oracle::Statement::InputBind: ");
+ msg += inputBind(ii)->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ }
+
+ const sword status = OCIStmtExecute(*connection, a_ociStmt, a_ociError, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ a_firstFetch = false;
+
+ ResultCode result(status, a_ociError);
+
+ if(result.successful() == true && result.notFound() == false) {
+ for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) {
+ outputBind(oo)->decode();
+ LOGDEBUG(
+ string msg("anna::dbms::oracle::Statement::OutputBind: ");
+ msg += outputBind(oo)->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ }
+
+ a_firstFetch = true;
+ }
+
+ return result;
+}
+
+//-------------------------------------------------------------------------------------------------
+// (1) Si es una consulta de seleccin, entonces, nada m� ejecutar la sentencia el primer registro
+// encontrado ya est�cargado en las variables de salida, para obtener los siguientes hay que invocar
+// a fetch. Vamos a hacer este esquema m� gen�ico de forma que siempre habr�que invocar a
+// 'fetch' para obtener los datos, pero en Oracle, la primera llamada no har�nada.
+//-------------------------------------------------------------------------------------------------
+bool dbms::oracle::Statement::fetch()
+throw(RuntimeException, dbms::DatabaseException) {
+ bool result;
+
+ if(a_firstFetch == true) { // (1)
+ a_firstFetch = false;
+ result = true;
+ } else {
+ ResultCode resultCode(OCIStmtFetch(a_ociStmt, a_ociError, 1, OCI_FETCH_NEXT, OCI_DEFAULT), a_ociError);
+ result = resultCode.successful();
+
+ if(result == false && resultCode.notFound() == false)
+ Logger::write(Logger::Error, asString(), resultCode.asString(), ANNA_FILE_LOCATION);
+
+ if(result == true) {
+ for(output_iterator oo = output_begin(), maxoo = output_end(); oo != maxoo; oo ++) {
+ outputBind(oo)->decode();
+ LOGDEBUG(Logger::write(Logger::Debug, outputBind(oo)->asString(), ANNA_FILE_LOCATION));
+ }
+ }
+ }
+
+ LOGDEBUG(
+ string msg("anna::dbms::oracle::Statement::fetch | Result: ");
+ msg += functions::asString(result);
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ return result;
+}
+
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/internal/sccs.hpp>
+#include <anna/dbms/internal/sccs.hpp>
+#include <anna/dbms.oracle/internal/sccs.hpp>
+
+#include <anna/core/internal/ModuleManager.hpp>
+
+anna_define_sccs_tag_ex(dbms_oracle, dbms.oracle, 1);
+
+void anna::dbms::oracle::sccs::activate()
+throw() {
+ dbms::sccs::activate();
+ ModuleManager::instantiate().insert(anna_use_sccs_tag(dbms_oracle), "00");
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/dbms/Bind.hpp>
+#include <anna/dbms/Data.hpp>
+
+using namespace anna;
+
+std::string dbms::Bind::asString() const
+throw() {
+ std::string result("dbms::Bind { Name: ");
+ result += a_name;
+ result += " | ";
+ result += a_data.asString();
+ return result += " }";
+}
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/config/defines.hpp>
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/xml/Node.hpp>
+#include <anna/xml/Attribute.hpp>
+
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Statement.hpp>
+#include <anna/dbms/Statement.hpp>
+
+using namespace std;
+using namespace anna;
+
+//-----------------------------------------------------------------------------------------------------------
+// (1) Si no tiene variables de salida => consideramos que es un update, insert o delete.
+//-----------------------------------------------------------------------------------------------------------
+dbms::ResultCode dbms::Connection::execute(Statement* statement)
+throw(RuntimeException, dbms::DatabaseException) {
+ if(statement == NULL) {
+ string msg(asString());
+ msg += " | Cannot execute a NULL sentence";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGMETHOD(TraceMethod ttmm("dbms::Connection", "execute", ANNA_FILE_LOCATION));
+ LOGDEBUG(
+ string msg("Using Connection | ");
+ msg += asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+ Guard guard(statement, "Statement from dbms::Connection::execute");
+ const Microsecond init = functions::hardwareClock();
+
+ if(statement->a_prepared == false) {
+ statement->prepare(this);
+ statement->a_prepared = true;
+ }
+
+ LOGDEBUG(
+ string msg("dbms::Connection::execute | ");
+ msg += statement->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+
+ if(statement->requiresCommit() == true && a_rollbackPending == true) { // (1)
+ string msg("dbms::Connection::execute | ");
+ msg += asString();
+ msg += " | Connection has pending ROLLBACKS for execution";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ ResultCode result;
+ int tryCounter = 0;
+
+ while(true) {
+ result = statement->execute(this);
+
+ if(result.lostConnection() == false)
+ break;
+
+ string msg = asString();
+ msg += " | ";
+ msg += statement->asString();
+ msg += " | ";
+ msg += result.asString();
+ Logger::alert(msg, ANNA_FILE_LOCATION);
+ a_database.recover(*this, ++ tryCounter);
+ }
+
+ statement->measureTiming(init, functions::hardwareClock());
+
+ if(result.successful() == false && result.notFound() == false) {
+ string msg(asString());
+ msg += " | Sentence: ";
+ msg += statement->getName();
+ Logger::write(Logger::Error, msg, result.asString(), ANNA_FILE_LOCATION);
+ }
+
+ if(statement->requiresCommit() == true) { // (1)
+ if(result.successful() == false) {
+ if(statement->isCritical() == true) {
+ a_rollbackPending = true;
+ throw DatabaseException(statement->getName(), result, ANNA_FILE_LOCATION);
+ }
+ } else {
+ a_commitPending ++;
+
+ if(a_maxCommitPending > 0 && a_commitPending > a_maxCommitPending) {
+ commit();
+ a_commitPending = 0;
+ a_rollbackPending = false;
+ }
+ }
+ }
+
+ return result;
+}
+
+//------------------------------------------------------------------------------------------------
+// (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas
+// y los volcados de contexto.
+//------------------------------------------------------------------------------------------------
+void dbms::Connection::commit()
+throw(RuntimeException, dbms::DatabaseException) {
+ LOGINFORMATION(
+ string msg("dbms::Connection::commit | ");
+ msg += asString();
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+
+ if(isAvailable() == false) {
+ string msg(asString());
+ msg += " | Unavailable connection";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ do_commit();
+ a_commitPending = 0; // (1)
+ a_rollbackPending = false;
+}
+
+//------------------------------------------------------------------------------------------------
+// (1) Esto no es estrictamente necesario, pero lo hacemos para que no nos despisten las trazas
+// y los volcados de contexto.
+//------------------------------------------------------------------------------------------------
+void dbms::Connection::rollback()
+throw() {
+ LOGWARNING(
+ string msg("dbms::Connection::rollback | ");
+ msg += asString();
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ );
+
+ if(isAvailable() == false) {
+ string msg(asString());
+ msg += " | Unavailable connection";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ do_rollback();
+ a_commitPending = 0;
+ a_rollbackPending = false; // (1)
+}
+
+void dbms::Connection::lock()
+throw(RuntimeException) {
+ if(isAvailable() == false) {
+ string msg(asString());
+ msg += " | Unavailable connection";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ comm::Resource::lock();
+
+ if(a_lockingCounter ++ == 0) {
+ a_commitPending = 0;
+ a_rollbackPending = false;
+
+ try {
+ if(do_beginTransaction() == true)
+ a_commitPending = 1;
+ } catch(dbms::DatabaseException& edb) {
+ throw RuntimeException(edb);
+ }
+ }
+
+ LOGDEBUG(
+ string msg("dbms::Connection::lock | ");
+ msg += asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+}
+
+void dbms::Connection::unlock()
+throw() {
+ LOGDEBUG(
+ string msg("dbms::Connection::unlock | ");
+ msg += asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+
+ if(-- a_lockingCounter <= 0) {
+ a_lockingCounter = 0;
+
+ try {
+ if(a_rollbackPending == true)
+ rollback();
+ else if(a_commitPending > 0)
+ commit();
+ } catch(Exception& ex) {
+ Logger::emergency(ex.getText(), ex.getFromFile(), ex.getFromLine());
+ }
+ }
+
+ comm::Resource::unlock();
+}
+
+string dbms::Connection::asString() const
+throw() {
+ string result("dbms::Connection { ");
+ result += comm::Resource::asString();
+ result += " | ";
+ result += a_database.asString();
+ result += " | user: ";
+ result += a_user;
+ result += functions::asText(" | LockingCounter: ", a_lockingCounter);
+ result += functions::asText(" | password: ******* | CommitPending: ", a_commitPending);
+ result += functions::asText(" | RollbackPending: ", a_rollbackPending);
+ return result += " }";
+}
+
+xml::Node* dbms::Connection::asXML(xml::Node* parent) const
+throw() {
+ xml::Node* result = comm::Resource::asXML(parent);
+ result->createAttribute("User", a_user);
+ result->createAttribute("LockingCounter", a_lockingCounter);
+ result->createAttribute("CommitPending", a_commitPending);
+ result->createAttribute("RollbackPending", functions::asString(a_rollbackPending));
+ return result;
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/Data.hpp>
+
+using namespace anna;
+
+std::string dbms::Data::asString() const
+throw() {
+ static const char* typeName [] = { "Integer", "String", "Float", "ShortBlock", "LongBlock", "Date", "TimeStamp" };
+ std::string result("dbms::Data { Type: ");
+ result += typeName [a_type];
+ result += " | Buffer: ";
+ result += functions::asHexString(anna_ptrnumber_cast(a_buffer));
+ result += " | MaxSize: ";
+ result += functions::asString(a_maxSize);
+ result += " | Null: ";
+ result += functions::asString(a_isNull);
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <stdlib.h>
+#include <locale.h>
+
+#include <string>
+#include <algorithm>
+
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/xml/Node.hpp>
+#include <anna/xml/Attribute.hpp>
+
+#include <anna/comm/INetAddress.hpp>
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Statement.hpp>
+#include <anna/dbms/FailRecoveryHandler.hpp>
+#include <anna/dbms/internal/sccs.hpp>
+#include <anna/dbms/Float.hpp>
+#include <anna/dbms/StatementTranslator.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+Database::Database(const char* className, const char* dbmsName) :
+ Component(className),
+ a_name((dbmsName == NULL) ? "local" : dbmsName),
+ a_type((dbmsName == NULL) ? Type::Local : Type::Remote),
+ a_failRecoveryHandler(NULL),
+ a_statementTranslator(NULL) {
+ dbms::sccs::activate();
+}
+
+Database::~Database() {
+ stop();
+}
+
+void Database::do_initialize()
+throw(RuntimeException) {
+ LOGMETHOD(TraceMethod tm("dbms::Database", "do_initialize", ANNA_FILE_LOCATION));
+ int counter(0);
+ bool error = false;
+
+ for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) {
+ try {
+ connection(iic)->open();
+ counter ++;
+ } catch(Exception& ex) {
+ ex.trace();
+ error = true;
+ }
+ }
+
+ if(counter == 0 && error == true) {
+ string msg(asString());
+ msg += " | No available connections";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGINFORMATION(
+ Logger::information(asString(), ANNA_FILE_LOCATION);
+ );
+}
+
+void Database::do_stop()
+throw() {
+ LOGMETHOD(TraceMethod tm("dbms::Database", "do_stop", ANNA_FILE_LOCATION));
+
+ try {
+ Connection* _connection;
+
+ for(connection_iterator iic = connection_begin(), maxiic = connection_end(); iic != maxiic; iic ++) {
+ _connection = connection(iic);
+ _connection->close();
+ delete _connection;
+ }
+
+ a_connections.clear();
+ } catch(Exception& ex) {
+ ex.trace();
+ a_connections.clear();
+ }
+}
+
+/**
+ * Para evitar que todos los clones usen la misma conexion a la base de datos, se realiza en
+ * cada uno de ellos una re-conexion, es decir, se cierra la original (abierta por el proceso
+ * padre) y se abre una nueva conexion con los mismos parametros y contra la misma base de datos.
+ */
+void Database::do_cloneChild()
+throw(RuntimeException) {
+ LOGMETHOD(TraceMethod tm("dbms::Database", "do_cloneChild", ANNA_FILE_LOCATION));
+
+ for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
+ dbms::Connection* conn = connection(ii);
+ LOGDEBUG(
+ string msg("dbms::Database::do_cloneChild | ");
+ msg += conn->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ recover(*conn, 0);
+ }
+}
+
+Connection* Database::createConnection(const char* name, const char* user, const char* password)
+throw(RuntimeException, DatabaseException) {
+ Guard guard(this, "dbms::Database (createConnection)");
+
+ if(a_connections.size() >= MaxConnection) {
+ string msg("Database::createConnection | ");
+ msg += asString();
+ msg += functions::asText(" | Cannot create more than %d connections per database", MaxConnection);
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
+ if(connection(ii)->getName() == name) {
+ string msg("Database::createConnection | ");
+ msg += asString();
+ msg += " | Connection: ";
+ msg += name;
+ msg += " | Previously registered";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+ }
+
+ string strname(name);
+ Connection* result = allocateConnection(strname, user, password);
+
+ if(result == NULL) {
+ string msg(asString());
+ msg += " | ";
+ msg += strname;
+ msg += " | Unable to instance connection";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg("dbms::Database::createConnection | ");
+ msg += result->asString();
+ Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION);
+ );
+
+ if(getState() == Component::State::Running) {
+ try {
+ result->open();
+ a_connections.push_back(result);
+ } catch(RuntimeException& ex) {
+ ex.trace();
+ delete result;
+ throw;
+ } catch(DatabaseException& edbms) {
+ edbms.trace();
+ delete result;
+ throw;
+ }
+ } else
+ a_connections.push_back(result);
+
+ return result;
+}
+
+Connection& Database::findConnection(const char* name)
+throw(RuntimeException) {
+ Guard guard(this, "dbms::Database (findConnection)");
+ Connection* result = NULL;
+
+ for(connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++) {
+ if(anna_strcmp(connection(ii)->getName().c_str(), name) == 0) {
+ result = connection(ii);
+ break;
+ }
+ }
+
+ if(result == NULL) {
+ string msg("Database::findConnection | ");
+ msg += asString();
+ msg += " | Conexion: ";
+ msg += name;
+ msg += " | Unregistered";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(result->isAvailable() == false || result->isEnabled() == false) {
+ string msg("Database::findConnection | ");
+ msg += asString();
+ msg += " | Connection: ";
+ msg += name;
+ msg += " | Unavailable";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg("Database::findConnection | ");
+ msg += result->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ return *result;
+}
+
+Statement* Database::createStatement(const char* name, const char* expression, const bool isCritical)
+throw(RuntimeException) {
+ if(findStatement(name) != NULL)
+ throw RuntimeException(functions::asString("Sentence: %s | Name already in use", name), ANNA_FILE_LOCATION);
+
+ Guard guard(this, "dbms::Database::createStatement");
+
+ if(a_statementTranslator != NULL)
+ expression = a_statementTranslator->apply(expression);
+
+ Statement* result = allocateStatement(name, expression, isCritical);
+ LOGDEBUG(
+ string msg("dbms::Database::createStatement | ");
+ msg += result->asString();
+
+ if(a_statementTranslator != NULL) {
+ msg += " | Translator: ";
+ msg += a_statementTranslator->getName();
+ }
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ a_statements.push_back(result);
+ return result;
+}
+
+Statement* Database::findStatement(const char* name)
+throw() {
+ Guard guard(this, "dbms::Database::findStatement");
+ vector <Statement*>::iterator ii, maxii;
+ Statement* result(NULL);
+
+ for(ii = a_statements.begin(), maxii = a_statements.end(); ii != maxii; ii ++) {
+ if(anna_strcmp((*ii)->getName().c_str(), name) == 0) {
+ result = *ii;
+ break;
+ }
+ }
+
+ return result;
+}
+
+void Database::releaseStatement(Statement* statement)
+throw() {
+ if(statement == NULL) {
+ Logger::write(Logger::Warning, asString(), "Cannot release a NULL SQL sentence", ANNA_FILE_LOCATION);
+ return;
+ }
+
+ LOGDEBUG(
+ string msg("dbms::Database::releaseStatement | ");
+ msg += statement->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ Guard guard(this, "dbms::Database::releaseStatement");
+ vector <Statement*>::iterator end = a_statements.end();
+ vector <Statement*>::iterator ii = find(a_statements.begin(), end, statement);
+
+ if(ii != end) {
+ a_statements.erase(ii);
+ delete statement;
+ }
+}
+
+void Database::recover(Connection& connection, const int tryCounter)
+throw(RuntimeException) {
+ try {
+ connection.close();
+ connection.open();
+ } catch(DatabaseException& edbms) {
+ edbms.trace();
+
+ if(a_failRecoveryHandler != NULL)
+ a_failRecoveryHandler->apply(connection, tryCounter);
+ }
+}
+
+string Database::asString() const
+throw() {
+ string result("dbms::Database { ");
+ result += Component::asString();
+
+ if(a_type == Type::Local)
+ result += " | Type: Local";
+ else {
+ result += " | Type: Remote | Name: ";
+ result += a_name;
+ }
+
+ return result += " }";
+}
+
+xml::Node* Database::asXML(xml::Node* parent) const
+throw() {
+ parent = Component::asXML(parent);
+ xml::Node* result = parent->createChild("dbms.Database");
+ xml::Node* node;
+ result->createAttribute("Type", (a_type == Type::Local) ? "Local" : "Remote");
+
+ if(a_type != Type::Local)
+ result->createAttribute("Name", a_name);
+
+ if(a_statementTranslator != NULL)
+ result->createAttribute("Translator", a_statementTranslator->getName());
+
+ node = result-> createChild("Connections");
+
+ for(const_connection_iterator ii = connection_begin(), maxii = connection_end(); ii != maxii; ii ++)
+ connection(ii)->asXML(node);
+
+ node = result-> createChild("Statements");
+
+ for(const_statement_iterator ii = statement_begin(), maxii = statement_end(); ii != maxii; ii ++)
+ statement(ii)->asXML(node);
+
+ return result;
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <string.h>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/Date.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+Date::Date(const bool isNulleable, const char* format) :
+ Data(Type::Date, MaxDateSize, isNulleable) {
+ Data::setBuffer(a_buffer);
+ a_buffer [0] = 0;
+ a_format = (format == NULL) ? NULL : strdup(format);
+ anna_memset(&a_value, 0, sizeof(a_value));
+}
+
+Date::Date(const Data::Type::_v type, const bool isNulleable, const char* format) :
+ Data(type, MaxDateSize, isNulleable) {
+ Data::setBuffer(a_buffer);
+ a_buffer [0] = 0;
+ a_format = (format == NULL) ? NULL : strdup(format);
+ anna_memset(&a_value, 0, sizeof(a_value));
+}
+
+Date::Date(const Date& other) :
+ Data(other) {
+ Data::setBuffer(a_buffer);
+ a_buffer [0] = 0;
+ a_format = (other.a_format == NULL) ? NULL : strdup(other.a_format);
+ anna_memcpy(&a_value, &other.a_value, sizeof(a_value));
+}
+
+Date::~Date() {
+ if(a_format != NULL)
+ free(a_format);
+}
+
+const char* dbms::Date::getCStringValue() const
+throw() {
+ const char* format;
+
+ if((format = a_format) == NULL)
+ format = "%d/%m/%Y %H:%M:%S";
+
+ return (strftime(const_cast <Date*>(this)->a_buffer, MaxDateSize, format, &a_value) == 0) ? NULL : a_buffer;
+}
+
+Date& Date::operator = (const Date & other)
+throw(RuntimeException) {
+ if(this != &other) {
+ if(other.isNull() == true) {
+ setNull(true);
+ anna_memset(&a_value, 0, sizeof(a_value));
+ } else {
+ setNull(false);
+ anna_memcpy(&a_value, &other.a_value, sizeof(a_value));
+ }
+ }
+
+ return *this;
+}
+
+void Date::setValue(const char* str)
+throw(RuntimeException) {
+ if(a_format == NULL) {
+ string msg(asString());
+ msg += " | anna::dbms::Data::setValue (const char*) requires format especification";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ tm aux;
+ char* r = strptime(str, a_format, &aux);
+
+ if(r == NULL) {
+ string msg(asString());
+ msg += " | String: ";
+ msg += str;
+ msg += " | Can't be interpreted as valid date";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ Data::setNull(false);
+ anna_memcpy(&a_value, &aux, sizeof(a_value));
+}
+
+void Date::setValue(const Second &second)
+throw(RuntimeException) {
+ tm* aux = localtime((time_t*) & second);
+
+ if(aux == NULL) {
+ string msg(asString());
+ msg += functions::asText(" | Second: ", (int) second);
+ msg += " | Can't be interpreted as valid date";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ Data::setNull(false);
+ anna_memcpy(&a_value, aux, sizeof(a_value));
+}
+
+void dbms::Date::set(const char* what, int& variable, const int value, const int min, const int max)
+throw(RuntimeException) {
+ if(value < min) {
+ string msg(what);
+ msg += functions::asText(" must be greater than or equal to ", min);
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(value > max && max != -1) {
+ string msg(what);
+ msg += functions::asText(" must be less than or equal to ", max);
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ Data::setNull(false);
+ variable = value;
+}
+
+string dbms::Date::asString() const
+throw() {
+ const char* cstring;
+ string result("dbms::Date { ");
+ result += dbms::Data::asString();
+ result += " | Format: ";
+ result += (a_format == NULL) ? "<null>" : a_format;
+ result += " | Value: ";
+
+ if(Data::isNull() == false) {
+ if((cstring = getCStringValue()) == NULL)
+ result += "<not valid>";
+ else
+ result += cstring;
+ } else
+ result += "<null>";
+
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/tracing/TraceMethod.hpp>
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Delivery.hpp>
+#include <anna/dbms/Connection.hpp>
+
+using namespace std;
+using namespace anna;
+
+void dbms::Delivery::createConnections(dbms::Database& database, const char* prefixName, const char* user, const char* password, const int n)
+throw(RuntimeException, dbms::DatabaseException) {
+ string name;
+
+ for(int i = 0; i < n; i ++) {
+ name = prefixName;
+ name += functions::asString("%04d", i);
+ this->add(database.createConnection(name.c_str(), user, password));
+ }
+
+ a_iiConnection = this->begin();
+}
+
+dbms::Connection& dbms::Delivery::getConnection()
+throw(RuntimeException) {
+ return *(static_cast <dbms::Connection*>(comm::Delivery::apply()));
+}
+
+//--------------------------------------------------------------------------------------------------
+// Se invoca desde la seccion critica establecida en comm::Delivery::apply.
+//
+// (0) Si no hay registrada ninguna conexion
+//--------------------------------------------------------------------------------------------------
+comm::Resource* dbms::Delivery::do_apply()
+throw(RuntimeException) {
+ iterator maxii = end();
+
+ if(a_iiConnection == maxii) // (0)
+ return NULL;
+
+ iterator init = a_iiConnection;
+ Connection* result = NULL;
+ Connection* w;
+
+ do {
+ w = connection(a_iiConnection);
+
+ if(a_iiConnection == maxii)
+ a_iiConnection = begin();
+
+ if(w->isAvailable() == true && w->isEnabled() == true) {
+ result = w;
+ break;
+ }
+ } while(a_iiConnection != init);
+
+ return result;
+}
--- /dev/null
+#include <stdio.h>
+
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms/Float.hpp>
+
+using namespace anna;
+using namespace anna::dbms;
+
+std::string dbms::Float::asString () const
+ throw ()
+{
+ std::string result ("dbms::Float { ");
+ result += dbms::Data::asString ();
+ result += " | Value: ";
+ result += functions::asString (a_format, a_value);
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <stdio.h>
+
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms/Float.hpp>
+
+using namespace anna;
+using namespace anna::dbms;
+
+std::string dbms::Float::asString() const
+throw() {
+ std::string result("dbms::Float { ");
+ result += dbms::Data::asString();
+ result += " | Value: ";
+ result += functions::asString(a_format, a_value);
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/Integer.hpp>
+
+using namespace anna;
+
+std::string dbms::Integer::asString() const
+throw() {
+ std::string result("dbms::Integer { ");
+ result += dbms::Data::asString();
+ result += " | Valor: ";
+ result += functions::asString(a_value);
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/LongBlock.hpp>
+
+using namespace anna;
+
+dbms::LongBlock& dbms::LongBlock::operator = (const dbms::LongBlock & other)
+throw(RuntimeException) {
+ if(this == &other)
+ return *this;
+
+ if(other.isNull() == true) {
+ setNull(true);
+ return *this;
+ }
+
+ return operator= (other.a_value);
+}
+
+dbms::LongBlock& dbms::LongBlock::operator = (const anna::DataBlock & value)
+throw(RuntimeException) {
+ a_value = value;
+ setNull(a_value.isEmpty());
+ return *this;
+}
+
+std::string dbms::LongBlock::asString() const
+throw() {
+ std::string result("dbms::LongBlock { ");
+ result += dbms::Data::asString();
+ result += " | Size: ";
+
+ if(isNull())
+ result += "(null)";
+ else
+ result += functions::asString(a_value.getSize());
+
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms/LongBlock.hpp>
+#include <anna/dbms/OutputBind.hpp>
+
+using namespace anna;
+using namespace std;
+
+void dbms::OutputBind::write() const
+throw(RuntimeException, dbms::DatabaseException) {
+ const dbms::Data& data = Bind::getData();
+
+ if(data.getType() != Data::Type::LongBlock) {
+ string msg("anna::dbms::OutputBind::write | ");
+ msg += data.asString();
+ msg += " | This method only can be called for anna::dbms::LongBlock types";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg("anna::dbms::OutputBind::write | ");
+ msg += data.asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ do_write(reinterpret_cast <const dbms::LongBlock&>(data));
+}
+
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/ResultCode.hpp>
+
+using namespace std;
+using namespace anna::dbms;
+
+bool ResultCode::notFound() const
+throw(anna::RuntimeException) {
+ if(a_errorDecoder == NULL) {
+ string msg(asString());
+ msg += " | Has no decoder for associated error";
+ throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return a_errorDecoder->notFound(a_errorCode);
+}
+
+bool ResultCode::successful() const
+throw(anna::RuntimeException) {
+ if(a_errorDecoder == NULL) {
+ string msg(asString());
+ msg += " | Has no decoder for associated error";
+ throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return a_errorDecoder->successful(a_errorCode);
+}
+
+bool ResultCode::locked() const
+throw(anna::RuntimeException) {
+ if(a_errorDecoder == NULL) {
+ string msg(asString());
+ msg += " | Has no decoder for associated error";
+ throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return a_errorDecoder->locked(a_errorCode);
+}
+
+bool ResultCode::lostConnection() const
+throw(anna::RuntimeException) {
+ if(a_errorDecoder == NULL) {
+ string msg(asString());
+ msg += " | Has no decoder for associated error";
+ throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return a_errorDecoder->lostConnection(a_errorCode);
+}
+
+//
+// No usamos la std::string porque la gran mayoría de las veces la ejecución de las sentencias SQL será
+// correcta => no hará falta reservar ninguna memoria.
+//
+void ResultCode::copy(const char* text)
+throw() {
+ if(text == NULL) {
+ if(a_errorText != NULL) {
+ free(a_errorText);
+ a_errorText = NULL;
+ }
+ } else {
+ char* aux;
+
+ if((aux = anna_strchr((char*) text, '\n')) != NULL)
+ * aux = 0;
+
+ const int textLen = anna_strlen(text);
+
+ if(a_errorText == NULL)
+ a_errorText = strdup(text);
+ else if(anna_strlen(a_errorText) >= textLen)
+ anna_strcpy(a_errorText, text);
+ else {
+ free(a_errorText);
+ a_errorText = strdup(text);
+ }
+ }
+}
+
+std::string ResultCode::asString() const
+throw() {
+ std::string result("dbms::ResultCode { Error: ");
+ result += functions::asString(a_errorCode);
+ result += " | Error: ";
+ result += (a_errorText == NULL) ? "(null)" : a_errorText;
+ result += " | Correct: ";
+
+ if(a_errorDecoder != NULL)
+ result += functions::asString(successful());
+ else
+ result += "<No ErrorDecoder>";
+
+ return result += " }";
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/xml/Node.hpp>
+#include <anna/xml/Attribute.hpp>
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/Sentence.hpp>
+#include <anna/dbms/Statement.hpp>
+
+using namespace std;
+using namespace anna;
+
+const string& dbms::Sentence::getName() const
+throw() {
+ static string empty;
+ return (a_dbStatement == NULL) ? empty : a_dbStatement->getName();
+}
+
+void dbms::Sentence::initialize(dbms::Database& database)
+throw(RuntimeException) {
+ Guard guard(this, "anna::dbms::Sentence (initialize)");
+ a_dbStatement = do_initialize(database);
+}
+
+//-------------------------------------------------------------------------------------
+// Ojo!! No activamos la seccion critica en este metodo porque debera estar
+// activa externamente ... para recoger datos multiples, etc, etc.
+//-------------------------------------------------------------------------------------
+dbms::ResultCode dbms::Sentence::execute(dbms::Connection& connection, dbms::Statement* statement)
+throw(RuntimeException) {
+ using namespace anna::dbms;
+ ResultCode result;
+
+ try {
+ result = connection.execute(statement);
+
+ if(result.successful() == false) {
+ if(a_mode == Mode::SilentWhenNotFound && result.notFound() == true)
+ return result;
+
+ throw DatabaseException(result, ANNA_FILE_LOCATION);
+ }
+ } catch(DatabaseException& edb) {
+ string msg("Sentence: ");
+ msg += getName();
+ msg += " | ";
+ msg += edb.getText();
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ return result;
+}
+
+bool dbms::Sentence::fetch()
+throw(RuntimeException) {
+ bool result = false;
+
+ try {
+ result = a_dbStatement->fetch();
+ } catch(dbms::DatabaseException& edb) {
+ throw RuntimeException(edb);
+ }
+
+ return result;
+}
+
+string dbms::Sentence::asString() const
+/*virtual*/
+throw() {
+ string result("dbms::Sentence { Mode: ");
+ result += (a_mode == Mode::SilentWhenNotFound) ? "SilentWhenNotFound" : "ExceptionWhenNotFound";
+ result += " | ";
+
+ if(a_dbStatement != NULL)
+ result += a_dbStatement->asString();
+ else
+ result += "dbms::Statement: <null>";
+
+ return result += " }";
+}
+
+/*virtual*/
+xml::Node* dbms::Sentence::asXML(xml::Node* parent) const
+throw() {
+ xml::Node* result = parent->createChild("dbms.Sentence");
+ result->createAttribute("Mode", (a_mode == Mode::SilentWhenNotFound) ? "SilentWhenNotFound" : "ExceptionWhenNotFound");
+
+ if(a_dbStatement)
+ a_dbStatement->asXML(result);
+
+ return result;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/ShortBlock.hpp>
+
+using namespace anna;
+
+dbms::ShortBlock& dbms::ShortBlock::operator = (const dbms::ShortBlock & other)
+throw(RuntimeException) {
+ if(this == &other)
+ return *this;
+
+ if(other.isNull() == true) {
+ setNull(true);
+ return *this;
+ }
+
+ return operator= (other.a_value);
+}
+
+dbms::ShortBlock& dbms::ShortBlock::operator = (const anna::DataBlock & value)
+throw(RuntimeException) {
+ if(value.getSize() > Data::getMaxSize()) {
+ throw RuntimeException(
+ functions::asString(
+ "Block out of range | Max: %d | Current: %d ", Data::getMaxSize(), value.getSize()
+ ),
+ ANNA_FILE_LOCATION
+ );
+ }
+
+ a_value = value;
+ setNull(a_value.isEmpty());
+ return *this;
+}
+
+std::string dbms::ShortBlock::asString() const
+throw() {
+ std::string result("dbms::ShortBlock { ");
+ result += dbms::Data::asString();
+ result += " | Value: ";
+ result += isNull() ? "(null)" : functions::asString(a_value).c_str();
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/tracing/TraceMethod.hpp>
+
+#include <anna/xml/Node.hpp>
+#include <anna/xml/Attribute.hpp>
+
+#include <anna/dbms/Statement.hpp>
+#include <anna/dbms/InputBind.hpp>
+#include <anna/dbms/OutputBind.hpp>
+#include <anna/dbms/Database.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+Statement::~Statement() {
+ InputBind* ibind;
+ OutputBind* obind;
+
+ for(input_iterator ii = input_begin(), maxii = input_end(); ii != maxii; ii ++) {
+ ibind = inputBind(ii);
+ ibind->release(this);
+ a_database.deallocate(ibind);
+ }
+
+ for(output_iterator ii = output_begin(), maxii = output_end(); ii != maxii; ii ++) {
+ obind = outputBind(ii);
+ obind->release(this);
+ a_database.deallocate(obind);
+ }
+}
+
+string Statement::asString() const
+throw() {
+ string result("dbms::Statement { Nombre: ");
+ result += a_name;
+ result += functions::asText(" | Var.Entrada: ", input_size());
+ result += functions::asText(" | Var.Salida: ", output_size());
+ result += " | ";
+ result += a_measureTiming.asString();
+ result += " | Expresion: ";
+ result += a_expression;
+ return result += " }";
+}
+
+xml::Node* dbms::Statement::asXML(xml::Node* parent) const
+throw() {
+ xml::Node* result = parent->createChild("dbms.Statement");
+ result->createAttribute("Name", a_name);
+ xml::Node* node = result->createChild("Timing");
+ node->createAttribute("N", a_measureTiming.size());
+ node->createAttribute("Accumulator", a_measureTiming.getAccumulator());
+ node->createAttribute("Timing", a_measureTiming.asString());
+ result->createChild("Expression")->createText(a_expression);
+ return result;
+}
+
+void Statement::bindInput(const char* name, Data& data)
+throw() {
+ a_inputBinds.push_back(a_database.allocateInputBind(name, data));
+}
+
+const OutputBind* Statement::bindOutput(const char* name, Data& i)
+throw() {
+ OutputBind* result = a_database.allocateOutputBind(name, i);
+ a_outputBinds.push_back(result);
+ return result;
+}
+
+Data& Statement::input(input_iterator& ii)
+throw() {
+ return (*ii)->getData();
+}
+
+Data& Statement::output(output_iterator& ii)
+throw() {
+ return (*ii)->getData();
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/dbms/String.hpp>
+
+using namespace anna;
+using namespace anna::dbms;
+
+String& String::operator = (const String & other)
+throw(RuntimeException) {
+ if(this == &other)
+ return *this;
+
+ if(other.isNull() == true) {
+ setNull(true);
+ a_value [0] = 0;
+ return *this;
+ }
+
+ return operator= (other.a_value);
+}
+
+String& String::operator = (const char * str)
+throw(RuntimeException) {
+ if(a_value != str) {
+ if(anna_strlen(str) > Data::getMaxSize())
+ throw RuntimeException(
+ functions::asString("'%s' out of range | MaxLen: %d | Len: %d ", str, Data::getMaxSize(), anna_strlen(str)),
+ ANNA_FILE_LOCATION
+ );
+
+ anna_strcpy(a_value, str);
+ }
+
+ Data::setNull(false);
+ return *this;
+}
+
+char* String::strip(char *str)
+throw() {
+ int len;
+
+ if(str == NULL || (len = anna_strlen(str)) == 0)
+ return str;
+
+ int end = len - 1;
+
+ while(end >= 0 && str [end] == ' ') end --;
+
+ if(end >= 0)
+ str [++ end] = 0;
+
+ return str;
+}
+
+std::string dbms::String::asString() const
+throw() {
+ std::string result("dbms::String { ");
+ result += dbms::Data::asString();
+ result += " | Value: ";
+ result += a_value;
+ return result += " }";
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <stdio.h>
+
+#include <anna/dbms/TimeStamp.hpp>
+
+#include <anna/config/defines.hpp>
+#include <anna/core/functions.hpp>
+
+using namespace std;
+using namespace anna;
+using namespace anna::dbms;
+
+const char* dbms::TimeStamp::getCStringValue() const
+throw() {
+ const char* format;
+
+ if((format = a_format) == NULL)
+ format = "%d/%m/%Y %H:%M:%S.%%d";
+
+ TimeStamp* _this = const_cast <TimeStamp*>(this);
+ char* result = _this->a_buffer;
+
+ if(strftime(result, MaxDateSize, format, &a_value) == 0)
+ return NULL;
+
+ if(anna_strstr(result, "%d")) {
+ anna_strcpy(_this->a_anotherBuffer, result);
+ sprintf(result, _this->a_anotherBuffer, a_fractionalSecond);
+ }
+
+ return result;
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/functions.hpp>
+#include <anna/dbms/String.hpp>
+#include <anna/dbms/Statement.hpp>
+
+using namespace std;
+using namespace anna;
+
+/*static*/
+void dbms::functions::verifyDataScheme(dbms::Connection& connection, const char* tableName, const char* requiredPatch, const char* columnID, const char* columnDate)
+throw(RuntimeException) {
+ dbms::Database& database = connection.getDatabase();
+ dbms::Statement* statement = NULL;
+ dbms::String id(8);
+ string sql = anna::functions::asString(
+ "select max(%s) from %s where %s in (select max(%s) from %s)",
+ columnID, tableName, columnDate,
+ columnDate, tableName
+ );
+
+ try {
+ statement = database.createStatement("dbms::functions::VerifyDataScheme", sql);
+ statement->bindOutput("max_id", id);
+ dbms::ResultCode resultCode = connection.execute(statement);
+
+ if(resultCode.successful() == false)
+ throw dbms::DatabaseException(resultCode, ANNA_FILE_LOCATION);
+
+ statement->fetch();
+ const string _id(id.getValue());
+ const string _required(requiredPatch);
+
+ if(_required != _id) {
+ std::string msg("DataScheme is out of date | Current patch: ");
+ msg += id;
+ msg += " | Required patch: ";
+ msg += requiredPatch;
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ database.releaseStatement(statement);
+ } catch(dbms::DatabaseException& edb) {
+ database.releaseStatement(statement);
+ throw RuntimeException(edb);
+ } catch(RuntimeException&) {
+ database.releaseStatement(statement);
+ throw;
+ }
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/internal/sccs.hpp>
+#include <anna/app/internal/sccs.hpp>
+#include <anna/xml/internal/sccs.hpp>
+#include <anna/comm/internal/sccs.hpp>
+
+#include <anna/dbms/internal/sccs.hpp>
+
+#include <anna/core/internal/ModuleManager.hpp>
+
+anna_define_sccs_tag(dbms, 2);
+
+void anna::dbms::sccs::activate()
+throw() {
+ anna::sccs::activate();
+ xml::sccs::activate();
+ app::sccs::activate();
+ comm::sccs::activate();
+ ModuleManager::instantiate().insert(anna_use_sccs_tag(dbms), "00");
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/dbms/Database.hpp>
+#include <anna/dbms/Connection.hpp>
+#include <anna/dbms/Statement.hpp>
+#include <anna/dbms/ResultCode.hpp>
+
+#include <anna/dbos/Accesor.hpp>
+#include <anna/dbos/StorageArea.hpp>
+
+using namespace std;
+using namespace anna;
+
+/*virtual*/
+dbos::Accesor::~Accesor() {
+ if(a_statement != NULL && a_database != NULL)
+ a_database->releaseStatement(a_statement);
+}
+
+//------------------------------------------------------------------------------------------
+// Transfiere la informacion del medio fisico al 'Loader' concreto.
+//
+// (1) Ojo!! Ejecuta la sentencia SQL y carga el primer registro en el area de intercambio
+// Slo habr�que invocar al 'fetch' para coger los siguientes registros'
+//------------------------------------------------------------------------------------------
+bool dbos::Accesor::load(dbms::Connection* connection, const dbos::StorageArea* ssaa)
+throw(RuntimeException, dbms::DatabaseException) {
+
+ if(connection == NULL) {
+ std::string msg(ssaa->asString());
+ msg += " | ";
+ msg += asString();
+ msg += " | Cannot execute this method with dbms::Connection == NULL";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ dbms::Statement* statement(getStatement());
+
+ if(statement == NULL) {
+ std::string msg(ssaa->asString());
+ msg += " | ";
+ msg += asString();
+ msg += " | Has no SQL sentence associated";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg("dbos::Accesor::load | ");
+ msg += ssaa->asString();
+ msg += " | ";
+ msg += asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ dbms::ResultCode resultCode = connection->execute(statement); // (1)
+
+ if(resultCode.notFound() == true) {
+ if(a_emodeIsNull == true) {
+ if(ssaa->getErrorCode() != StorageArea::NoExceptionWhenNotFound) {
+ std::string msg(ssaa->asString());
+ msg += " | ";
+ msg += asString();
+ msg += " | Register not found";
+ RuntimeException ex(msg, ANNA_FILE_LOCATION);
+ ex.setErrorCode(ssaa->getErrorCode());
+ throw ex;
+ } else
+ return false;
+ } else {
+ std::string msg(ssaa->asString());
+ msg += " | ";
+ msg += asString();
+ msg += " | Register not found";
+
+ if(a_exceptionMode == Exception::Mode::Ignore) {
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ return false;
+ }
+
+ if(a_exceptionMode == Exception::Mode::Throw) {
+ RuntimeException ex(msg, ANNA_FILE_LOCATION);
+ ex.setErrorCode(ssaa->getErrorCode());
+ throw ex;
+ } else if(Logger::isActive(Logger::Warning)) {
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ }
+ }
+ }
+
+ if(resultCode.successful() == false) {
+ string msg(ssaa->getName());
+ msg += " | ";
+ msg += asString();
+ throw dbms::DatabaseException(msg, resultCode, ANNA_FILE_LOCATION);
+ }
+
+ return statement->fetch();
+}
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <stdlib.h>
+
+#include <anna/core/tracing/Logger.hpp>
+
+#include <anna/xml/Node.hpp>
+#include <anna/xml/Attribute.hpp>
+
+#include <anna/dbos/Repository.hpp>
+#include <anna/dbos/StorageArea.hpp>
+#include <anna/dbos/internal/sccs.hpp>
+
+using namespace std;
+using namespace anna;
+
+dbos::Repository::Repository(const char* name) :
+ a_name(name) {
+ sccs::activate();
+}
+
+dbos::Repository::Repository(const std::string& name) :
+ a_name(name) {
+ sccs::activate();
+}
+
+dbos::StorageArea* dbos::Repository::createStorageArea(const dbos::StorageId index, const char* name, const dbos::Size maxSize, dbos::ObjectAllocator objectAllocator, const int errorCode, const StorageArea::AccessMode::_v accessMode)
+throw(RuntimeException) {
+ Guard guard(this, "dbos::Repository from createStorageArea");
+ storage_iterator ii = a_storageAreas.find(index) ;
+
+ if(ii != a_storageAreas.end()) {
+ string msg(ii->second->asString());
+ msg += " | Already in use";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ StorageArea* result = new StorageArea(name, maxSize, objectAllocator, accessMode, errorCode);
+ a_storageAreas.insert(container::value_type(index, result));
+ LOGDEBUG(
+ string msg("dbos::Repository::createStorageArea | Name: ");
+ msg += a_name;
+ msg += " | ";
+ msg += result->asString();
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ return result;
+}
+
+dbos::StorageArea* dbos::Repository::findStorageArea(const dbos::StorageId index)
+throw() {
+ Guard guard(this, "dbos::Repository from findStorageArea");
+ storage_iterator ii = a_storageAreas.find(index);
+ return (ii != a_storageAreas.end()) ? storageArea(ii) : NULL;
+}
+
+void dbos::Repository::clear()
+throw(RuntimeException) {
+ Guard guard(this, "dbos::Repository from clear");
+ LOGWARNING(
+ string msg("dbos::Repository::clear | Name: ");
+ msg += a_name;
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ );
+
+ for(storage_iterator ii = storage_begin(), maxii = storage_end(); ii != maxii; ii ++)
+ storageArea(ii)->clear();
+}
+
+xml::Node* dbos::Repository::asXML(xml::Node* parent) const
+throw() {
+ xml::Node* result = parent->createChild("dbos.Repository");
+ dbos::Size maxSize(0);
+ dbos::Size size(0);
+ const StorageArea* ssaa;
+ result->createAttribute("Name", a_name);
+
+ for(const_storage_iterator ii = storage_begin(), maxii = storage_end(); ii != maxii; ii ++) {
+ ssaa = storageArea(ii);
+ maxSize += ssaa->getMaxSizeOf();
+ size += ssaa->getSizeOf();
+ ssaa->asXML(result);
+ }
+
+ result->createAttribute("SizeOf", StorageArea::asMemorySize(size));
+ result->createAttribute("MaxSizeOf", StorageArea::asMemorySize(maxSize));
+ return result;
+}
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <typeinfo>
+
+#include <algorithm>
+
+#include <anna/core/tracing/Logger.hpp>
+#include <anna/core/functions.hpp>
+
+#include <anna/dbms/dbms.hpp>
+#include <anna/dbos/dbos.hpp>
+
+#include <anna/xml/Node.hpp>
+#include <anna/xml/Attribute.hpp>
+
+using namespace std;
+using namespace anna;
+
+StorageArea::StorageArea(const char* name, const Size maxSize, ObjectAllocator objectAllocator, const StorageArea::AccessMode::_v accessMode, const int errorCode) :
+ a_name(name),
+ a_maxSize(maxSize),
+ a_objectAllocator(objectAllocator),
+ a_accessMode(accessMode),
+ a_errorCode(errorCode),
+ a_indexBlock(0),
+ a_sizeof(0),
+ a_doneReuse(0) {
+ a_blocks.push_back(a_currentBlock = new Block(objectAllocator, maxSize));
+ a_hit = a_fault = 0;
+}
+
+StorageArea::~StorageArea() {
+}
+
+//------------------------------------------------------------------------------------------------
+// Carga los datos del objeto y los guarda en el area de almacemiento.
+//
+// (1) Si no esta en memoria => se carga.
+// (1.1) Si el registro no existe => se progresa la posible excepcion.
+//
+// (2) Cambia la politica de refresco de las areas de almacenamiento ReadWrite/Dirty. La carga solo se
+// realizara cuando la copia de utilizacion sea 0. Ademas de la mejora de rendimiento aseguramos que
+// la estabilidad de una instancia se mantiene durante toda la vida de esta. Por ejmplo evitamos que
+// una instancia A este trabajando con una copia de una instancia que estamos liberando y volviendo
+// a cargar con datos totalmente distintos ... imaginad que estamos recorriendo un vector asociado
+// o algo asi.
+//
+// (3) Si no ha podido ser recargada (seguramente tiene mas de una referencia) debe evitar el
+// uso en caso de que este marcada como Dirty.
+// (4) Si el contador de uso es cero => que ya esta marcado como memoria libre, pero recordar que
+// tambien puede estar en la memoria activa (pendiente de liberar y/o volver a usar). En este
+// caso se ha reusado.
+//------------------------------------------------------------------------------------------------
+Object* StorageArea::instance(Connection* connection, Loader& loader)
+throw(RuntimeException, DatabaseException) {
+ const Index index = loader.getIndex();
+ Object* result(NULL);
+ Instance* instance(NULL);
+ LOGDEBUG(
+ string msg("Instantiate (init) | ");
+ msg += asString();
+ msg += " | ";
+ msg += loader.asString();
+ msg += " | Index: ";
+ msg += functions::asHexString(index);
+ Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
+ );
+ loader.a_connection = connection;
+ std::string name("dbos::StorageArea::instance with ");
+ name += typeid(loader).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find(index);
+
+ if(ii == a_directory.end()) { // (1)
+ a_fault ++;
+
+ if(loader.load(connection, this) == true) { // (1.1)
+ pair <iterator, bool> rr;
+ bool wasInserted = false;
+ instance = allocate();
+
+ try {
+ instance->object->setIndex(index);
+ /* Al añadir la instancia antes de invocar al método Object::initialize
+ * nos aseguramos de que se permitan implementar relaciones circulares
+ */
+ rr = a_directory.insert(value_type(index, instance));
+ wasInserted = true;
+ result = instance->object;
+ instance->flags |= Flag::InProgress;
+ instance->object->initialize(loader);
+ instance->object->a_isStored = true;
+ instance->flags &= Flag::Done;
+ } catch(DatabaseException&) {
+ instance->flags &= Flag::Done;
+
+ if(wasInserted)
+ a_directory.erase(rr.first);
+
+ a_holes.insert(instance, Holes::Mode::ReadyToReuse);
+ throw;
+ } catch(RuntimeException&) {
+ instance->flags &= Flag::Done;
+
+ if(wasInserted)
+ a_directory.erase(rr.first);
+
+ a_holes.insert(instance, Holes::Mode::ReadyToReuse);
+ throw;
+ }
+ }
+ } else {
+ static const bool IgnoreDirty = true;
+ verifyStatus(instance = StorageArea::instance(ii), IgnoreDirty);
+
+ switch(a_accessMode) {
+ case AccessMode::ReadOnly:
+ result = ((instance->flags & Flag::Dirty) == 0) ? instance->object : reload(connection, loader, instance);
+ break;
+ case AccessMode::ReadWrite:
+ result = (instance->copyCounter > 0) ? instance->object : reload(connection, loader, instance);
+ break;
+ case AccessMode::ReadEver:
+ result = reload(connection, loader, instance);
+ break;
+ }
+
+ if(instance->flags & Flag::Dirty) { // (3)
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Instance selected as unusable";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(result != NULL) {
+ a_holes.erase(instance); // (4)
+ instance->copyCounter ++;
+ a_hit ++;
+ }
+ }
+
+ LOGINFORMATION(
+ string msg("Instantiate (final) | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION)
+ );
+ return result;
+}
+
+Object* StorageArea::instance(Connection* connection, CrossedLoader& crossedLoader, Loader& loader)
+throw(RuntimeException, DatabaseException) {
+ Object* result = NULL;
+ crossedLoader.a_connection = connection;
+ // Si el seek devuelve 'true' es que ya tiene cargada la correspondencia entre la clave alternativa y la
+ // clave principal usada en el Loader recibido como parámetro.
+ bool loaded = (crossedLoader.seek() == false) ? crossedLoader.load(connection, this) : true;
+
+ if(loaded == true) {
+ /*
+ * Transfiere la clave principal conseguida por el cargador cruzado.
+ */
+ loader.upload(crossedLoader);
+ result = instance(connection, loader);
+ /*
+ * Da la posibilidad de que el cargador cruzado mantenga la correspondencia entre sus claves y las claves primarias
+ */
+ crossedLoader.download(loader);
+ }
+
+ return result;
+}
+
+//-------------------------------------------------------------------------
+// Crea un nuevo objeto en el area de almacenamiento.
+//-------------------------------------------------------------------------
+Object* StorageArea::create(Connection* connection, Creator& creator)
+throw(RuntimeException, DatabaseException) {
+ const Index index = creator.getIndex();
+ Instance* instance = NULL;
+ Object* result = NULL;
+
+ if(a_accessMode == AccessMode::ReadOnly) {
+ string msg(asString());
+ msg += " | Cannot create object with AccessMode::ReadOnly";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg(asString());
+ msg += " | ";
+ msg += creator.asString();
+ msg += " | Index: ";
+ msg += functions::asHexString(index);
+ Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
+ );
+ creator.a_connection = connection;
+ std::string name("dbos::StorageArea::create with ");
+ name += typeid(creator).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find(index);
+
+ if(ii == a_directory.end()) {
+ pair <iterator, bool> rr;
+ bool wasInserted = false;
+ a_fault ++;
+ instance = allocate();
+
+ try {
+ instance->object->setIndex(index);
+ instance->copyCounter = 1;
+ result = instance->object;
+ rr = a_directory.insert(value_type(index, instance));
+ wasInserted = true;
+ instance->flags |= Flag::InProgress;
+ instance->object->create(creator);
+ instance->flags &= Flag::Done;
+ instance->object->a_isStored = false;
+ } catch(DatabaseException&) {
+ instance->flags &= Flag::Done;
+
+ if(wasInserted)
+ a_directory.erase(rr.first);
+
+ a_holes.insert(instance, Holes::Mode::ReadyToReuse);
+ throw;
+ } catch(RuntimeException&) {
+ instance->flags &= Flag::Done;
+
+ if(wasInserted)
+ a_directory.erase(rr.first);
+
+ a_holes.insert(instance, Holes::Mode::ReadyToReuse);
+ throw;
+ }
+ } else {
+ verifyStatus(instance = StorageArea::instance(ii));
+ a_hit ++;
+ a_holes.erase(instance);
+ instance->copyCounter ++;
+ result = instance->object;
+ }
+
+ LOGINFORMATION(
+ string msg("Create | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION)
+ );
+ return result;
+}
+
+//-------------------------------------------------------------------------
+// Carga los datos del objeto y los guarda en el area de almacemiento.
+//
+// (1) Si tiene cuenta 0 => estaba en la lista de objetos liberados =>
+// lo sacamos de ah�
+//-------------------------------------------------------------------------
+Object* StorageArea::find(Loader& loader)
+throw(RuntimeException) {
+ const Index index = loader.getIndex();
+ Instance* instance = NULL;
+ Object* result = NULL;
+ LOGDEBUG(
+ string msg(asString());
+ msg += " | ";
+ msg += loader.asString();
+ msg += " | Index: ";
+ msg += functions::asHexString(index);
+ Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
+ );
+ std::string name("dbos::StorageArea::find with ");
+ name += typeid(loader).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find(index);
+
+ if(ii != a_directory.end()) {
+ verifyStatus(instance = StorageArea::instance(ii));
+ a_hit ++;
+ a_holes.erase(instance);
+ instance->copyCounter ++;
+ result = instance->object;
+ } else
+ a_fault ++;
+
+ LOGDEBUG(
+ string msg("Find | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::write(Logger::Debug, msg, ANNA_FILE_LOCATION)
+ );
+ return result;
+}
+
+Object* StorageArea::duplicate(const Object* object)
+throw(RuntimeException) {
+ if(object == NULL) return NULL;
+
+ std::string name("dbos::StorageArea::duplicate with ");
+ name += typeid(*object).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find(object->getIndex());
+
+ if(ii == a_directory.end()) {
+ a_fault ++;
+ string msg(asString());
+ msg += " | Index: ";
+ msg += functions::asHexString(object->getIndex());
+ msg += " | Invalid instance";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ Instance* instance = NULL;
+ verifyStatus(instance = StorageArea::instance(ii));
+ a_holes.erase(instance);
+ instance->copyCounter ++;
+ a_hit ++;
+ LOGINFORMATION(
+ string msg("Duplicate | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION)
+ );
+ return instance->object;
+}
+
+bool StorageArea::isLoaded(const Loader& loader)
+throw(RuntimeException) {
+ const Index index = loader.getIndex();
+ std::string name("dbos::StorageArea::isLoaded with ");
+ name += typeid(loader).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find(index);
+ const bool result = (ii != a_directory.end());
+ LOGDEBUG(
+ string msg(asString());
+ msg += " | ";
+ msg += loader.asString();
+ msg += " | Index: ";
+ msg += functions::asHexString((int) index);
+ msg += functions::asText(" | isLoaded: ", result);
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ return result;
+}
+
+void StorageArea::apply(Connection& connection, Recorder& recorder)
+throw(RuntimeException, DatabaseException) {
+ ResultCode resultCode = connection.execute(recorder.getStatement());
+
+ if(resultCode.successful() == false)
+ throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
+}
+
+//------------------------------------------------------------------------------------------------
+// Borra un objeto del medio fisico => lo borra tambien de la cache
+//
+// (1) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y
+// si fuera necesario invocara al 'destroy'.
+// (2) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la
+// marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la
+// instancia en cuanto pueda.
+//------------------------------------------------------------------------------------------------
+void StorageArea::apply(Connection& connection, Eraser& eraser)
+throw(RuntimeException, DatabaseException) {
+ if(a_accessMode == AccessMode::ReadOnly) {
+ string msg(asString());
+ msg += " | Cannot erase object with AccessMode::ReadOnly";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ Object* object = eraser.getObject();
+ eraser.a_connection = &connection;
+ std::string name("dbos::StorageArea::apply with ");
+ name += typeid(eraser).name();
+ Guard guard(this, name.c_str());
+ Instance* instance = NULL;
+
+ if(object != NULL) {
+ iterator ii = a_directory.find(object->getIndex());
+
+ if(ii != a_directory.end()) {
+ instance = StorageArea::instance(ii);
+
+ if(instance->copyCounter > 1) {
+ instance->flags |= Flag::Incoherent; // (2)
+ string msg(eraser.asString());
+ msg += " | Instances: ";
+ msg += functions::asString(instance->copyCounter);
+ msg += " | Cannot delete object";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+ }
+ }
+
+ ResultCode resultCode = connection.execute(eraser.getStatement());
+
+ if(resultCode.successful() == false)
+ throw DatabaseException(resultCode, ANNA_FILE_LOCATION);
+
+ if(instance != NULL) {
+ instance->copyCounter = 0;
+ quickReusing(instance); // (1)
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+// Decrementa la cuenta de utilizacin del objeto recibido como parametro.
+//
+// (1) Si la instancia que estamos liberando esta marcada como 'Incoherente' y es la ultima
+// referencia => es el momento de expulsarla de la memoria.
+// (2) Queda a la espera de que se vuelva a usar la referencia o que el numero de registros en
+// memoria alcance un numero tal que implique comenzar a reusar objetos liberados.
+//------------------------------------------------------------------------------------------------
+void StorageArea::release(Object** object)
+throw(RuntimeException) {
+ if(object == NULL) return;
+
+ if(*object == NULL) return;
+
+ std::string name("dbos::StorageArea::release with ");
+ name += typeid(**object).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find((*object)->getIndex());
+
+ if(ii == a_directory.end())
+ return;
+
+ Instance* instance = StorageArea::instance(ii);
+
+ if(instance->copyCounter > 0) {
+ if(-- instance->copyCounter == 0) {
+ if(instance->flags & Flag::Incoherent) // (1)
+ quickReusing(instance);
+ else
+ a_holes.insert(instance, Holes::Mode::TimeWait); // (2)
+ }
+ }
+
+ LOGINFORMATION(
+ string msg("Release | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION)
+ );
+ *object = NULL;
+}
+
+//------------------------------------------------------------------------------------------------
+// Elimina toda la informacin referente al objeto recibido como parametro.
+//
+// (1) No la puede sacar de la memoria porque tiene referencias activas, pero por lo menos la
+// marca como no usable para intentar provocar los avisos de uso incorrecto y expulsar la
+// instancia en cuanto pueda.
+// (2) Como copyCounter = 0 => Lo metera en lista de huecos, le quitara del directorio y
+// si fuera necesario invocara al 'destroy'.
+//------------------------------------------------------------------------------------------------
+void StorageArea::erase(Object** object)
+throw(RuntimeException) {
+ if(object == NULL) return;
+
+ if(*object == NULL) return;
+
+ std::string name("dbos::StorageArea::erase with ");
+ name += typeid(**object).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find((*object)->getIndex());
+
+ if(ii == a_directory.end())
+ return;
+
+ Instance* instance = StorageArea::instance(ii);
+
+ if(instance->copyCounter > 1) {
+ instance->flags |= Flag::Incoherent; // (1)
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Cannot dump instance";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg("Erase | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+ instance->copyCounter = 0;
+ quickReusing(instance); // (2)
+ *object = NULL;
+}
+
+void StorageArea::dirty(Object* object)
+throw(RuntimeException) {
+ if(object == NULL) return;
+
+ std::string name("dbos::StorageArea::dirty with ");
+ name += typeid(*object).name();
+ Guard guard(this, name.c_str());
+ iterator ii = a_directory.find(object->getIndex());
+
+ if(ii == a_directory.end())
+ return;
+
+ Instance* instance = StorageArea::instance(ii);
+
+ if(instance->copyCounter > 1 && Logger::isActive(Logger::Warning)) {
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | More than one copy on instance to be selected";
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ }
+
+ LOGDEBUG(
+ string msg("Dirty | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::debug(msg, ANNA_FILE_LOCATION)
+ );
+}
+
+//--------------------------------------------------------------------------------------------
+// Descarga todos los objetos de este area de almacenamiento.
+//
+// (1) Para que permite incluirla en los huecos.
+// (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo.
+// (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido
+// expulsarla de cache.
+//--------------------------------------------------------------------------------------------
+void StorageArea::clear()
+throw(RuntimeException) {
+ Guard guard(this, "dbos::StorageArea::clear");
+ Instance* instance;
+ int n = 0;
+
+ for(iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
+ instance = StorageArea::instance(ii);
+ instance->copyCounter = 0; // (1)
+ a_holes.insert(instance, Holes::Mode::ReadyToReuse);
+
+ if((instance->flags & Flag::Empty) == 0) { // (3)
+ LOGINFORMATION(
+ string msg("Destroy (clear) | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ instance->object->destroy();
+ instance->flags |= Flag::Empty;
+ }
+
+ instance->flags &= Flag::NoIncoherent; // (4)
+ n ++;
+ }
+
+ a_directory.clear();
+ LOGWARNING(
+ string msg("Clear | ");
+ msg += asString();
+ msg += functions::asText(" | Destroyed objects: ", n);
+ Logger::warning(msg, ANNA_FILE_LOCATION)
+ );
+}
+
+//---------------------------------------------------------------------------------------------------
+// Intenta recargar la informacion del medio fisico en la instancia del objeto.
+// Si hay algun problema y la instancia no puede guardarse en la de objetos disponibles
+// (a_holes.insert == false) => se marca como corrupto y no se podra usar hasta que
+// que no se libere su ultima instancia.
+//
+// (1) Si hubiera algun problema al invocar al 'initialize' no habria que volver a invocar
+// a este metodo.
+// (2) Recordar que la recarga solo se intenta cuando la copyCounter = 0, por tanto en el caso de
+// intentar recargar un registro que ha sido borrado no se vuelve a grabar como Ready porque
+// YA esta en la lista de huecos y seria necesario borrarlo de esta, cambiarle el msHoleTime y
+// volverlo a grabar, pero la cosa funciona porque se saca del directorio de objetos cargados
+// y se libera su memoria.
+//---------------------------------------------------------------------------------------------------
+Object* StorageArea::reload(dbms::Connection* connection, Loader& loader, StorageArea::Instance* instance)
+throw(RuntimeException, dbms::DatabaseException) {
+ const bool enableUpdate = (instance->flags & Flag::Dirty) ? true : instance->object->enableUpdate();
+ bool hasChanges(false);
+
+ if(enableUpdate == true) {
+ try {
+ if(loader.load(connection, this) == false) {
+ checkIncoherence(instance); // (2)
+ return NULL;
+ }
+ } catch(RuntimeException&) {
+ checkIncoherence(instance);
+ throw;
+ } catch(dbms::DatabaseException&) {
+ checkIncoherence(instance);
+ throw;
+ }
+
+ hasChanges = (instance->flags & Flag::Dirty) ? true : instance->object->hasChanges(loader);
+ }
+
+ LOGDEBUG(
+ string msg("Reload | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ msg += anna::functions::asText(" | EnableUpdate: ", enableUpdate);
+ msg += anna::functions::asText(" | HasChanges: ", hasChanges);
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+
+ if(hasChanges == true) {
+ LOGINFORMATION(
+ string msg("Destroy (reload) | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ instance->object->destroy();
+ instance->flags |= Flag::Empty; // (1)
+ instance->object->initialize(loader);
+ instance->flags &= Flag::NoEmpty;
+ instance->flags &= Flag::NoDirty;
+ }
+
+ return instance->object;
+}
+
+//------------------------------------------------------------------------------------------------
+// Cuando intenta recargar la informacion de una instancia desde el medio fisico, pero el
+// registro ha sido borrado =>
+// 1.- Si hay alguna instancia en uso => no puede liberar la instancia porque algun otro
+// objeto la tiene referenciada => la marca como corrupta.
+// 2.- Si hay una unica instancia en uso => puede liberarla
+//
+// (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => saca el objeto
+// del directorio porque yo no es valido. Recupera la coherencia memoria-medio_fisico
+// porque ha conseguido "expulsar" de la cache el registro borrado.
+// (2) No puede "expulsar" el registro de la cache porque hay algun otro objeto que lo esta
+// referenciando => Marca ESTA instancia como incoherente => no se podra duplicar y volver
+// a instanciar, etc, etc
+//------------------------------------------------------------------------------------------------
+void StorageArea::checkIncoherence(StorageArea::Instance* instance)
+throw() {
+ if(quickReusing(instance) == true) {
+ LOGWARNING(
+ string msg("dbos::StorageArea::checkIncoherence | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Recover coherence between physical media and memory";
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ );
+ } else { // (2)
+ instance->flags |= Flag::Incoherent;
+ LOGWARNING(
+ string msg("dbos::StorageArea::checkIncoherence | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Detected incoherence between physical media and memory";
+ Logger::warning(msg, ANNA_FILE_LOCATION);
+ );
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+// (1) si la puede grabar en los huecos o la instancia ya esta en los huecos => (2)
+// (2) saca el objeto del directorio porque yo no es valido.
+// (3) Si fuera necesario invoca al destroy => cuando se reuse no tendra que hacerlo.
+// (4) Si la entrada estaba marcada como 'incoherente' la desmarca, ya que hemos conseguido
+// expulsarla de cache.
+//
+// Recordar que en el caso de intentar recargar un registro que ha sido borrado no se vuelve
+// a grabar como Ready porque ya esta en la lista de huecos y seria necesario borrarlo de
+// esta, cambiarle el msHoleTime y volverlo a grabar.
+//------------------------------------------------------------------------------------------------
+bool StorageArea::quickReusing(StorageArea::Instance* instance)
+throw() {
+ bool result(false);
+
+ if(a_holes.insert(instance, Holes::Mode::ReadyToReuse) == true) { // (1)
+ iterator ii = a_directory.find(instance->object->getIndex());
+
+ if(ii != a_directory.end()) // (2)
+ a_directory.erase(ii);
+
+ if((instance->flags & Flag::Empty) == 0) { // (3)
+ LOGINFORMATION(
+ string msg("Destroy (quickreusing) | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(instance);
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ instance->object->destroy();
+ instance->flags |= Flag::Empty;
+ }
+
+ instance->flags &= Flag::NoIncoherent; // (4)
+ result = true;
+ }
+
+ return result;
+}
+
+void StorageArea::verifyStatus(StorageArea::Instance* instance, const bool ignoreDirty)
+throw(RuntimeException) {
+ if(instance->flags & Flag::Incoherent) {
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Physical media and memory do not match";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(instance->flags & Flag::Empty) {
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Instance is empty";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(ignoreDirty == false && (instance->flags & Flag::Dirty)) {
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Instance is temporary locked";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+
+ if(instance->flags & Flag::InProgress) {
+ string msg(asString());
+ msg += " | ";
+ msg += asString(instance);
+ msg += " | Instance already has word in progress";
+ throw RuntimeException(msg, ANNA_FILE_LOCATION);
+ }
+}
+
+string StorageArea::asString() const
+throw() {
+ string result("dbos::StorageArea { Name: ");
+ const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit);
+ /* Nº real de objetos en uso. En el directorio también se mantienen los que tienen la cuenta de utilización a 0 */
+ const int n = a_directory.size() - a_holes.size();
+ result += a_name;
+ result += " | N: ";
+ result += functions::asString(a_maxSize);
+ result += " | n: ";
+ result += functions::asString(n);
+ result += " | r: ";
+ result += functions::asString(a_directory.size());
+ result += " | AccessMode: ";
+ result += AccessMode::asString(a_accessMode);
+ result += " | Holes: ";
+ result += functions::asString(a_holes.size());
+ result += " | Reuse: ";
+ result += functions::asString(a_doneReuse);
+ result += " | Hit: ";
+ result += functions::asString(a_hit);
+ result += " | Fault: ";
+ result += functions::asString(a_fault);
+ result += " | Ratio: ";
+ result += functions::asString(ratio);
+ return result += "% }";
+}
+
+xml::Node* StorageArea::asXML(xml::Node* parent) const
+throw() {
+ xml::Node* result = parent->createChild("dbos.StorageArea");
+ xml::Node* node;
+ const int ratio = (a_hit == 0) ? 0 : (a_hit * 100) / (a_fault + a_hit);
+ result->createAttribute("Name", a_name);
+ result->createAttribute("AccessMode", AccessMode::asString(a_accessMode));
+ node = result->createChild("Size");
+ node->createAttribute("Value", a_directory.size() - a_holes.size());
+ node->createAttribute("Reserve", a_directory.size());
+ node->createAttribute("MaxValue", a_maxSize);
+ node->createAttribute("Holes", a_holes.size());
+ node = result->createChild("SizeOf");
+ node->createAttribute("Value", asMemorySize(getSizeOf()));
+ node->createAttribute("MaxValue", asMemorySize(getMaxSizeOf()));
+ node = result->createChild("Statistics");
+ node->createAttribute("Hit", a_hit);
+ node->createAttribute("Fault", a_fault);
+ node->createAttribute("Ratio", anna::functions::asString("%d%%", ratio));
+ node->createAttribute("DoneReuse", a_doneReuse);
+ return result;
+}
+
+string StorageArea::asMemorySize(const Size size)
+throw() {
+ string result;
+
+ if(size < 1024) {
+ result = functions::asString("%u bytes", size);
+ } else if(size < 1024 * 1024) {
+ static const Size ka = 1024;
+ result += functions::asString("%u Kb", size / ka);
+ } else {
+ static const Size mega = 1024 * 1024;
+ result += functions::asString("%u Mb", size / mega);
+ }
+
+ return result;
+}
+
+StorageArea::Instance* StorageArea::allocate()
+throw() {
+ Instance* result = NULL;
+
+ if((result = reuse()) == NULL) {
+ if((result = a_currentBlock->getInstance()) == NULL) {
+ if(++ a_indexBlock == a_blocks.size())
+ a_blocks.push_back(a_currentBlock = new Block(a_objectAllocator, a_maxSize));
+ else
+ a_currentBlock = a_blocks [a_indexBlock];
+
+ result = a_currentBlock->getInstance();
+ }
+ }
+
+ result->copyCounter = 1;
+//xxx result->msHoleTime = 0;
+ result->flags = Flag::None;
+//xxx result->hasHole = false;
+ return result;
+}
+
+//-----------------------------------------------------------------------------------------------------
+// Reusa un objeto que lleva demasiado tiempo sin ser utilizado.
+//
+// (0) Si el tiempo que lleva en la lista de objetos liberados es cero => Podemos usar el re-usado
+// rapido; ya ha sido eliminado del directorio, invoca al destroy, etc, etc.
+// (0.1) Para asegurar que NO desborde los 32 bits.
+// (1) Cuando n -> Nmax => Talpha = now => a poco tiempo que pase sin reusar los registros, estos
+// se comienzan a resuar. Cuando n -> 0 => talpha = 0 => No se reusan registros, sino que se crearan
+// nuevos.
+// (2) Si el primero de los registros disponibles no es suficientemente antiguo => no hay huecos libres
+//-----------------------------------------------------------------------------------------------------
+StorageArea::Instance* StorageArea::reuse()
+throw() {
+ if(a_holes.empty() == true)
+ return NULL;
+
+ Instance* result = NULL;
+ Instance* front = a_holes.front();
+ bool quickReuse;
+
+ if((front->flags & Flag::Ready) == false) {
+ if(a_directory.size() >= a_maxSize) { // El directorio contiene los que tienen cuenta 0 + los que están activos.
+ result = front;
+ iterator ii = a_directory.find(result->object->getIndex());
+
+ if(ii != a_directory.end())
+ a_directory.erase(ii);
+
+ if((result->flags & Flag::Empty) == 0) {
+ LOGINFORMATION(
+ string msg("Destroy (reuse) | ");
+ msg += asString();
+ msg += " | ";
+ msg += asString(result);
+ Logger::information(msg, ANNA_FILE_LOCATION);
+ );
+ result->object->destroy();
+ result->flags &= Flag::NoEmpty;
+ }
+ }
+
+ quickReuse = false;
+ } else {
+ // Si la entrada se cargó en los huecos como "usado rápido" se toma
+ result = front;
+ quickReuse = true;
+ }
+
+ if(result != NULL) {
+ a_doneReuse ++;
+ result->flags &= Flag::NoReady;
+ result->flags &= Flag::NoHasHole;
+ a_holes.pop_front();
+ }
+
+ LOGDEBUG(
+ string msg("dbos::StorageArea::reuse | ");
+ msg += asString();
+ msg += " | ";
+ msg += StorageArea::asString(result);
+ msg += functions::asText(" | QuickReuse: ", quickReuse);
+ Logger::debug(msg, ANNA_FILE_LOCATION);
+ );
+ return result;
+}
+
+std::string StorageArea::asString(const Instance* instance)
+throw() {
+ std::string result("Instance { ");
+
+ if(instance == NULL)
+ return result += "<null> } ";
+
+ result += "Reference: ";
+ result += functions::asHexString(anna_ptrnumber_cast(instance->object));
+ result += " | Index: ";
+ result += functions::asHexString(instance->object->getIndex());
+ result += functions::asText(" | Stored: ", instance->object->a_isStored);
+ result += " | CopyCounter: ";
+ result += functions::asString((unsigned int) instance->copyCounter);
+ result += " | Flags (";
+ result += functions::asHexString(instance->flags);
+ result += "):";
+
+ if(instance->flags == Flag::None)
+ result += " None";
+ else {
+ if(instance->flags & Flag::Dirty)
+ result += " Dirty";
+
+ if(instance->flags & Flag::Incoherent)
+ result += " Incoherent";
+
+ if(instance->flags & Flag::Empty)
+ result += " Empty";
+
+ if(instance->flags & Flag::HasHole)
+ result += " HasHole";
+
+ if(instance->flags & Flag::InProgress)
+ result += " InProgress";
+
+ result += (instance->flags & Flag::Ready) ? " Ready" : " TimeWait";
+ }
+
+ return result += " }";
+}
+
+const char* StorageArea::AccessMode::asString(const AccessMode::_v v)
+throw() {
+ static const char* text [] = { "ReadOnly", "ReadWrite", "ReadEver" };
+ return text [v];
+}
+
+/****************************************************************************************
+* Bloque de memoria.
+****************************************************************************************/
+StorageArea::Block::Block(ObjectAllocator objectAllocator, const Size maxSize) :
+ a_size(0) {
+ a_maxSize = std::min(8U, std::max(256U, maxSize >> 7));
+ a_instances = new Instance [a_maxSize];
+
+ for(int i = 0; i < a_maxSize; i ++)
+ a_instances [i].object = (*objectAllocator)();
+}
+
+bool StorageArea::Holes::insert(Instance* instance, const StorageArea::Holes::Mode::_v mode)
+throw() {
+ if(instance->copyCounter > 0)
+ return false;
+
+ /* Si la instancia ya ha sido registrada en la lista de huecos, sale sin más */
+ if((instance->flags & Flag::HasHole) == true)
+ return true;
+
+ switch(mode) {
+ case Mode::ReadyToReuse:
+ instance->holeIterator = a_holes.insert(a_holes.begin(), instance);
+ instance->flags |= Flag::HasHole;
+ instance->flags |= Flag::Ready;
+ a_size ++;
+ break;
+ case Mode::TimeWait:
+ instance->holeIterator = a_holes.insert(a_holes.end(), instance);
+ instance->flags |= Flag::HasHole;
+ instance->flags &= Flag::NoReady;
+ a_size ++;
+ break;
+ }
+
+ LOGLOCAL6(
+ string msg("dbos::StorageArea::Holes::insert | This: ");
+ msg += functions::asHexString(anna_ptrnumber_cast(this));
+ msg += " | ";
+ msg += StorageArea::asString(instance);
+ Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
+ );
+ return true;
+}
+
+void StorageArea::Holes::erase(Instance* instance)
+throw() {
+ // instance->msHoleTime = 0;
+ instance->flags |= Flag::Ready;
+
+ if(instance->copyCounter != 0)
+ return;
+
+ /* Si la instancia NO ha sido registrada en la lista de huecos, sale sin más */
+ if((instance->flags & Flag::HasHole) == false)
+ return;
+
+ LOGLOCAL6(
+ string msg("dbos::StorageArea::Holes::erase | This: ");
+ msg += functions::asHexString(anna_ptrnumber_cast(this));
+ msg += " | ";
+ msg += StorageArea::asString(instance);
+ Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
+ );
+ a_holes.erase(instance->holeIterator);
+ instance->flags &= Flag::NoHasHole;
+ a_size --;
+}
+
+/****************************************************************************************
+* Iterador
+
+class A {
+public:
+ A () : a (0) { cout << "C0: " << (int) this << endl; }
+ A (const int _a): a (_a) { cout << "C1: " << (int) this << " " << a << endl; }
+ A (const A& other) : a (other.a) { cout << "C2: " << (int) this << " " << a << endl; }
+
+ A& operator = (const A& other) {
+ cout << "CP: " << (int) this << " " << (a = other.a) << endl;
+ return *this;
+ }
+
+ int get () const { return a; }
+private:
+ int a;
+};
+
+A fx () { return A (2000); }
+
+int main ()
+{
+ A aa = 100;
+ A bb (200);
+ A xx = aa;
+ A cc = fx ();
+
+ cout << "CC: " << (int) &cc << " " << cc.get () << endl;
+
+}
+
+La salida del programucho es la siguiente:
+
+C1: -4198808 100
+C1: -4198812 200
+C2: -4198816 100
+C1: -4198820 2000
+CC: -4198820 2000
+
+Lo que quiere decir que la "cc" la crea directamente sobre la pila y la asigna en fx sin aplicar ningn
+otro constructor.
+
+Por eso cuando hac� StorageArea::Iterator ii = xxx->begin (), maxi = xxx->end (); .....
+no estaba pasando por el contructor copia ni por ningn otro constructor.
+
+****************************************************************************************/
+// Dejo todo el ejemplo para que sirva de recordatorio.
+
--- /dev/null
+// ANNA - Anna is Not Nothingness Anymore //
+// //
+// (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
+// //
+// See project site at http://redmine.teslayout.com/projects/anna-suite //
+// See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
+
+
+#include <anna/core/internal/sccs.hpp>
+#include <anna/dbms/internal/sccs.hpp>
+
+#include <anna/dbos/internal/sccs.hpp>
+
+#include <anna/core/internal/ModuleManager.hpp>
+
+anna_define_sccs_tag(dbos, 1);
+
+void anna::dbos::sccs::activate()
+throw() {
+ dbms::sccs::activate();
+ ModuleManager::instantiate().insert(anna_use_sccs_tag(dbos), "00");
+}
+