#include "pgconnection.h"

#include "pgserver.h"

#include "utilities.h"
#include "tools.h"
#include "hashtable.h"
#include "hashtypes.h"

#include "stat.h"

#include <string.h>
#include <ctype.h>

/* Log Management */
#define FATAL_PGCONNECTION
#define ERROR_PGCONNECTION
//#define INFO_PGCONNECTION
//#define WARN_PGCONNECTION
//#define DEBUG_PGCONNECTION
//#define DEBUG_PGCONNECTION_RECV
//#define DEBUG_PGCONNECTION_RECVSIZE
//#define DEBUG_PGCONNECTION_SEND
//#define DEBUG_PGCONNECTION_HASH
//#define DEBUG_PGCONNECTION_SUSPECT
//#define DEBUG_PGCONNECTION_STATS
//#define DEBUG_PGCONNECTION_FAKE

// socket support
#include "socku.h"

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

// errors
#include <errno.h>

// postgres
//#include <libpq-fe.h>

// ip multicast
#include "mc_send.h"

// Middleware
//#include "declarations.h"
#include "groupcomm.h"
// 230603
#include "qmsockets.h"

//char my_name[100];
char username[100 /* + EXTRASIZE - RMEXTRASIZE */];

//int isConnection = 0;
// 0 the connection have been created
// 1 the connection is been created

//int numFields;

#ifdef DEBUG_PGCONNECTION_FAKE    
	#define TAMFAKE 2048//lim 1024 tuples by client!!!!!!!
	char *fake[TAMFAKE];
	int fakeval[TAMFAKE];
	int ftuples = 0;
	int nexec = 0;
#endif

#define TAMBUFCLIENT 16 * 1024
struct tclientresp {
	int cbuftam;
	char clientbuf[TAMBUFCLIENT];
	
};
struct tclientinfo {
	struct tclientresp client_resp;
	char dbname[MAXDBNAME];	
};

//char * SendQuery(char *, hot_uint32, hot_uint32 *, hot_uint32, char, hot_uint32, hot_uint32);
//void SendQueryUnicast(char *, hot_uint32, hot_uint32 *, hot_uint32, hot_uint32, hot_uint32);
int executeQuery(char *, hot_uint32, int, hot_uint32, hot_uint32 *, char[MAXDBNAME], char, hot_uint32, hot_uint32, struct tclientinfo*);

int sendToDriver(int socket, void *data, int length){
  int rval = 0;
  if ((rval = send(socket, data, length, 0)) < 0) {
    return -1;

  } else if (rval == 0){
    return 0;

  } else {
    return 1;
  }
}

/*int sendRecordsUpdates(int thId, int type, int recordsUpdates, int socketDriver) {
  int rval = 1;
  char buf_in[TAMBUFFER]; // + EXTRASIZE  - RMEXTRASIZE];
  char recUpd[INTASCHAR + EOF_SIZE]; // Store int as char/ / + EXTRASIZE - RMEXTRASIZE /];

  // Send command status
  bzero(buf_in, sizeof(buf_in));
  buf_in[0] = 'C';

#ifdef DEBUG_PGCONNECTION
  printf("(Thread%d) type = %c\n", thId, type);
#endif

  switch (type) {
    case 'U': strcat(buf_in, "UPDATE "); break;
    case 'I': strcat(buf_in, "INSERT "); break;
    case 'D': strcat(buf_in, "DELETE "); break;
    case 'R': strcat(buf_in, "DROP "); break;
    case 'C': strcat(buf_in, "CREATE "); break;
    case 'A': strcat(buf_in, "ALTER "); break;
    case 'T': strcat(buf_in, "SET VARIABLE "); break;
    default: strcat(buf_in, "ERROR NOT TYPE ");
  }

  bzero(recUpd, sizeof(recUpd));
  itoa(recordsUpdates, recUpd);
  strcat(buf_in, recUpd);
  buf_in[strlen(buf_in)] = '\0';

#ifdef DEBUG_PGCONNECTION_SEND
  printf("(Thread%d) (SEND 2) Bytes <%d> Message <%s> (RECONNECTION COMMAND STATUS)\n", thId,
       strlen(buf_in) + 1, buf_in);
#endif
  // Send command status to Driver
  if ((rval = sendToDriver(socketDriver, buf_in, strlen(buf_in) + 1)) <= 0) {
    return rval;
  }

  //TODO unir en uno con lo de arriba
  // Send Fields information
  bzero(buf_in, sizeof(buf_in));
  buf_in[0] = 'Z';

#ifdef DEBUG_PGCONNECTION_SEND
  printf("(Thread%d) (SEND 3) Bytes <%d> Message <%s> (RECONNECTION FIELDS INFORMATION)\n", thId, 1, buf_in);
#endif
  // Send fields information
  if ((rval = sendToDriver(socketDriver, buf_in, 1)) <= 0) {
    return rval;
  }

  return 1;
}*/

int sendCommandStatus(struct itemhPetition *item, int socketDriver) {
  int rval = 1;

  // Send command status to Driver
  if ((rval = sendToDriver(socketDriver, item->last.response, item->last.response_length)) <= 0) {
    return rval;
  }
  return 1;
}

//TODO
//int NotifyChangeLocalReplica(int petition, int localnode, int queue) {
  //return 0;
