Где могут быть ограничения на запросы SQLite?

xintrea

Новичок
Сайт использует БД SQLite3. Фреймверк CI2. PHP 5.6.24.

После переноса сайта на новый хостинг, перестали выполняться SQL запросы UPDATE с длинным (десятки Кб) содержимым одного поля. Ну, то есть, есть поле data с типом TEXT, хранит текст статей, которые могут быть по ~50Кб. По идее никакого ограничения на длину поля TEXT быть не должно. Но выполнение команды вида:

UPDATE "articles" SET "data" = 'тут очень длинный html' WHERE "id" = '709131de8092025b6d3865ecf90fa123'​

Приводит к неопределенной ошибке:

Error Number: Unavaiable
Error Message: Unavaiable​

А если укоротить html примерно в два раза, то UPDATE нормально выполняется.

Вопрос: где может стоять какое ограничение на SQLite (или на PDO?) что команда с длинными данными не может выполниться?
 

fixxxer

К.О.
Партнер клуба
Не фантазируй и не вводи вручную, а скопируй точную ошибку pdo (или sqlite).
 

xintrea

Новичок
Не фантазируй и не вводи вручную, а скопируй точную ошибку pdo (или sqlite).
Тут мне никто походу не поможет.

Проблема оказалась в CI2, который толком не умеет работать с неперсистентными соединениями с БД, и самописном драйвере. Для MySQL/Postgree проблемы нет - там включается персистентное соединение и вперед.

А для SQLite все немного сложнее. Персистентного соединения с файловой БД установить по ее природе невозможно. Поэтому там работает режим неперсистентного соединения: идентификатор соединения устанавливается каждый раз при выполнении скрипта, после того, как пройдут команды использования определенного файла SQLite.

И мне посчастливилось наткнуться на момент, когда соединения еще нет, но зато вызывается функция экранирования строки quote(). Эта функция зависит от типа соединения с базой данных, и в зависимости от типа базы данных использует разные правила экранирования. Но если соединения нет, то определить тип бд нельзя, нельзя определить правила экранирования, ну и quote() работать не будет.

Соответственно, нижеприведенный код не срабатывает:

//Escape the string
if(gettype($this->conn_id)===«object»)
{
$str = $this->conn_id->quote($str);
log_message('debug', «String after quote: ».print_r($str, true));
}

И строка не экранируется. Но зато запоминается для дальнейшего запроса, который может быть вызван т.к. потом соединение устанавливается. Ну просто код БД-подсистемы CI написан без учета, что вообще может возникнуть ситуация, что соединение недоступно в какой-то момент, исходя из предположения, что соединение персистентно.

И если в строке был амперсанд, то он не экранируется, и при конструировании портит SQL-запрос.

А так как это дело находится внутри БД-драйвера, то всякие плейсхолдеры тут не помогут: БД-драйвер сам и является как раз реализацией плейсхолдеров.

Раньше помогала отдельная функция quote() (или как-то так называлась, подзабыл), которая экранировала согласно переданным флагам и не была завязана на соединении с БД. Потом в какой-то версии PHP 5.x ее выпилили, и получилась засада.
 

fixxxer

К.О.
Партнер клуба
Оставив за скобками справедливость этих рассуждений... какое это имеет отношение к длине содержимого поля?
 

xintrea

Новичок
Оставив за скобками справедливость этих рассуждений... какое это имеет отношение к длине содержимого поля?
Никакого. Проблема оказалась совершенно не в длине поля. Просто амперсанд был во второй части длинного текста, и когда я текст укорачивал, проблема исчезала. А когда восстанавливал - проблема появлялась.
 

DiMA

php.spb.ru
Команда форума
плотно работал с sqlite - полное говно, может зависать на ровном месте
если только хранить инфу, которую придется читать/писать не слишком часто
 

AnrDaemon

Продвинутый новичок
Если только читать, и небольшой объём данных (маршрутизацию хранить например) - вполне годится.
Если писать - то только очень и очень редко. Иначе проблем не оберёшься с ожиданием блокировок.
 
Сверху