// i/o
#include <stdio.h>

// JM Milan
#include <string.h>

// system imports
#include <sys/time.h>
#include <sys/utsname.h>

// postgres
#include "libpq-fe.h"

//#define D

#define TRANS 100

int 
main(int argc, char *argv[]) {
  int bytes[TRANS];
  static struct utsname mname;
  // vars for postgres connections
  PGconn *conn=NULL;
  char *pghost=NULL, *pgport=NULL, *pgtty=NULL;
  PGresult *res;
  char pgoptions[200];
  PQArgBlock ar[1];
  char dummy[1000];
  int dummy_length;
  struct timeval tp1, tp2;
  char sqlcode[2000], sqlcode2[2000], sqlcode3[2000], sqlcode4[2000],
       sqlcode5[2000], sqlcode6[2000], sqlcode7[2000], sqlcode8[2000];
  int com, stp, i, len;
  char tab[2];
  char dbname[100];
  char writeset[TRANS][10000];
  long time, total, total2;

  /* QM */
  printf("Starting\n");

  //strcpy(pgoptions, "-R  -b -o /local/postgres2/localog");
  //  strcpy(pgoptions, "-R  -b -o /local/postgres/localog");
  //strcpy(pgoptions, "-R  -b -o /home/dcadena/postgres-r/localog");
  strcpy(pgoptions, "-R  -b -o /local/jsalas/localog");
  uname(&mname);
  strcpy(dbname, "repl_");
  strcat(dbname, strtok(mname.nodename, "."));
  printf("connecting to postgres, dbname = %s\n",dbname);
  printf("pgoptions = %s\n", pgoptions);
  conn=PQsetdb(pghost, pgport, pgoptions, pgtty, dbname);
#ifdef DEBUG_JSALAS
     printf("(Timetrans) ***************** Open Connection %s *****************\n", dbname);
#endif
  if (PQstatus(conn) == CONNECTION_BAD) {
    printf("Error connecting to postgres <%s>\n", PQerrorMessage(conn));
    PQfinish(conn);
    exit(0);
  } else
    printf("connected to postgres\n");
  printf("Warming up the system\n");
  for (i='a';i<='j';i++) {
      printf("select table %d\n", i-'a');
      tab[0]=i;
      tab[1]=0;
      sprintf(sqlcode, 
         "select sum(t_%s_param3) from t_%s;", 
         tab, tab);
      res=PQexec(conn, sqlcode);
      if ((PQresultStatus(res) != PGRES_COMMAND_OK) 
             && (PQresultStatus(res) !=PGRES_TUPLES_OK)) {
        printf("Error executing query in postgres <%s>\n", PQerrorMessage(conn));
      } //if
  } //for

  gettimeofday(&tp1, NULL);
 total = total2 = 0;
for (i=0;i<TRANS;i++) {
  gettimeofday(&tp1, NULL);
  tab[0]=i%9+'a';
  tab[1]=0;
  sprintf(sqlcode, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2+1);
  tab[0]=(i+1)%9+'a';
  sprintf(sqlcode2, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2);
  tab[0]=(i+2)%9+'a';
  sprintf(sqlcode3, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2);
  tab[0]=(i+3)%9+'a';
  sprintf(sqlcode4, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2+1);
  tab[0]=(i+4)%9+'a';
  sprintf(sqlcode5, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2);
  tab[0]=(i+5)%9+'a';
  sprintf(sqlcode6, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2);
  tab[0]=(i+6)%9+'a';
  sprintf(sqlcode7, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2);
  tab[0]=(i+7)%9+'a';
  sprintf(sqlcode8, "update t_%s set t_%s_param1 = 'blub%s', t_%s_param2 = t_%s_param2 + 4 where t_%s_id = %d;", tab, tab, tab, tab, tab, tab, i*2);
  //sprintf(sqlcode4, "select sum(t_%s_param3) from t_%s;", tab, tab);
  //sprintf(sqlcode5, "select sum(t_%s_param3) from t_%s;", tab, tab);
  //tab[0]='j';
  //sprintf(sqlcode6, "select avg(t_%s_param3) from t_%s;", tab, tab);
  //sprintf(sqlcode5, "select sum(t_%s_param3) from t_%s;", tab, tab);
  //sprintf(sqlcode6, "select  sum(t_%s_param3) from t_%s;", tab, tab, tab);
  //sprintf(sqlcode7, "select  avg(t_%s_param3), sum(t_%s_param3) from t_%s;", tab, tab, tab);
  //sprintf(sqlcode8, "select  avg(t_%s_param3), sum(t_%s_param3) from t_%s;", tab, tab, tab);
  // send transaction to postgres
#ifdef D
  printf("sending <begin> to postgres\n");
#endif
  res=PQexec(conn, "begin");
  if (PQresultStatus(res) != PGRES_COMMAND_OK) {
     printf("Error PQexec postgres <%s>\n", PQerrorMessage(conn));
     PQfinish(conn);
     exit(0);
  } 
#ifdef D
   else
      printf("executed <begin>\n");

   printf("executing <%s>\n", sqlcode);
#endif
   res=PQexec(conn, sqlcode);
   if ((PQresultStatus(res) != PGRES_COMMAND_OK) 
       && (PQresultStatus(res) !=PGRES_TUPLES_OK)) {
      printf("Error executing sql in postgres <%s>\n", PQerrorMessage(conn));
      PQfinish(conn);
      exit(0);
   } //if

   
   //res=PQexec(conn, sqlcode2);
   if ((PQresultStatus(res) != PGRES_COMMAND_OK) 
      && (PQresultStatus(res) !=PGRES_TUPLES_OK)) {
      printf("Error executing sql in postgres <%s>\n", PQerrorMessage(conn));
      PQfinish(conn);
      exit(0);
   } //if

   //res=PQexec(conn, sqlcode3);
   //res=PQexec(conn, sqlcode4);
   //res=PQexec(conn, sqlcode5);
   //res=PQexec(conn, sqlcode6);
   //res=PQexec(conn, sqlcode7);
   //res=PQexec(conn, sqlcode8);

#ifdef D
   else
      printf("executed sql\n");
#endif

   // get the writeset and fill in the msg
   PQfn(conn, 1653, (int*) writeset[i], &bytes[i], 0, ar, 0);
   printf("GOT a writeset of %d bytes\n", bytes[i]);

  gettimeofday(&tp2, NULL);
  printf("total time = %d ms \n", time = (tp2.tv_sec-tp1.tv_sec)*1000L
          +(tp2.tv_usec-tp1.tv_usec)/1000L);
  total+=time;
  gettimeofday(&tp1, NULL);
   res=PQexec(conn, "end;");
   if (PQresultStatus(res) != PGRES_COMMAND_OK) {
      printf("Error executing <end> in postgres <%s>\n", PQerrorMessage(conn));
      PQfinish(conn);
      exit(0);
   } 
  gettimeofday(&tp2, NULL);
  printf("total time sql= %d us \n", time = ((tp2.tv_sec-tp1.tv_sec)*1000000L
          +(tp2.tv_usec-tp1.tv_usec)));
  total2+=time;
#ifdef D
   else
      printf("QM executed <end>\n");
#endif
} //for
  gettimeofday(&tp1, NULL);
  for (i=0;i<TRANS;i++) {
        ar[0].len = bytes[i];
        ar[0].isint=0;
        ar[0].u.ptr = (int*) writeset[i];
       PQfn(conn, 1654, (int*) dummy, &dummy_length, 0, ar, 1); 
  } //for
  gettimeofday(&tp2, NULL);
  printf("total time = %d ms \n", time = (tp2.tv_sec-tp1.tv_sec)*1000L
          +(tp2.tv_usec-tp1.tv_usec)/1000L);
  printf("avg time apply ws = %f ms \n", time * 1.0 / TRANS);
  printf("avg time sql = %f ms \n", total * 1.0 / TRANS);
  printf("avg time commit = %f us \n", total2 * 1.0 / TRANS);
} //main