//}
#ifdef DEBUG_PGCONNECTION_FAKE
void playfake(int socketJDBC){
	int i, pos;
	int rval;
	char buf_out[10];
	char fake_aux[TAMFAKE*10];
	
	//printf("PLAYFAKE\n");
	bzero(buf_out, sizeof(buf_out));
  	buf_out[0] = 'Z';
  	pos = 0;
	for (i = 0; i<ftuples; i++){
		memcpy(fake_aux+pos, fake[i], fakeval[i]);
		pos += fakeval[i];			
	}
	memcpy(fake_aux+pos, buf_out, 1);
	pos+=1;
	if ((rval = send(socketJDBC, fake_aux, pos, 0)) < 0) {}
	//if ((rval = sendToDriver(socketJDBC, buf_out, 1)) <= 0) {}
}
#endif
/**  */
/* Connect with Postgres and */
/* accept connection. */
/**  */
int pgconnectionStart(int socketDriver, hot_uint32 thId, hot_uint32 *id_connection, char databaseName[MAXDBNAME], hot_uint32 *last_petition) {

  int rval, i, pos;
  int closeConnect = 0;
  hot_uint32 idCC;
  hot_uint32 * transactionCC, noCC;
  hot_uint32 idConnection, idPetition, petition, forward;
  char resp;
  char buf_in[TAMBUFFER /* + EXTRASIZE  - RMEXTRASIZE */];
  /* S select, U update, I insert, D delete, R drop, C create, A alter, B begin, E end, O abort, T set, H other */
  char type;
  char * tablesR = NULL, * tablesW = NULL, * tablesALL = NULL; // Format : table.table.table  ...
  char * mainTable = NULL; //[100 /*+ EXTRASIZE - RMEXTRASIZE*/]; ////COMMENT NOW JSalas Debe tener el mismo tamanno que sql, definirla dinamica
  char * k = NULL;
  char recUpd[INTASCHAR + EOF_SIZE /* Store int as char */ /* + EXTRASIZE - RMEXTRASIZE */];
  char * sql = NULL;
  struct itemhMiddler * foundCC = NULL;
  struct itemhPetition * foundPet = NULL;

  int j;
  char *tablesCC;

  struct tclientinfo client_info;
  
#ifdef DEBUG_PGCONNECTION_STATS
   struct timeval time;
#endif

  /**  */
  /* Connect with Postgres */
  /**  */
#ifdef DEBUG_PGCONNECTION
  printf("(Thread%d) databaseName = %s\n", thId, databaseName);
  printf("(Thread%d) socketDriver = %d\n", thId, socketDriver);
  printf("(Thread%d) sockResTh = %d\n", thId, sockResTh[thId]);
  printf("(Thread%d) idConn = %d\n", thId, *id_connection);
#endif

  bzero(client_info.dbname, sizeof(client_info.dbname));
  strcpy(client_info.dbname, databaseName);
  
  /* Is Reconnection? */
  if (*id_connection != 0) {
    /* necessary to delay_disconnect */
    idConnection = *id_connection;
    *last_petition = 0;

#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) not startUpPacket\n", thId);
#endif
  }
  else {
#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) startUpPacket...\n", thId);
#endif
    if (startUpPacket(thId, socketDriver, transactionCC, databaseName, & idConnection, &client_info) < 0) {
#ifdef DEBUG_PGCONNECTION
      printf("StartUpPacketError\n");
#endif
      return -1;
    }

    /* necessary to delay_disconnect */
    *last_petition = 0;
    *id_connection = idConnection;
  }

  while (!closeConnect) {
#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) Accepting query...\n", thId);
#endif
    bzero(buf_in, sizeof(buf_in));
    if ((rval = recv(socketDriver, buf_in, sizeof(buf_in), 0)) < 0) {
#ifdef ERROR_PGCONNECTION
      printf("(Thread%d) Error Received Datas in PGConnection <%d>\n", thId, rval);
#endif
      return -2;
    }

#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) Received query bytes <%d>...\n", thId, rval);
#endif

    if (rval == 0) { //JSalas Patch because driver close sockets
#ifdef DEBUG_PGCONNECTION
      printf("Driver Close Socket\n");
#endif
      //resp = 'X';
      return 0;
    }
    else {
      resp = buf_in[0];
    }
#ifdef DEBUG_PGCONNECTION_RECV
    printf("(Thread%d) (RECV 1) Bytes <%d> Resp <%c> (RESP:IDCONNECTION:IDPETITION:TABLESR:TABLESW:TABLESALL:SQL:TYPESQL)\n",
         thId, rval, resp);
#endif

    if (resp != 'X') {
      if (!(sql = (char *) calloc(sizeof(char), (rval - 11)))) {
#ifdef FATAL_QMSOCKETS
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }
      if (!(tablesR = (char *) calloc(sizeof(char), (rval - 11)))) {
#ifdef FATAL_QMSOCKETS
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }
      if (!(tablesW = (char *) calloc(sizeof(char), (rval - 11)))) {
#ifdef FATAL_QMSOCKETS
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }
      if (!(tablesALL = (char *) calloc(sizeof(char), (rval - 11)))) {
#ifdef FATAL_QMSOCKETS
        printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
        exit(0);
      }

      convertToInt(buf_in, 2, (int *) & idPetition, 1);
      convertToInt(buf_in, 2, (int *) & idConnection, 3);

#ifdef DEBUG_PGCONNECTION_STATS
   //struct timeval time;   
   gettimeofday(&time, NULL);//STATS      
   SETSTARTTIME(0, idConnection, idPetition, time.tv_sec, time.tv_usec);    
   //(steps[0][idConnection][idPetition]).startTime.tv_sec = time.tv_sec;
   //(steps[0][idConnection][idPetition]).startTime.tv_usec = time.tv_usec;
   //(steps[0][idConnection][idPetition]).inUse = 1;   
   //printf("PGConnection[%d][%d]\n", idConnection, idPetition);
#endif

      /* necessary to delay_disconnect */
      *last_petition = idPetition;
      *id_connection = idConnection;

#ifdef DEBUG_PGCONNECTION_RECV
      printf("(Thread%d) idPetition = %d\n", thId, idPetition);
      printf("(Thread%d) idConnection = %d\n", thId, idConnection);
#endif

      // is sentence sql already processed?
      petition = (idConnection * MAX_PETITION_PER_CLIENT) + 0 /*idPetition*/;
#ifdef DEBUG_PGCONNECTION_HASH
      printf("(HASHTABLE) Table <hPetition> Operation <hash_lookup> Key <%u> File <%s> Line <%d>\n",
           petition, __FILE__, __LINE__);
#endif
      //TODO getSemaphoreTable();
      decSemaphore(& semaConnections[0/*TODO thId*/]);
      if (((foundPet = (struct itemhPetition *) get_hashtable(& hPetition, & petition)) != NULL) && (foundPet->last.id_petition == idPetition)){
        if ((foundPet->last.recordsUpdates) >= 0) {
#ifdef DEBUG_PGCONNECTION
          printf("(Thread%d) Petition %d is processed -> sendCommandStatus\n", thId, petition);
#endif
          sendCommandStatus(foundPet, socketDriver);
          //setSemaphoreTable();
          incSemaphore(& semaConnections[0/* TODO thId*/]);
          continue;

        } else {
          char *bufrecv = NULL;

          //int queueCC;
#ifdef DEBUG_PGCONNECTION
          printf("(Thread%d) Petition %d is not processed, wait command status\n", thId, petition);
#endif
          foundPet->last.is_change_nodelocal_new = 1;
          foundPet->last.is_change_nodelocal_old = 0;
          incSemaphore(& semaConnections[0/*TODO thId*/]);

          /* Wait to received Command Status */
          //printf("Wait command status\n");
          if ((rval = selectSuspect(socketDriver, sockResTh[thId], &bufrecv, 1)) <= 0){

          }
          //printf("Wait command status\n");
#ifdef DEBUG_PGCONNECTION
          printf("(Thread%d) Petition <%d> command status <%s>\n", thId, petition, bufrecv);
#endif
		  bufrecv[0] = 'T';  		  
  		  convertToChar (bufrecv, sizeof(int), 1, 0);  		          
//        bufrecv[6] = '0';
          bufrecv[5] = '\0';
          bufrecv[6] = 'Z';
          if ((rval = sendToDriver(socketDriver, bufrecv, 7)) <= 0) {
            #ifdef ERROR_PGCONNECTION
            printf("(Thread%d) (SEND 10) (ERROR | NOT Z)\n", thId);
            #endif
            return rval; /* Error Sending datas to driver */
          }
          Free(bufrecv);
          continue;
          //queueCC = foundPet->queueCC;
          //setSemaphoreTable();
          //The local replica has changed. I am the new local replica
          //NotifyChangeLocalReplica(petition, 1, queueCC);
        }
        incSemaphore(& semaConnections[0/*TODO thId*/]);

      } else {

        incSemaphore(& semaConnections[0/* TODO thId*/]);

#ifdef DEBUG_PGCONNECTION
        printf("(Thread%d) Petition %d is not processed\n", thId, petition);
#endif
//printf("(Thread%d) Petition %d is not processed <%s>\n", thId, petition, buf_in+6);
        pos = getToken(buf_in + 6, ':', 0, tablesR);
        pos = getToken(buf_in + 6, ':', pos, tablesW);
        pos = getToken(buf_in + 6, ':', pos, tablesALL);
        pos = getToken(buf_in + 6, ';', pos, sql);

        /* DAR HACK FIXME JSalas En los Insert, Update y Delete hay un espacio -> Solucion provisional: */
        //strcat(sql, ";");
        //pos = getToken (buf_in+6, '\0', pos, sql);
        //printf("TypeString <%s>\n", sql);
        type = buf_in[pos + 6];
        i = 1;
        while (type == ' ') {
          type = buf_in[pos + 6 + i];
          i++;
        }

#ifdef DEBUG_PGCONNECTION_RECV
        printf("(Thread%d) tablesR = %s\n", thId, tablesR);
        printf("(Thread%d) tablesW = %s\n", thId, tablesW);
        printf("(Thread%d) tablesALL = %s\n", thId, tablesALL);
        printf("(Thread%d) sql = %s\n", thId, sql);
        printf("(Thread%d) typeSQL = %c\n", thId, type);
#endif
        // HACER : ESTO HABRA QUE CAMBIARLO CUANDO TENGAMOS CLASES CONFLICTO COMPUESTAS
        // LAS LISTAS DE TABLAS SERAN CHAR** DONDE CADA ELEMENTO SERA UNA TABLA
        if (!(mainTable = (char *) malloc(sizeof(char) * (rval - 11)))) {
#ifdef FATAL_QMSOCKETS
          printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
          exit(0);
        }

        if (type == 'S') {
          tablesCC = tablesR;
          noCC = CountCC(tablesR);
        } else if ((type == 'U') || (type == 'I') || (type == 'D')) {
          tablesCC = tablesW;
          noCC = 1 + CountCC(tablesR);
        } else if ((type == 'R') || (type == 'A') || (type == 'C')) {
          tablesCC = tablesALL;
          noCC = 1;
        }

        if (!(transactionCC = (hot_uint32 *) malloc(sizeof(hot_uint32) * noCC))) {
#ifdef FATAL_QMSOCKETS
          printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
          exit(0);
        }

        pos = 0;
        for (j = 0; j < noCC; j++) {
          bzero(mainTable, sizeof(mainTable));
          pos = getToken(tablesCC, '.', pos, mainTable);

          // Find the conflict class
          if (strlen(mainTable) > 0) {
            if (!(k = (char *) malloc(sizeof(char) * (strlen(databaseName) + strlen(mainTable) + 2)))) {
#ifdef FATAL_QMSOCKETS
              printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
              exit(0);
            }
            strcpy(k, databaseName);
            strcat(k, ".");
            strcat(k, mainTable);
#ifdef DEBUG_PGCONNECTION_HASH
            printf("--->(HASHTABLE) Table <hMiddler> Operation <hash_lookup> Key <%s> File <%s> Line <%d>\n",
                 k, __FILE__, __LINE__);
#endif
            if ((foundCC = (struct itemhMiddler *) get_hashtable(& hMiddler, k)) == NULL) {
#ifdef DEBUG_PGCONNECTION
              printf("(Thread%d) key %s not found in hMiddler\n", thId, k);
#endif
              idCC = 0;

            } else { idCC = foundCC->id_CC; }
              Free(k);

          } else { idCC = 0; }

          transactionCC[j] = idCC;
          if (j == 0) {
            if (type == 'S') {

            } else if ((type == 'U') || (type == 'I') || (type == 'D')) {
              tablesCC = tablesR;
              pos = 0;

            } else if ((type == 'R') || (type == 'A')) {}
          }
        }
        Free(mainTable);

#ifdef DEBUG_PGCONNECTION
        printf("(Thread%d) id_CC = %d\n", thId, idCC);
#endif
        /* Free Resources */
        Free(tablesR);
        Free(tablesW);
        Free(tablesALL);
      }
    } /* if (resp != 'X') */

    switch (resp) {
      case 'Q':
#ifdef DEBUG_PGCONNECTION
        printf("(Thread%d) Executing query\n", thId);
#endif
        // Executy Query

        // 280803
        // HACER : CUANDO TENGAMOS CLASES CONFLICTO COMPUESTAS ESTO HABRA QUE CAMBIARLO
        // EL TAMANNO DE TRANSACTIONCC SERA EL NUMERO DE TABLAS ACCEDIDAS Y NO SOLO LA
        // PRIMERA
#ifdef DEBUG_PGCONNECTION
        printf("(Thread%d)Information->", thId);
        printf("sql<%s>", sql);
        printf("thId<%d>", thId);
        printf("socketDriver<%d>", socketDriver);
        printf("noCC<%d>", noCC);
        printf("databaseName<%s>", databaseName);
        printf("type<%c>", type);
        printf("idConnection<%d>", idConnection);
        printf("idPetition<%d>\n", idPetition);
        for (j = 0; j < noCC; j++) {
          printf("(Thread%d)transactionCC[%d] = %d\n", thId, j, transactionCC[j]);
        }
#endif	
#ifdef DEBUG_PGCONNECTION_FAKE
		if (nexec == 0)	{
#endif			
       	rval = executeQuery(sql, thId, socketDriver, noCC, transactionCC, databaseName, type, idConnection, idPetition, &client_info);

#ifdef DEBUG_PGCONNECTION_FAKE
      	nexec++;
    	printf("NORMAL\n");
#endif    		

        if (rval <= 0) {
#ifdef ERROR_PGCONNECTION
          //printf("(Thread%d) ERROR executing Query : %s \n", thId, sys_errlist[errno]);
#endif
          Free(sql);
          Free(transactionCC);
          return rval;
        }
#ifdef DEBUG_PGCONNECTION_FAKE        
		}else{
			//printf("FAKE\n");
			playfake(socketDriver);
		}
#endif		
        Free(transactionCC);
        Free(sql);
        //printf("RVAL <%d>\n", rval);
      break;

      case 'X':
        // close connection
#ifdef DEBUG_PGCONNECTION
        printf("(Thread%d) Close connection...\n", thId);
        printf("(Thread%d) Socket %d\n", thId, socketDriver);
#endif

        /* Remove forward petition */
        /*if ((idPetition - 1) > 0) {
          forward = petition - 1;
          if (delete_hashtable(& hPetition, & forward) == 0) {
#ifdef DEBUG_PGCONNECTION_HASH
            printf("(Thread%d) Forward Petition %d not found\n", thId, petition - 1);

          }
          else {
            printf("(Thread%d) HashTable Petition number of elements <%d>\n", thId, num_elements_hashtable(& hPetition));
#endif
          }
        }*/

        closeConnect = 1;
        buf_in[0] = 'X';
#ifdef DEBUG_PGCONNECTION_SEND
        printf("(Thread%d) (SEND 4) Bytes <%d> Message <%s> (CLOSE CONNECTION)\n", thId, 1, buf_in);
#endif
        if ((rval = sendToDriver(socketDriver, buf_in, 1)) <= 0) {
          return rval;
        }
      break;

      default:
        Free(transactionCC);
        Free(sql);
#ifdef DEBUG_PGCONNECTION_RECV
        printf("(Thread%d) Error in received type\n", thId);
#endif
    }
  }
#ifdef DEBUG_PGCONNECTION
  printf("(Thread%d) Finished Connection with Driver\n", thId);
#endif
  return 1;
}

int CountCC(char * tables) {
  char c;
  int length, i;
  int countcc = 0;

  if ((tables == NULL) || (strcmp(tables, "") == 0)) {
    return 0;
  }

  length = strlen(tables);
  for (i = 0; i < length; i++) {
    c = tables[i];
    if (c == '.') {
      countcc++;
    }
  }

  return countcc + 1;
}

/**  */
/* Connect with Posrtgres */
/* sending the statrUpPacket */

/**  */
int startUpPacket(hot_uint32 id, int socketJDBC, hot_uint32 * transactionCC, char databaseName[MAXDBNAME],
     hot_uint32 * idConnection, struct tclientinfo* client_info) {
       int rval, i, j;
       char resp;
       char buf_in[TAMBUFFER /* + EXTRASIZE - RMEXTRASIZE */];
       char query[MAX_TXT /* + EXTRASIZE - RMEXTRASIZE */];
       hot_uint32 idPetition, noCC;
       char * sql;

       /**  */
       /* Obtain StartUpPacket of Driver JDBC */
       /**  */
//printf("Obtain StartUpPacket of Driver JDBC\n");
       //bzero(buf_in,sizeof(buf_in));
       if ((rval = recv(socketJDBC, buf_in, sizeof(buf_in), 0)) < 0) {
         printf("Error StartUpPacket Recv\n");
         return -1;
       }
//printf("Get StartUpPacket of Driver JDBC\n");
       // Struct of buf_in in this moment
       /**  */
       /* 0 - 3 (unused) */
       /* 4 - 5 (protocolMayor) */
       /* 6 - 7 (protocolMinor) */
       /* 8 - 9 (idConnection) */
       /* 10 - 234 (user name) */
       /**  */

       convertToInt(buf_in, 2, (int *) idConnection, 8);

     #ifdef DEBUG_PGCONNECTION_RECV
       printf("(Thread%d) (RECV 2) Bytes <%d> IdConnection <%d> (IDCONNECTION)\n", id, rval, * idConnection);
     #endif

       // Send stored procedure connection to Middleware
       bzero(query, strlen(query));
       sprintf(query, "%2d ", CON_RESPONSE);
       strcat(query, databaseName);

     #ifdef DEBUG_PGCONNECTION
       printf("(Thread%d) StartUpPacket CON query=<%s>\n", id, query);
     #endif

       if (!(transactionCC = (hot_uint32 *) malloc(sizeof(hot_uint32)))) {
     #ifdef FATAL_QMSOCKETS
         printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
     #endif
         exit(0);
       }
       transactionCC[0] = 0;
       noCC = 1;
       //printf("THID CON %d\n", id);
       SendQuery(query, noCC, transactionCC, id, 'H', * idConnection, 0, client_info->dbname);

       if (authentication(id, socketJDBC) == -1) {
         return -1;
       }

       bzero(buf_in, sizeof(buf_in));
       if ((rval = recv(socketJDBC, buf_in, sizeof(buf_in), 0)) < 0) {
         return -1;
       }

       // copy the sentence sql
       //sql = malloc (rval - 9); // rval - the ":" and "Q", idConnection, idPetition
       if (!(sql = (char *) malloc(sizeof(char) * (rval - 9)))) {
     #ifdef FATAL_QMSOCKETS
         printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
     #endif
         exit(0);
       }
       resp = buf_in[0];

       i = 9;
       j = 0;

       while (buf_in[i] != ';') {
         sql[j++] = buf_in[i++];
       }
       sql[j] = '\0';

     #ifdef DEBUG_PGCONNECTION_RECV
       printf("(Thread%d) (RECV 3) Bytes <%d> SQL <%s> Resp <%c> (RESP:SQL)\n", id, rval, sql, resp);
     #endif

       switch (resp) {
         case 'Q':
           convertToInt(buf_in, 2, (int *) & idPetition, 1);
           convertToInt(buf_in, 2, (int *) idConnection, 3);

     #ifdef DEBUG_PGCONNECTION
           printf("(Thread%d) StartUpPacket query=<%s>\n", id, sql);
     #endif
		   
		   //sendMsgConnectionOk();
		   
           // Executy Query
           if (executeQuery(sql, id, socketJDBC, noCC, transactionCC, NULL, 'T', * idConnection, idPetition, client_info) < 0) {
             #ifdef DEBUG_PGCONNECTION
                printf("(Thread%d) Error executeQuery StartUpPacket query=<%s>\n", id, sql);
             #endif
             return -1;
           }
       }

       Free(sql);
       Free(transactionCC);
       return 0;
}

/**  */
/* Perform authentication */

/**  */
int authentication(hot_uint32 id, int socketJDBC) {
  int rval;
  //char buf_in[TAMBUFFER /*+ EXTRASIZE - RMEXTRASIZE*/];
  char * bufrecv = NULL;

#ifdef DEBUG_PGCONNECTION_RECVSIZE
  printf("(Thread%d) Waiting message autenthicacion and pid ...0\n", id);
#endif

  if ((rval = recvWithSizeMem(sockResTh[id], & bufrecv, 0)) < 0) {
    Free(bufrecv);
    return -1;
  }

#ifdef DEBUG_PGCONNECTION_RECVSIZE
  printf("(Thread%d) (RECVSIZE ) Receiving message autenthicacion and pid ... <%s>\n", id, bufrecv);
#endif

#ifdef DEBUG_PGCONNECTION_SEND
  printf("(Thread%d) (SEND 5) Bytes <%d> Message <%s> ()\n", id, rval, bufrecv);
#endif

  if ((rval = send(socketJDBC, bufrecv, rval, 0)) < 0) {
    Free(bufrecv);
    return -1;
  }

  if (bufrecv[0] == 'E') {
    Free(bufrecv);
    return -1;
  }

  Free(bufrecv);
  return 0;
}

char *createInternQuery(char typeSQL, char *sqlaux, char *databaseName){
  char *query;
 
  //Change if add a new type sql. Memory is reserved for the most requeriments (types C and R -> CDB)
  if (!(query = (char *) malloc(sizeof(char) * (INTASCHAR + strlen(sqlaux) + 1 + MAXDBNAME + 1 + EOF_SIZE)))) {
  #ifdef FATAL_PGCONNECTION
   printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
  #endif
   exit(0);
  }
  bzero(query, sizeof(query));

  // Create Query in function of the type of sql
  switch (typeSQL) {
   case 'S':
     sprintf(query, "%2d ", SQG);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = SELECT (SQG)\n", id);
  #endif
   break;
   case 'U':
     sprintf(query, "%2d ", UPDG);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = UPDATE (UPDG)\n", id);
  #endif
   break;
   case 'I':
     sprintf(query, "%2d ", UPDG);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = INSERT (UPDG)\n", id);
  #endif
   break;
   case 'D':
     sprintf(query, "%2d ", UPDG);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = DELETE (UPDG)\n", id);
  #endif
   break;
   case 'C':
     sprintf(query, "%2d ", CDB);
     strcat(query, sqlaux);
     strcat(query, ";");
     strcat(query, databaseName);
     strcat(query, ";");
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = CREATE (CDB)\n", id);
  #endif
   break;
   case 'R':
     sprintf(query, "%2d ", CDB);
     strcat(query, sqlaux);
     strcat(query, ";");
     strcat(query, databaseName);
     strcat(query, ";");
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = DROP (CDB)\n", id);
  #endif
   break;
   case 'A':
     sprintf(query, "%2d ", CDB);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = (ALTER) CDB\n", id);
  #endif
   break;
   case 'B':
     sprintf(query, "%2d ", BEG);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = BEGIN (BEG)\n", id);
  #endif
   break;
   case 'E':
     sprintf(query, "%2d ", END);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = END (END)\n", id);
  #endif
   break;
   case 'O':
     sprintf(query, "%2d ", ABO);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = ABORT (ABO)\n", id);
  #endif
   break;
   case 'T':
     sprintf(query, "%2d ", CDB);
     strcat(query, sqlaux);
  #ifdef DEBUG_PGCONNECTION
     printf("(Thread%d) typeQuery = SET (CDB)\n", id);
  #endif
   break;
   default:
     Free(query);
     return NULL;
  }
  return query;
}

