/* modoci.c: -*- C -*-  How to use the Oracle Call Interface.

   This code implements with-open-database and friends for SQL when
   the database type passed to <sql::set-database-type> is "OCI". */

/*  Copyright (c) 1998 Brian J. Fox
    Author: Brian J. Fox (bfox@ai.mit.edu) Thu Nov 26 10:28:52 1998.

    This file is part of <Meta-HTML>(tm), a system for the rapid
    deployment of Internet and Intranet applications via the use of
    the Meta-HTML language.

    Copyright (c) 1995, 1996, Brian J. Fox (bfox@ai.mit.edu).
    Copyright (c) 1996, Universal Access Inc. (http://www.ua.com).

    Meta-HTML is free software; you can redistribute it and/or modify
    it under the terms of the UAI Free Software License as published
    by Universal Access Inc.; either version 1, or (at your option) 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
    UAI Free Software License for more details.

    You should have received a copy of the UAI Free Software License
    along with this program; if you have not, you may obtain one by
    writing to:

    Universal Access Inc.
    129 El Paseo Court
    Santa Barbara, CA
    93101  */

#include "modules.h"

#if defined (__cplusplus)
extern "C"
{
#endif

/* 0) #include any files that are specific to your module. */
#include <oratypes.h>
#include <ocidfn.h>
#if defined (__STDC__)
#  include <ociapr.h>
#else
#  include <ocikpr.h>
#endif /* !__STD_C__ */

/* 1) Declare the functions which implement the Meta-HTML functionality. */
static void pf_oci_exec (PFunArgs);

/* 2) Create a static table which associates function name, type, debug-flags,
      and address of code for each function. */
static PFunDesc ftab[] =
{
  /*   tag           complex? debug_level          code    */
  { "OCI::EXEC-SQL",    0,       0,             pf_oci_exec },
  { (char *)NULL,       0,       0,             (PFunHandler *)NULL }
};

/* 3)  Insert the following statement, with the name of your module file
   as a string.  This allows Meta-HTML to install the functions in your
   module when it is loaded. */
MODULE_INITIALIZE ("oci", ftab)

/* 4) Write a blurb about what this module does.  The text here will make
   it directly into the documentation, as a section of its own, and the
   functions that you declare with DEFUN, DEFMACRO, etc., will be documented
   in that section. */
DEFINE_SECTION (OCI-MODULE, Oracle;OCI;SQL;database,
"The functions in this module implement the underlying interface to
<tag SQL::WITH-OPEN-DATABASE> when the database type in
<tag SQL::SET-DATABASE-TYPE> is passed as \"OCI\".

The underlying interface is written using the Oracle Call Interface (OCI),
which provides a non-networked, direct connection to a running Oracle 7 or
Oracle 8 server.", "")

/* 5) Write the actual code which implements your functionality. */

DEFUNX (oci::exec, sql-expr, "Test the OCI with this function.")

typedef struct
{
  Cda_Def cda;
  Lda_Def lda;
  int initialized;
  char *username;
  char *password;
} OCI_STATE;

typedef struct
{
  int result_code;
  char *message;
  int num_rows;
  int more_rows;
  int row_limit;
  OCI_STATE state;
} OCI_RESULT;

static void
pf_oci_exec (PFunArgs)
{
}

static
long OraExecSql (char *sql, OCI_RESULT *result)
{
  long numberOfRows = 0;

  /* Initialize return values */
  result->result_code = 0;
  result->message = (char *)NULL;
  result->num_rows = 0;
  result->more_rows = 0;

  if ((result->state.initialized == 0) &&
      (oci_initialize (&result->state) != 0))
    return (-1);
    
  
  if (( rc = oexfet( &oLogon->state.cda, (sword) oLogon->rowLimit,
		  NO_CURSOR_CANCEL, ROW_LIMIT_MATCH ) ) != 0 )
	{
#ifdef DEBUG
	  sprintf(msg, "oexfet rc=<%ld> cda rc=<%ld>",
		  rc, oLogon->state.cda.rc );
	  OraPrintLogMsg( oLogon, func, msg );
#endif	 
	  /*
	   * Either no data has been returned or all the data
	   * has been returned less than or equal to the row limit
	   */
	  if ( oLogon->state.cda.rc == ORA_NO_DATA_FOUND )
	    {
#ifdef DEBUG
	      if (!oLogon->state.cda.rpc)
		OraPrintLogMsg( oLogon, func, "No rows satisfying query" );
	      else
		OraPrintLogMsg( oLogon, func, "No more data to be returned" );
#endif
	    }
	  else if ( oLogon->state.cda.rc == ORA_ROWS_EXCEED_LIMIT )
	    {
#ifdef DEBUG
	      OraPrintLogMsg( oLogon, func, "Rows returned exceed limit" );
#endif
	      oLogon->moreRows = 1;
	    }
	  else
	    {
	      oLogon->numRows = -1;
#ifdef DEBUG
	      OraPrintLogMsg( oLogon, func, "Oracle oexfet call failed" );
#endif
	      OraError( oLogon );
	      return (ORA_ERROR);
	    }
	} /* rc != 0 */

#ifdef DEBUG
      PrintElapsedCallTime( oLogon, "oexfet", END_TIMER );
#endif

      oLogon->numRows = oLogon->state.cda.rpc;

#ifdef DEBUG
      sprintf( msg, "Number of rows fetched <%ld>",
	      oLogon->numRows );
      OraPrintLogMsg( oLogon, func, msg );
#endif
  
    break;

    default:  /* Handle non select functions */

#ifdef DEBUG
      sprintf( msg, "Sql function %d", oLogon->sqlFunction );
      OraPrintLogMsg( oLogon, func, msg );
#endif

      /*
       * Execute the SQL or PL/SQL block
       */
#ifdef TIMER_ON
      PrintElapsedCallTime( oLogon, "oexec", START_TIMER );
#endif 

      if ( (rc = oexec( &oLogon->state.cda )) != 0 )
	{
#ifdef DEBUG
	  OraPrintLogMsg( oLogon, func, "Oracle oexec call failed" );
#endif
	  OraError( oLogon );
	  return(ORA_ERROR);
	}

#ifdef TIMER_ON
      PrintElapsedCallTime( oLogon, "oexec", END_TIMER );
#endif
      
      break;

    } /* end switch */

  return (ORA_OK);
}

#if defined (__cplusplus)
}
#endif
