/* KInterbasDB Python Package - Implementation of SQL Statement Execution, etc.
 *
 * Version 3.3
 *
 * The following contributors hold Copyright (C) over their respective
 * portions of code (see license.txt for details):
 *
 * [Original Author (maintained through version 2.0-0.3.1):]
 *   1998-2001 [alex]  Alexander Kuznetsov   <alexan@users.sourceforge.net>
 * [Maintainers (after version 2.0-0.3.1):]
 *   2001-2002 [maz]   Marek Isalski         <kinterbasdb@maz.nu>
 *   2002-2007 [dsr]   David Rushby          <woodsplitter@rocketmail.com>
 * [Contributors:]
 *   2001      [eac]   Evgeny A. Cherkashin  <eugeneai@icc.ru>
 *   2001-2002 [janez] Janez Jere            <janez.jere@void.si>
 */

static PyObject *pyob_create_database(PyObject *self, PyObject *args) {
  CConnection *con = NULL;
  char *sql = NULL;
  Py_ssize_t sql_len = -1;
  short dialect = 0;

  if (!PyArg_ParseTuple(args, "s#|h", &sql, &sql_len, &dialect)) { goto fail; }

  if (!_check_statement_length(sql_len)) { goto fail; }

  /* A negative value for the dialect is not acceptable because the IB/FB API
   * requires an UNSIGNED SHORT. */
  if (dialect < 0) {
    raise_exception(ProgrammingError, "connection dialect must be > 0");
    goto fail;
  }

  con = Connection_create();
  if (con == NULL) { goto fail; }
  assert (con->main_trans == NULL);

  /* conn->dialect is set to a default value in the Connection_create
   * function, so we only need to change it if we received a dialect argument
   * to this function. */
  if (dialect > 0) {
    con->dialect = (unsigned short) dialect;
  }
  assert (con->dialect > 0);


  {
    isc_tr_handle unused_trans_handle = NULL_TRANS_HANDLE;

    LEAVE_GIL_WITHOUT_AFFECTING_DB
    ENTER_GDAL_WITHOUT_LEAVING_PYTHON
    ENTER_GCDL_WITHOUT_LEAVING_PYTHON

    isc_dsql_execute_immediate(
        con->status_vector,
        &con->db_handle,
        &unused_trans_handle,
        /* Cast is safe because sql_len has already been constrained: */
        (unsigned short) sql_len,
        sql,
        con->dialect,
        NULL
      );

    LEAVE_GCDL_WITHOUT_ENTERING_PYTHON
    LEAVE_GDAL_WITHOUT_ENTERING_PYTHON
    ENTER_GIL_WITHOUT_AFFECTING_DB

    /* For CREATE DATABASE statements, isc_dsql_execute_immediate is not
     * supposed to touch the transaction handle: */
    assert (unused_trans_handle == NULL_TRANS_HANDLE);
  }
  if (DB_API_ERROR(con->status_vector)) {
    raise_sql_exception(ProgrammingError, "pyob_create_database: ",
        con->status_vector
      );
    goto fail;
  }

  con->state = CON_STATE_OPEN;
  return (PyObject *) con;

  fail:
    assert (PyErr_Occurred());

    Py_XDECREF((PyObject *) con);

    return NULL;
} /* pyob_create_database */

static PyObject *pyob_Connection_drop_database(PyObject *self, PyObject *args) {
  CConnection *con;
  if (!PyArg_ParseTuple(args, "O!", &ConnectionType, &con) ) { goto fail; }

  CONN_REQUIRE_OPEN(con);
  /* CONN_REQUIRE_OPEN should enforce non-null db_handle, but assert anyway: */
  assert (con->db_handle != NULL_DB_HANDLE);

  /* Here, we first save the connection's db_handle, then ask Connection_close
   * to "close the connection, but don't actually detach."  This preserves the
   * uniformity of the cleanup code between the normal closure paths and
   * drop_database. */
  {
    isc_db_handle db_handle = con->db_handle;
    assert (con->state == CON_STATE_OPEN);
    assert (NOT_RUNNING_IN_CONNECTION_TIMEOUT_THREAD);
    if (Connection_close(con, TRUE, FALSE) != 0) {
      goto fail;
    }
    assert (con->state == CON_STATE_CLOSED);
    assert (con->db_handle == NULL_DB_HANDLE);
    /* We now restore the OPEN state and the db_handle to con; they'll be cleared
     * below, but only if the isc_drop_database call succeeds. */
    con->state = CON_STATE_OPEN;
    con->db_handle = db_handle;
  }

  LEAVE_GIL_WITHOUT_AFFECTING_DB
  ENTER_GDAL_WITHOUT_LEAVING_PYTHON
  ENTER_GCDL_WITHOUT_LEAVING_PYTHON

  isc_drop_database(con->status_vector, &con->db_handle);

  LEAVE_GCDL_WITHOUT_ENTERING_PYTHON
  LEAVE_GDAL_WITHOUT_ENTERING_PYTHON
  ENTER_GIL_WITHOUT_AFFECTING_DB

  if (DB_API_ERROR(con->status_vector)) {
    raise_sql_exception(OperationalError, "pyob_Connection_drop_database: ",
        con->status_vector
      );
    goto fail;
  }

  con->db_handle = NULL_DB_HANDLE;
  con->state = CON_STATE_CLOSED;

  RETURN_PY_NONE;

  fail:
    assert (PyErr_Occurred());
    return NULL;
} /* pyob_Connection_drop_database */
