Revert "Remove mysql and oracle resources for anna-ericsson project"
authorEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 7 Jul 2019 02:24:46 +0000 (04:24 +0200)
committerEduardo Ramos Testillano <eduardo.ramos.testillano@ericsson.com>
Sun, 7 Jul 2019 02:24:46 +0000 (04:24 +0200)
This reverts commit a3b95648bd76140ef55e0b5941d423eee6c3856f.

123 files changed:
example/dbms.mysql/insert/libraries.txt [new file with mode: 0644]
example/dbms.mysql/insert/main.cpp [new file with mode: 0644]
example/dbms.mysql/select/libraries.txt [new file with mode: 0644]
example/dbms.mysql/select/main.cpp [new file with mode: 0644]
example/dbms.mysql/xInsert/libraries.txt [new file with mode: 0644]
example/dbms.mysql/xInsert/main.cpp [new file with mode: 0644]
example/dbms.mysql/xSelect/libraries.txt [new file with mode: 0644]
example/dbms.mysql/xSelect/main.cpp [new file with mode: 0644]
example/dbos/workdir/filesystem/Abstract.cpp [new file with mode: 0644]
example/dbos/workdir/filesystem/Abstract.hpp [new file with mode: 0644]
example/dbos/workdir/filesystem/Directory.cpp [new file with mode: 0644]
example/dbos/workdir/filesystem/Directory.hpp [new file with mode: 0644]
example/dbos/workdir/filesystem/File.cpp [new file with mode: 0644]
example/dbos/workdir/filesystem/File.hpp [new file with mode: 0644]
example/dbos/workdir/libraries.txt [new file with mode: 0644]
example/dbos/workdir/main.cpp [new file with mode: 0644]
example/dbos/workdir/storage/Directory.cpp [new file with mode: 0644]
example/dbos/workdir/storage/Directory.hpp [new file with mode: 0644]
example/dbos/workdir/storage/File.cpp [new file with mode: 0644]
example/dbos/workdir/storage/File.hpp [new file with mode: 0644]
include/anna/dbms.mysql/BaseBind.hpp [new file with mode: 0644]
include/anna/dbms.mysql/Connection.hpp [new file with mode: 0644]
include/anna/dbms.mysql/Database.hpp [new file with mode: 0644]
include/anna/dbms.mysql/InputBind.hpp [new file with mode: 0644]
include/anna/dbms.mysql/OracleTranslator.hpp [new file with mode: 0644]
include/anna/dbms.mysql/OutputBind.hpp [new file with mode: 0644]
include/anna/dbms.mysql/ResultCode.hpp [new file with mode: 0644]
include/anna/dbms.mysql/Statement.hpp [new file with mode: 0644]
include/anna/dbms.mysql/forward.hpp [new file with mode: 0644]
include/anna/dbms.mysql/internal/sccs.hpp [new file with mode: 0644]
include/anna/dbms.mysql/mysql.hpp [new file with mode: 0644]
include/anna/dbms.oracle/BaseBind.hpp [new file with mode: 0644]
include/anna/dbms.oracle/Connection.hpp [new file with mode: 0644]
include/anna/dbms.oracle/Database.hpp [new file with mode: 0644]
include/anna/dbms.oracle/Descriptor.hpp [new file with mode: 0644]
include/anna/dbms.oracle/InputBind.hpp [new file with mode: 0644]
include/anna/dbms.oracle/OutputBind.hpp [new file with mode: 0644]
include/anna/dbms.oracle/ResultCode.hpp [new file with mode: 0644]
include/anna/dbms.oracle/Statement.hpp [new file with mode: 0644]
include/anna/dbms.oracle/internal/sccs.hpp [new file with mode: 0644]
include/anna/dbms.oracle/oracle.hpp [new file with mode: 0644]
include/anna/dbms/Bind.hpp [new file with mode: 0644]
include/anna/dbms/Connection.hpp [new file with mode: 0644]
include/anna/dbms/Data.hpp [new file with mode: 0644]
include/anna/dbms/Database.hpp [new file with mode: 0644]
include/anna/dbms/DatabaseException.hpp [new file with mode: 0644]
include/anna/dbms/Date.hpp [new file with mode: 0644]
include/anna/dbms/Delivery.hpp [new file with mode: 0644]
include/anna/dbms/FailRecoveryHandler.hpp [new file with mode: 0644]
include/anna/dbms/Float.hpp [new file with mode: 0644]
include/anna/dbms/InputBind.hpp [new file with mode: 0644]
include/anna/dbms/Integer.hpp [new file with mode: 0644]
include/anna/dbms/LongBlock.hpp [new file with mode: 0644]
include/anna/dbms/OutputBind.hpp [new file with mode: 0644]
include/anna/dbms/ResultCode.hpp [new file with mode: 0644]
include/anna/dbms/Sentence.hpp [new file with mode: 0644]
include/anna/dbms/ShortBlock.hpp [new file with mode: 0644]
include/anna/dbms/Statement.hpp [new file with mode: 0644]
include/anna/dbms/StatementTranslator.hpp [new file with mode: 0644]
include/anna/dbms/String.hpp [new file with mode: 0644]
include/anna/dbms/TimeStamp.hpp [new file with mode: 0644]
include/anna/dbms/dbms.hpp [new file with mode: 0644]
include/anna/dbms/functions.hpp [new file with mode: 0644]
include/anna/dbms/internal/sccs.hpp [new file with mode: 0644]
include/anna/dbos/Accesor.hpp [new file with mode: 0644]
include/anna/dbos/AutoObject.hpp [new file with mode: 0644]
include/anna/dbos/AutoSet.hpp [new file with mode: 0644]
include/anna/dbos/Creator.hpp [new file with mode: 0644]
include/anna/dbos/CrossedLoader.hpp [new file with mode: 0644]
include/anna/dbos/Eraser.hpp [new file with mode: 0644]
include/anna/dbos/Loader.hpp [new file with mode: 0644]
include/anna/dbos/Object.hpp [new file with mode: 0644]
include/anna/dbos/ObjectAllocator.hpp [new file with mode: 0644]
include/anna/dbos/ObjectFacade.hpp [new file with mode: 0644]
include/anna/dbos/Recorder.hpp [new file with mode: 0644]
include/anna/dbos/Repository.hpp [new file with mode: 0644]
include/anna/dbos/Set.hpp [new file with mode: 0644]
include/anna/dbos/SetFacade.hpp [new file with mode: 0644]
include/anna/dbos/StorageArea.hpp [new file with mode: 0644]
include/anna/dbos/dbos.hpp [new file with mode: 0644]
include/anna/dbos/defines.hpp [new file with mode: 0644]
include/anna/dbos/internal/sccs.hpp [new file with mode: 0644]
source/dbms.mysql/BaseBind.cpp [new file with mode: 0644]
source/dbms.mysql/Connection.cpp [new file with mode: 0644]
source/dbms.mysql/Database.cpp [new file with mode: 0644]
source/dbms.mysql/InputBind.cpp [new file with mode: 0644]
source/dbms.mysql/OracleTranslator.cpp [new file with mode: 0644]
source/dbms.mysql/OutputBind.cpp [new file with mode: 0644]
source/dbms.mysql/ResultCode.cpp [new file with mode: 0644]
source/dbms.mysql/Statement.cpp [new file with mode: 0644]
source/dbms.mysql/internal/sccs.cpp [new file with mode: 0644]
source/dbms.oracle/BaseBind.cpp [new file with mode: 0644]
source/dbms.oracle/Connection.cpp [new file with mode: 0644]
source/dbms.oracle/Database.cpp [new file with mode: 0644]
source/dbms.oracle/Descriptor.cpp [new file with mode: 0644]
source/dbms.oracle/InputBind.cpp [new file with mode: 0644]
source/dbms.oracle/OutputBind.cpp [new file with mode: 0644]
source/dbms.oracle/ResultCode.cpp [new file with mode: 0644]
source/dbms.oracle/Statement.cpp [new file with mode: 0644]
source/dbms.oracle/internal/sccs.cpp [new file with mode: 0644]
source/dbms/Bind.cpp [new file with mode: 0644]
source/dbms/Connection.cpp [new file with mode: 0644]
source/dbms/Data.cpp [new file with mode: 0644]
source/dbms/Database.cpp [new file with mode: 0644]
source/dbms/Date.cpp [new file with mode: 0644]
source/dbms/Delivery.cpp [new file with mode: 0644]
source/dbms/Float.cc.new [new file with mode: 0644]
source/dbms/Float.cpp [new file with mode: 0644]
source/dbms/Integer.cpp [new file with mode: 0644]
source/dbms/LongBlock.cpp [new file with mode: 0644]
source/dbms/OutputBind.cpp [new file with mode: 0644]
source/dbms/ResultCode.cpp [new file with mode: 0644]
source/dbms/Sentence.cpp [new file with mode: 0644]
source/dbms/ShortBlock.cpp [new file with mode: 0644]
source/dbms/Statement.cpp [new file with mode: 0644]
source/dbms/String.cpp [new file with mode: 0644]
source/dbms/TimeStamp.cpp [new file with mode: 0644]
source/dbms/functions.cpp [new file with mode: 0644]
source/dbms/internal/sccs.cpp [new file with mode: 0644]
source/dbos/Accesor.cpp [new file with mode: 0644]
source/dbos/Repository.cpp [new file with mode: 0644]
source/dbos/StorageArea.cpp [new file with mode: 0644]
source/dbos/internal/sccs.cpp [new file with mode: 0644]

