/***************************************************************************
                          SIMPLY POWERFUL TOOLKIT (SPTK)
                               DEMO PROGRAMS SET
                          odbc_test2.cpp  -  description
                             -------------------
    begin                : October 23, 2005
    copyright            : (C) 2005 by Alexey S.Parshin
    email                : alexeyp@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef __BORLANDC__
#include <vcl.h>
#pragma hdrstop
#endif

#include <stdio.h>
#include <stdlib.h>

#include <sptk3/CException.h>

#include <sptk3/CODBCDatabase.h>
#include <sptk3/CQuery.h>

using namespace std;

// This function tries to execute the query. If the query
// was prepared earlier and the resourse it is using was
// dropped or altered, it switches to no-auto-prepare mode.
// Then the execution attempt is repeated.
void smartQueryExec(CQuery& query) {
   string sqlError;
   try {
      query.exec();
      return;
   }
   catch (exception& e) {
      if (!query.autoPrepare())
         throw;   // Query is already in no-auto-prepare mode
      if (strstr(e.what(),"altered") == 0L)
         throw;   // Table was not altered - something else is wrong
   }
   query.autoPrepare(false);
   query.unprepare();
   query.exec();
}

// This function tries to open the query. If the query
// was prepared earlier and the resourse it is using was
// dropped or altered, it switches to no-auto-prepare mode.
// Then the open attempt is repeated.
void smartQueryOpen(CQuery& query) {
   string sqlError;
   try {
      query.open();
      return;
   }
   catch (exception& e) {
      if (!query.autoPrepare())
         throw;   // Query is already in no-auto-prepare mode
      if (strstr(e.what(),"altered") == 0L)
         throw;   // Table was not altered - something else is wrong
   }
   query.autoPrepare(false);
   query.unprepare();
   query.open();
}

// This function creates the temporary table, fills it with data,
// prints the data from the table, and deletes the table.
// At the first call ALL the queries are automatically auto-prepared.
// The second call makes the auto-prepared queries to try to work 
// with destroyed and created table.
void testPrepareAndUnprepare(
   CQuery& step1Query,
   CQuery& step2Query,
   CQuery& step3Query,
   CQuery& step4Query
) {
   printf("Ok.\nStep 1: Creating the temp table.. ");
   smartQueryExec(step1Query);

   printf("Ok.\nStep 2: Inserting data into the temp table.. ");

   // The following example shows how to use the paramaters
   step2Query.param("person_id") = 1;
   step2Query.param("person_name") = "John Doe";
   smartQueryExec(step2Query);

   step2Query.param("person_id") = 2;
   step2Query.param("person_name") = "Jane Doe";
   smartQueryExec(step2Query);

   printf("Ok.\nStep 3: Selecting the information from the table ..\n");
   //step3Query.param("some_id") = 1;
   smartQueryOpen(step3Query);

   while ( ! step3Query.eof() ) {

         // getting data from the query by the field name
      int id = step3Query["id"].asInteger();

         // another method - getting data by the column number
      string name = step3Query["name"].asString();

      printf ("\t%i\t%s\n", id, name.c_str() );

      step3Query.fetch();
   }
   step3Query.close();

   smartQueryExec(step4Query);

   puts("Ok.\n***********************************************");
}

int main() {

   puts("This program tests how the prepare()/unprepare() methods work\n");

   // If you want to test the database abilities of the data controls
   // you have to setup the ODBC database connection.
   // Typical connect string is something like: "DSN=odbc_demo;UID=user;PWD=password".
   // If UID or PWD are omitted they are read from the datasource settings.
   CODBCDatabase     db("DSN=odbc_demo");

   for (unsigned i = 0; i < 2; i++) {
      try {
         printf("Openning the database.. ");
         db.open();
         printf("Ok.\nDriver description: %s\n",db.driverDescription().c_str());

         string tableName = "test_odbc";
         string isTemp = "TEMP";
         if (db.driverDescription() == "SQL Server") {
            tableName = "##test_odbc";
            isTemp = "";
         }
         // Defining the queries
         CQuery  step1Query(&db,"CREATE "+isTemp+" TABLE "+tableName+"(id INT,name CHAR(20))");
         CQuery  step2Query(&db,"INSERT INTO "+tableName+" VALUES ( :person_id, :person_name )");
         CQuery  step3Query(&db,"SELECT * FROM "+tableName);
         CQuery  step4Query(&db,"DROP TABLE "+tableName);

         puts("Pass 1 of the test");
         testPrepareAndUnprepare(
            step1Query,step2Query,step3Query,step4Query);

         puts("Pass 2 of the test");
         testPrepareAndUnprepare(
            step1Query,step2Query,step3Query,step4Query);

         puts("Pass 3 of the test");
         testPrepareAndUnprepare(
            step1Query,step2Query,step3Query,step4Query);

         printf("Ok.\nStep 6: Closing the database.. ");
         db.close();
         printf("Ok.\n");
      }
      catch (exception& e) {
         db.close();
         printf("\nError: %s\n",e.what());
         puts("\nSorry, you have to fix your database connection.");
         puts("Please, read the README.txt for more information.");
      }
   }

   return 0;
}
