LINUX.ORG.RU

SQLite Segmentation Fault при INSERT и метки времени в миллисекундах DEFAULT

 , , ,


0

1

Доброго времени, друзья! Для начала опишу в общем виде цепочку взаимодействий: Есть ардуино, к которой подключены некоторые датчики, показания которых необходимо писать в БД. Микроконтроллер общается с шилдом (OpenWRT+php+sqlite3) отправляя и читая текст из консоли. Раз в пять минут ардуино пишет в БД sqlite строку с показаниями датчиков и значениями выходных параметров. Метка времени хранится в поле 'timestamp' с типом INTEGER в виде секунд с 01.01.1970 (1534384161) и добавляется автоматически при добавлении строк при помощи DEFAULT (strftime('%s','now','localtime')). Для построения графиков на веб-странице при помощи flotcharts, дату необходимо масштабировать в миллисекунды с той же точкой отсчета 01.01.1970. Пробовал различными способами от «DEFAULT (strftime('%s','now','localtime')*1000)» до «DEFAULT (CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER))». При попытке добавить строку через консоль (в т.ч. и по SSH) получаю Segmentation Fault и вылет из sqlite. Та же самая строка «insert into tab1 (p1, t1, t2) values (150.544, 47.52, 12.55);», если выполнить её в PHPLiteAdmin - выполняется и верно сохраняет метку времени. Подозреваю, что на лету из консоли sqlite не может справиться с арифметикой, а PHPLiteAdmin берет расчет на себя или же проблема связана с ограничениями integer. Насколько мне удалось понять, объем данных, выделенный для хранения int может быть от 1 до 8 байт. В секундах метка времени займет 4 байта, а вот в миллисекундах - уже 6! В общем, сколько ни искал ответов на эту тему - так и не нашел ничего. Строго не судите, ибо с php, SQL, и JS только знакомлюсь. Очень надеюсь на помощь компетентных!

Уберите все эти ардуины и пр. Возьмите обычный sqlite под Windows. Создайте в нем БД, напишите нужные запросы. Добейтесь, чтобы это работало. Потом уже подключайте php и т.д.

И нам сюда напишите структуру таблицы, и запрос, который не работает.

Serik ()
Ответ на: комментарий от Serik

Спасибо за ответ! Структура таблицы следующая:

CREATE TABLE "temperature" ( 'id' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 'timestamp' INTEGER DEFAULT (CAST((julianday('now') - 2440587.5)*86400000 AS INTEGER)), 'p1' REAL DEFAULT NULL, 'h1' REAL DEFAULT NULL, 't1' REAL DEFAULT NULL, 'ds1' REAL DEFAULT NULL, 'ds2' REAL DEFAULT NULL, 'ds3' REAL DEFAULT NULL, 'ds4' REAL DEFAULT NULL, 'ds5' REAL DEFAULT NULL, 'ds6' REAL DEFAULT NULL, 'ds7' REAL DEFAULT NULL, 'ds8' REAL DEFAULT NULL, 'ds9' REAL DEFAULT NULL, 'ds10' REAL DEFAULT NULL,'do1' BOOLEAN DEFAULT NULL,'do2' BOOLEAN DEFAULT NULL,'do3' BOOLEAN DEFAULT NULL,'do4' BOOLEAN DEFAULT NULL,'do5' BOOLEAN DEFAULT NULL,'do6' BOOLEAN DEFAULT NULL,'do7' BOOLEAN DEFAULT NULL);
Создаю её в PHPLiteAdmin. При попытке создания таблицы аналогичным запросом по SSH получаю результат:
А вот, что происходит, если предварительно создать таблицу в PHPLiteAdmin:

thelife ()
Ответ на: комментарий от thelife

1) у меня на sqlite 3.13 все скрипты выполнились, возможно, проблема в разных версиях/вариантах сборки
2) поле

timestamp INTEGER DEFAULT (CAST ( (julianday('now') - 2440587.5) * 86400000 AS INTEGER) )

какая-то химия, человеконечитаемая, лучше сделать что-то типа

timestamp DATETIME NOT NULL DEFAULT (datetime(CURRENT_TIMESTAMP, 'localtime') )

а в нужные вам единицы измерения пересчитывать в запросе на чтение, а еще лучше в клиенте

Serik ()
Ответ на: комментарий от Serik

Спасибо за совет! А я тут таблицы создаю)))
В общем ни одно из моих выражений не выдало никакого значения, кроме ошибок:

 root@localhost:~# sqlite3
SQLite version 3.8.11.1 2015-07-29 20:00:57
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> select CAST ( (julianday('now') - 2440587.5) * 86400000 AS INTEGER);
Segmentation fault
root@localhost:~# sqlite3
SQLite version 3.8.11.1 2015-07-29 20:00:57
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> select  (strftime('%s','now','localtime')*1000);
Bus error
root@localhost:~#
 

Что скажете? Может всё-таки с памятью траблы (мало)?
Подумываю уже через php костыль сделать. Вызывать php скрипт с параметрами в виде данных, которые нужно будет уже писать в базу.
А то умножать на 1000 каждую ячейку столбца с датой на этапе выборки, насколько помню, у меня не вышло. А умножить на стороне клиента перед использованием в json каждую запись с датой - для меня пока непосильная задача, хоть это и было бы самым изящным решением моей проблемы.

thelife ()
Ответ на: комментарий от Serik

Немного покурив, разобрался) Удалось реализовать в следующем виде:
в таблицу пишется поле в формате 2018-08-22 00:11:42

 timestamp DATE DEFAULT (datetime('now','localtime')) 
далее читаем выборку из таблицы и пишем необходимые поля из результата в jquery объект:
$db = new PDO('sqlite:../sql/ardb.db'); 
$st = $db->query('SELECT id,timestamp,t1,h1,ds1,ds3 FROM temperature WHERE id>(SELECT MAX(id)-300 FROM temperature)');
$results = $st->fetchAll(); foreach ($results as $row) 
{$dataset[] = array($row['timestamp'],$row['ds1'],$row['ds3'],$row['h1']);} 
преобразуем jquery объект в двумерный массив 300х4:
 var sqlite = <?php echo json_encode($dataset); ?> 
далее в цикле перерабатываем дату из строки в целое число с поправкой на часовой пояс и результат сохраняем в предварительно созданные двумерные массивы 300х2, по которым и строим графики:
 for(var i = 0; i < sqlite.length; ++i){
   ds1[i][0] = (Date.parse(sqlite[i][0]) + 10800000); //3*60*60*10^3
   ds1[i][1] = sqlite[i][1];
   ds3[i][0] = (Date.parse(sqlite[i][0]) + 10800000);
   ds3[i][1] = sqlite[i][2];   
   h1[i][0] = (Date.parse(sqlite[i][0]) + 10800000);
   h1[i][1] = sqlite[i][3];   
}
Результат на компьютере: [img]https://preview.ibb.co/eEXche/image.png[/img] Как видно, всё замечательно. А вот в ios не работает. [img]https://preview.ibb.co/fLQNhe/unnamed.png[/img] Скорее всего, это связано с форматом, принимаемым в качестве аргумента Date.parse(). Буду разбираться. Поправьте, если где недопонял. Главное получил то, что и хотел - обработку на стороне клиента и бонусом - записи бд в человекочитабельном формате.

thelife ()
Ответ на: комментарий от thelife

Добился отображения и на ios, поменяв формат даты на %Y/%m/%dT%H:%M:%f Но теперь на ios другая проблема. Время на ios отображается на 3 часа больше, чем на win7. На обеих ОС пользуюсь Google Chrome.

thelife ()
Ответ на: комментарий от thelife

Всё дело оказалось в том, что объект Date по-разному преобразуется в строку различными браузерами. Дабы не ломать голову, было принято решение вернуться от человекочитабельного формата даты к счетчику секунд и вместо Date.parse() применить *1000. Спасибо огромное за помощь, проблему считаю решенной (ну или как минимум - не актуальной).

thelife ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.