Python smartsql компиляция вставки - PullRequest
0 голосов
/ 09 сентября 2018

Я хочу использовать sqlbuilder (https://sqlbuilder.readthedocs.io/en/latest/) библиотека для создания собственных запросов к sqlite. Вот мой код для вставки данных:

import sqlite3
from sqlbuilder.smartsql import Q, T
from sqlbuilder.smartsql.dialects.sqlite import compile


if __name__ == '__main__':
    connection = sqlite3.connect(':memory:')

    with connection:
        connection.execute('CREATE TABLE temp (t TEXT, i INTEGER)')

        insert = compile(Q(T.temp).insert({T.temp.t: 'text', T.temp.i: 1}))
        sql, params = insert

        connection.execute(
            sql, params
        )

    connection.close()

Этот код не работает, потому что compile создает неправильный sql и params для sqlite: ('(?, (?, ?))', ['INSERT INTO "temp" ("i", "t") VALUES (%s, %s)', 1, 'text']), и я получил ошибку: sqlite3.OperationalError: near "(": syntax error

Интересно, что нет проблем с компиляцией и выполнением операторов select.

UPDATE

Код для выбора операторов и его работы:

import sqlite3
from sqlbuilder.smartsql import Q, T
from sqlbuilder.smartsql.dialects.sqlite import compile

if __name__ == '__main__':
    connection = sqlite3.connect(':memory:')

    with connection:
        connection.execute('CREATE TABLE temp (t TEXT, i INTEGER)')

        select = compile(Q(T.temp).fields('*'))
        print(select)  # ('SELECT * FROM `temp`', [])
        sql, params = select

        connection.execute(
            sql, params
        )

    connection.close()

1 Ответ

0 голосов
/ 10 сентября 2018

Ответ исправлен

Из Python Doc для API sqlite3:

Обычно для ваших операций SQL нужно использовать значения из Python переменные. Вы не должны собирать ваш запрос, используя строку Python операции, потому что это небезопасно; это делает вашу программу уязвимы для атаки SQL-инъекцией (см. https://xkcd.com/327/ для юмористический пример того, что может пойти не так).

Вместо этого используйте подстановку параметров DB-API. Положил ? как заполнитель везде, где вы хотите использовать значение, а затем предоставить кортеж значений в качестве второго аргумента метода execute () курсора. (Другие модули базы данных могут использовать другой заполнитель, такой как% s или : 1.) Например:

# Никогда не делай этого - небезопасно!
symbol = 'RHAT' c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Сделайте это вместо
t = ('RHAT',) c.execute('SELECT * FROM stocks WHERE symbol=?', t)

Возвращаемое значение insert` `('(?, (?, ?))', ['INSERT INTO "temp" ("i", "t") VALUES (%s, %s)', 1, 'text']) означает, что sqlbuilder пытается воспользоваться этим советом. Осталось только выполнить интерполяцию строк, чтобы привести ее в правильный синтаксис sqlite. Оказывается, аргумент result для конструктора Q сделает именно это.

insert = Q(T.temp,result=Result(compile=compile)).insert({T.temp.t: 'text', T.temp.i: 1}) вернет кортеж, который «готов к SQL», то есть: ('INSERT INTO `temp` (`i`, `t`) VALUES (?, ?)', [1, 'text']). Теперь вы видите, что «% s» был заменен на «?». Не забудьте импортировать Result.

...