/*************************************************************************
*									 *
*	 YAP Prolog 							 *
*									 *
*	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
*									 *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
*									 *
**************************************************************************
*									 *
* File:		myddas_shared.c						 *
* Last rev:	22/03/05						 *
* mods:									 *
* comments:	Predicates for maintaining MYDDAS                        *
*									 *
*************************************************************************/

#if defined MYDDAS_MYSQL || defined MYDDAS_ODBC

#include "Yap.h"
#include "Yatom.h"
#include "cut_c.h"
#include "myddas.h"
#include <stdlib.h>
#include "myddas_structs.h"
#ifdef MYDDAS_STATS
#include "myddas_statistics.h"
#endif

STATIC_PROTO(Int c_db_initialize_myddas,( USES_REGS1 ));
STATIC_PROTO(Int c_db_connection_type,( USES_REGS1 ));
STATIC_PROTO(Int c_db_add_preds,( USES_REGS1 ));
STATIC_PROTO(Int c_db_preds_conn_start ,( USES_REGS1 ));
STATIC_PROTO(Int c_db_preds_conn_continue ,( USES_REGS1 ));
STATIC_PROTO(Int c_db_connection_start ,( USES_REGS1 ));
STATIC_PROTO(Int c_db_connection_continue ,( USES_REGS1 ));
STATIC_PROTO(Int c_db_check_if_exists_pred,( USES_REGS1 ));
STATIC_PROTO(Int c_db_delete_predicate,( USES_REGS1 ));
STATIC_PROTO(Int c_db_multi_queries_number,( USES_REGS1 ));
#ifdef MYDDAS_STATS
STATIC_PROTO(Int c_db_stats,( USES_REGS1 ));
STATIC_PROTO(Int c_db_stats_walltime,( USES_REGS1 ));
STATIC_PROTO(Int c_db_stats_translate,( USES_REGS1 ));
STATIC_PROTO(Int c_db_stats_time,( USES_REGS1 ));
#endif 
#ifdef DEBUG
STATIC_PROTO(Int c_db_check,( USES_REGS1 ));
#endif

void Yap_InitMYDDAS_SharedPreds(void)
{
  /* c_db_initialize_myddas */
  Yap_InitCPred("c_db_initialize_myddas",0,c_db_initialize_myddas, 0);
  
  /* c_db_connection_type: Connection x Type */
  Yap_InitCPred("c_db_connection_type",2,c_db_connection_type, 0);

  /* CORRECT THIS: db_add_preds : PredName * Arity * Connection */
  Yap_InitCPred("c_db_add_preds",4,c_db_add_preds, 0);

  /* c_db_check_if_exists_pred : PredName * Arity * Connection */
  Yap_InitCPred("c_db_check_if_exists_pred",3,c_db_check_if_exists_pred, 0);
  
  /* c_db_delete_pred : Module * PredName * Arity */
  Yap_InitCPred("c_db_delete_predicate",3,c_db_delete_predicate, 0);

  /* c_db_delete_pred : Module * PredName * Arity */
  Yap_InitCPred("c_db_multi_queries_number",2,c_db_multi_queries_number, 0);

#ifdef MYDDAS_STATS
  /* c_db_stats: Connection * Stats */
  Yap_InitCPred("c_db_stats",2, c_db_stats, 0);

  /* c_db_stats_walltime */
  Yap_InitCPred("c_db_stats_walltime",1, c_db_stats_walltime, 0);

  /* c_db_stats_translate */
  Yap_InitCPred("c_db_stats_translate",2,c_db_stats_translate, 0);

  /* c_db_stats_time */
  Yap_InitCPred("c_db_stats_time",2,c_db_stats_time, 0);
#endif

#ifdef DEBUG
  Yap_InitCPred("c_db_check",0, c_db_check, 0);
#endif
}

void Yap_InitBackMYDDAS_SharedPreds(void)
{
  /* Gives all the predicates associated to a given connection */
  Yap_InitCPredBack("c_db_preds_conn", 4, sizeof(Int),
		    c_db_preds_conn_start, 
		    c_db_preds_conn_continue,  0);
  /* Gives all the connections stored on the MYDDAS Structure*/
  Yap_InitCPredBack("c_db_connection", 1, sizeof(Int),
		    c_db_connection_start, 
		    c_db_connection_continue,  0); 
  

}

