// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-FileCopyrightText: Copyright 2008 Sandia Corporation
// SPDX-License-Identifier: LicenseRef-BSD-3-Clause-Sandia-USGov

/**
 * @class   vtkODBCDatabase
 * @brief   maintain an ODBC connection to a SQL database
 *
 *
 *
 * ODBC is a standard for connecting to an SQL database regardless of
 * vendor or implementation.  In order to make it work you need two
 * separate pices of software: a driver manager and then a
 * database-specific driver.  On Windows, the driver manager is built
 * into the OS.  On Unix platforms, the open-source packages iODBC and
 * unixODBC will do the job.  Mac OS X has its own driver manager and
 * can also use the open-source packages.  Database-specific drivers
 * must be obtained from the entity that makes the database(s) you
 * use.
 *
 * Unlike the other VTK database drivers, ODBC can read its parameters
 * from a configuration file (odbc.ini).  That file can define an
 * entire set of connection parameters and give it a single name
 * called a data source name (DSN).  Writing and maintaining odbc.ini
 * files is beyond the scope of this header file.
 *
 *
 * @warning
 * The password supplied as an argument to the Open call will override
 * whatever password is set (if any) in the DSN definition.  To use
 * the password from the DSN definition, pass in nullptr for
 * the password argument.
 *
 * @warning
 * Also, vtkSQLDatabase::CreateFromURL() will only handle URLs of the
 * following form for ODBC:
 *
 * @warning
 * odbc://[user@]datsourcename[:port]/[dbname]
 *
 * @warning
 * Anything more complicated than that needs to be set up manually.
 *
 * @warning
 * Finally, this class does not yet support the schema API present in
 * the SQLite, MySQL and PostgreSQL drivers.  Those functions will be
 * added once the bare-bones driver has been successfully integrated
 * into VTK.
 *
 * @sa
 * vtkODBCQuery
 */

#ifndef vtkODBCDatabase_h
#define vtkODBCDatabase_h

#include "vtkIOODBCModule.h" // For export macro
#include "vtkSQLDatabase.h"

VTK_ABI_NAMESPACE_BEGIN
class vtkSQLQuery;
class vtkODBCQuery;
class vtkStringArray;
class vtkODBCInternals;

class VTKIOODBC_EXPORT vtkODBCDatabase : public vtkSQLDatabase
{

  friend class vtkODBCQuery;

public:
  vtkTypeMacro(vtkODBCDatabase, vtkSQLDatabase);
  void PrintSelf(ostream& os, vtkIndent indent) override;
  static vtkODBCDatabase* New();

  /**
   * Open a new connection to the database.  You need to set the
   * filename before calling this function.  Returns true if the
   * database was opened successfully; false otherwise.
   */
  bool Open(const char* password) override;

  /**
   * Close the connection to the database.
   */
  void Close() override;

  /**
   * Return whether the database has an open connection
   */
  bool IsOpen() override;

  /**
   * Return an empty query on this database.
   */
  vtkSQLQuery* GetQueryInstance() override;

  /**
   * Get the last error text from the database
   */
  const char* GetLastErrorText() override;

  /**
   * Get the list of tables from the database
   */
  vtkStringArray* GetTables() override;

  /**
   * Get the list of fields for a particular table
   */
  vtkStringArray* GetRecord(const char* table) override;

  /**
   * Return whether a feature is supported by the database.
   */
  bool IsSupported(int feature) override;

  ///@{
  /**
   * Set the data source name.  For ODBC connections this will be
   * something listed in odbc.ini.  The location of that file varies wildly
   * based on system, ODBC library, and installation.  Good luck.
   */
  vtkSetStringMacro(DataSourceName);
  vtkGetStringMacro(DataSourceName);
  ///@}

  vtkSetMacro(ServerPort, int);
  vtkSetStringMacro(HostName);
  vtkSetStringMacro(UserName);
  vtkSetStringMacro(DatabaseName);
  vtkGetStringMacro(DatabaseName);
  vtkSetStringMacro(Password);

  bool HasError() override;

  ///@{
  /**
   * String representing database type (e.g. "ODBC").
   */
  const char* GetDatabaseType() override { return this->DatabaseType; }
  ///@}

  vtkStdString GetURL() override;

  /**
   * Return the SQL string with the syntax to create a column inside a
   * "CREATE TABLE" SQL statement.
   * NB2: if a column has type SERIAL in the schema, this will be turned
   * into INT NOT nullptr. Therefore, one should not pass
   * NOT nullptr as an attribute of a column whose type is SERIAL.
   */
  vtkStdString GetColumnSpecification(
    vtkSQLDatabaseSchema* schema, int tblHandle, int colHandle) override;

  /**
   * Return the SQL string with the syntax to create an index inside a
   * "CREATE TABLE" SQL statement.
   */
  vtkStdString GetIndexSpecification(
    vtkSQLDatabaseSchema* schema, int tblHandle, int idxHandle, bool& skipped) override;

  /**
   * Create a new database, optionally dropping any existing database of the same name.
   * Returns true when the database is properly created and false on failure.
   */
  bool CreateDatabase(const char* dbName, bool dropExisting);

  /**
   * Drop a database if it exists.
   * Returns true on success and false on failure.
   */
  bool DropDatabase(const char* dbName);

  /**
   * This will only handle URLs of the form
   * odbc://[user@]datsourcename[:port]/[dbname].  Anything
   * more complicated than that needs to be set up manually.
   */
  bool ParseURL(const char* url) override;

protected:
  vtkODBCDatabase();
  ~vtkODBCDatabase() override;

  vtkSetStringMacro(LastErrorText);

private:
  vtkStringArray* Tables;
  vtkStringArray* Record;

  char* LastErrorText;

  char* HostName;
  char* UserName;
  char* Password;
  char* DataSourceName;
  char* DatabaseName;
  int ServerPort;

  vtkODBCInternals* Internals;

  // We want this to be private, a user of this class
  // should not be setting this for any reason
  vtkSetStringMacro(DatabaseType);

  char* DatabaseType;

  vtkODBCDatabase(const vtkODBCDatabase&) = delete;
  void operator=(const vtkODBCDatabase&) = delete;
};

VTK_ABI_NAMESPACE_END
#endif // vtkODBCDatabase_h