/**  */
/* execute a query */
/* return -1 if error */
/* return 0 if not error */

/** execute a query */
/* -3 Fatal Error */
/* -2 Error Receiving datas of middler */
/* 0 Error Sending datas to driver */
/* 1 Query is Empty */
/* 2 Unrecognize type */
/* 3 Error execute in QM */

// 280803 [MAX_CC] por *
int executeQuery(char * sql, hot_uint32 id, int socketJDBC, hot_uint32 noCC, hot_uint32 * transactionCC,
     char databaseName[MAXDBNAME], char typeSQL, hot_uint32 idConnection, hot_uint32 idPetition, struct tclientinfo *client_info) {

  char resp = 'Q';
  int rval, i, j, sizesql, sizecs;
  char * sqlaux;
  int tuple, ntuples;
  char buf_out[TAMBUFFER /* + EXTRASIZE - RMEXTRASIZE */]; //Only store one char
  char * query = NULL; //[1000 /*+ EXTRASIZE - RMEXTRASIZE */];
  char * bufrecv = NULL;
  int numFields = 0;
  int f;
  char *lex;
  
#ifdef DEBUG_PGCONNECTION_STATS
   struct timeval time;
#endif

  // 0 query
  // 1 update
  // 2 change database
  // 4 begin transaction
  // 5 end transaction
  // 6 abort transaction

  // sql can have more than 1 sentence. This sentences are separeted by ";"
  sizesql = strlen(sql);
  if (sizesql == 0) {
    // Empty query
    bzero(buf_out, sizeof(buf_out));
    buf_out[0] = 'I';
#ifdef DEBUG_PGCONNECTION_SEND
    printf("(Thread%d) (SEND 6) Bytes <%d> Message <%s> ()\n", id, 1, buf_out);
#endif
    if ((rval = sendToDriver(socketJDBC, buf_out, 1)) <= 0) {
     return rval; /* Error Sending datas to driver */
    }
    return 1; /* Query is Empty */
  }

  if (!(sqlaux = (char *) malloc(sizeof(char) * (sizesql + EOF_SIZE)))) {
#ifdef FATAL_PGCONNECTION
    printf("%s# %d # Out of memory.\n", __FILE__, __LINE__);
#endif
    exit(0);
  }

  i = 0;
  while (i < sizesql) {
    j = 0;
    //bzero(sqlaux, sizeof(sqlaux));
    while ((sql[i] != ';') && (i < sizesql)) {
     sqlaux[j++] = sql[i++];
    }
    sqlaux[j] = '\0';

#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) Received sql : %s\n", id, sqlaux);
    printf("(Thread%d) TypeSQL : %d\n", id, typeSQL);
#endif

    if ((query = createInternQuery(typeSQL, sqlaux, databaseName)) == NULL){
      Free(sqlaux);
      // Unrecognize type
      bzero(buf_out, sizeof(buf_out));
      buf_out[0] = typeSQL;
#ifdef DEBUG_PGCONNECTION_SEND
      printf("(Thread%d) (SEND 6) Bytes <%d> Message <%s> ()\n", id, 1, buf_out);
#endif
      if ((rval = sendToDriver(socketJDBC, buf_out, 1)) <= 0) {
        return rval; /* Error Sending datas to driver */
      }
      return 2; /* Unrecognize type */
    }
    Free(sqlaux);

    // 280803
    //transactionCC[0]= 0;
#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) query=<%s>\n", id, query);
#endif
#ifdef DEBUG_PGCONNECTION_STATS
   //struct timeval time;   
   gettimeofday(&time, NULL);//STATS   
   SETSTARTTIME(5, idConnection, idPetition, time.tv_sec, time.tv_usec);
   //(steps[5][idConnection][idPetition]).startTime.tv_sec = time.tv_sec;
   //(steps[5][idConnection][idPetition]).startTime.tv_usec = time.tv_usec;
   //(steps[5][idConnection][idPetition]).inUse = 1;
#endif
    // Send query to Middleware
    if (typeSQL != 'S') {
      // typeSQL != SELECT
      SendQuery(query, noCC, transactionCC, id, typeSQL, idConnection, idPetition, client_info->dbname);
    } else {
      SendQueryUnicast(query, noCC, transactionCC, id, idConnection, idPetition, client_info->dbname);
    }
    Free(query);

#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) Waiting command status...\n", id);
#endif

/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
/*
#ifdef DEBUG_PGCONNECTION_RECVSIZE
   printf("Waiting message (RECVSIZE 1) ...\n");
#endif
   if ((rval = recvWithSizeMem(sockResTh[id], & bufrecv)) < 0) {
#ifdef ERROR_PGCONNECTION
    printf("(Thread%d) (RECVSIZE 1) Bytes <%d> Message <%s> (ERROR | NOT RECV)\n", id, rval, bufrecv);
#endif
    Free(bufrecv);
     //TODO error interno que hacer?
    return -2; //Error Receiving datas of middler
   }
#ifdef DEBUG_PGCONNECTION_RECVSIZE
   printf("(Thread%d) (RECVSIZE 1) Bytes <%d> Message <%s>\n", id, rval, bufrecv);
#endif

#ifdef DEBUG_PGCONNECTION_SEND
   printf("(Thread%d) (SEND 7) Bytes <%d> Message <%s> ()\n", id, rval, bufrecv);
#endif
   if ((rval = sendToDriver(socketJDBC, bufrecv, rval)) <= 0) {
     #ifdef ERROR_PGCONNECTION
      printf("(Thread%d) (SEND 7) Bytes <%d> Message <%s> (ERROR | NOT SEND)\n", id, rval, bufrecv);
     #endif
     Free(bufrecv);
     return rval; //Error Sending datas to driver
   }
*/
/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
//printf("1\n");	
	client_info->client_resp.cbuftam = 0;//Compact
	bzero(client_info->client_resp.clientbuf, sizeof(client_info->client_resp.clientbuf));//Compact
	
    rval = selectSuspect(socketJDBC, sockResTh[id], &bufrecv, 0/*FAKE 1*/);
        
    memcpy((client_info->client_resp.clientbuf)+(client_info->client_resp.cbuftam), bufrecv, rval);//Compact
    client_info->client_resp.cbuftam+=rval;//Compact
    
/*    printf("%d", cbuftam);	
	for(f=0;f<cbuftam;f++){
		printf("%c", clientbuf[f]);
	}
	printf("\n");
*/	
    if (rval <= 0){
      if (client_info->client_resp.cbuftam > 0){ 
      	rval = send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0);//Compact
      }
      Free(bufrecv);
      return rval;
    }
//printf("2\n");    
#ifdef DEBUG_PGCONNECTION_FAKE    
    fakeval[0] = rval;
    fake[0] = (char *)calloc(sizeof(char), fakeval[0]);
	memcpy(fake[0], bufrecv, fakeval[0]);
	/*printf("%d", rval);
	lex = fake[0];
	for(f=0;f<rval;f++){
		printf("%c", lex[f]);
	}
	printf("\n");*/
	//printf("fake[0]=<%s>\n", fake[0]);	
#endif	
	
#ifdef DEBUG_PGCONNECTION_STATS
   //struct timeval time;
   //("GETTIME\n");   
   gettimeofday(&time, NULL);//STATS 
   //printf("GETTIME <%ld> <%ld>\n", time.tv_sec, time.tv_usec);  
   //setFinishTimeArray(5, idConnection, idPetition, time.tv_sec, time.tv_usec);
   SETFINISHTIME(5, idConnection, idPetition, time.tv_sec, time.tv_usec);
   SETSTARTTIME(6, idConnection, idPetition, time.tv_sec, time.tv_usec);
   //printf("inUse[%d][%d][%d] = %d\n", 5, idConnection, idPetition, (steps[5][idConnection][idPetition]).inUse);
   //printf("GETTIME CHECK<%ld> <%ld>\n", (steps[5][idConnection][idPetition]).finishTime.tv_sec, (steps[6][idConnection][idPetition]).startTime.tv_usec);
   //(steps[6][idConnection][idPetition]).startTime.tv_sec = time.tv_sec;
   //(steps[6][idConnection][idPetition]).startTime.tv_usec = time.tv_usec;
   //(steps[6][idConnection][idPetition]).inUse = 1;
#endif

#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) Received command status %s\n", id, bufrecv);
#endif
//printf("3\n");
    if (bufrecv[0] == 'E') {    	      		
      int ret = 0;
      
      if (client_info->client_resp.cbuftam > 0){
	      rval = send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0);//Compact
      }
      
      #ifdef ERROR_PGCONNECTION
      printf("(Thread%d) Message <%s> (ERROR | Received command status)\n", id, bufrecv);
      #endif

      //TODO necesario distinguir errores
      if (bufrecv[0] == 'F') {
        ret = -3; /* Fatal Error */
      } else {
        ret = 3; /* Error execute in QM */
      }
      Free(bufrecv);
      //TODO
      //printf ("RETURN <%d>\n", ret);
      return ret;
    }
    Free(bufrecv);

    /**  */
    /* send  metadata field descriptor to JDBC */
    /**  */