/* Initialize all of the MYDDAS global structures */
static Int 
c_db_initialize_myddas( USES_REGS1 ){
  Yap_REGS.MYDDAS_GLOBAL_POINTER = myddas_init_initialize_myddas(); 
#ifdef MYDDAS_STATS
  Yap_REGS.MYDDAS_GLOBAL_POINTER = myddas_stats_initialize_global_stats(Yap_REGS.MYDDAS_GLOBAL_POINTER);
#endif /* MYDDAS_STATS */
  return TRUE;
}


/* Gives the type of a given connection, 
   in other words, type will be mysql or odbc 
   
   NOTE: In order to use this predicate, the connection*/
/* c_db_connection_type: +Connection * ?Type */
static Int 
c_db_connection_type ( USES_REGS1 ){
  Term arg_con = Deref(ARG1);
  Term arg_type = Deref(ARG2);
  
  Int *con = (Int *) IntegerOfTerm(arg_con);
  Int type = myddas_util_connection_type(con);
  
  if (type == 1) /* MYSQL Connection */
    Yap_unify(arg_type, MkAtomTerm(Yap_LookupAtom("mysql")));
  else if (type ==2) /* ODBC Connection */
    Yap_unify(arg_type, MkAtomTerm(Yap_LookupAtom("odbc")));
  else /* Not a valid connection*/
    return FALSE;
  
  return TRUE;
}

/* db_add_preds: PredName * Arity * Module * Connection*/
static Int 
c_db_add_preds ( USES_REGS1 ){
  Term arg_nome = Deref(ARG1);
  Term arg_aridade = Deref(ARG2);
  Term arg_module = Deref(ARG3);
  Term arg_conn = Deref(ARG4);
  
/*   PredEntry *pe; */
/*   pe = RepPredProp(PredPropByFunc(FunctorOfTerm(arg_pred),arg_module)); */
  

  char *nome = AtomName(AtomOfTerm(arg_nome));
  char *module = AtomName(AtomOfTerm(arg_module));
  Int aridade = IntegerOfTerm(arg_aridade);
  Int *conn = (Int *) IntegerOfTerm(arg_conn);

  if (myddas_util_add_predicate(nome,aridade,module,conn) == NULL)
    {
#ifdef DEBUG
      printf ("ERROR : Could not add Predicate: Line: %d File: %s\n",__LINE__,__FILE__);
#endif
      return FALSE;
    }
  
  return TRUE;
}


static Int 
c_db_check_if_exists_pred ( USES_REGS1 ){
  Term arg_nome = Deref(ARG1);
  Term arg_aridade = Deref(ARG2);
  Term arg_module = Deref(ARG3);
    
 
  char *nome = AtomName(AtomOfTerm(arg_nome));
  char *module = AtomName(AtomOfTerm(arg_module));
  Int aridade = IntegerOfTerm(arg_aridade);
  
  if (myddas_util_search_predicate(nome,aridade,module) == NULL)
    return FALSE;
  else
    return TRUE;
}


static Int 
c_db_delete_predicate( USES_REGS1 ){
  Term arg_module = Deref(ARG1);
  Term arg_name = Deref(ARG2);
  Term arg_arity = Deref(ARG3);
  
  char *module = AtomName(AtomOfTerm(arg_module));
  char *name = AtomName(AtomOfTerm(arg_name));
  Int arity = IntegerOfTerm(arg_arity);

  MYDDAS_UTIL_PREDICATE predicate = 
    myddas_util_search_predicate(name,arity,module);
  if (predicate == NULL)
    return FALSE;

  myddas_util_delete_predicate(predicate);

  return TRUE;
}


static Int 
c_db_multi_queries_number( USES_REGS1 ){
  Term arg_conn = Deref(ARG1);
  Term arg_number = Deref(ARG2);

  Int *conn = (Int *) IntegerOfTerm(arg_conn);
  MYDDAS_UTIL_CONNECTION node = 
    myddas_util_search_connection(conn);
  
  if (node == NULL)
    return FALSE;

  if (IsVarTerm(arg_number)){
    Yap_unify(arg_number,MkIntegerTerm(((Int)myddas_util_get_total_multi_queries_number(node))+1));
  } 
  else {
    Int number = IntegerOfTerm(arg_number);
    number--;
    myddas_util_set_total_multi_queries_number(node,number);
  }
  
  return TRUE;
  
}