diff --git a/example/dbms.mysql/insert/libraries.txt b/example/dbms.mysql/insert/libraries.txt
new file mode 100644 (file)
index 0000000..18c098a
--- /dev/null
@@ -0,0 +1 @@
+mysqlclient
diff --git a/example/dbms.mysql/insert/main.cpp b/example/dbms.mysql/insert/main.cpp
new file mode 100644 (file)
index 0000000..7ed298e
--- /dev/null
@@ -0,0 +1,141 @@
+#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;
+}
diff --git a/example/dbms.mysql/select/libraries.txt b/example/dbms.mysql/select/libraries.txt
new file mode 100644 (file)
index 0000000..18c098a
--- /dev/null
@@ -0,0 +1 @@
+mysqlclient
diff --git a/example/dbms.mysql/select/main.cpp b/example/dbms.mysql/select/main.cpp
new file mode 100644 (file)
index 0000000..3a13785
--- /dev/null
@@ -0,0 +1,188 @@
+#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);
+   }
+
+}
diff --git a/example/dbms.mysql/xInsert/libraries.txt b/example/dbms.mysql/xInsert/libraries.txt
new file mode 100644 (file)
index 0000000..9806884
--- /dev/null
@@ -0,0 +1,10 @@
+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
diff --git a/example/dbms.mysql/xInsert/main.cpp b/example/dbms.mysql/xInsert/main.cpp
new file mode 100644 (file)
index 0000000..d52b9a1
--- /dev/null
@@ -0,0 +1,156 @@
+// 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); 
+   }
+}
+
+
+
diff --git a/example/dbms.mysql/xSelect/libraries.txt b/example/dbms.mysql/xSelect/libraries.txt
new file mode 100644 (file)
index 0000000..9806884
--- /dev/null
@@ -0,0 +1,10 @@
+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
diff --git a/example/dbms.mysql/xSelect/main.cpp b/example/dbms.mysql/xSelect/main.cpp
new file mode 100644 (file)
index 0000000..6f7fdcc
--- /dev/null
@@ -0,0 +1,139 @@
+// 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); 
+   }
+}
+
+
+
diff --git a/example/dbos/workdir/filesystem/Abstract.cpp b/example/dbos/workdir/filesystem/Abstract.cpp
new file mode 100644 (file)
index 0000000..f304470
--- /dev/null
@@ -0,0 +1,52 @@
+// 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;
+}
diff --git a/example/dbos/workdir/filesystem/Abstract.hpp b/example/dbos/workdir/filesystem/Abstract.hpp
new file mode 100644 (file)
index 0000000..de28336
--- /dev/null
@@ -0,0 +1,69 @@
+// 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
diff --git a/example/dbos/workdir/filesystem/Directory.cpp b/example/dbos/workdir/filesystem/Directory.cpp
new file mode 100644 (file)
index 0000000..e22c859
--- /dev/null
@@ -0,0 +1,69 @@
+// 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);
+   }      
+}
diff --git a/example/dbos/workdir/filesystem/Directory.hpp b/example/dbos/workdir/filesystem/Directory.hpp
new file mode 100644 (file)
index 0000000..95490d7
--- /dev/null
@@ -0,0 +1,38 @@
+// 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
diff --git a/example/dbos/workdir/filesystem/File.cpp b/example/dbos/workdir/filesystem/File.cpp
new file mode 100644 (file)
index 0000000..888f46a
--- /dev/null
@@ -0,0 +1,21 @@
+// 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;
+}
diff --git a/example/dbos/workdir/filesystem/File.hpp b/example/dbos/workdir/filesystem/File.hpp
new file mode 100644 (file)
index 0000000..f3da2df
--- /dev/null
@@ -0,0 +1,38 @@
+// 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
diff --git a/example/dbos/workdir/libraries.txt b/example/dbos/workdir/libraries.txt
new file mode 100644 (file)
index 0000000..5a99acb
--- /dev/null
@@ -0,0 +1,9 @@
+anna_dbos_static
+anna_dbms_static
+anna_comm_static
+anna_app_static
+anna_xml_static
+anna_io_static
+anna_core_static
+rt
+xml2
diff --git a/example/dbos/workdir/main.cpp b/example/dbos/workdir/main.cpp
new file mode 100644 (file)
index 0000000..3b9c99f
--- /dev/null
@@ -0,0 +1,351 @@
+// 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);         
+      }
+   }      
+}
diff --git a/example/dbos/workdir/storage/Directory.cpp b/example/dbos/workdir/storage/Directory.cpp
new file mode 100644 (file)
index 0000000..7c35dc6
--- /dev/null
@@ -0,0 +1,129 @@
+// 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 += " }";
+}
+
diff --git a/example/dbos/workdir/storage/Directory.hpp b/example/dbos/workdir/storage/Directory.hpp
new file mode 100644 (file)
index 0000000..3bffdf3
--- /dev/null
@@ -0,0 +1,93 @@
+// 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
diff --git a/example/dbos/workdir/storage/File.cpp b/example/dbos/workdir/storage/File.cpp
new file mode 100644 (file)
index 0000000..6a23430
--- /dev/null
@@ -0,0 +1,133 @@
+// 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 += " }";
+}
+
diff --git a/example/dbos/workdir/storage/File.hpp b/example/dbos/workdir/storage/File.hpp
new file mode 100644 (file)
index 0000000..51d4293
--- /dev/null
@@ -0,0 +1,97 @@
+// 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
diff --git a/include/anna/dbms.mysql/BaseBind.hpp b/include/anna/dbms.mysql/BaseBind.hpp
new file mode 100644 (file)
index 0000000..a9a3b85
--- /dev/null
@@ -0,0 +1,53 @@
+// 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
+
diff --git a/include/anna/dbms.mysql/Connection.hpp b/include/anna/dbms.mysql/Connection.hpp
new file mode 100644 (file)
index 0000000..ea817c3
--- /dev/null
@@ -0,0 +1,72 @@
+// 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
diff --git a/include/anna/dbms.mysql/Database.hpp b/include/anna/dbms.mysql/Database.hpp
new file mode 100644 (file)
index 0000000..b9ad79e
--- /dev/null
@@ -0,0 +1,105 @@
+// 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
diff --git a/include/anna/dbms.mysql/InputBind.hpp b/include/anna/dbms.mysql/InputBind.hpp
new file mode 100644 (file)
index 0000000..8f58e1e
--- /dev/null
@@ -0,0 +1,57 @@
+// 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
+
diff --git a/include/anna/dbms.mysql/OracleTranslator.hpp b/include/anna/dbms.mysql/OracleTranslator.hpp
new file mode 100644 (file)
index 0000000..95573e1
--- /dev/null
@@ -0,0 +1,54 @@
+// 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
diff --git a/include/anna/dbms.mysql/OutputBind.hpp b/include/anna/dbms.mysql/OutputBind.hpp
new file mode 100644 (file)
index 0000000..72e9929
--- /dev/null
@@ -0,0 +1,68 @@
+// 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
+
diff --git a/include/anna/dbms.mysql/ResultCode.hpp b/include/anna/dbms.mysql/ResultCode.hpp
new file mode 100644 (file)
index 0000000..1c27be9
--- /dev/null
@@ -0,0 +1,56 @@
+// 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
+
diff --git a/include/anna/dbms.mysql/Statement.hpp b/include/anna/dbms.mysql/Statement.hpp
new file mode 100644 (file)
index 0000000..48c9f86
--- /dev/null
@@ -0,0 +1,95 @@
+// 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
+
diff --git a/include/anna/dbms.mysql/forward.hpp b/include/anna/dbms.mysql/forward.hpp
new file mode 100644 (file)
index 0000000..36fe912
--- /dev/null
@@ -0,0 +1,26 @@
+// 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*/
diff --git a/include/anna/dbms.mysql/internal/sccs.hpp b/include/anna/dbms.mysql/internal/sccs.hpp
new file mode 100644 (file)
index 0000000..4c8a529
--- /dev/null
@@ -0,0 +1,28 @@
+// 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
+
diff --git a/include/anna/dbms.mysql/mysql.hpp b/include/anna/dbms.mysql/mysql.hpp
new file mode 100644 (file)
index 0000000..bee3ca9
--- /dev/null
@@ -0,0 +1,44 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/BaseBind.hpp b/include/anna/dbms.oracle/BaseBind.hpp
new file mode 100644 (file)
index 0000000..c99699c
--- /dev/null
@@ -0,0 +1,79 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/Connection.hpp b/include/anna/dbms.oracle/Connection.hpp
new file mode 100644 (file)
index 0000000..2259d9e
--- /dev/null
@@ -0,0 +1,73 @@
+// 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
diff --git a/include/anna/dbms.oracle/Database.hpp b/include/anna/dbms.oracle/Database.hpp
new file mode 100644 (file)
index 0000000..39d9d5f
--- /dev/null
@@ -0,0 +1,128 @@
+// 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
diff --git a/include/anna/dbms.oracle/Descriptor.hpp b/include/anna/dbms.oracle/Descriptor.hpp
new file mode 100644 (file)
index 0000000..af2395d
--- /dev/null
@@ -0,0 +1,49 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/InputBind.hpp b/include/anna/dbms.oracle/InputBind.hpp
new file mode 100644 (file)
index 0000000..3b0b6ee
--- /dev/null
@@ -0,0 +1,60 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/OutputBind.hpp b/include/anna/dbms.oracle/OutputBind.hpp
new file mode 100644 (file)
index 0000000..ce41a22
--- /dev/null
@@ -0,0 +1,58 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/ResultCode.hpp b/include/anna/dbms.oracle/ResultCode.hpp
new file mode 100644 (file)
index 0000000..b9f8fd5
--- /dev/null
@@ -0,0 +1,52 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/Statement.hpp b/include/anna/dbms.oracle/Statement.hpp
new file mode 100644 (file)
index 0000000..d959c0b
--- /dev/null
@@ -0,0 +1,75 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/internal/sccs.hpp b/include/anna/dbms.oracle/internal/sccs.hpp
new file mode 100644 (file)
index 0000000..fd02966
--- /dev/null
@@ -0,0 +1,28 @@
+// 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
+
diff --git a/include/anna/dbms.oracle/oracle.hpp b/include/anna/dbms.oracle/oracle.hpp
new file mode 100644 (file)
index 0000000..c34c766
--- /dev/null
@@ -0,0 +1,44 @@
+// 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
+
diff --git a/include/anna/dbms/Bind.hpp b/include/anna/dbms/Bind.hpp
new file mode 100644 (file)
index 0000000..5bc3b7b
--- /dev/null
@@ -0,0 +1,53 @@
+// 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
+
diff --git a/include/anna/dbms/Connection.hpp b/include/anna/dbms/Connection.hpp
new file mode 100644 (file)
index 0000000..4744128
--- /dev/null
@@ -0,0 +1,194 @@
+// 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
diff --git a/include/anna/dbms/Data.hpp b/include/anna/dbms/Data.hpp
new file mode 100644 (file)
index 0000000..03de108
--- /dev/null
@@ -0,0 +1,147 @@
+// 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
+
diff --git a/include/anna/dbms/Database.hpp b/include/anna/dbms/Database.hpp
new file mode 100644 (file)
index 0000000..bbe46c5
--- /dev/null
@@ -0,0 +1,296 @@
+// 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
diff --git a/include/anna/dbms/DatabaseException.hpp b/include/anna/dbms/DatabaseException.hpp
new file mode 100644 (file)
index 0000000..66bccee
--- /dev/null
@@ -0,0 +1,76 @@
+// 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
+
diff --git a/include/anna/dbms/Date.hpp b/include/anna/dbms/Date.hpp
new file mode 100644 (file)
index 0000000..92e96cc
--- /dev/null
@@ -0,0 +1,337 @@
+// 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
+
diff --git a/include/anna/dbms/Delivery.hpp b/include/anna/dbms/Delivery.hpp
new file mode 100644 (file)
index 0000000..6cd4603
--- /dev/null
@@ -0,0 +1,79 @@
+// 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
diff --git a/include/anna/dbms/FailRecoveryHandler.hpp b/include/anna/dbms/FailRecoveryHandler.hpp
new file mode 100644 (file)
index 0000000..7519854
--- /dev/null
@@ -0,0 +1,44 @@
+// 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
+
+
+
diff --git a/include/anna/dbms/Float.hpp b/include/anna/dbms/Float.hpp
new file mode 100644 (file)
index 0000000..427668e
--- /dev/null
@@ -0,0 +1,115 @@
+// 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
+
diff --git a/include/anna/dbms/InputBind.hpp b/include/anna/dbms/InputBind.hpp
new file mode 100644 (file)
index 0000000..069fb22
--- /dev/null
@@ -0,0 +1,32 @@
+// 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
+
diff --git a/include/anna/dbms/Integer.hpp b/include/anna/dbms/Integer.hpp
new file mode 100644 (file)
index 0000000..ce98691
--- /dev/null
@@ -0,0 +1,98 @@
+// 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
+
diff --git a/include/anna/dbms/LongBlock.hpp b/include/anna/dbms/LongBlock.hpp
new file mode 100644 (file)
index 0000000..d0cb9c0
--- /dev/null
@@ -0,0 +1,122 @@
+// 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
+
diff --git a/include/anna/dbms/OutputBind.hpp b/include/anna/dbms/OutputBind.hpp
new file mode 100644 (file)
index 0000000..e0c7c70
--- /dev/null
@@ -0,0 +1,53 @@
+// 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
+
diff --git a/include/anna/dbms/ResultCode.hpp b/include/anna/dbms/ResultCode.hpp
new file mode 100644 (file)
index 0000000..6489594
--- /dev/null
@@ -0,0 +1,172 @@
+// 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
+
diff --git a/include/anna/dbms/Sentence.hpp b/include/anna/dbms/Sentence.hpp
new file mode 100644 (file)
index 0000000..39d045e
--- /dev/null
@@ -0,0 +1,122 @@
+// 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
+
diff --git a/include/anna/dbms/ShortBlock.hpp b/include/anna/dbms/ShortBlock.hpp
new file mode 100644 (file)
index 0000000..cf22c7b
--- /dev/null
@@ -0,0 +1,115 @@
+// 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
+
diff --git a/include/anna/dbms/Statement.hpp b/include/anna/dbms/Statement.hpp
new file mode 100644 (file)
index 0000000..df20293
--- /dev/null
@@ -0,0 +1,291 @@
+// 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
diff --git a/include/anna/dbms/StatementTranslator.hpp b/include/anna/dbms/StatementTranslator.hpp
new file mode 100644 (file)
index 0000000..8610aaa
--- /dev/null
@@ -0,0 +1,86 @@
+// 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
+
+
diff --git a/include/anna/dbms/String.hpp b/include/anna/dbms/String.hpp
new file mode 100644 (file)
index 0000000..a591eed
--- /dev/null
@@ -0,0 +1,114 @@
+// 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
+
diff --git a/include/anna/dbms/TimeStamp.hpp b/include/anna/dbms/TimeStamp.hpp
new file mode 100644 (file)
index 0000000..9f53aea
--- /dev/null
@@ -0,0 +1,188 @@
+// 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
+
diff --git a/include/anna/dbms/dbms.hpp b/include/anna/dbms/dbms.hpp
new file mode 100644 (file)
index 0000000..cccdad3
--- /dev/null
@@ -0,0 +1,51 @@
+// 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
+
diff --git a/include/anna/dbms/functions.hpp b/include/anna/dbms/functions.hpp
new file mode 100644 (file)
index 0000000..e782d34
--- /dev/null
@@ -0,0 +1,96 @@
+// 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
diff --git a/include/anna/dbms/internal/sccs.hpp b/include/anna/dbms/internal/sccs.hpp
new file mode 100644 (file)
index 0000000..d518c6a
--- /dev/null
@@ -0,0 +1,25 @@
+// 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
+
diff --git a/include/anna/dbos/Accesor.hpp b/include/anna/dbos/Accesor.hpp
new file mode 100644 (file)
index 0000000..a719c51
--- /dev/null
@@ -0,0 +1,175 @@
+// 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
+
+
+
diff --git a/include/anna/dbos/AutoObject.hpp b/include/anna/dbos/AutoObject.hpp
new file mode 100644 (file)
index 0000000..6c3992e
--- /dev/null
@@ -0,0 +1,152 @@
+// 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
+
+
diff --git a/include/anna/dbos/AutoSet.hpp b/include/anna/dbos/AutoSet.hpp
new file mode 100644 (file)
index 0000000..5882bb1
--- /dev/null
@@ -0,0 +1,158 @@
+// 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
+
+
diff --git a/include/anna/dbos/Creator.hpp b/include/anna/dbos/Creator.hpp
new file mode 100644 (file)
index 0000000..2f806cd
--- /dev/null
@@ -0,0 +1,65 @@
+// 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
+
+
+
diff --git a/include/anna/dbos/CrossedLoader.hpp b/include/anna/dbos/CrossedLoader.hpp
new file mode 100644 (file)
index 0000000..c1516ec
--- /dev/null
@@ -0,0 +1,97 @@
+// 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
+
+
+
diff --git a/include/anna/dbos/Eraser.hpp b/include/anna/dbos/Eraser.hpp
new file mode 100644 (file)
index 0000000..3994714
--- /dev/null
@@ -0,0 +1,70 @@
+// 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
+
+
+
diff --git a/include/anna/dbos/Loader.hpp b/include/anna/dbos/Loader.hpp
new file mode 100644 (file)
index 0000000..ec71709
--- /dev/null
@@ -0,0 +1,77 @@
+// 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
+
+
+
diff --git a/include/anna/dbos/Object.hpp b/include/anna/dbos/Object.hpp
new file mode 100644 (file)
index 0000000..fc4e38c
--- /dev/null
@@ -0,0 +1,112 @@
+// 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
diff --git a/include/anna/dbos/ObjectAllocator.hpp b/include/anna/dbos/ObjectAllocator.hpp
new file mode 100644 (file)
index 0000000..df9f190
--- /dev/null
@@ -0,0 +1,25 @@
+// 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
+
diff --git a/include/anna/dbos/ObjectFacade.hpp b/include/anna/dbos/ObjectFacade.hpp
new file mode 100644 (file)
index 0000000..18577f0
--- /dev/null
@@ -0,0 +1,406 @@
+// 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
diff --git a/include/anna/dbos/Recorder.hpp b/include/anna/dbos/Recorder.hpp
new file mode 100644 (file)
index 0000000..696e665
--- /dev/null
@@ -0,0 +1,51 @@
+// 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
+
+
+
diff --git a/include/anna/dbos/Repository.hpp b/include/anna/dbos/Repository.hpp
new file mode 100644 (file)
index 0000000..57a90ea
--- /dev/null
@@ -0,0 +1,154 @@
+// 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
diff --git a/include/anna/dbos/Set.hpp b/include/anna/dbos/Set.hpp
new file mode 100644 (file)
index 0000000..a4325b9
--- /dev/null
@@ -0,0 +1,173 @@
+// 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
+
+
diff --git a/include/anna/dbos/SetFacade.hpp b/include/anna/dbos/SetFacade.hpp
new file mode 100644 (file)
index 0000000..babadc9
--- /dev/null
@@ -0,0 +1,126 @@
+// 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
diff --git a/include/anna/dbos/StorageArea.hpp b/include/anna/dbos/StorageArea.hpp
new file mode 100644 (file)
index 0000000..e9bda03
--- /dev/null
@@ -0,0 +1,625 @@
+// 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
diff --git a/include/anna/dbos/dbos.hpp b/include/anna/dbos/dbos.hpp
new file mode 100644 (file)
index 0000000..1e7609e
--- /dev/null
@@ -0,0 +1,50 @@
+// 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
+
diff --git a/include/anna/dbos/defines.hpp b/include/anna/dbos/defines.hpp
new file mode 100644 (file)
index 0000000..7e9a25f
--- /dev/null
@@ -0,0 +1,26 @@
+// 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
+
diff --git a/include/anna/dbos/internal/sccs.hpp b/include/anna/dbos/internal/sccs.hpp
new file mode 100644 (file)
index 0000000..e4699c5
--- /dev/null
@@ -0,0 +1,25 @@
+// 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
+
diff --git a/source/dbms.mysql/BaseBind.cpp b/source/dbms.mysql/BaseBind.cpp
new file mode 100644 (file)
index 0000000..b91ca85
--- /dev/null
@@ -0,0 +1,107 @@
+// 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);
+  }
+}
+
diff --git a/source/dbms.mysql/Connection.cpp b/source/dbms.mysql/Connection.cpp
new file mode 100644 (file)
index 0000000..aae802c
--- /dev/null
@@ -0,0 +1,103 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms.mysql/Database.cpp b/source/dbms.mysql/Database.cpp
new file mode 100644 (file)
index 0000000..9508158
--- /dev/null
@@ -0,0 +1,77 @@
+// 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;
+}
diff --git a/source/dbms.mysql/InputBind.cpp b/source/dbms.mysql/InputBind.cpp
new file mode 100644 (file)
index 0000000..edfb2d3
--- /dev/null
@@ -0,0 +1,110 @@
+// 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();
+}
+
diff --git a/source/dbms.mysql/OracleTranslator.cpp b/source/dbms.mysql/OracleTranslator.cpp
new file mode 100644 (file)
index 0000000..4db0d52
--- /dev/null
@@ -0,0 +1,94 @@
+// 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;
+}
+
diff --git a/source/dbms.mysql/OutputBind.cpp b/source/dbms.mysql/OutputBind.cpp
new file mode 100644 (file)
index 0000000..016b9e9
--- /dev/null
@@ -0,0 +1,174 @@
+// 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);
+}
diff --git a/source/dbms.mysql/ResultCode.cpp b/source/dbms.mysql/ResultCode.cpp
new file mode 100644 (file)
index 0000000..c4e8f2d
--- /dev/null
@@ -0,0 +1,63 @@
+// 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;
+}
diff --git a/source/dbms.mysql/Statement.cpp b/source/dbms.mysql/Statement.cpp
new file mode 100644 (file)
index 0000000..df18acc
--- /dev/null
@@ -0,0 +1,192 @@
+// 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;
+}
diff --git a/source/dbms.mysql/internal/sccs.cpp b/source/dbms.mysql/internal/sccs.cpp
new file mode 100644 (file)
index 0000000..5317de4
--- /dev/null
@@ -0,0 +1,22 @@
+// 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");
+}
+
diff --git a/source/dbms.oracle/BaseBind.cpp b/source/dbms.oracle/BaseBind.cpp
new file mode 100644 (file)
index 0000000..4eb7b75
--- /dev/null
@@ -0,0 +1,107 @@
+// 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;
+}
+
diff --git a/source/dbms.oracle/Connection.cpp b/source/dbms.oracle/Connection.cpp
new file mode 100644 (file)
index 0000000..b3cea7a
--- /dev/null
@@ -0,0 +1,147 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms.oracle/Database.cpp b/source/dbms.oracle/Database.cpp
new file mode 100644 (file)
index 0000000..a90785e
--- /dev/null
@@ -0,0 +1,139 @@
+// 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");
+}
diff --git a/source/dbms.oracle/Descriptor.cpp b/source/dbms.oracle/Descriptor.cpp
new file mode 100644 (file)
index 0000000..b7e5011
--- /dev/null
@@ -0,0 +1,39 @@
+// 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);
+  }
+}
diff --git a/source/dbms.oracle/InputBind.cpp b/source/dbms.oracle/InputBind.cpp
new file mode 100644 (file)
index 0000000..c554843
--- /dev/null
@@ -0,0 +1,208 @@
+// 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);
+  }
+}
diff --git a/source/dbms.oracle/OutputBind.cpp b/source/dbms.oracle/OutputBind.cpp
new file mode 100644 (file)
index 0000000..9b18d68
--- /dev/null
@@ -0,0 +1,278 @@
+// 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);
+  }
+}
diff --git a/source/dbms.oracle/ResultCode.cpp b/source/dbms.oracle/ResultCode.cpp
new file mode 100644 (file)
index 0000000..d9a2200
--- /dev/null
@@ -0,0 +1,65 @@
+// 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;
+}
diff --git a/source/dbms.oracle/Statement.cpp b/source/dbms.oracle/Statement.cpp
new file mode 100644 (file)
index 0000000..1cf6e8a
--- /dev/null
@@ -0,0 +1,128 @@
+// 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;
+}
+
+
+
diff --git a/source/dbms.oracle/internal/sccs.cpp b/source/dbms.oracle/internal/sccs.cpp
new file mode 100644 (file)
index 0000000..aa19165
--- /dev/null
@@ -0,0 +1,22 @@
+// 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");
+}
+
diff --git a/source/dbms/Bind.cpp b/source/dbms/Bind.cpp
new file mode 100644 (file)
index 0000000..b54cdbe
--- /dev/null
@@ -0,0 +1,23 @@
+// 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 += " }";
+}
+
+
diff --git a/source/dbms/Connection.cpp b/source/dbms/Connection.cpp
new file mode 100644 (file)
index 0000000..9dcdcb5
--- /dev/null
@@ -0,0 +1,230 @@
+// 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;
+}
+
diff --git a/source/dbms/Data.cpp b/source/dbms/Data.cpp
new file mode 100644 (file)
index 0000000..3e75b0f
--- /dev/null
@@ -0,0 +1,28 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/Database.cpp b/source/dbms/Database.cpp
new file mode 100644 (file)
index 0000000..987038f
--- /dev/null
@@ -0,0 +1,325 @@
+// 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;
+}
+
diff --git a/source/dbms/Date.cpp b/source/dbms/Date.cpp
new file mode 100644 (file)
index 0000000..5c9afaf
--- /dev/null
@@ -0,0 +1,149 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/Delivery.cpp b/source/dbms/Delivery.cpp
new file mode 100644 (file)
index 0000000..8ae88e4
--- /dev/null
@@ -0,0 +1,66 @@
+// 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;
+}
diff --git a/source/dbms/Float.cc.new b/source/dbms/Float.cc.new
new file mode 100644 (file)
index 0000000..92ffbac
--- /dev/null
@@ -0,0 +1,19 @@
+#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 += " }";
+}
+
diff --git a/source/dbms/Float.cpp b/source/dbms/Float.cpp
new file mode 100644 (file)
index 0000000..7f4185d
--- /dev/null
@@ -0,0 +1,26 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/Integer.cpp b/source/dbms/Integer.cpp
new file mode 100644 (file)
index 0000000..605a20b
--- /dev/null
@@ -0,0 +1,23 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/LongBlock.cpp b/source/dbms/LongBlock.cpp
new file mode 100644 (file)
index 0000000..da1796a
--- /dev/null
@@ -0,0 +1,48 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/OutputBind.cpp b/source/dbms/OutputBind.cpp
new file mode 100644 (file)
index 0000000..53e6b23
--- /dev/null
@@ -0,0 +1,37 @@
+// 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));
+}
+
+
diff --git a/source/dbms/ResultCode.cpp b/source/dbms/ResultCode.cpp
new file mode 100644 (file)
index 0000000..453f78b
--- /dev/null
@@ -0,0 +1,104 @@
+// 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 += " }";
+}
diff --git a/source/dbms/Sentence.cpp b/source/dbms/Sentence.cpp
new file mode 100644 (file)
index 0000000..34dfaf3
--- /dev/null
@@ -0,0 +1,99 @@
+// 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;
+}
diff --git a/source/dbms/ShortBlock.cpp b/source/dbms/ShortBlock.cpp
new file mode 100644 (file)
index 0000000..a47de5f
--- /dev/null
@@ -0,0 +1,52 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/Statement.cpp b/source/dbms/Statement.cpp
new file mode 100644 (file)
index 0000000..e2895e0
--- /dev/null
@@ -0,0 +1,86 @@
+// 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();
+}
+
diff --git a/source/dbms/String.cpp b/source/dbms/String.cpp
new file mode 100644 (file)
index 0000000..2e7e6fb
--- /dev/null
@@ -0,0 +1,69 @@
+// 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 += " }";
+}
+
diff --git a/source/dbms/TimeStamp.cpp b/source/dbms/TimeStamp.cpp
new file mode 100644 (file)
index 0000000..7cfe654
--- /dev/null
@@ -0,0 +1,39 @@
+// 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;
+}
diff --git a/source/dbms/functions.cpp b/source/dbms/functions.cpp
new file mode 100644 (file)
index 0000000..97a4e88
--- /dev/null
@@ -0,0 +1,60 @@
+// 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;
+  }
+}
diff --git a/source/dbms/internal/sccs.cpp b/source/dbms/internal/sccs.cpp
new file mode 100644 (file)
index 0000000..313df2c
--- /dev/null
@@ -0,0 +1,28 @@
+// 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");
+}
+
diff --git a/source/dbos/Accesor.cpp b/source/dbos/Accesor.cpp
new file mode 100644 (file)
index 0000000..f77d2aa
--- /dev/null
@@ -0,0 +1,105 @@
+// 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();
+}
diff --git a/source/dbos/Repository.cpp b/source/dbos/Repository.cpp
new file mode 100644 (file)
index 0000000..49dd961
--- /dev/null
@@ -0,0 +1,95 @@
+// 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;
+}
+
diff --git a/source/dbos/StorageArea.cpp b/source/dbos/StorageArea.cpp
new file mode 100644 (file)
index 0000000..830f647
--- /dev/null
@@ -0,0 +1,1081 @@
+// 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.
+
diff --git a/source/dbos/internal/sccs.cpp b/source/dbos/internal/sccs.cpp
new file mode 100644 (file)
index 0000000..9c2905d
--- /dev/null
@@ -0,0 +1,23 @@
+// 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");
+}
+