//printf("4\n");    
    numFields = sendFieldsToDriver(socketJDBC, id, &bufrecv, &rval);
     
    //Free(bufrecv);
//printf("7\n");    
#ifdef DEBUG_PGCONNECTION
    printf("(Thread%d) Received number of fields: %d\n", id, numFields);
#endif    
    //if (numFields == 0) {
      //rval = send(socketJDBC, clientbuf, cbuftam, 0);//Compact    	
    //}else
//printf("8\n");    
    if (numFields == 0) {
    	Free(bufrecv);
    	
    }else if (numFields < 0) {
    	Free(bufrecv);
//printf("9\n");    	
#ifdef ERROR_PGCONNECTION
      printf("(Thread%d) Message <%s> (ERROR | sendFieldsToDriver)\n", id, bufrecv);
#endif
	  if (client_info->client_resp.cbuftam > 0){
	  	rval = send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0);//Compact
	  }
	  
      //TODO
      return -1; /* Error Sending datas to driver */
      
    } else if (numFields > 0) {
    	if (rval>0){        
	        if (client_info->client_resp.cbuftam+rval > TAMBUFCLIENT){
	        	if (send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0) < 0){	        		
	        		Free(bufrecv);
	        		return -1;
	        	}
	        	client_info->client_resp.cbuftam = 0;
	        	bzero(client_info->client_resp.clientbuf, sizeof(client_info->client_resp.clientbuf));        	
	        }      	
	        memcpy((client_info->client_resp.clientbuf)+(client_info->client_resp.cbuftam), bufrecv, rval);
	        if (client_info->client_resp.cbuftam+rval <= TAMBUFCLIENT){client_info->client_resp.cbuftam+=rval;}
	    }
        Free(bufrecv);
/*	    printf("%d", cbuftam);	
		for(f=0;f<cbuftam;f++){
			printf("%c", clientbuf[f]);
		}
		printf("\n");
*/
//printf("10\n");    	
      // Receive number of tuples
#ifdef DEBUG_PGCONNECTION
      printf("(Thread%d) Waiting number of Tuples...\n", id);
#endif

/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
/*
  #ifdef DEBUG_PGCONNECTION_RECVSIZE
     printf("Waiting message (RECVSIZE 2) ...\n");
  #endif
     if ((rval = recvWithSizeMem(sockResTh[id], & bufrecv)) < 0) {
       #ifdef ERROR_PGCONNECTION
        printf("(Thread%d) (RECVSIZE 2) Message (ERROR | NOT NTUPLES)\n", id);
       #endif
       Free(bufrecv);
       //TODO error interno que hacer?
       return -2; //Error Receiving datas of middler
     }
  #ifdef DEBUG_PGCONNECTION_RECVSIZE
     printf("(RECVSIZE 2) Bytes <%d> Message <---> (NTUPLES)\n", rval);
  #endif
*/
/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
      if ((rval = selectSuspect(socketJDBC, sockResTh[id], &bufrecv, 0)) <= 0){
        Free(bufrecv);
        return rval;
      }
//printf("11\n");
      convertToInt(bufrecv, sizeof(int), & ntuples, 0);
      Free(bufrecv);

#ifdef DEBUG_PGCONNECTION
      printf("(Thread%d) Number of tuples is %d\n", id, ntuples);
#endif
#ifdef DEBUG_PGCONNECTION_FAKE    
    ftuples = 2+(2*ntuples);
    //printf("FTUPLES <%d>\n", ftuples);	
#endif
      for (tuple = 0; tuple < ntuples; tuple++) {
/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
/*
  #ifdef DEBUG_PGCONNECTION_RECVSIZE
       printf("Waiting message (RECVSIZE 3) ...\n");
  #endif
       if ((rval = recvWithSizeMem(sockResTh[id], & bufrecv)) < 0) {
         #ifdef ERROR_PGCONNECTION
          printf("(Thread%d) (RECVSIZE 3) Message (ERROR | NOT [B|D]BITMASK)\n", id);
         #endif
         Free(bufrecv);
         //TODO error interno que hacer?
         return -2; //Error Receiving datas of middler
       }
  #ifdef DEBUG_PGCONNECTION_RECVSIZE
       printf("(RECVSIZE 3) Bytes <%d> Message <---> ([B|D]BITMASK)\n", rval);
  #endif

  #ifdef DEBUG_PGCONNECTION_SEND
       printf("(Thread%d) (SEND 8) Bytes <%d> Message <---> ([B|D]BITMASK)\n", id, rval);
  #endif
       if ((rval = sendToDriver(socketJDBC, bufrecv, rval)) <= 0) {
         #ifdef ERROR_PGCONNECTION
          printf("(Thread%d) (SEND 8) (ERROR | NOT [B|D]BITMASK)\n", id);
         #endif
         Free(bufrecv);
         return rval; //Error Sending datas to driver
       }
*/
/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
        // Receive and eco to drive type of tuple and bitmask
        rval = selectSuspect(socketJDBC, sockResTh[id], &bufrecv, 0/*FAKE 1*/);
        
		if (rval>0){        
	        if (client_info->client_resp.cbuftam+rval > TAMBUFCLIENT){
	        	if (send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0) < 0){	        		
	        		Free(bufrecv);
	        		return -1;
	        	}
	        	client_info->client_resp.cbuftam = 0;
	        	bzero(client_info->client_resp.clientbuf, sizeof(client_info->client_resp.clientbuf));        	
	        }      	
	        memcpy((client_info->client_resp.clientbuf)+client_info->client_resp.cbuftam, bufrecv, rval);
	        if (client_info->client_resp.cbuftam+rval <= TAMBUFCLIENT){client_info->client_resp.cbuftam+=rval;}
        }
        