static Int
c_db_connection_start( USES_REGS1 ){

  MYDDAS_UTIL_CONNECTION node =
    Yap_REGS.MYDDAS_GLOBAL_POINTER->myddas_top_connections;

  EXTRA_CBACK_ARG(1,1)=(CELL) MkIntegerTerm((Int)node);
  
  return (c_db_connection_continue( PASS_REGS1 ));
}

static Int
c_db_connection_continue( USES_REGS1 ){
  Term arg_conn = Deref(ARG1);
  
  MYDDAS_UTIL_CONNECTION node;
  node = (MYDDAS_UTIL_CONNECTION) IntegerOfTerm(EXTRA_CBACK_ARG(1,1));
  
  /* There is no connections */
  if (node == NULL)
    {
      cut_fail();
      return FALSE;
    }

  Yap_unify(arg_conn, MkIntegerTerm((Int)(node->connection)));
  EXTRA_CBACK_ARG(1,1)=(CELL) MkIntegerTerm((Int)(node->next));
  
  return TRUE;
  
}

/* db_preds_conn : Connection(+) * Pred_name(-) * Pred_arity */
static Int
c_db_preds_conn_start ( USES_REGS1 ){
  Term arg_conn = Deref(ARG1);
   
  Int *conn = (Int *) IntegerOfTerm(arg_conn);
  MYDDAS_UTIL_CONNECTION node = 
    myddas_util_search_connection(conn);
  
  /* Caso a ligacao já tenha sido apagada*/
  if (node == NULL)
    {
      cut_fail();
      return FALSE;
    }
  
  void *pointer = myddas_util_get_list_pred(node);
  EXTRA_CBACK_ARG(4,1)=(CELL) MkIntegerTerm((Int)pointer);
  
  return (c_db_preds_conn_continue( PASS_REGS1 ));
}

/* db_preds_conn : Connection(+) * Pred_name(-) * Pred_arity*/
static Int 
c_db_preds_conn_continue ( USES_REGS1 ){
  Term module = Deref(ARG2);
  Term name = Deref(ARG3);
  Term arity = Deref(ARG4);

  void *pointer;
  pointer = (void *) IntegerOfTerm(EXTRA_CBACK_ARG(4,1));
    
  if (pointer != NULL)
    {
      EXTRA_CBACK_ARG(4,1)=(CELL) MkIntegerTerm((Int)myddas_util_get_pred_next(pointer));
      
      if (!Yap_unify(module, MkAtomTerm(Yap_LookupAtom(myddas_util_get_pred_module(pointer))))){
	return FALSE;
      }
      if (!Yap_unify(name,MkAtomTerm(Yap_LookupAtom(myddas_util_get_pred_name(pointer))))){
	return FALSE;
      }
      if (!Yap_unify(arity, MkIntegerTerm((Int)myddas_util_get_pred_arity(pointer)))){
	return FALSE;
      }
      return TRUE;
    }
  else
    {
      cut_fail();
      return FALSE;
    }
}



#ifdef DEBUG
static Int 
c_db_check( USES_REGS1 ){
  check_int();
  return TRUE;
}
#endif /*DEBUG*/

#ifdef MYDDAS_STATS

static Int
c_db_stats_walltime( USES_REGS1 ){
  Term arg_time = Deref(ARG1);

#ifdef DEBUG
  if (IsVarTerm(arg_time)){
#endif
    Yap_unify(arg_time,MkIntegerTerm((Int)myddas_stats_walltime()));
    return TRUE;
#ifdef DEBUG
  }
  else{
    printf ("ERROR: c_db_stats_walltime got a variable\n");
    return FALSE;
  }
#endif
}

