Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 7 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

Add the following in the require section of your **composer.json**:

### Laravel >=7.x
### Laravel 11 >=
```json
"uepg/laravel-sybase": "~4.0"
"uepg/laravel-sybase": "~5.0"
```

Update the package dependencies executing:
Expand Down Expand Up @@ -47,12 +47,6 @@ Update your **config/database.php's** default driver with the settings for the *
return [
...

'sybase' =>
[
'application_encoding' => false,
'application_charset' => '',
'database_charset' => ''
],

'connections' => [
...
Expand All @@ -67,7 +61,9 @@ return [
'charset' => 'utf8',
'prefix' => '',
'cache_tables' => true,
'cache_time' => 3600
'cache_time' => 3600,
'application_encoding' => false,
'application_charset' => '',
],

...
Expand Down Expand Up @@ -107,18 +103,13 @@ The file is usualy found in **/etc/freetds/freetds.conf**. Set the configuration
## Configuring the charset conversion
This package offers to method to charset conversion, it can be converted in application layer or in database layer, we offered both methods because it can be useful for debugging, to config the application layer conversion you need to set up the following entries on the `database.php` file. You can view an example of the application encoding setup below:

```database
'sybase' =>
[
'application_encoding' => true,
'application_charset' => '',
'database_charset' => ''
],
```
To use the database layer conversion add the property charset to connection configuration on the sybase configuration array

```charset
'charset' => 'utf8',
'application_encoding' => false,
'application_charset' => '',
```


Expand Down
159 changes: 116 additions & 43 deletions src/Database/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,72 @@ class Connection extends IlluminateConnection
*
* @var array
*/
private array $numeric = [
'int', 'numeric', 'bigint', 'integer', 'smallint', 'tinyint', 'decimal', 'double', 'float', 'real', 'bit',
'binary', 'varbinary', 'timestamp', 'money',
private $numeric = [
'int',
'numeric',
'bigint',
'integer',
'smallint',
'tinyint',
'decimal',
'double',
'float',
'real',
'bit',
'binary',
'varbinary',
'timestamp',
'money',
];


/**
* @var string The application charset
*/
private $applicationCharset;

/**
* @var string The database charset
*/
private $databaseCharset;

private $applicationEncoding = false;

/**
* Create a new database connection instance.
*
* @param \PDO|\Closure $pdo
* @param string $database
* @param string $tablePrefix
* @param array $config
* @return void
*/
public function __construct($pdo, $database = '', $tablePrefix = '', array $config = [])
{
parent::__construct($pdo, $database, $tablePrefix, $config);
$this->configureExtraSettings($config);
}

/**
* Configures the encoding for the connection.
*
* @param array $config
* @return void
*/
public function configureExtraSettings($config = [])
{
$this->applicationEncoding = key_exists('application_encoding',$config) ? $config['application_encoding'] : false;
if ($this->applicationEncoding)
{
if (!key_exists('application_charset',$config,) || !key_exists('database_charset',$config))
{
throw new \Exception('When application encoding is configured, you need to set up application_charset and database_charset');
}
$this->applicationCharset = $config['application_charset'];
$this->databaseCharset = $config['charset'];
}
}

/**
* Execute a Closure within a transaction.
*
Expand All @@ -54,10 +115,10 @@ public function transaction(Closure $callback, $attempts = 1)
$this->pdo->exec('COMMIT TRAN');
}

// If we catch an exception, we will roll back so nothing gets messed
// up in the database. Then we'll re-throw the exception so it can
// be handled how the developer sees fit for their applications.
catch (Exception $e) {
// If we catch an exception, we will roll back so nothing gets messed
// up in the database. Then we'll re-throw the exception so it can
// be handled how the developer sees fit for their applications.
catch (\Exception|\PDOException $e) {
$this->pdo->exec('ROLLBACK TRAN');

throw $e;
Expand All @@ -69,9 +130,9 @@ public function transaction(Closure $callback, $attempts = 1)
/**
* Run a select statement against the database.
*
* @param string $query
* @param array $bindings
* @param bool $useReadPdo
* @param string $query
* @param array $bindings
* @param bool $useReadPdo
* @return array
*/
public function select($query, $bindings = [], $useReadPdo = true)
Expand All @@ -84,8 +145,10 @@ public function select($query, $bindings = [], $useReadPdo = true)
return [];
}

$statement = $this->getPdo()
->prepare($this->compileNewQuery($query, $bindings));
$statement = $this->getPdo()->prepare($this->compileNewQuery(
$query,
$bindings
));

$statement->execute();

Expand All @@ -95,31 +158,31 @@ public function select($query, $bindings = [], $useReadPdo = true)
do {
$result += $statement->fetchAll($this->getFetchMode());
} while ($statement->nextRowset());
} catch (Exception $e) {
} catch (\Exception $e) {
}

$result = [...$result];

$application_encoding = config('database.sybase.application_encoding');
if (!$application_encoding) {
if (is_null($application_encoding) || $application_encoding == false) {
return $result;
}
$database_charset = config('database.sybase.database_charset');
$application_charset = config('database.sybase.application_charset');
if (is_null($database_charset) || is_null($application_charset)) {
throw new Exception('[SYBASE] Database Charset and App Charset not set');
throw new \Exception('[SYBASE] Database Charset and App Charset not set');
}
foreach ($result as &$r) {
foreach ($r as $k => &$v) {
$v = gettype($v) === 'string' ? mb_convert_encoding($v, $application_charset,
$database_charset) : $v;
$v = gettype($v) === 'string' ? mb_convert_encoding($v, $application_charset, $database_charset) : $v;
}
}

return $result;
});
}


/**
* Set new bindings with specified column types to Sybase.
*
Expand All @@ -129,42 +192,47 @@ public function select($query, $bindings = [], $useReadPdo = true)
*
* @link http://stackoverflow.com/questions/2718628/pdoparam-for-type-decimal
*
* @param string $query
* @param array $bindings
* @param string $query
* @param array $bindings
* @return string $query
* @throws Exception
*/
private function compileNewQuery(string $query, array $bindings)
private function compileNewQuery($query, $bindings)
{
$newQuery = '';

$bindings = $this->compileBindings($query, $bindings);
$partQuery = explode('?', $query);

$bindings = array_map(fn($v) => gettype($v) === 'string' ? str_replace('\'', '\'\'', $v) : $v, $bindings);
$bindings = array_map(fn($v) => gettype($v) === 'string' ? "'{$v}'" : $v, $bindings);
$bindings = array_map(fn($v) => gettype($v) === 'NULL' ? 'NULL' : $v, $bindings);

$newQuery = join(array_map(fn($k1, $k2) => $k1.$k2, $partQuery, $bindings));
$newQuery = join(array_map(fn($k1, $k2) => $k1 . $k2, $partQuery, $bindings));
$newQuery = str_replace('[]', '', $newQuery);
$application_encoding = config('database.sybase.application_encoding');
if (!$application_encoding) {

if (is_null($application_encoding) || $application_encoding == false) {
return $newQuery;
}
$database_charset = config('database.sybase.database_charset');
$application_charset = config('database.sybase.application_charset');
if (is_null($database_charset) || is_null($application_charset)) {
throw new Exception('[SYBASE] Database Charset and App Charset not set');
throw new \Exception('[SYBASE] Database Charset and App Charset not set');
}
return mb_convert_encoding($newQuery, $database_charset, $application_charset);
$newQuery = mb_convert_encoding($newQuery, $database_charset, $application_charset);

return $newQuery;
}


/**
* Set new bindings with specified column types to Sybase.
*
* @param string $query
* @param array $bindings
* @return array $newBinds
* @param string $query
* @param array $bindings
* @return mixed $newBinds
*/
private function compileBindings(string $query, array $bindings)
private function compileBindings($query, $bindings)
{
if (count($bindings) == 0) {
return [];
Expand All @@ -180,6 +248,7 @@ private function compileBindings(string $query, array $bindings)
}
}


/**
* Compile the bindings for select/insert/update/delete.
*
Expand Down Expand Up @@ -210,7 +279,7 @@ private function compile(Builder $builder)
}
}

$cache = $builder->connection->config['cache_tables'];
$cache = key_exists('cache_tables',$builder->connection->config) ? $builder->connection->config['cache_tables'] : false;
$types = [];

foreach ($arrTables as $tables) {
Expand Down Expand Up @@ -305,7 +374,6 @@ private function compile(Builder $builder)
}
}
}

return $keys;
}

Expand Down Expand Up @@ -347,11 +415,7 @@ private function queryString(string $tables)
}
}

/**
* Get the default fetch mode for the connection.
*
* @return int
*/

public function getFetchMode()
{
return $this->fetchMode;
Expand Down Expand Up @@ -451,28 +515,37 @@ protected function getDefaultPostProcessor()
*
* @param string $query
* @param array $bindings
* @param Closure $callback
* @param \Closure $callback
* @return mixed
*
* @throws QueryException
* @throws \Illuminate\Database\QueryException
*/
protected function runQueryCallback($query, $bindings, Closure $callback)
{
try {
$result = $callback($query, $bindings);

if ($result instanceof PDOStatement) {
if ($result instanceof \PDOStatement) {
$errorInfo = $result->errorInfo();
if (isset($errorInfo[0]) && $errorInfo[0] !== '00000') {
$finalErrorMessage = sprintf('SQLSTATE[%s] [%d] %s', $errorInfo[0], (int) $errorInfo[1],
trim(preg_replace(['/^\[\d+]\s\(severity\s\d+\)\s/', '/\s+/'], ['', ' '], $errorInfo[2])));
throw new PDOException($finalErrorMessage, (int) $errorInfo[1]);
$finalErrorMessage = sprintf(
'SQLSTATE[%s] [%d] %s',
$errorInfo[0],
(int)$errorInfo[1],
trim(preg_replace(['/^\[\d+\]\s\(severity\s\d+\)\s/', '/\s+/'], ['', ' '], $errorInfo[2]))
);
throw new \PDOException($finalErrorMessage, (int)$errorInfo[1]);
}
}
return $result;

} catch (Throwable $e) {
throw new QueryException($this->getName(), $query, $this->prepareBindings($bindings), $e);
throw new QueryException(
$this->getName(),
$query,
$this->prepareBindings($bindings),
$e
);
}
}
}
Loading