sanchezzzhak / kak-clickhouse

Yii2 ext. ClickHouse
69 stars 43 forks source link

Wrong escaping single quote sign #56

Closed Akdmeh closed 2 years ago

Akdmeh commented 2 years ago

Hello! I'm trying to batch insert some value with single quote sign using batchInsert command, f.e.:

<?php Yii::$app->clickhouse->
    createCommand()->
    batchInsert('table', ['column'], [["value with single ' quote inside"]])->
    execute();

What I expect? The value inside DB should be: value with single ' quote inside But instead I get: value with single '' quote inside (two single quotes in DB value!) I found in Schema.php next code:

    public function quoteValue($str)
    {
        if (!is_string($str)) {
            return $str;
        }
        return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032\047") . "'";
    }

First we doubling single quote with this code: str_replace("'", "''", $str) but after we adding backslashes to single quotes because of listing single quote sign in octal form: \047 So we get \'\' as the result, but we need \' OR '' [two single quote signs together].

I'm not so experienced in GitHub things and want to consult with you: I'm not sure, is it bug or I'm missing some important behaviour in escaping? I think the right function should be:

public function quoteValue($str)
    {
        if (!is_string($str)) {
            return $str;
        }
        return "'" . addcslashes($str, "\000\n\r\\\032\047") . "'";
    }

or

public function quoteValue($str)
    {
        if (!is_string($str)) {
            return $str;
        }
        return "'" . addcslashes(str_replace("'", "''", $str), "\000\n\r\\\032") . "'";
    }

Am I right and can you fix this? Thank you a lot for this library, it's very helpful!

sanchezzzhak commented 2 years ago

hi, yes this is a mistake https://clickhouse.tech/docs/en/sql-reference/syntax/#syntax-string-literal

UP. new result

        /** @var \kak\clickhouse\Connection $clickhouse */
  $clickhouse = Yii::$app->clickhouse;

  $sql = $clickhouse->getQueryBuilder()
      ->batchInsert('test_table', ['browser_version'], [
          ["its '"]
      ]);
  echo $sql;

INSERT INTOtest_table(browser_version) VALUES ('its \'')

Akdmeh commented 2 years ago

Yes, I've updated code from dev-master via Composer, now it's work correctly. Thank you!