static Int
c_db_stats_translate( USES_REGS1 ){
  Term arg_start = Deref(ARG1);
  Term arg_end = Deref(ARG2);

  MYDDAS_STATS_TIME start;
  MYDDAS_STATS_TIME end;
  
  MYDDAS_STATS_TIME total_time,diff;

#ifdef DEBUG
  //Both args must be instanciated
  if (IsNonVarTerm(arg_start) && IsNonVarTerm(arg_end)){
#endif
    start = (MYDDAS_STATS_TIME) IntegerOfTerm(arg_start);
    end = (MYDDAS_STATS_TIME) IntegerOfTerm(arg_end);

    MYDDAS_STATS_GET_TRANSLATE(total_time);
    
    MYDDAS_STATS_INITIALIZE_TIME_STRUCT(diff,time_copy);
    myddas_stats_subtract_time(diff,end,start);
    
    diff = myddas_stats_time_copy_to_final(diff);
    myddas_stats_add_time(total_time,diff,total_time);
    MyddasULInt count;
    MYDDAS_STATS_GET_TRANSLATE_COUNT(count);
    MYDDAS_STATS_SET_TRANSLATE_COUNT(++count);
    
    MYDDAS_FREE(diff,struct myddas_stats_time_struct);
    MYDDAS_FREE(start, struct myddas_stats_time_struct);
    MYDDAS_FREE(end, struct myddas_stats_time_struct);
    
    return TRUE;
#ifdef DEBUG
  }
  else{
    printf ("ERROR: c_db_stats_translate got a variable\n");
    return FALSE;
  }
#endif
}

static Int
c_db_stats_time( USES_REGS1 ){
  Term arg_reference = Deref(ARG1);
  Term arg_time = Deref(ARG2);
  
  Term final_term;
  
  MYDDAS_STATS_STRUCT struc = (MYDDAS_STATS_STRUCT)IntegerOfTerm(arg_reference);
  Functor functor_count = Yap_MkFunctor(Yap_LookupAtom("count"),1);
  Term count_number[1];
  Functor unit;
  Term number[1];

  switch(struc->type){
  
  case integer:
    {
      Functor functor = Yap_MkFunctor(Yap_LookupAtom("myddas_integer"),2);
      Term integer_number[1];
      MyddasULInt integer;

      unit = Yap_MkFunctor(Yap_LookupAtom("number"),1);
      integer = struc->u.integer.integer;
      number[0] = MkIntegerTerm(integer);
      integer_number[0] = Yap_MkApplTerm(unit,1,number);;
      
      count_number[0] = MkIntegerTerm(struc->count);
      integer_number[1] = Yap_MkApplTerm(functor_count,1,count_number);
      final_term = Yap_MkApplTerm(functor,2,integer_number);
      break;
    }
    
  case time_str:
    {
      MYDDAS_STATS_TIME time = struc->u.time_str.time_str;
    
      Functor functor = Yap_MkFunctor(Yap_LookupAtom("myddas_time"),6);
      Term time_numbers[6];
      MyddasUInt time_number;
            
      unit = Yap_MkFunctor(Yap_LookupAtom("hours"),1);
      time_number = MYDDAS_STATS_TIME_HOURS(time);
      number[0] = MkIntegerTerm(time_number);
      time_numbers[0] = Yap_MkApplTerm(unit,1,number);;
      
      unit = Yap_MkFunctor(Yap_LookupAtom("minutes"),1);
      time_number = MYDDAS_STATS_TIME_MINUTES(time);
      number[0] = MkIntegerTerm(time_number);
      time_numbers[1] = Yap_MkApplTerm(unit,1,number);;

      unit = Yap_MkFunctor(Yap_LookupAtom("seconds"),1);
      time_number = MYDDAS_STATS_TIME_SECONDS(time);
      number[0] = MkIntegerTerm(time_number);
      time_numbers[2] = Yap_MkApplTerm(unit,1,number);;
            
      unit = Yap_MkFunctor(Yap_LookupAtom("miliseconds"),1);
      time_number = MYDDAS_STATS_TIME_MILISECONDS(time);
      number[0] = MkIntegerTerm(time_number);
      time_numbers[3] = Yap_MkApplTerm(unit,1,number);;
      
      unit = Yap_MkFunctor(Yap_LookupAtom("microseconds"),1);
      time_number = MYDDAS_STATS_TIME_MICROSECONDS(time); 
      number[0] = MkIntegerTerm(time_number);
      time_numbers[4] = Yap_MkApplTerm(unit,1,number);;
      
      count_number[0] = MkIntegerTerm(struc->count);
      time_numbers[5] = Yap_MkApplTerm(functor_count,1,count_number);
      final_term = Yap_MkApplTerm(functor,6,time_numbers);
      break;
    }
  
    default:
#ifdef DEBUG
    printf ("ERROR: c_db_stats_time unknow option\n");
#endif
    return FALSE;
    break;
  }
  
  if (!Yap_unify(arg_time,final_term )){
    return FALSE;
  }

  return TRUE;
}

