Если мой оператор SQL вычисляется только один раз, то зачем мне использовать sqlite3_bind ()? - PullRequest
0 голосов
/ 10 апреля 2020

Например, первый комментарий к вопросу Как правильно экранировать одинарные кавычки в операторе вставки SQLite - iOS говорит: «Не используйте stringWithFormat для построения запрос. Сделайте это правильно с sqlite3_bind_xxx заявлениями. " Я видел (в переполнении стека и за его пределами) много подобных комментариев / ответов, которые безоговорочно предлагают использовать параметры вместо литералов.

Однако я не вижу подобных предложений на сайте SQLite . Я вижу, что в разделе « 6. Связывание параметров и повторное использование подготовленных операторов » в « Введение в интерфейс SQLite C / C ++ » говорится, что «SQLite позволяет тому же подготовленному оператору быть вычисляется несколько раз "с помощью sqlite3_bind () .

Так что, если я оцениваю только один оператор SQL, то зачем мне использовать параметры вместо использования литералов (и когда необходимо ли экранировать вводимый пользователем текст или преобразовывать данные в литералы BLOB самостоятельно? Я что-то здесь упускаю? Я понимаю, что «повторное использование подготовленных операторов» и, таким образом, «отказ от вызовов sqlite3_prepare () может дать значительное улучшение производительности», но я бы хотел пока сделать свой код максимально простым и, возможно, повысить производительность позже.

Ответы [ 2 ]

1 голос
/ 10 апреля 2020

" когда необходимо " является ключом здесь. Будучи таким открытым, такой подход неизбежно приведет к инъекции SQL. Что такое вводимый пользователем текст? Является ли часть интерфейса введенной пользователем? Текст, полученный из базы данных, введен пользователем? Можете ли вы гарантировать, что у любого, кто работает с базой кода, будут правильные ответы?

Обработка данных для SQL должна быть равномерной и предсказуемой. И подготовленные заявления предлагают именно это.

Кроме того, «побег» не предназначен для защиты. Давая вам ложное чувство безопасности, он предаст вас при первой же возможности. Попробуйте защитить имя поля с помощью экранирования строки и посмотрите. В отличие от побега, использование подготовленных заявлений гарантирует защиту, когда это применимо.

Я бы хотел сделать свой код максимально простым заставляя себя обдумывать каждый раз, когда выполняется запрос, «необходимо ли экранировать введенный пользователем текст или нет?»

Наконец, чтобы упростить повторяющуюся задачу, существует определяемая пользователем функция на помощь. Просто напишите функцию, которая объединяет подготовку / связывание / выполнение в одном вызове, а затем используйте ее, чтобы сделать код приложения максимально простым и понятным.

0 голосов
/ 12 апреля 2020

Причины всегда использовать sql_bind () :

  • Это позволяет вставлять больше данных, поскольку SQLite ограничивает длину оператора SQL
  • Это быстрее для большой строки, так как «не нужно так много анализировать или копировать»
  • Это быстрее и использует меньше памяти для большого BLOB, поскольку преобразование данных в литерал BLOB требует времени, а шестнадцатеричные строки - больше памяти, чем данные, которые они представляют
  • Рекомендуется в " Пределы в SQLite " в разделе " 3. Максимальная длина SQL Оператор "

    Если оператор SQL ограничен длиной в миллион байтов, то, очевидно, вы не сможете вставить многомиллионные строки байтов, внедрив их как литералы внутри операторов INSERT. Но вы все равно не должны этого делать. Используйте хост параметры для ваших данных. Подготовьте короткие SQL операторы, подобные этому:

    INSERT INTO tab1 VALUES (?,?,?);

    Затем используйте функции sqlite3_bind_XXXX () для привязки вашего большого строковые значения для оператора SQL. Использование связывания избавляет от необходимости экранировать кавычки в строке, снижая риск атак SQL. Это [ si c] также работает быстрее, поскольку большую строку не нужно анализировать или копировать столько же.

Примечание: I найти причину, по которой «использование связывания избавляет от необходимости экранировать символы кавычек в строке» само по себе недостаточно, потому что сделать это достаточно просто, просто сделать это явно на языке программирования моего приложения или с помощью одного из SQLite's Formatted Функции строковой печати с подстановкой % q или% Q .

...