<?php

namespace Doctrine\DBAL;

use Closure;
use Doctrine\DBAL\Cache\CacheException;
use Doctrine\DBAL\Cache\QueryCacheProfile;
use Doctrine\DBAL\Types\Type;
use Throwable;

class Connection
{
    /**
     * Prepares an SQL statement.
     *
     * @param __doctrine-literal-string $sql The SQL statement to prepare.
     *
     * @throws Exception
     */
    public function prepare(string $sql): Statement;

    /**
     * Executes an SQL statement with the given parameters and returns the number of affected rows.
     *
     * Could be used for:
     *  - DML statements: INSERT, UPDATE, DELETE, etc.
     *  - DDL statements: CREATE, DROP, ALTER, etc.
     *  - DCL statements: GRANT, REVOKE, etc.
     *  - Session control statements: ALTER SESSION, SET, DECLARE, etc.
     *  - Other statements that don't yield a row set.
     *
     * This method supports PDO binding types as well as DBAL mapping types.
     *
     * @param __doctrine-literal-string                                                       $sql    SQL statement
     * @param list<mixed>|array<string, mixed>                                     $params Statement parameters
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types  Parameter types
     *
     * @return int|string The number of affected rows.
     *
     * @throws Exception
     */
    public function executeStatement($sql, array $params = [], array $types = []);

    /**
     * Executes an, optionally parameterized, SQL query.
     *
     * If the query is parametrized, a prepared statement is used.
     * If an SQLLogger is configured, the execution is logged.
     *
     * @param __doctrine-literal-string                                                       $sql    SQL query
     * @param list<mixed>|array<string, mixed>                                     $params Query parameters
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types  Parameter types
     *
     * @throws Exception
     */
    public function executeQuery(
        string $sql,
        array $params = [],
        $types = [],
        ?QueryCacheProfile $qcp = null
    ): Result;

    /**
     * Executes a caching query.
     *
     * @param __doctrine-literal-string                                                       $sql    SQL query
     * @param list<mixed>|array<string, mixed>                                     $params Query parameters
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types  Parameter types
     *
     * @throws CacheException
     * @throws Exception
     */
    public function executeCacheQuery($sql, $params, $types, QueryCacheProfile $qcp): Result;

    /**
     * @param-immediately-invoked-callable $func
     * @param Closure(self): T $func
     * @return T
     *
     * @template T
     *
     * @throws Throwable
     */
    public function transactional(Closure $func);

    /**
     * Executes an SQL DELETE statement on a table.
     *
     * Table expression and columns are not escaped and are not safe for user-input.
     *
     * @param __doctrine-literal-string                                                               $table    Table name
     * @param array<__doctrine-literal-string, mixed>                                                 $criteria Deletion criteria
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types    Parameter types
     *
     * @return int|string The number of affected rows.
     *
     * @throws Exception
     */
    public function delete($table, array $criteria, array $types = []);

    /**
     * Executes an SQL UPDATE statement on a table.
     *
     * Table expression and columns are not escaped and are not safe for user-input.
     *
     * @param __doctrine-literal-string                                                               $table    Table name
     * @param array<__doctrine-literal-string, mixed>                                                 $data     Column-value pairs
     * @param array<__doctrine-literal-string, mixed>                                                 $criteria Update criteria
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types    Parameter types
     *
     * @return int|string The number of affected rows.
     *
     * @throws Exception
     */
    public function update($table, array $data, array $criteria, array $types = []);

    /**
     * Inserts a table row with specified data.
     *
     * Table expression and columns are not escaped and are not safe for user-input.
     *
     * @param __doctrine-literal-string                                                               $table Table name
     * @param array<__doctrine-literal-string, mixed>                                                 $data  Column-value pairs
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types Parameter types
     *
     * @return int|string The number of affected rows.
     *
     * @throws Exception
     */
    public function insert($table, array $data, array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return array<string, mixed>|false
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchAssociative(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return list<mixed>|false
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchNumeric(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return mixed
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchOne(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return list<list<mixed>>
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchAllNumeric(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return list<array<string,mixed>>
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchAllAssociative(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return array<mixed,mixed>
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchAllKeyValue(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return array<mixed,array<string,mixed>>
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchAllAssociativeIndexed(string $query, array $params = [], array $types = []);

    /**
     * @param list<mixed>|array<string, mixed> $params
     * @param array<int, int|string|Type|null>|array<string, int|string|Type|null> $types
     *
     * @return list<mixed>
     *
     * @throws Exception
     *
     * @phpstan-impure
     */
    public function fetchFirstColumn(string $query, array $params = [], array $types = []);

}
