/*
  +----------------------------------------------------------------------+
  | Copyright © The PHP Group and Contributors.                          |
  +----------------------------------------------------------------------+
  | This source file is subject to the Modified BSD License that is      |
  | bundled with this package in the file LICENSE, and is available      |
  | through the World Wide Web at <https://www.php.net/license/>.        |
  |                                                                      |
  | SPDX-License-Identifier: BSD-3-Clause                                |
  +----------------------------------------------------------------------+
  | Author: Edin Kadribasic <edink@emini.dk>                             |
  +----------------------------------------------------------------------+
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "ext/pdo/php_pdo.h"
#include "ext/pdo/php_pdo_error.h"
#include "ext/pdo/php_pdo_driver.h"
#include "php_pdo_pgsql.h"
#include "php_pdo_pgsql_int.h"
#include "pdo_pgsql_arginfo.h"

static zend_class_entry *PdoPgsql_ce;

/* {{{ pdo_pgsql_deps */
static const zend_module_dep pdo_pgsql_deps[] = {
	ZEND_MOD_REQUIRED("pdo")
	ZEND_MOD_END
};
/* }}} */

/* {{{ pdo_pgsql_module_entry */
zend_module_entry pdo_pgsql_module_entry = {
	STANDARD_MODULE_HEADER_EX, NULL,
	pdo_pgsql_deps,
	"pdo_pgsql",
	NULL,
	PHP_MINIT(pdo_pgsql),
	PHP_MSHUTDOWN(pdo_pgsql),
	NULL,
	NULL,
	PHP_MINFO(pdo_pgsql),
	PHP_PDO_PGSQL_VERSION,
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_PDO_PGSQL
ZEND_GET_MODULE(pdo_pgsql)
#endif

/* Escape an identifier for insertion into a text field	*/
PHP_METHOD(Pdo_Pgsql, escapeIdentifier)
{
	zend_string *from = NULL;
	char *tmp;
	pdo_dbh_t *dbh;
	pdo_pgsql_db_handle *H;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &from) == FAILURE) {
		RETURN_THROWS();
	}

	dbh = Z_PDO_DBH_P(ZEND_THIS);
	PDO_CONSTRUCT_CHECK;
	PDO_DBH_CLEAR_ERR();

	/* Obtain db Handle */
	H = (pdo_pgsql_db_handle *)dbh->driver_data;
	if (H->server == NULL) {
		zend_throw_error(NULL, "PostgreSQL connection has already been closed");
		RETURN_THROWS();
	}

	tmp = PQescapeIdentifier(H->server, ZSTR_VAL(from), ZSTR_LEN(from));
	if (!tmp) {
		pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL);
		PDO_HANDLE_DBH_ERR();
		RETURN_THROWS();
	}

	RETVAL_STRING(tmp);
	PQfreemem(tmp);
}

/* Returns true if the copy worked fine or false if error */
PHP_METHOD(Pdo_Pgsql, copyFromArray)
{
	pgsqlCopyFromArray_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Returns true if the copy worked fine or false if error */
PHP_METHOD(Pdo_Pgsql, copyFromFile)
{
	pgsqlCopyFromFile_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Returns true if the copy worked fine or false if error */
PHP_METHOD(Pdo_Pgsql, copyToFile)
{
	pgsqlCopyToFile_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Returns true if the copy worked fine or false if error */
PHP_METHOD(Pdo_Pgsql, copyToArray)
{
	pgsqlCopyToArray_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Creates a new large object, returning its identifier.  Must be called inside a transaction. */
PHP_METHOD(Pdo_Pgsql, lobCreate)
{
	pgsqlLOBCreate_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Opens an existing large object stream.  Must be called inside a transaction. */
PHP_METHOD(Pdo_Pgsql, lobOpen)
{
	pgsqlLOBOpen_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Deletes the large object identified by oid.  Must be called inside a transaction. */
PHP_METHOD(Pdo_Pgsql, lobUnlink)
{
	pgsqlLOBUnlink_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Get asynchronous notification */
PHP_METHOD(Pdo_Pgsql, getNotify)
{
	pgsqlGetNotify_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Get backend(server) pid */
PHP_METHOD(Pdo_Pgsql, getPid)
{
	pgsqlGetPid_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

/* Sets a callback to receive DB notices (after client_min_messages has been set */
PHP_METHOD(Pdo_Pgsql, setNoticeCallback)
{
	zend_fcall_info fci = empty_fcall_info;
	zend_fcall_info_cache fcc = empty_fcall_info_cache;
	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "F!", &fci, &fcc)) {
		RETURN_THROWS();
	}

	pdo_dbh_t *dbh = Z_PDO_DBH_P(ZEND_THIS);
	PDO_CONSTRUCT_CHECK_WITH_CLEANUP(cleanup);

	pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;

	pdo_pgsql_cleanup_notice_callback(H);

	if (ZEND_FCC_INITIALIZED(fcc)) {
		H->notice_callback = emalloc(sizeof(zend_fcall_info_cache));
		zend_fcc_dup(H->notice_callback, &fcc);
	}

	return;

cleanup:
	zend_release_fcall_info_cache(&fcc);
	RETURN_THROWS();
}

/* true global environment */

#define REGISTER_PDO_PGSQL_CLASS_CONST_LONG_DEPRECATED_ALIAS_85(base_name, value) \
		REGISTER_PDO_CLASS_CONST_LONG_DEPRECATED_ALIAS_85(base_name, "PGSQL_", "Pdo\\Pgsql::", value)

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_pgsql)
{
	REGISTER_PDO_PGSQL_CLASS_CONST_LONG_DEPRECATED_ALIAS_85("ATTR_DISABLE_PREPARES", PDO_PGSQL_ATTR_DISABLE_PREPARES);
	REGISTER_PDO_CLASS_CONST_LONG_DEPRECATED_85("PGSQL_TRANSACTION_IDLE", (zend_long)PGSQL_TRANSACTION_IDLE);
	REGISTER_PDO_CLASS_CONST_LONG_DEPRECATED_85("PGSQL_TRANSACTION_ACTIVE", (zend_long)PGSQL_TRANSACTION_ACTIVE);
	REGISTER_PDO_CLASS_CONST_LONG_DEPRECATED_85("PGSQL_TRANSACTION_INTRANS", (zend_long)PGSQL_TRANSACTION_INTRANS);
	REGISTER_PDO_CLASS_CONST_LONG_DEPRECATED_85("PGSQL_TRANSACTION_INERROR", (zend_long)PGSQL_TRANSACTION_INERROR);
	REGISTER_PDO_CLASS_CONST_LONG_DEPRECATED_85("PGSQL_TRANSACTION_UNKNOWN", (zend_long)PGSQL_TRANSACTION_UNKNOWN);

	PdoPgsql_ce = register_class_Pdo_Pgsql(pdo_dbh_ce);
	PdoPgsql_ce->create_object = pdo_dbh_new;

	if (php_pdo_register_driver(&pdo_pgsql_driver) == FAILURE) {
		return FAILURE;
	}

	return php_pdo_register_driver_specific_ce(&pdo_pgsql_driver, PdoPgsql_ce);
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(pdo_pgsql)
{
	php_pdo_unregister_driver(&pdo_pgsql_driver);
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(pdo_pgsql)
{
	char buf[16];

	php_info_print_table_start();
	php_info_print_table_row(2, "PDO Driver for PostgreSQL", "enabled");
	pdo_libpq_version(buf, sizeof(buf));
	php_info_print_table_row(2, "PostgreSQL(libpq) Version", buf);
	php_info_print_table_end();
}
/* }}} */
