
#include "tclsql.h"
/*
 * Copyright 1992 Regents of the University of California. Permission to use,
 * copy, modify, and distribute this software and its documentation for any
 * purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies.  The University of California makes
 * no representations about the suitability of this software for any purpose.
 * It is provided 'as is' without express or implied warranty.
 */
#ifndef lint
static char     rcsid[] = "$Id: tclsql.c,v 1.2 1992/09/29 21:20:13 cxh Exp cxh $";
#endif

/* Create a collection of tcl procedures to access Ingres */
SQLinit(interp)
     Tcl_Interp     *interp;
{
  Tcl_CreateCommand(interp, "SQLopendb", SQLopendbCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLdbName", SQLdbNameCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLclosedb", SQLclosedbCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLexec", SQLexecCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLselect", SQLselectCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLcolNamesSelect", SQLcolNamesSelectCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLcolTypesSelect", SQLcolTypesSelectCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLselectRow", SQLselectRowCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLcommit", SQLcommitCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLimmediate", SQLimmediateCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLdelete", SQLdeleteCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLinsert", SQLinsertCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLupdate", SQLupdateCmd, 0, 0);

  /* The commands below are all cursor commands */
  Tcl_CreateCommand(interp, "SQLdeclareCursor", SQLdeclareCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLprepareCursor", SQLprepareCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLdescribeCursor", SQLdescribeCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLopenCursor", SQLopenCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLfetchCursor", SQLfetchCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLmoreRows", SQLmoreRowsCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLcloseCursor", SQLcloseCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLcolNamesCursor", SQLcolNamesCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLcolTypesCursor", SQLcolTypesCursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLlistCursors", SQLlistCursorsCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLisACursor", SQLisACursorCmd, 0, 0);
  Tcl_CreateCommand(interp, "SQLdeleteCursor", SQLdeleteCursorCmd, 0, 0);
}

/***********************************************************************/
/* General sql commands commands */


/*
 * SQLopendb <database_name>
 */
SQLopendbCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  char           *strncpy();

#ifdef MALLOC_DEBUG
  malloc_debug(2);
#endif

  if (argc != 2) {
    USAGE("Wrong number of args", "dbname");
  }

  if (!Db_open) {
    if (opendb(interp, argv[1]) == TCL_ERROR)
      return TCL_ERROR;
  }
  else {
    Tcl_AppendResult(interp, argv[0], ": Database already open. ", 0);
    return TCL_ERROR;
  }

  Db_open = 1;
  strncpy((char *) Db_name, argv[1], DBNAME_LEN);
  return TCL_OK;
}

/*
 * SQLdbName If database is open, then return the name of the open database,
 * otherwise return an empty string.
 */
SQLdbNameCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc != 1) {
    USAGE("Wrong number of args","");
  }

  /*
   * It would be nice to test for a db connection here, but instead we depend
   * on the flag being correct.
   */
  if (Db_open)
    Tcl_SetResult(interp, Db_name, TCL_VOLATILE);
  else
    Tcl_SetResult(interp, "",TCL_VOLATILE);

  return TCL_OK;
}


/*
 * SQLcommit
 */
SQLcommitCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc != 1) {
    USAGE("Wrong number of args", "");
  }

  if (Db_open)
    return commit(interp);
  else {
    Tcl_AppendResult(interp, argv[0], " No database currently open. ", 0);
    return TCL_ERROR;
  }
  /* NOTREACHED */
}


/*
 * SQLclosedb Close the database.  If the database is not open, print an
 * error message.
 */
SQLclosedbCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
#ifdef MALLOC_DEBUG
  malloc_verify();
#endif

  if (argc != 1) {
    USAGE("Wrong number of args", "");
  }
  if (Db_open)
    sql_cleanup(interp);
  else {
    Tcl_AppendResult(interp, argv[0], ": No database currently open. ", 0);
    return TCL_ERROR;
  }
  return TCL_OK;
}


/*
 * SQLexec <results_variable> <sql_statement> Execute the sql_statement,
 * placing the results in results_variable. Note that the sql_statement can
 * be a select statement.
 */
SQLexecCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  char           *cbuf;
  int             retval;

  if (argc < 2) {
    USAGE("Wrong number of args", "command_word [command_word]*");
  }

  cbuf = Tcl_Concat(argc - 2, argv + 2);
  retval = exec_sql(interp, argv[1], argv[0], cbuf, SELECT_ALL);
  free(cbuf);
  return retval;
}

/*
 * SQLselect [-noheader] [-1d] <result_array> <sql_statement>
 */
SQLselectCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  int             op;
  int             i;


  if (argc < 3) {
    USAGE("Wrong number of args",
	  "[-noheaders] [-1d] result_array command_word [command_word]*");
  }

  op = SELECT_ALL;

  /*
   * Run through the args twice, once to catch each arg (They could be in
   * different orders).  TODO: fix this to use some sort of getopt() that
   * will handle long arg names.
   */
  for (i = 1; i <= 2; i++) {
    if (argc > 0 && !strcmp(argv[1], "-noheaders")) {
      argv[1] = argv[0];
      argc--;
      argv++;
      op = op | SELECT_NOHDR;
    }
    else if (argc > 0 && !strcmp(argv[1], "-1d")) {
      argv[1] = argv[0];
      argc--;
      argv++;
      op = op | SELECT_1D;
    }
  }

  if (argc < 3) {
    USAGE("Wrong number of args",
	  "[-noheaders] [-1d] result_array command_word [command_word]*");
  }

  return setup_select(clientData, interp, argc, argv, op);
}

/*
 * SQLcolNamesSelect -1d <results_variable> <sql_statement>
 */
SQLcolNamesSelectCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  int             op = SELECT_COLNAMES;

  if (argc < 2) {
    USAGE("Wrong number of args", "[-1d] results_variable sql_statment");
  }
  if (argc > 0 && !strcmp(argv[1], "-1d")) {
    argv[1] = argv[0];
    argc--;
    argv++;
    op = op | SELECT_1D;
  }
  if (argc < 3) {
    USAGE("Wrong number of args", "[-1d] results_variable sql_statment");
  }
  return setup_select(clientData, interp, argc, argv, op);
}

/*
 * SQLcolTypesSelect <results_variable> <sql_statement>
 */
SQLcolTypesSelectCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc < 3) {
    USAGE("Wrong number of args", "results_variable sql_statement");
  }
  return setup_select(clientData, interp, argc, argv, SELECT_COLTYPES);
}

/*
 * SQLselectRow [-1d] <row> <results_variable> <sql_statement>
 */
SQLselectRowCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  int             op = SELECT_ROW;

  if (argc < 3) {
    USAGE("Wrong number of args", "[-1d] row_number results_variable sql_statement");
  }

  if (argc > 0 && !strcmp(argv[1], "-1d")) {
    argv[1] = argv[0];
    argc--;
    argv++;
    op = op | SELECT_1D;
  }

  SelectRow = atoi(argv[1]);
  if (SelectRow < 0) {
    Tcl_AppendResult(interp, argv[0],
		     ": row must be positive integer ", 0);
    return TCL_ERROR;
  }
  argv[1] = argv[0];
  if (argc < 3) {
    USAGE("Wrong number of args", "[-1d] row_number results_variable sql_statement");
  }

  if (SelectRow > 0)
    return setup_select(clientData, interp, argc - 1, argv + 1, op);
  else if (op & SELECT_1D)
    return setup_select(clientData, interp, argc - 1, argv + 1,
			SELECT_COLNAMES | SELECT_1D);
  else
    return setup_select(clientData, interp, argc - 1, argv + 1, SELECT_COLNAMES);
}

/*
 * SQLimmediate statement_string
 */
SQLimmediateCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc < 2) {
    USAGE("Wrong number of args", " SQLimmediate statement_string");
  }

  return immediate(interp, argc, argv, "", " SQLimmediate statement_string");
}

/*
 * SQLdelete [repeated] tablename [corr_name]
 * [WHERE search_condition]
 */
SQLdeleteCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc < 2) {
    USAGE("Wrong number of args", " SQLdelete [repeated] tablename [corr_name] [WHERE search_condition]");
  }

  return immediate(interp, argc, argv, "delete from",
		" SQLdelete [repeated] tablename [corr_name] [WHERE search_condition]");

}

/*
 * SQLinsert [repeated] tablename [(column {,column})] [values (expr{,
 * expr})]|[subselect]
 */
SQLinsertCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc < 2) {
    USAGE("Wrong number of args", "[repeated] tablename [(column {,column})] [values (expr{, expr})]|[subselect]");
  }
  return immediate(interp,argc,argv,"insert into",
		   "[repeated] tablename [(column {,column})] [values (expr{, expr})]|[subselect]");

}


/*
 * SQLupdate [repeated] tablename [corr_name] [FROM tablename [corr_name] {,
 * tablename [corr_name]}] SET column = expression [, column = expression ]
 * [WHERE search_condition]
 */
SQLupdateCmd(clientData, interp, argc, argv)
     ClientData      clientData;
     Tcl_Interp     *interp;
     int             argc;
     char          **argv;
{
  if (argc < 2) {
    USAGE("Wrong number of args", " SQLupdate [repeated] tablename [corr_name] [FROM tablename [corr_name] {, tablename [corr_name]}] SET column = expression [, column = expression ] [WHERE search_condition]");
  }

  return immediate(interp, argc, argv, "update",
		" SQLupdate [repeated] tablename [corr_name] [FROM tablename [corr_name] {, tablename [corr_name]}] SET column = expression [, column = expression ] [WHERE search_condition]");

}