/*        printf("%d", cbuftam);	
		for(f=0;f<cbuftam;f++){
			printf("%c", clientbuf[f]);
		}
		printf("\n");*/
	
//printf("12\n");    	
        if (rval <= 0){
          if (client_info->client_resp.cbuftam > 0){
	  		rval = send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0);//Compact
	  	  }
          Free(bufrecv);
          return rval;
        }
#ifdef DEBUG_PGCONNECTION_FAKE    
    fakeval[2+tuple] = rval;
    fake[2+tuple] = (char *)calloc(sizeof(char), fakeval[2+tuple]);
	memcpy(fake[2+tuple], bufrecv, fakeval[2+tuple]);
	/*printf("%d", rval);
	lex = fake[2+tuple];
	for(f=0;f<rval;f++){
		printf("%c", lex[f]);
	}
	printf("\n");	*/
#endif        
        Free(bufrecv);
//printf("13\n");
/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
/*
  #ifdef DEBUG_PGCONNECTION_RECVSIZE
       printf("Waiting message (RECVSIZE 4) ...\n");
  #endif
       if ((rval = recvWithSizeMem(sockResTh[id], & bufrecv)) < 0) {
         #ifdef ERROR_PGCONNECTION
          printf("(Thread%d) (RECVSIZE 4) Message (ERROR | NOT (SIZE VALUE)_NFIELDS)\n", id);
         #endif
         Free(bufrecv);
         //TODO error interno que hacer?
         return -2; // Error Receiving datas of middler
       }
  #ifdef DEBUG_PGCONNECTION_RECVSIZE
       printf("(RECVSIZE 4) Bytes <%d> Message <%s> ((SIZE VALUE)_NFIELDS)\n", rval, bufrecv);
  #endif

  #ifdef DEBUG_PGCONNECTION_SEND
       printf("(Thread%d) (SEND 9) Bytes <%d> Message <%s> ((SIZE VALUE)_NFIELDS)\n", id, rval, bufrecv);
  #endif
       if ((rval = sendToDriver(socketJDBC, bufrecv, rval)) <= 0) {
         #ifdef ERROR_PGCONNECTION
          printf("(Thread%d) (SEND 8) (ERROR | NOT (SIZE VALUE)_NFIELDS)\n", id);
         #endif
         Free(bufrecv);
         return rval; // Error Sending datas to driver
       }
*/
/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
        // Receive tuple
        // Receive and eco to drive type of tuple and bitmask
        rval = selectSuspect(socketJDBC, sockResTh[id], &bufrecv, 0/*FAKE 1*/);
        
        if (rval>0){        
	        if (client_info->client_resp.cbuftam+rval > TAMBUFCLIENT){
	        	if (send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0) < 0){
	        		return -1;
	        		Free(bufrecv);
	        	}
	        	client_info->client_resp.cbuftam = 0;
	        	bzero(client_info->client_resp.clientbuf, sizeof(client_info->client_resp.clientbuf));        	
	        }      	
	        memcpy((client_info->client_resp.clientbuf)+(client_info->client_resp.cbuftam), bufrecv, rval);
	        if (client_info->client_resp.cbuftam+rval <= TAMBUFCLIENT){client_info->client_resp.cbuftam+=rval;}
        }
    	 
/*    	printf("%d", cbuftam);	
		for(f=0;f<cbuftam;f++){
			printf("%c", clientbuf[f]);
		}
		printf("\n");
*/	    	
        if (rval <= 0){
          if (client_info->client_resp.cbuftam > 0){
	  		rval = send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0);//Compact
	  	  }
          Free(bufrecv);
          return rval;
        }        
//printf("14\n");      
#ifdef DEBUG_PGCONNECTION_FAKE    
    fakeval[3+tuple] = rval;
    fake[3+tuple] = (char *)calloc(sizeof(char), fakeval[3+tuple]);
	memcpy(fake[3+tuple], bufrecv, fakeval[3+tuple]);
	/*printf("%d", rval);
	lex = fake[3+tuple];
	for(f=0;f<rval;f++){
		printf("%c", lex[f]);
	}
	printf("\n");	*/
#endif        
        Free(bufrecv);
      } // for (tuple = 0; tuple < ntuples; tuple++)            
    } //if (numFields > 0)
    i++;
  } //while (i < sizesql)

#ifdef DEBUG_PGCONNECTION
  printf("(Thread%d) Send end of query\n", id);
#endif
#ifdef DEBUG_PGCONNECTION_SEND
  printf("(Thread%d) (SEND 10) Bytes <%d> Message <%s> ()\n", id, 1, buf_out);
#endif

  rval = 1;
  bzero(buf_out, sizeof(buf_out));
  buf_out[0] = 'Z';
  if ((client_info->client_resp.cbuftam)+rval > TAMBUFCLIENT){  	
	if (send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0) < 0){
	  return -1;
  	  Free(bufrecv);
	}
	client_info->client_resp.cbuftam = 0;
	bzero(client_info->client_resp.clientbuf, sizeof(client_info->client_resp.clientbuf));        	
  }      	
  memcpy((client_info->client_resp.clientbuf)+(client_info->client_resp.cbuftam), buf_out, rval);
  if (client_info->client_resp.cbuftam+rval <= TAMBUFCLIENT){client_info->client_resp.cbuftam+=rval;}

  if (client_info->client_resp.cbuftam > 0){    	
//printf("20\n");
/*  	printf("%d", cbuftam);	
	for(f=0;f<cbuftam;f++){
		printf("%c", clientbuf[f]);
	}
	printf("\n");*/
 	if (rval = send(socketJDBC, client_info->client_resp.clientbuf, client_info->client_resp.cbuftam, 0) < 0){//Compact
    	return -1;
 	}
  }
      
  //bzero(buf_out, sizeof(buf_out));
  //buf_out[0] = 'Z';
  //if ((rval = sendToDriver(socketJDBC, buf_out, 1)) <= 0) {
//#ifdef ERROR_PGCONNECTION
    //printf("(Thread%d) (SEND 10) (ERROR | NOT Z)\n", id);
//#endif
    //return rval; /* Error Sending datas to driver */
  //}

#ifdef DEBUG_PGCONNECTION_STATS
   //struct timeval time;   
   gettimeofday(&time, NULL);//STATS   
   //setFinishTimeArray(6, idConnection, idPetition, time);
   SETFINISHTIME(6, idConnection, idPetition, time.tv_sec, time.tv_usec);
#endif

  return 1;
}

