/* -*- mode: c++; indent-tabs-mode: nil -*- */
/*
    ql_dbi.qpp

    Qore Programming Language

    Copyright (C) 2003 - 2023 Qore Technologies, s.r.o.

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.

    Note that the Qore library is released under a choice of three open-source
    licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
    information.
*/

#include <qore/Qore.h>
#include "qore/intern/qore_dbi_private.h"

/** @defgroup old_dbi_functions Old DBI Functions
    Old DBI functions; see @ref dbi_functions
 */
///@{
namespace Qore::SQL;

//! Returns a @ref datasource_hash "datasource hash" of the components of a datasource string
/**
    @param ds a string describing the datasource with the following syntax:\n
    <tt>[</tt><em>driver</em><tt>:][</tt><em>user</em><tt>/</tt><em>pass</em><tt>]\@</tt><em>db</em><tt>[(</tt><em>charset</em><tt>)][%</tt><em>host</em><tt>[:</tt><em>port</em><tt>][{</tt><em>option</em><tt>=</tt><em>val</em><tt>[,...]}]</tt> \n
    where all elements except <tt>\@</tt><em>db</em> are optional

    @return a @ref datasource_hash "datasource hash" of the components of a datasource string

    @throw DATASOURCE-PARSE-ERROR a syntax error occurred parsing the datasource string (missing field, unexpected character, etc)

    @deprecated use parse_datasource() instead; camel-case function names were deprecated in %Qore 0.8.12
 */
hash parseDatasource(string ds) [flags=RET_VALUE_ONLY,DEPRECATED] {
    return parseDatasource(ds->c_str(), xsink);
}

//! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments
/**
 */
nothing parseDatasource() [flags=NOOP,DEPRECATED] {
}

//! Returns a list of strings of DBI drivers currently loaded or @ref nothing if no drivers are loaded
/**
    @return a list of strings of DBI drivers currently loaded or @ref nothing if no drivers are loaded

    @deprecated use dbi_get_driver_list() instead; camel-case function names were deprecated in %Qore 0.8.12
 */
*list<string> getDBIDriverList() [flags=CONSTANT,DEPRECATED] {
    return DBI.getDriverList();
}

//! Returns a list of each capability supported by the given DBI driver (see @ref dbi_capabilities) or @ref nothing if the driver cannot be found
/**
    @param driver the name of the driver; if the given driver is not loaded then the function returns @ref nothing

    @return a list of each capability supported by the given DBI driver (see @ref dbi_capabilities) or @ref nothing if the driver cannot be found

    @deprecated use dbi_get_driver_capability_list() instead; camel-case function names were deprecated in %Qore 0.8.12
 */
*list<string> getDBIDriverCapabilityList(string driver) [flags=CONSTANT,DEPRECATED] {
    DBIDriver *dd = DBI.find(driver->getBuffer());
    return !dd ? QoreValue() : QoreValue(qore_dbi_private::get(*dd)->getCapList());
}

//! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments
/**
 */
nothing getDBIDriverCapabilityList() [flags=NOOP,DEPRECATED] {
}

//! Returns an integer representing the capabilities of a DBI driver binary-OR'ed together (see @ref dbi_capabilities) or @ref nothing if the driver is not already loaded
/**
    @param driver the name of the driver; if the given driver is not already loaded then this function returns @ref nothing

    @return an integer representing the capabilities of a DBI driver binary-OR'ed together (see @ref dbi_capabilities) or @ref nothing if the driver is not already loaded

    @deprecated use dbi_get_driver_capabilities() instead; camel-case function names were deprecated in %Qore 0.8.12
 */
*int getDBIDriverCapabilities(string driver) [flags=CONSTANT,DEPRECATED] {
    DBIDriver* dd = DBI.find(driver->getBuffer());
    return !dd ? QoreValue() : QoreValue(qore_dbi_private::get(*dd)->getCaps());
}

//! This function variant does nothing at all; it is only included for backwards-compatibility with qore prior to version 0.8.0 for functions that would ignore type errors in arguments
/**
*/
nothing getDBIDriverCapabilities() [flags=NOOP,DEPRECATED] {
}
///@}

/** @defgroup dbi_functions DBI Functions
    These DBI functions were added in %Qore 0.8.6; the original functions used camel case names and had @ref NOOP variants (see @ref old_dbi_functions)

    @section datasource_hash Datasource Hash
    |!Key|!Description
    |\c type|the name of the driver, if present
    |\c user|the username given in the string
    |\c pass|the password for the connection
    |\c db|the database name for the connection
    |\c charset|The name of the DB-specific character encoding to use for the connection, if present in the string
    |\c host|the hostname for the connection, if present in the string
    |\c port|the port number to use for the connection, if present in the string
    |\c options|A hash of options given in the string, if present. Special options are \c "min" and \c "max", which \
        are respected by the @ref Qore::SQL::DatasourcePool::constructor(hash) "DatasourcePool::constructor(hash)" \
        variant for setting the minimum and maximum connections in the pool, respectively; other options are passed \
        to the DBI driver
*/
///@{
namespace Qore::SQL;

//! Returns a @ref datasource_hash "datasource hash" of the components of a datasource string
/**
    @param ds a string describing the datasource with the following syntax:\n
    <tt>[</tt><em>driver</em><tt>:][</tt><em>user</em><tt>/</tt><em>pass</em><tt>]\@</tt><em>db</em><tt>[(</tt><em>charset</em><tt>)][%</tt><em>host</em><tt>[:</tt><em>port</em><tt>][{</tt><em>option</em><tt>=</tt><em>val</em><tt>[,...]}]</tt> \n
    where all elements except <tt>\@</tt><em>db</em> are optional

    @return a @ref datasource_hash "datasource hash" of the components of a datasource string

    @par Example:
    @code{.py}
hash<auto> h = parse_datasource("pgsql:user/pass@dbname(utf8)%dbhost.internal:1521{min=4,max=10}");
    @endcode

    @throw DATASOURCE-PARSE-ERROR a syntax error occurred parsing the datasource string (missing field, unexpected
    character, etc)

    @note similar to parseDatasource() except uses the standard function naming scheme (i.e. \c "names_like_this()"
    instead of \c "camelCase()") and does not have a @ref NOOP variant

    @since %Qore 0.8.6
*/
hash<auto> parse_datasource(string ds) [flags=RET_VALUE_ONLY] {
    return parseDatasource(ds->getBuffer(), xsink);
}

//! Returns a list of strings of DBI drivers currently loaded or @ref nothing if no drivers are loaded
/**
    @return a list of strings of DBI drivers currently loaded or @ref nothing if no drivers are loaded

    @par Example:
    @code{.py}
*list<string> l = dbi_get_driver_list();
    @endcode

    @note similar to getDBIDriverList() except uses the standard function naming scheme (i.e. \c "names_like_this()"
    instead of \c "camelCase()")

    @since %Qore 0.8.6
*/
*list<string> dbi_get_driver_list() [flags=CONSTANT] {
    return DBI.getDriverList();
}

//! Returns a list of each capability supported by the given DBI driver (see @ref dbi_capabilities) or @ref nothing if the driver cannot be found
/**
    @param driver the name of the driver; if the given driver is not loaded then the function returns @ref nothing

    @return a list of each capability supported by the given DBI driver (see @ref dbi_capabilities) or @ref nothing if
    the driver cannot be found

    @par Example:
    @code{.py}
*list<string> l = dbi_get_driver_capability_list("pgsql");
    @endcode

    @note similar to getDBIDriverCapabilityList() except uses the standard function naming scheme (i.e.
    \c "names_like_this()" instead of \c "camelCase()") and does not have a @ref NOOP variant

    @since %Qore 0.8.6
*/
*list<string> dbi_get_driver_capability_list(string driver) [flags=CONSTANT] {
    DBIDriver *dd = DBI.find(driver->getBuffer());
    return !dd ? 0 : qore_dbi_private::get(*dd)->getCapList();
}

//! Returns an integer representing the capabilities of a DBI driver binary-OR'ed together (see @ref dbi_capabilities) or 0 if the driver is not already loaded
/** @param driver the name of the driver; if the given driver is not already loaded then this function returns
    @ref nothing

    @return an integer representing the capabilities of a DBI driver binary-OR'ed together (see @ref dbi_capabilities)
    or 0 if the driver is not already loaded

    @par Example:
    @code{.py}
int caps = dbi_get_driver_capabilities("pgsql");
    @endcode

    @note similar to getDBIDriverCapabilities() except uses the standard function naming scheme (i.e.
    \c "names_like_this()" instead of \c "camelCase()"), always returns an @ref int_type, and does not have a
    @ref NOOP variant

    @since %Qore 0.8.6
*/
int dbi_get_driver_capabilities(string driver) [flags=CONSTANT] {
    DBIDriver* dd = DBI.find(driver->getBuffer());
    return !dd ? 0 : qore_dbi_private::get(*dd)->getCaps();
}

//! returns a hash of driver options
/**
    @param driver the name of the driver; if the given driver is not already loaded then this function returns
    @ref nothing

    @return if the given driver is not already loaded then the function returns @ref nothing; if the driver does not
    support any options then an empty hash is returned, otherwise a hash is returned where the keys are valid option
    names, and the values are hashes with the following keys:
    - \c "desc": a string description of the option
    - \c "type": a string giving the data type restriction for the option

    @par Example:
    @code{.py}
*hash<auto> h = dbi_get_driver_options("pgsql");
    @endcode

    @since %Qore 0.8.6
*/
*hash<auto> dbi_get_driver_options(string driver) [flags=CONSTANT] {
    DBIDriver* dd = DBI.find(driver->getBuffer());
    return !dd ? 0 : qore_dbi_private::get(*dd)->getOptionHash();
}
///@}

/** @defgroup sql_constants SQL Constants
    SQL constants
*/
///@{
namespace Qore::SQL;

//! for binding string values
const VARCHAR = "string";

//! for binding number values as a number
/** @since %Qore 0.8.6 the value of this constant is \c "number" instead of \c "string"
*/
const NUMBER = "number";

//! for binding numeric values as a number
/** @since %Qore 0.8.6 the value of this constant is \c "number" instead of \c "string"
*/
const NUMERIC = "number";

//! for binding decimal values as a number
/** @since %Qore 0.8.6 the value of this constant is \c "number" instead of \c "string"
*/
const DECIMAL = "number";

//! for binding CLOB values
const CLOB = "clob";

//! for binding BLOB values
const BLOB = "blob";

//! for binding date/time values
const DATE = "date";

//! For binding @ref resultset_output_binding "result set" placeholders
/** For @ref Qore::SQL::SQLStatement "SQLStatement" output values in supported DBI drivers

    @since %Qore 0.8.13
*/
const RESULTSET = "resultset";
///@}

