Настроить сообщение об ошибке дублирования mysql_error? [Дубликат]

Здесь было много полезных ответов, в целом достигающих высшей точки в два пункта.

  1. BACKTICKS() `используются вокруг имен идентификаторов.
  2. QUOTES(') используются вокруг значений.

И как @MichaelBerkowski сказал

Backticks должны использоваться для идентификаторов таблиц и столбцов, но необходимы только тогда, когда идентификатор является MySQL зарезервированным ключевое слово или когда идентификатор содержит символы пробела или символы за пределами ограниченного набора (см. ниже) Часто рекомендуется избегать использования зарезервированных ключевых слов в качестве идентификаторов столбцов или таблиц, если это возможно, во избежание проблемы с кавычками.

Существует случай, когда идентификатор не может быть зарезервированным ключевым словом или содержать символы whitespace или за пределами ограниченного набора , но обязательно требует обратных ссылок вокруг их.

ПРИМЕР

123E10 является допустимым именем идентификатора, а также действительным INTEGER литералом.

[Не вдаваясь в подробности, как вы могли бы получить такое имя идентификатора] Предположим, что я хочу создать временную таблицу с именем 123456e6.

Нет ОШИБКИ на обратных циклах.

DB [XXX]> create temporary table `123456e6` (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

ОШИБКА, если вы не используете обратные ссылки.

DB [XXX]> create temporary table 123451e6 (`id` char (8));
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '123451e6 (`id` char (8))' at line 1

Однако 123451a6 [* g15]

DB [XXX]> create temporary table 123451a6 (`id` char (8));
Query OK, 0 rows affected (0.03 sec)

Это полностью, потому что 1234156e6 также является показательным номером.

3
задан PhantomReference 22 December 2013 в 09:33
поделиться

2 ответа

Я думаю, что «вариант 2» (ручная проверка ограничения перед попыткой вставить) ужасен не только из-за опасности гонки (чего можно избежать с помощью блокировки чтения ), но также (как вы примечание) из-за дополнительной нагрузки на базу данных: в конце концов, ручная проверка ограничений полностью отрицает цель и преимущество использования ограничений в базе данных.

Я согласен, что строки сообщений об ошибках синтаксического анализа чувствуют себя «грязными», , но строки определены правильно . Можно даже ссылаться на основные errmsg.txt или исходные файлы заголовков.

Как только вы извлекли имя ключа из сообщения об ошибке, можно использовать информационную схему KEY_COLUMN_USAGE для идентификации злоумышленников:

public static final int ER_DUP_ENTRY = 1062;
public static final int ER_DUP_ENTRY_WITH_KEY_NAME = 1586;

public static final String REGEX_DUP_ENTRY_WITH_KEY_NAME =
  "Duplicate entry '(.*)' for key '(.*)'";

// ...


try {
// ...
} catch (MySQLIntegrityConstraintViolationException e) {
  switch (e.getErrorCode()) {
    case ER_DUP_ENTRY:
    case ER_DUP_ENTRY_WITH_KEY_NAME:
      Pattern p = Pattern.compile(REGEX_DUP_ENTRY_WITH_KEY_NAME);
      Matcher m = p.matcher(e.getMessage());

      SQLQuery query = session.createSQLQuery(
      " SELECT COLUMN_NAME" +
      " FROM   INFORMATION_SCHEMA.KEY_COLUMN_USAGE" +
      " WHERE  CONSTRAINT_SCHEMA = :schema" +
      "    AND CONSTRAINT_NAME   = :key"
      );
      query.setString("schema", "my_schema");
      query.setString("key"   , m.group(2));

      showDuplicateError(query.list());

      break;
  }
}
7
ответ дан eggyal 27 August 2018 в 19:33
поделиться

Вот PHP-версия ответа eggyal , используя MySQLi.

// Error: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)               Message: Duplicate entry '%s' for key %d
// Error: 1586 SQLSTATE: 23000 (ER_DUP_ENTRY_WITH_KEY_NAME) Message: Duplicate entry '%s' for key '%s'
if($mysqli->errno === 1062 || $mysqli->errno === 1586)
{
    if(preg_match("/Duplicate entry '(.*)' for key '(.*)'/", $mysqli->error, $matchArray) === 1)
    {
        $duplicatedValue = $matchArray[1];
        $uniqueKeyName = $matchArray[2];

        if(!($stmt = $mysqli->prepare('SELECT COLUMN_NAME'
                                    . '  FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE'
                                    . ' WHERE CONSTRAINT_SCHEMA = ?'
                                    . '   AND CONSTRAINT_NAME = ?')))
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        $schemaName = // Name of the schema (string).
        if(!$stmt->bind_param('ss', $schemaName, $uniqueKeyName))
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        if(!$stmt->execute())
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        $res = $stmt->get_result();
        if(!$res)
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        $row = $res->fetch_assoc();
        if($row === null)
        {
            die;    // No results?
        }
        $columnName = $row['COLUMN_NAME'];
    }
}
-1
ответ дан Community 27 August 2018 в 19:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: