Unicode и неверное количество аргументов ошибки с Python 3 и MySQL соединителем - PullRequest
1 голос
/ 19 февраля 2020

Я пытаюсь выполнить простой запрос SELECT для базы данных MySQL (MariaDB) в Python 3.

Я получаю очень странные ошибки

        query = (
            'SELECT user_id, user_password_hash, user_password_salt '
            'FROM users '
            'WHERE user_username = "%s"'
        )

        print(f'Trying login, username {username}, password {password}')

        try:
            cursor = self.connection.cursor(prepared=True)
            cursor.execute(query, (username,))

            results = cursor.fetchone()

            print(results)
            ...

        except Error as e:
            print('Error in login query: ' + str(e))
            raise e

Выполнение этого кода дает мне следующую ошибку: Error in login query: 1210: Incorrect number of arguments executing prepared statement

Я не понимаю - это требует одного аргумента, и я дал ему один аргумент. Удаление запятой в кортеже в execute() не решает эту проблему.

Теперь, если я удалю кавычки из запроса, я получу совершенно другую ошибку:

        query = (
            'SELECT user_id, user_password_hash, user_password_salt '
            'FROM users '
            'WHERE user_username = %s'
        )
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9b in position 0: invalid start byte

The above exception was the direct cause of the following exception:

SystemError: <class 'UnicodeDecodeError'> returned a result with an error set

В таблице используется utf8mb4, поэтому проблем не должно быть.

Кроме того, работа SELECT * FROM users WHERE user_username="jeff" в консоли MySQL работает нормально.

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

РЕДАКТИРОВАТЬ: Экспериментируя в изолированном Python процессе, я воспроизвел проблему, выполнив следующее:

import mysql.connector

conn = mysql.connector.connect(host="localhost",
                               database="lucidlab",
                               user="lucidlab",
                               password="lucidlab")

cur = conn.cursor()
cur.execute("SELECT * FROM users WHERE user_username='jeff'")

results = cur.fetchall() # ERROR
print(results)

Это заставляет меня думать, что, возможно, это проблема кодирования базы данных?

РЕДАКТИРОВАТЬ: Я решил эту проблему. Пожалуйста, смотрите мой ответ ниже.

Ответы [ 3 ]

1 голос
/ 20 февраля 2020

Я нашел проблему. Чтобы исправить это, нужно было посмотреть на схему, которую я, к сожалению, не опубликовал - урок усвоен.

Моя схема содержала следующее:

CREATE TABLE users (
...
  user_password_hash BINARY(20) NOT NULL,
  user_password_salt BINARY(20) NOT NULL,
...
);

Выполнение SELECT * FROM users... запроса любой тип извлекает эти двоичные данные, которые Python услужливо (!) немедленно преобразует в строку UTF-8 ... что не удается, поскольку соль - это байты, полученные из os.urandom().

I исправили это, вместо этого используя sha256_crypt из библиотеки passlib и сохраняя мою закодированную комбинацию хеш + соль как CHAR(77).

Спасибо тем, кто помогал - к сожалению, я думал об этой проблеме слишком узко и поэтому сформулировал свой вопрос как таковой.

0 голосов
/ 19 февраля 2020

query = """SELECT user_id, user_password_hash, user_password_salt FROM users WHERE user_username = %s"""

использовать это будет работать ..

0 голосов
/ 19 февраля 2020

Попробуйте использовать двойные кавычки:

    query = ("SELECT user_id, user_password_hash, user_password_salt "
        "FROM users "
        "WHERE user_username = %s"
    )

или тройные кавычки:

    query = ("""SELECT user_id, user_password_hash, user_password_salt 
        FROM users 
        WHERE user_username = %s"""
    )

...