Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Allowing columns with spaces, dash and numbers #208

Open
@wellingguzman

Description

@wellingguzman

Hello, we have been using Zend-Db as the database abstraction layer for our Directus framework and there has been a significant bug where columns with dashes (e-mail), spaces first name and starting with numbers (3dImage) creates a malformed query.

All issues described here are experienced on MySQL using PDO.

This is related to #8 which is SqlServer.

Examples of Select:

SELECT `users`.`id` AS `id`, `users`.`3dImage` AS `3dImage`, `users`.`e``-``mail` AS `e-mail`, `users`.`first` `name` AS `first name`
FROM `users`

This was hot-fixed by changing:

return $isIdentifier
                ? $fromTable . $platform->quoteIdentifierInFragment($column)
                : $platform->quoteValue($column);

to this:

$startsWithNumber = preg_match('/^[0-9]+/', $column);
$hasSpaceOrDash = preg_match('/^(.+)(\s|-)+(.+)$/i', $column);
if ($isIdentifier) {
    if ($startsWithNumber || $hasSpaceOrDash) {
        $column = $platform->quoteIdentifier($column);
    } else {
        $column = $platform->quoteIdentifierInFragment($column);
    }
}

return $isIdentifier
                ? $fromTable . $column
                : $platform->quoteValue($column);

When inserting or updating with a column starting with number you get: A non well formed numeric value encountered error at line 293 in /src/Adapter/Driver/Pdo/Statement.php

This will try to use a parameter named :3dImage which results in: A non well formed numeric value encountered.

Both dash and space have the same error: Statement could not be executed (HY093 - - ).

I hot-fixed this by changing src/Sql/Insert.php#L161-L176 from:

$columns = [];
$values  = [];
foreach ($this->columns as $column=>$value) {
    $columns[] = $platform->quoteIdentifier($column);
    if (is_scalar($value) && $parameterContainer) {
        $values[] = $driver->formatParameterName($column);
        $parameterContainer->offsetSet($column, $value);
    } else {
        $values[] = $this->resolveColumnValue(
            $value,
            $platform,
            $driver,
            $parameterContainer
        );
    }
}

To this:

$columns = [];
$values  = [];
$cIndex = 0;
foreach ($this->columns as $column => $value) {
    $columns[] = $platform->quoteIdentifier($column);
    $parameterName = 'column' . $cIndex++;
    if (is_scalar($value) && $parameterContainer) {
        $values[] = $driver->formatParameterName($parameterName);
        $parameterContainer->offsetSet($parameterName, $value);
    } else {
        $values[] = $this->resolveColumnValue(
            $value,
            $platform,
            $driver,
            $parameterContainer
        );
    }
}

Also, src/Sql/Update.php#L143-L157 was change from:

$setSql = [];
foreach ($this->set as $column => $value) {
    $prefix = $platform->quoteIdentifier($column) . ' = ';
    if (is_scalar($value) && $parameterContainer) {
        $setSql[] = $prefix . $driver->formatParameterName($column);
        $parameterContainer->offsetSet($column, $value);
    } else {
        $setSql[] = $prefix . $this->resolveColumnValue(
            $value,
            $platform,
            $driver,
            $parameterContainer
        );
    }
}

To this:

$setSql = [];
$pIndex = 0;
foreach ($this->set as $column => $value) {
    $prefix = $platform->quoteIdentifier($column) . ' = ';
    if (is_scalar($value) && $parameterContainer) {
        $parameterName = 'set' . $pIndex++;
        $setSql[] = $prefix . $driver->formatParameterName($parameterName);
        $parameterContainer->offsetSet($parameterName, $value);
    } else {
        $setSql[] = $prefix . $this->resolveColumnValue(
            $value,
            $platform,
            $driver,
            $parameterContainer
        );
    }
}

What it does is stop using the column name as parameter. Instead it uses a constant column and a index value so instead of name, age, country it uses column0, column1, column2 and it prevents the use of spaces, dashes and numbers at the beginning of the column parameters.

We love Zend-DB and we have been thinking about creating a PR, but we need your input and feedback on this solution.

Thank you!

Welling Guzmán and The Directus Team

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions