/*
BOIL (Brunni's Own Interpreter Language)
(c) 1998 netEstate (http://www.netestate.de/, info@netestate.de),
Michael Brunnbauer & Markus Hendel, Gesellschaft fuer Netzwerkkommunikation bR
Am Bluetenanger 8, 80995 Muenchen, Germany

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
any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "general.h"
#include "handles.cc"
#include "boil.h"
#include "boil.tab.h"
#include "libs.h"

#ifdef WITH_POSTGRES 

int args_pg_close[]= { TYPE_VALUE_LONG,
                       0 };

flowctrl func_pg_close(type_block* aktblock,opt* options,
                       joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  PGconn* conn;

  if (!options->ptr_h->pg_connections.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_close: illegal postgres connection number");
      return back;
    };
  conn=options->ptr_h->pg_connections.gethandle((*args)[0].val.longval);

  PQfinish(conn);
  options->ptr_h->pg_connections.del((*args)[0].val.longval);
  back.returnval.val.ulongval=1;
  return back;
}

int args_pg_connect[]= { TYPE_VALUE_STRING,
                         TYPE_VALUE_STRING,
                         TYPE_VALUE_STRING,
                         TYPE_VALUE_STRING,
                         TYPE_VALUE_STRING,
                         0 };

flowctrl func_pg_connect(type_block* aktblock,opt* options,
                         joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back,call;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_LONG;
  back.returnval.val.longval=-1;
  PGconn* conn;

  if (!defined((*args)[0].stringval) ||
      !defined((*args)[1].stringval) ||
      !defined((*args)[2].stringval) ||
      !defined((*args)[3].stringval) ||
      !defined((*args)[4].stringval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_connect: string not defined");
      return back;
    };

  conn=PQsetdb((*args)[0].stringval,
               (*args)[1].stringval,
               (*args)[2].stringval,
               (*args)[3].stringval,
               (*args)[4].stringval);
  if (PQstatus(conn)==CONNECTION_BAD)
    {
      PQfinish(conn);
      setvarulong("error",1);
      setvarstring("perror","pg_connect: cannot connect");
      return back;
    };
  
  back.returnval.val.longval=options->ptr_h->pg_connections.insert(conn);
  return back;
}

int args_pg_exec[]= { TYPE_VALUE_LONG,
                      TYPE_VALUE_STRING,
                      0 };

flowctrl func_pg_exec(type_block* aktblock,opt* options,
                      joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back,call;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_LONG;
  back.returnval.val.longval=-1;
  PGconn* conn;
  PGresult* result;
  string errormessage;

  if (!defined((*args)[1].stringval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_exec: string not defined");
      return back;
    };

  if (!options->ptr_h->pg_connections.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_exec: illegal postgres connection number");
      return back;
    };
  conn=options->ptr_h->pg_connections.gethandle((*args)[0].val.longval);

  result=PQexec(conn,(*args)[1].stringval);
  if (!result)
    {
      errormessage=PQerrorMessage(conn);
      if (!defined(errormessage)) { errormessage=""; };
      setvarulong("error",1);
      setvarstring("perror","pg_exec: query failed: "+(*args)[1].stringval+
		   " error: "+errormessage);
      return back;
    };
  ExecStatusType status=PQresultStatus(result);
  if (status==PGRES_BAD_RESPONSE ||
      status==PGRES_NONFATAL_ERROR ||
      status==PGRES_FATAL_ERROR)
    {
      errormessage=PQerrorMessage(conn);
      if (!defined(errormessage)) { errormessage=""; };
      setvarulong("error",1);
      setvarstring("perror","pg_exec: query failed: "+(*args)[1].stringval+
		   " error: "+errormessage);
      PQclear(result);
      return back;
    };
  
  back.returnval.val.longval=options->ptr_h->pg_querys.insert(result);
  return back;
}  

int args_pg_freeresult[]= { TYPE_VALUE_LONG,
                            0 };

flowctrl func_pg_freeresult(type_block* aktblock,opt* options,
                            joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  PGresult* result;

  if (!options->ptr_h->pg_querys.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_freeresult: illegal postgres result number");
      return back;
    };
  result=options->ptr_h->pg_querys.gethandle((*args)[0].val.longval);

  PQclear(result);
  options->ptr_h->pg_querys.del((*args)[0].val.longval);
  back.returnval.val.ulongval=1;
  return back;
}

int args_pg_numfields[]= { TYPE_VALUE_LONG,
                           0 };

flowctrl func_pg_numfields(type_block* aktblock,opt* options,
                           joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  PGresult* result;

  if (!options->ptr_h->pg_querys.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_numfields: illegal postgres result number");
      return back;
    };
  result=options->ptr_h->pg_querys.gethandle((*args)[0].val.longval);

  back.returnval.val.ulongval=(unsigned long) PQnfields(result);
  return back;
}

int args_pg_numrows[]= { TYPE_VALUE_LONG,
                         0 };

flowctrl func_pg_numrows(type_block* aktblock,opt* options,
                         joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  PGresult* result;

  if (!options->ptr_h->pg_querys.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_numrows: illegal postgres result number");
      return back;
    };
  result=options->ptr_h->pg_querys.gethandle((*args)[0].val.longval);

  back.returnval.val.ulongval=(unsigned long) PQntuples(result);
  return back;
}

int args_pg_fieldname[]= { TYPE_VALUE_LONG,
                           TYPE_VALUE_ULONG,
                           0 };

flowctrl func_pg_fieldname(type_block* aktblock,opt* options,
                           joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_STRING;
  PGresult* result;

  if (!options->ptr_h->pg_querys.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_fieldname: illegal postgres result number");
      return back;
    };
  result=options->ptr_h->pg_querys.gethandle((*args)[0].val.longval);

  char* value=PQfname(result,(int) (*args)[1].val.ulongval);
  if (!value)
    {
      setvarulong("error",1);
      setvarstring("perror","pg_fieldname: result was NULL");
      return back;
    };

  back.returnval.stringval=value;
  return back;
};

int args_pg_fieldtype[]= { TYPE_VALUE_LONG,
                           TYPE_VALUE_ULONG,
                           0 };

flowctrl func_pg_fieldtype(type_block* aktblock,opt* options,
                           joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_STRING;
  PGresult* result;
  
  if (!options->ptr_h->pg_querys.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_fieldtype: illegal postgres result number");
      return back;
    };
  result=options->ptr_h->pg_querys.gethandle((*args)[0].val.longval);

  unsigned long type=
    (unsigned long) PQftype(result,(int) (*args)[1].val.ulongval);
  char buf[MAX_LINE_SIZE];
  snprintf(buf,MAX_LINE_SIZE,"%lu",type);

  PGconn* conn;
  if (!options->ptr_h->pg_connections.values.length())
    {
      setvarulong("error",1);
      setvarstring("perror","pg_fieldtype: no postgres connection");
      return back;
    };
  conn=options->ptr_h->pg_connections.values[0];

  PGresult* result1=PQexec(conn,"select typname from pg_type where oid="+
                           (string) buf+";");
  if (!result1)
    {
      setvarulong("error",1);
      setvarstring("perror","pg_fieldtype: cannot query pg_type for typename");
      return back;
    };
  if (PQntuples(result1)!=1)
    {
      setvarulong("error",1);
      setvarstring("perror","pg_fieldtype: typename not defined or ambiguous");
      return back;
    };
  char* value=PQgetvalue(result1,0,0);
  if (!value)
    {
      setvarulong("error",1);
      setvarstring("perror",
                   "pg_fieldtype: result from query for name was NULL");
    };
  back.returnval.stringval=value;
  PQclear(result1);

  return back;
};

int args_pg_result[]= { TYPE_VALUE_LONG,
                        TYPE_VALUE_ULONG,
                        TYPE_VALUE_ULONG,
                        0 };

flowctrl func_pg_result(type_block* aktblock,opt* options,
                        joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_STRING;
  PGresult* result;

  if (!options->ptr_h->pg_querys.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pg_numfields: illegal postgres result number");
      return back;
    };
  result=options->ptr_h->pg_querys.gethandle((*args)[0].val.longval);

  char* value=PQgetvalue(result,
                         (int) (*args)[1].val.ulongval,
                         (int) (*args)[2].val.ulongval);
  if (!value)
    {
      setvarulong("error",1);
      setvarstring("perror","pg_result: result was NULL");
      return back;
    };
  
  back.returnval.stringval=value;
  return back;
}

#endif