//Returns the stats of this module in a list
static Int 
c_db_stats( USES_REGS1 ) {
  Term arg_conn = Deref(ARG1);
  Term arg_list = Deref(ARG2);
  
  MyddasPointer *conn = (MyddasPointer *) (IntegerOfTerm(arg_conn));
    
  // TODO
  if (get_myddas_top() == 0 ){ /* We want all the statistics */
    return FALSE;
  }

  MYDDAS_STATS_STRUCT str;
  MYDDAS_UTIL_CONNECTION 
   node = myddas_util_search_connection(conn);
  Term head, list;
  list = arg_list;

#ifdef DEBUG
  MYDDAS_STATS_TIME time = NULL;
#endif
  //[Index 1] -> Total Number of Rows by connection
  //Total number of Rows returned by the server
  //WARNING: only works with store_result
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
  str = myddas_stats_get_stat(node->stats,5);
  Yap_unify(head, MkIntegerTerm((MyddasInt)str));
#ifdef DEBUG
  MyddasUInt number = 0;

  MYDDAS_STATS_CON_GET_TOTAL_ROWS(node,number);
  printf ("Total Number of Rows returned from the Server\n");
  printf ("%lu\n\n",(unsigned long)number);
#endif

  //[Index 2] -> Total of Time Spent by the DB Server
  // processing all the  SQL Querys
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
    
  str = myddas_stats_get_stat(node->stats,1);
  Yap_unify(head, MkIntegerTerm((MyddasInt)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_TOTAL_TIME_DBSERVER(node,time);
  printf ("Reference to time Spent by the Server, on all the SQL Querys\n");
  MYDDAS_STATS_PRINT_TIME_STRUCT(time);
  printf ("\n\n");
#endif  

  //[Index 3] -> Total of Time Spent by the DB Server
  // processing a the last SQL Query
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
  
  str = myddas_stats_get_stat(node->stats,2);
  Yap_unify(head, MkIntegerTerm((MyddasInt)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_LAST_TIME_DBSERVER(node,time);
  printf ("Reference to time Spent by the Server, on the last SQL Query\n");
  MYDDAS_STATS_PRINT_TIME_STRUCT(time);
  printf ("\n\n");
#endif
  
  //[Index 4] -> Total of Time Spent by the DB Server
  // transfering all the results of the  SQL Querys
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
  
  str = myddas_stats_get_stat(node->stats,3);
  Yap_unify(head, MkIntegerTerm((MyddasInt)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_TOTAL_TIME_TRANSFERING(node,time);
  printf ("Refence to time Spent by the Server, transfering all the results SQL Query\n");
  MYDDAS_STATS_PRINT_TIME_STRUCT(time);
  printf ("\n\n");
#endif
  
  //[Index 5] -> Total of Time Spent by the DB Server
  // transfering the result of the last SQL Query
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
  
  str = myddas_stats_get_stat(node->stats,4);
  Yap_unify(head, MkIntegerTerm((MyddasInt)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_LAST_TIME_TRANSFERING(node,time);
  printf ("Reference to time Spent by the Server, transfering the result of the last SQL Query\n");
  MYDDAS_STATS_PRINT_TIME_STRUCT(time);
  printf ("\n\n");
#endif
  
  //[Index 6] -> Total of Time Spent by the 
  // db_row_function
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
  
  str = myddas_stats_get_stat(Yap_REGS.MYDDAS_GLOBAL_POINTER->myddas_statistics->stats,1);
  
  Yap_unify(head, MkIntegerTerm((MyddasInt)str));
#ifdef DEBUG
  MYDDAS_STATS_GET_DB_ROW_FUNCTION(time);
  printf ("Reference to time Spent by the db_row_function\n");
  MYDDAS_STATS_PRINT_TIME_STRUCT(time);
  printf ("\n\n");
#endif
  
  //[Index 7] -> Total of Bytes Transfered by the 
  // DB Server on all SQL Querys
  head = HeadOfTerm(list);
  list = TailOfTerm(list);

  str = myddas_stats_get_stat(node->stats,6);
  Yap_unify(head, MkIntegerTerm((MyddasPointer)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_TOTAL_BYTES_TRANSFERING_FROM_DBSERVER(node,number);
  printf ("Bytes Transfered by the DB Server from all querys\n");
  printf ("%llu\n\n",(MyddasULInt)number);
#endif
  
  //[Index 8] -> Total of Bytes Transfered by the 
  // DB Server on the last SQL Query
  head = HeadOfTerm(list);
  list = TailOfTerm(list);
  
  str = myddas_stats_get_stat(node->stats,7);
  Yap_unify(head, MkIntegerTerm((MyddasPointer)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_LAST_BYTES_TRANSFERING_FROM_DBSERVER(node,number);
  printf ("Bytes Transfered by the DB Server on the last query\n");
  printf ("%llu\n\n",(MyddasULInt)number);
#endif
  //[Index 9] -> Number of querys made to the DBserver
  head = HeadOfTerm(list);
  list = TailOfTerm(list);

  str = myddas_stats_get_stat(node->stats,8);
  Yap_unify(head, MkIntegerTerm((MyddasPointer)str));
#ifdef DEBUG
  MYDDAS_STATS_CON_GET_NUMBER_QUERIES_MADE(node,number);
  printf ("Number of Querys made to the server\n");
  printf ("%llu\n\n",(MyddasULInt)number);
#endif

  //[Index 10] -> Total of Time Spent by the 
  // translate predicate
  head = HeadOfTerm(list);
  list = TailOfTerm(list);

  str = myddas_stats_get_stat(Yap_REGS.MYDDAS_GLOBAL_POINTER->myddas_statistics->stats,2);
  Yap_unify(head, MkIntegerTerm((Int)str));

#ifdef DEBUG
  MYDDAS_STATS_GET_TRANSLATE(time);
  printf ("Reference to time Spent by the translate predicate\n");
  MYDDAS_STATS_PRINT_TIME_STRUCT(time);
  printf ("\n\n");
#endif

  /* Memory management */
#ifdef DEBUG
  MyddasULInt nr;
  MYDDAS_MEMORY_MALLOC_NR(nr);
  printf ("Number of times malloc was called in MYDDAS: %lu \n",nr);
  MYDDAS_MEMORY_FREE_NR(nr);
  printf ("Number of times free was called in MYDDAS  : %lu \n",nr);
  
  MYDDAS_MEMORY_MALLOC_SIZE(nr);
  printf ("Total memory allocated in MYDDAS: %lu \n",nr);
  MYDDAS_MEMORY_FREE_SIZE(nr);
  printf ("Total memory freed in MYDDAS    : %lu \n",nr);
#endif
  
  return TRUE;
}

#endif /* MYDDAS_STATS */


/* Function to delete all the temporary tables */
/* from the mysql server */
void Yap_MYDDAS_delete_all_myddas_structs(void)
{
  CACHE_REGS

  /* NAO ESQUECER DE FAZER ISTO TB PARA O DB_CLOSE*/
  MYDDAS_GLOBAL global = 
    Yap_REGS.MYDDAS_GLOBAL_POINTER;

  /* In case that the MYDDAS module isn't loaded */
  if (global == NULL)
    return;

  MYDDAS_UTIL_CONNECTION connections =
    global->myddas_top_connections;
  
  /* Delete all connections */
  for(;connections!=NULL;connections=connections->next)
    myddas_util_delete_connection(connections->connection);
  
#ifdef MYDDAS_STATS
  myddas_stats_delete_stats_list(global->myddas_statistics->stats);
  MYDDAS_FREE(global->myddas_statistics,struct myddas_global_stats);
#endif

  MYDDAS_FREE(global,struct myddas_global);

#ifdef DEBUG
  MyddasULInt nr;
  MYDDAS_MEMORY_MALLOC_NR(nr);
  printf ("Number of times malloc was called in MYDDAS: " UInt_FORMAT " \n",(UInt)nr);
  MYDDAS_MEMORY_FREE_NR(nr);
  printf ("Number of times free was called in MYDDAS  : " UInt_FORMAT " \n",(UInt)nr);
  
  MYDDAS_MEMORY_MALLOC_SIZE(nr);
  printf ("Total memory allocated in MYDDAS: " UInt_FORMAT " \n",(UInt)nr);
  MYDDAS_MEMORY_FREE_SIZE(nr);
  printf ("Total memory freed in MYDDAS    : " UInt_FORMAT " \n",(UInt)nr);
#endif
  
}





#endif /*CUT_C && (MYDDAS_MYSQL || MYDDAS_ODBC)*/