int selectSuspect(int socketJDBC, int sockNotThread, char **bufrecv, int ecoTodriver){
  int isOpenJDBC = 1;
  int response = 0;
  int status = 1;
  int fdmax = 2;
  int rval = 0;
  fd_set readfds;
  int max = 0;

  while (!response){
  	FD_ZERO (&readfds);
  	FD_SET (sockNotThread, &readfds);
    FD_SET (socketJDBC, &readfds);
    
#ifdef DEBUG_PGCONNECTION_SUSPECT
    printf("%s:%d [selectSuspect] -> select\n", __FILE__, __LINE__);
#endif
    if (socketJDBC > sockNotThread){
    	max = socketJDBC+1;	
    }else{
    	max = sockNotThread+1;
    }
    if ((rval = select(max, &readfds, NULL, NULL, NULL)) == -1) {
#ifdef DEBUG_PGCONNECTION_SUSPECT
      printf("%s:%d [selectSuspect] -> ERROR\n", __FILE__, __LINE__);
#endif
        if (errno == EINTR) {
            // Any signal interrupt, return to select()
            continue;
        }
        // error in select:
        perror("select");
        response = 1;
        status = -1;
        continue;
    }
#ifdef DEBUG_PGCONNECTION_SUSPECT
    //printf("%s:%d [selectSuspect] -> action in socket?\n", __FILE__, __LINE__);
#endif

    if (FD_ISSET (socketJDBC, &readfds)) {
      char buffer[TAMBUFFER /* + EXTRASIZE - RMEXTRASIZE */];

#ifdef DEBUG_PGCONNECTION_SUSPECT
      printf("%s:%d [selectSuspect] -> socketJDBC\n", __FILE__, __LINE__);
#endif

      if ((rval = recv(socketJDBC, buffer, sizeof(buffer), 0)) > 0) {
#ifdef DEBUG_PGCONNECTION_SUSPECT
        printf("%s:%d [selectSuspect] -> recv<%s>\n", __FILE__, __LINE__, buffer);
#endif
        if (buffer[0] == 'S'){
#ifdef DEBUG_PGCONNECTION_SUSPECT
          printf("%s:%d [selectSuspect] -> recv<%s>\n", __FILE__, __LINE__, buffer);
#endif
          /* Driver is suspecting about us */
          buffer[0] = 'W';
          buffer[1] = '\0';
          if ((rval = send(socketJDBC, buffer, 1, 0)) < 0) {
#ifdef DEBUG_PGCONNECTION_SUSPECT
            printf("%s:%d [selectSuspect] -> send wait not possible\n", __FILE__, __LINE__);
#endif
            isOpenJDBC = 0;
            FD_CLR(socketJDBC, &readfds);
          }
        } else if (buffer[0] == 'E') {
#ifdef DEBUG_PGCONNECTION_SUSPECT
          printf("%s:%d [selectSuspect] -> ERROR\n", __FILE__, __LINE__);
#endif
          /* Driver disconnected */
          isOpenJDBC = 0;
          FD_CLR(socketJDBC, &readfds);
        }

      } else {
#ifdef DEBUG_PGCONNECTION_SUSPECT
        printf("%s:%d [selectSuspect] -> ERROR\n", __FILE__, __LINE__);
#endif
        if (rval == 0){
          /* Driver disconnected */
          isOpenJDBC = 0;
          FD_CLR(socketJDBC, &readfds);
        } else {
          /* Error in driverJDBC socket */
          response = 1;
          status = -2;
          continue;
        }
      }
    }

    if (FD_ISSET (sockNotThread, &readfds)) {
#ifdef DEBUG_PGCONNECTION_SUSPECT
      printf("%s:%d [selectSuspect] -> sockNotThread\n", __FILE__, __LINE__);
#endif
      if ((rval = recvWithSizeMem(sockNotThread, bufrecv, 0)) > 0) {
        if (isOpenJDBC == 1) {
          if (ecoTodriver == 1) {
          	int i;
          	char *lex;
          	//#ifdef DEBUG_PGCONNECTION_SUSPECT
      		  printf("%s:%d [selectSuspect] -> ECO <%s><%d>\n", __FILE__, __LINE__, *bufrecv,rval);
			//#endif
			lex = *bufrecv;
			//printf("%d", rval);
			//for(i=0;i<rval;i++){
				//printf("%c", lex[i]);
			//}
			//printf("\n");
            if ((rval = send(socketJDBC, *bufrecv, rval, 0)) > 0) {
              response = 1;
              status = 1;
            } else {
              if (rval == 0){
                /* Driver disconnected */
#ifdef DEBUG_PGCONNECTION_SUSPECT
        printf("%s:%d [selectSuspect] -> ERROR\n", __FILE__, __LINE__);
#endif                
                isOpenJDBC = 0;
                response = 1;
                status = -2;
                Free(*bufrecv);

              } else {
#ifdef DEBUG_PGCONNECTION_SUSPECT
        printf("%s:%d [selectSuspect] -> ERROR\n", __FILE__, __LINE__);
#endif              	
                /* Error in driverJDBC socket */
                response = 1;
                status = -2;
                Free(*bufrecv);
                continue;
              }
            }
          } else {
#ifdef DEBUG_PGCONNECTION_SUSPECT
        printf("%s:%d [selectSuspect] -> NOT ECO TO DRIVER <%s>\n", __FILE__, __LINE__, *bufrecv);
#endif          	
            response = 1;
            status = 1;
          }
        } else {
#ifdef DEBUG_PGCONNECTION_SUSPECT
        printf("%s:%d [selectSuspect] -> DRIVER IS CLOSE\n", __FILE__, __LINE__);
#endif        	
          response = 1;
          status = 0;
        }

      } else {
        /* Error in Notification Thread socket */
        response = 1;
        status = -3;
        continue;
      }
    }
  }
  if (isOpenJDBC == 0) {
    return 0;
  } else {
  	if (status == 1){
  		return status * rval;
  	}else{
  	    return status;
  	}
  }
}

/**  */
/* send the fields to driver JDBC */
/**  */
int sendFieldsToDriver(int socketJDBC, hot_uint32 id, char **bufrecv, int *rval) {
  //int rval;
  int numFields = 0;
  int i, j, typeField, longField, modifierField, tamBuffer;
  //char buf_out[TAMBUFFER /*+ EXTRASIZE - RMEXTRASIZE */];
  //char * bufrecv = NULL;

  // Receive field information

#ifdef DEBUG_PGCONNECTION
  printf("(Thread%d) Waiting fields...\n", id);
#endif

/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */

#ifdef DEBUG_PGCONNECTION_RECVSIZE
  printf("Waiting message (RECVSIZE 5) ...\n");
#endif
  //if ((*rval = recvWithSizeMem(sockResTh[id], bufrecv, 0)) < 0) {
    //Free(*bufrecv);
    //return (-1 /** numFields*/);
  //}
#ifdef DEBUG_PGCONNECTION_RECVSIZE
  printf("(RECVSIZE 5) Bytes <%d> Message <---> (TNFIELDSMETADATA)\n", rval);
#endif

/* --------------------------------  Sustituido por selectSuspect  -------------------------------- */
  if ((*rval = selectSuspect(socketJDBC, sockResTh[id], bufrecv, 0)) < 0){
    //Free(*bufrecv);
    return -1;
  }

  //printf("(Thread%d) numFields -----> %d\n", id, numFields);
  convertToInt(*bufrecv, sizeof(int), & numFields, 1);
//printf("NUMFIELDS <%d>", numFields);
  if (numFields > 0) {
#ifdef DEBUG_PGCONNECTION_SEND
    printf("(Thread%d) (SEND 11) Bytes <%d> Message <---> (TNFIELDSMETADATA)\n", id, numFields);
#endif
#ifdef DEBUG_PGCONNECTION_FAKE    
    fakeval[1] = rval;
    fake[1] = (char *)calloc(sizeof(char), fakeval[1]);
	memcpy(fake[1], bufrecv, fakeval[1]);
	//printf("fake[1]=<%s>\n", fake[1]);	
#endif
    //if ((*rval = send(socketJDBC, bufrecv, *rval, 0)) < 0) {
#ifdef DEBUG_PGCONNECTION_SEND
      printf("Error: <%d>\n", numFields);
#endif
      //Free(*bufrecv);
      //return (-1 * numFields);
    //}
  }
  
  //Free(*bufrecv);
  return numFields;
}
