mirror of
https://github.com/Motion-Project/motion.git
synced 2026-05-16 18:46:50 -04:00
1114 lines
40 KiB
C++
1114 lines
40 KiB
C++
/*
|
|
* This file is part of MotionPlus.
|
|
*
|
|
* MotionPlus is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MotionPlus is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MotionPlus. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* Copyright 2020-2022 MotionMrDave@gmail.com
|
|
*/
|
|
|
|
|
|
#include "motionplus.hpp"
|
|
#include "conf.hpp"
|
|
#include "util.hpp"
|
|
#include "logger.hpp"
|
|
#include "dbse.hpp"
|
|
|
|
static int dbse_global_edits(struct ctx_cam **cam_list)
|
|
{
|
|
|
|
int retcd = 0;
|
|
|
|
if (cam_list[0]->conf->database_dbname == "") {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Invalid database name"));
|
|
retcd = -1;
|
|
}
|
|
if ((((cam_list[0]->conf->database_type == "mysql")) ||
|
|
((cam_list[0]->conf->database_type == "mariadb")) ||
|
|
((cam_list[0]->conf->database_type == "pgsql"))) &&
|
|
(cam_list[0]->conf->database_port == 0)) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Must specify database port for mysql/mariadb/pgsql"));
|
|
retcd = -1;
|
|
}
|
|
|
|
if (retcd == -1) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Database functionality disabled."));
|
|
cam_list[0]->conf->database_type = "";
|
|
}
|
|
|
|
return retcd;
|
|
|
|
}
|
|
|
|
void dbse_global_deinit(struct ctx_motapp *motapp)
|
|
{
|
|
|
|
int indx;
|
|
|
|
#if defined(HAVE_MYSQL)
|
|
if (motapp->cam_list[0]->conf->database_type != "") {
|
|
if ((motapp->cam_list[0]->conf->database_type == "mysql")) {
|
|
MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing MYSQL"));
|
|
mysql_library_end();
|
|
}
|
|
}
|
|
#else
|
|
(void)motapp;
|
|
#endif /* HAVE_MYSQL */
|
|
|
|
#if defined(HAVE_MARIADB)
|
|
if (motapp->cam_list[0]->conf->database_type != "") {
|
|
if ((motapp->cam_list[0]->conf->database_type == "mariadb")) {
|
|
MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing MYSQL"));
|
|
mysql_library_end();
|
|
}
|
|
}
|
|
#else
|
|
(void)motapp;
|
|
#endif /* HAVE_MYSQL */
|
|
|
|
indx = 0;
|
|
while (motapp->cam_list[indx] != NULL) {
|
|
myfree(&motapp->cam_list[indx]->dbse);
|
|
indx++;
|
|
}
|
|
|
|
}
|
|
|
|
void dbse_global_init(struct ctx_motapp *motapp)
|
|
{
|
|
int indx;
|
|
|
|
indx = 0;
|
|
while (motapp->cam_list[indx] != NULL) {
|
|
motapp->cam_list[indx]->dbse = (struct ctx_dbse *)mymalloc(sizeof(struct ctx_dbse));
|
|
indx++;
|
|
}
|
|
|
|
if (motapp->cam_list[0]->conf->database_type != "") {
|
|
if (dbse_global_edits(motapp->cam_list) == -1) {
|
|
return;
|
|
}
|
|
|
|
MOTION_LOG(DBG, TYPE_DB, NO_ERRNO,_("Initializing database"));
|
|
/* Initialize all the database items */
|
|
#if defined(HAVE_MYSQL)
|
|
if ((motapp->cam_list[0]->conf->database_type == "mysql")) {
|
|
if (mysql_library_init(0, NULL, NULL)) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Could not initialize database %s")
|
|
,motapp->cam_list[0]->conf->database_type.c_str());
|
|
motapp->cam_list[0]->conf->database_type = "";
|
|
return;
|
|
}
|
|
}
|
|
#endif /* HAVE_MYSQL */
|
|
|
|
#if defined(HAVE_MARIADB)
|
|
if ((motapp->cam_list[0]->conf->database_type == "mariadb")) {
|
|
if (mysql_library_init(0, NULL, NULL)) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Could not initialize database %s")
|
|
,motapp->cam_list[0]->conf->database_type.c_str());
|
|
motapp->cam_list[0]->conf->database_type = "";
|
|
return;
|
|
}
|
|
}
|
|
#endif /* HAVE_MARIADB */
|
|
|
|
#ifdef HAVE_SQLITE3
|
|
/* database_sqlite3 == NULL if not changed causes each thread to create their own
|
|
* sqlite3 connection this will only happens when using a non-threaded sqlite version */
|
|
motapp->cam_list[0]->dbse->database_sqlite3=NULL;
|
|
if ((motapp->cam_list[0]->conf->database_type == "sqlite3") &&
|
|
(motapp->cam_list[0]->conf->database_dbname != "")) {
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
|
|
,_("SQLite3 Database filename %s")
|
|
,motapp->cam_list[0]->conf->database_dbname.c_str());
|
|
|
|
int thread_safe = sqlite3_threadsafe();
|
|
if (thread_safe > 0) {
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("SQLite3 is threadsafe"));
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, _("SQLite3 serialized %s")
|
|
,(sqlite3_config(SQLITE_CONFIG_SERIALIZED)?_("FAILED"):_("SUCCESS")));
|
|
if (sqlite3_open(motapp->cam_list[0]->conf->database_dbname.c_str()
|
|
, &motapp->cam_list[0]->dbse->database_sqlite3) != SQLITE_OK) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Can't open database %s : %s")
|
|
,motapp->cam_list[0]->conf->database_dbname.c_str()
|
|
,sqlite3_errmsg(motapp->cam_list[0]->dbse->database_sqlite3));
|
|
sqlite3_close(motapp->cam_list[0]->dbse->database_sqlite3);
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Could not initialize database %s")
|
|
,motapp->cam_list[0]->conf->database_dbname.c_str());
|
|
motapp->cam_list[0]->conf->database_type = "";
|
|
return;
|
|
}
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO,_("database_busy_timeout %d msec"),
|
|
motapp->cam_list[0]->conf->database_busy_timeout);
|
|
if (sqlite3_busy_timeout(motapp->cam_list[0]->dbse->database_sqlite3
|
|
, motapp->cam_list[0]->conf->database_busy_timeout) != SQLITE_OK)
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO,_("database_busy_timeout failed %s")
|
|
,sqlite3_errmsg(motapp->cam_list[0]->dbse->database_sqlite3));
|
|
}
|
|
}
|
|
/* Cascade to all threads */
|
|
indx = 1;
|
|
while (motapp->cam_list[indx] != NULL) {
|
|
motapp->cam_list[indx]->dbse->database_sqlite3 = motapp->cam_list[0]->dbse->database_sqlite3;
|
|
indx++;
|
|
}
|
|
|
|
#endif /* HAVE_SQLITE3 */
|
|
}
|
|
}
|
|
|
|
static void dbse_init_mysql(struct ctx_cam *cam)
|
|
{
|
|
|
|
#if defined(HAVE_MYSQL)
|
|
// close database to be sure that we are not leaking
|
|
mysql_close(cam->dbse->database_mysql);
|
|
cam->dbse->database_event_id = 0;
|
|
|
|
cam->dbse->database_mysql = (MYSQL *) mymalloc(sizeof(MYSQL));
|
|
mysql_init(cam->dbse->database_mysql);
|
|
|
|
if (!mysql_real_connect(cam->dbse->database_mysql
|
|
, cam->conf->database_host.c_str(), cam->conf->database_user.c_str()
|
|
, cam->conf->database_password.c_str(), cam->conf->database_dbname.c_str()
|
|
, cam->conf->database_port, NULL, 0)) {
|
|
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Cannot connect to MySQL database %s on host %s with user %s")
|
|
,cam->conf->database_dbname.c_str(), cam->conf->database_host.c_str()
|
|
,cam->conf->database_user.c_str());
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("MySQL error was %s"), mysql_error(cam->dbse->database_mysql));
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Disabling database functionality"));
|
|
dbse_global_deinit(cam->motapp);
|
|
cam->conf->database_type = "";
|
|
return;
|
|
}
|
|
#if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012)
|
|
bool my_true = true;
|
|
mysql_options(cam->dbse->database_mysql, MYSQL_OPT_RECONNECT, &my_true);
|
|
#endif
|
|
#else
|
|
(void)cam; /* Avoid compiler warnings */
|
|
#endif /* HAVE_MYSQL */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void dbse_init_mariadb(struct ctx_cam *cam)
|
|
{
|
|
|
|
#if defined(HAVE_MARIADB)
|
|
// close database to be sure that we are not leaking
|
|
mysql_close(cam->dbse->database_mariadb);
|
|
cam->dbse->database_event_id = 0;
|
|
|
|
cam->dbse->database_mariadb = (MYSQL *) mymalloc(sizeof(MYSQL));
|
|
mysql_init(cam->dbse->database_mariadb);
|
|
|
|
if (!mysql_real_connect(cam->dbse->database_mariadb
|
|
, cam->conf->database_host.c_str(), cam->conf->database_user.c_str()
|
|
, cam->conf->database_password.c_str(), cam->conf->database_dbname.c_str()
|
|
, cam->conf->database_port, NULL, 0)) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Cannot connect to MySQL database %s on host %s with user %s")
|
|
,cam->conf->database_dbname.c_str(), cam->conf->database_host.c_str()
|
|
,cam->conf->database_user.c_str());
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("MySQL error was %s"), mysql_error(cam->dbse->database_mariadb));
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Disabling database functionality"));
|
|
dbse_global_deinit(cam->motapp);
|
|
cam->conf->database_type = "";
|
|
return;
|
|
}
|
|
#if (defined(MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID > 50012)
|
|
bool my_true = true;
|
|
mysql_options(cam->dbse->database_mariadb, MYSQL_OPT_RECONNECT, &my_true);
|
|
#endif
|
|
#else
|
|
(void)cam; /* Avoid compiler warnings */
|
|
#endif /* HAVE_MARIADB */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void dbse_init_sqlite3(struct ctx_cam *cam)
|
|
{
|
|
#ifdef HAVE_SQLITE3
|
|
if (cam->motapp->cam_list[0]->dbse->database_sqlite3 != 0) {
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO,_("SQLite3 using shared handle"));
|
|
cam->dbse->database_sqlite3 = cam->motapp->cam_list[0]->dbse->database_sqlite3;
|
|
} else {
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
|
|
,_("SQLite3 Database filename %s"), cam->conf->database_dbname.c_str());
|
|
if (sqlite3_open(cam->conf->database_dbname.c_str(), &cam->dbse->database_sqlite3) != SQLITE_OK) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Can't open database %s : %s")
|
|
,cam->conf->database_dbname.c_str(), sqlite3_errmsg(cam->dbse->database_sqlite3));
|
|
sqlite3_close(cam->dbse->database_sqlite3);
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Disabling database functionality"));
|
|
cam->conf->database_type = "";
|
|
return;
|
|
}
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
|
|
,_("database_busy_timeout %d msec"), cam->conf->database_busy_timeout);
|
|
if (sqlite3_busy_timeout(cam->dbse->database_sqlite3, cam->conf->database_busy_timeout) != SQLITE_OK)
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("database_busy_timeout failed %s")
|
|
,sqlite3_errmsg(cam->dbse->database_sqlite3));
|
|
}
|
|
#else
|
|
(void)cam; /* Avoid compiler warnings */
|
|
#endif /* HAVE_SQLITE3 */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void dbse_init_pgsql(struct ctx_cam *cam)
|
|
{
|
|
#ifdef HAVE_PGSQL
|
|
char connstring[255];
|
|
/* Create the connection string.
|
|
* Quote the values so we can have null values (blank)
|
|
*/
|
|
snprintf(connstring, 255,
|
|
"dbname='%s' host='%s' user='%s' password='%s' port='%d'",
|
|
cam->conf->database_dbname.c_str(), /* dbname */
|
|
(cam->conf->database_host=="" ? cam->conf->database_host.c_str() : ""), /* host (may be blank) */
|
|
(cam->conf->database_user=="" ? cam->conf->database_user.c_str() : ""), /* user (may be blank) */
|
|
(cam->conf->database_password=="" ? cam->conf->database_password.c_str() : ""), /* password (may be blank) */
|
|
cam->conf->database_port
|
|
);
|
|
|
|
cam->dbse->database_pg = PQconnectdb(connstring);
|
|
if (PQstatus(cam->dbse->database_pg) == CONNECTION_BAD) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Connection to PostgreSQL database '%s' failed: %s")
|
|
,cam->conf->database_dbname.c_str(), PQerrorMessage(cam->dbse->database_pg));
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Disabling database functionality"));
|
|
cam->conf->database_type = "";
|
|
return;
|
|
}
|
|
#else
|
|
(void)cam; /* Avoid compiler warnings */
|
|
#endif /* HAVE_PGSQL */
|
|
|
|
return;
|
|
}
|
|
|
|
void dbse_init(struct ctx_cam *cam)
|
|
{
|
|
|
|
if (cam->conf->database_type != "") {
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
|
|
,_("Database backend %s"), cam->conf->database_type.c_str());
|
|
if (cam->conf->database_type == "mysql") {
|
|
dbse_init_mysql(cam);
|
|
} else if (cam->conf->database_type == "mariadb") {
|
|
dbse_init_mariadb(cam);
|
|
} else if (cam->conf->database_type == "postgresql") {
|
|
dbse_init_pgsql(cam);
|
|
} else if (cam->conf->database_type == "sqlite3") {
|
|
dbse_init_sqlite3(cam);
|
|
} else {
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO
|
|
,_("Invalid Database backend %s")
|
|
, cam->conf->database_type.c_str());
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void dbse_deinit(struct ctx_cam *cam)
|
|
{
|
|
if (cam->conf->database_type != "") {
|
|
MOTION_LOG(DBG, TYPE_ALL, NO_ERRNO, _("Closing database"));
|
|
|
|
#if defined(HAVE_MYSQL)
|
|
if (cam->conf->database_type == "mysql") {
|
|
mysql_close(cam->dbse->database_mysql);
|
|
cam->dbse->database_event_id = 0;
|
|
}
|
|
#endif /* HAVE_MYSQL */
|
|
|
|
#if defined(HAVE_MARIADB)
|
|
if (cam->conf->database_type == "mariadb") {
|
|
mysql_close(cam->dbse->database_mariadb);
|
|
cam->dbse->database_event_id = 0;
|
|
}
|
|
#endif /* HAVE_MYSQL */
|
|
|
|
#ifdef HAVE_PGSQL
|
|
if (cam->conf->database_type == "postgresql") {
|
|
PQfinish(cam->dbse->database_pg);
|
|
}
|
|
#endif /* HAVE_PGSQL */
|
|
|
|
#ifdef HAVE_SQLITE3
|
|
/* Close the SQLite database */
|
|
if (cam->conf->database_type == "sqlite3") {
|
|
sqlite3_close(cam->dbse->database_sqlite3);
|
|
cam->dbse->database_sqlite3 = NULL;
|
|
}
|
|
#endif /* HAVE_SQLITE3 */
|
|
}
|
|
|
|
}
|
|
|
|
static void dbse_mysql_exec(char *sqlquery,struct ctx_cam *cam, int save_id)
|
|
{
|
|
|
|
#if defined(HAVE_MYSQL)
|
|
MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing mysql query");
|
|
if (mysql_query(cam->dbse->database_mysql, sqlquery) != 0) {
|
|
int error_code = mysql_errno(cam->dbse->database_mysql);
|
|
|
|
MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO
|
|
,_("Mysql query failed %s error code %d")
|
|
,mysql_error(cam->dbse->database_mysql), error_code);
|
|
/* Try to reconnect ONCE if fails continue and discard this sql query */
|
|
if (error_code >= 2000) {
|
|
// Close connection before start a new connection
|
|
mysql_close(cam->dbse->database_mysql);
|
|
|
|
cam->dbse->database_mysql = (MYSQL *) mymalloc(sizeof(MYSQL));
|
|
mysql_init(cam->dbse->database_mysql);
|
|
|
|
if (!mysql_real_connect(cam->dbse->database_mysql, cam->conf->database_host.c_str(),
|
|
cam->conf->database_user.c_str(), cam->conf->database_password.c_str(),
|
|
cam->conf->database_dbname.c_str(), cam->conf->database_port, NULL, 0)) {
|
|
MOTION_LOG(ALR, TYPE_DB, NO_ERRNO
|
|
,_("Cannot reconnect to MySQL"
|
|
" database %s on host %s with user %s MySQL error was %s"),
|
|
cam->conf->database_dbname.c_str(),
|
|
cam->conf->database_host.c_str(), cam->conf->database_user.c_str(),
|
|
mysql_error(cam->dbse->database_mysql));
|
|
} else {
|
|
MOTION_LOG(INF, TYPE_DB, NO_ERRNO
|
|
,_("Re-Connection to Mysql database '%s' Succeed")
|
|
,cam->conf->database_dbname.c_str());
|
|
if (mysql_query(cam->dbse->database_mysql, sqlquery) != 0) {
|
|
int error_my = mysql_errno(cam->dbse->database_mysql);
|
|
MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO
|
|
,_("after re-connection Mysql query failed %s error code %d")
|
|
,mysql_error(cam->dbse->database_mysql), error_my);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (save_id) {
|
|
cam->dbse->database_event_id = (uint64_t) mysql_insert_id(cam->dbse->database_mysql);
|
|
}
|
|
#else
|
|
(void)sqlquery;
|
|
(void)cam;
|
|
(void)save_id;
|
|
#endif /* HAVE_MYSQL HAVE_MARIADB*/
|
|
|
|
}
|
|
|
|
static void dbse_mariadb_exec(char *sqlquery,struct ctx_cam *cam, int save_id)
|
|
{
|
|
|
|
#if defined(HAVE_MARIADB)
|
|
MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing mysql query");
|
|
if (mysql_query(cam->dbse->database_mariadb, sqlquery) != 0) {
|
|
int error_code = mysql_errno(cam->dbse->database_mariadb);
|
|
|
|
MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO
|
|
,_("Mysql query failed %s error code %d")
|
|
,mysql_error(cam->dbse->database_mariadb), error_code);
|
|
/* Try to reconnect ONCE if fails continue and discard this sql query */
|
|
if (error_code >= 2000) {
|
|
// Close connection before start a new connection
|
|
mysql_close(cam->dbse->database_mariadb);
|
|
|
|
cam->dbse->database_mariadb = (MYSQL *) mymalloc(sizeof(MYSQL));
|
|
mysql_init(cam->dbse->database_mariadb);
|
|
|
|
if (!mysql_real_connect(cam->dbse->database_mariadb, cam->conf->database_host.c_str(),
|
|
cam->conf->database_user.c_str(), cam->conf->database_password.c_str(),
|
|
cam->conf->database_dbname.c_str(),cam->conf->database_port, NULL, 0)) {
|
|
MOTION_LOG(ALR, TYPE_DB, NO_ERRNO
|
|
,_("Cannot reconnect to MySQL"
|
|
" database %s on host %s with user %s MySQL error was %s"),
|
|
cam->conf->database_dbname.c_str(),
|
|
cam->conf->database_host.c_str(), cam->conf->database_user.c_str(),
|
|
mysql_error(cam->dbse->database_mariadb));
|
|
} else {
|
|
MOTION_LOG(INF, TYPE_DB, NO_ERRNO
|
|
,_("Re-Connection to Mysql database '%s' Succeed")
|
|
,cam->conf->database_dbname.c_str());
|
|
if (mysql_query(cam->dbse->database_mariadb, sqlquery) != 0) {
|
|
int error_my = mysql_errno(cam->dbse->database_mariadb);
|
|
MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO
|
|
,_("after re-connection Mysql query failed %s error code %d")
|
|
,mysql_error(cam->dbse->database_mariadb), error_my);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (save_id) {
|
|
cam->dbse->database_event_id = (uint64_t) mysql_insert_id(cam->dbse->database_mariadb);
|
|
}
|
|
#else
|
|
(void)sqlquery;
|
|
(void)cam;
|
|
(void)save_id;
|
|
#endif /* HAVE_MARIADB*/
|
|
|
|
}
|
|
|
|
static void dbse_pgsql_exec(char *sqlquery,struct ctx_cam *cam, int save_id)
|
|
{
|
|
#ifdef HAVE_PGSQL
|
|
MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing postgresql query");
|
|
PGresult *res;
|
|
|
|
res = PQexec(cam->dbse->database_pg, sqlquery);
|
|
|
|
if (PQstatus(cam->dbse->database_pg) == CONNECTION_BAD) {
|
|
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Connection to PostgreSQL database '%s' failed: %s")
|
|
,cam->conf->database_dbname.c_str(), PQerrorMessage(cam->dbse->database_pg));
|
|
|
|
// This function will close the connection to the server and attempt to reestablish a new connection to the same server,
|
|
// using all the same parameters previously used. This may be useful for error recovery if a working connection is lost
|
|
PQreset(cam->dbse->database_pg);
|
|
|
|
if (PQstatus(cam->dbse->database_pg) == CONNECTION_BAD) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Re-Connection to PostgreSQL database '%s' failed: %s")
|
|
,cam->conf->database_dbname.c_str(), PQerrorMessage(cam->dbse->database_pg));
|
|
} else {
|
|
MOTION_LOG(INF, TYPE_DB, NO_ERRNO
|
|
,_("Re-Connection to PostgreSQL database '%s' Succeed")
|
|
,cam->conf->database_dbname.c_str());
|
|
}
|
|
|
|
} else if (!(PQresultStatus(res) == PGRES_COMMAND_OK || PQresultStatus(res) == PGRES_TUPLES_OK)) {
|
|
MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO, "PGSQL query failed: [%s] %s %s",
|
|
sqlquery, PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res));
|
|
}
|
|
if (save_id) {
|
|
//ToDO: Find the equivalent option for pgsql
|
|
cam->dbse->database_event_id = 0;
|
|
}
|
|
|
|
PQclear(res);
|
|
#else
|
|
(void)sqlquery;
|
|
(void)cam;
|
|
(void)save_id;
|
|
#endif /* HAVE_PGSQL */
|
|
|
|
}
|
|
|
|
static void dbse_sqlite3_exec(char *sqlquery,struct ctx_cam *cam, int save_id)
|
|
{
|
|
#ifdef HAVE_SQLITE3
|
|
int res;
|
|
char *errmsg = 0;
|
|
MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, "Executing sqlite query");
|
|
res = sqlite3_exec(cam->dbse->database_sqlite3, sqlquery, NULL, 0, &errmsg);
|
|
if (res != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("SQLite error was %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
}
|
|
if (save_id) {
|
|
cam->dbse->database_event_id = 0;
|
|
}
|
|
#else
|
|
(void)sqlquery;
|
|
(void)cam;
|
|
(void)save_id;
|
|
#endif /* HAVE_SQLITE3 */
|
|
}
|
|
|
|
void dbse_exec(struct ctx_cam *cam, char *filename
|
|
, int sqltype, struct timespec *ts1, const char *cmd)
|
|
{
|
|
char sqlquery[PATH_MAX];
|
|
|
|
if (cam->conf->database_type == "") {
|
|
return;
|
|
}
|
|
|
|
if (mystreq(cmd,"pic_save")) {
|
|
mystrftime(cam, sqlquery, sizeof(sqlquery)
|
|
, cam->conf->sql_pic_save.c_str()
|
|
, ts1, filename, sqltype);
|
|
} else if (mystreq(cmd,"movie_start")) {
|
|
mystrftime(cam, sqlquery, sizeof(sqlquery)
|
|
, cam->conf->sql_movie_start.c_str()
|
|
, ts1, filename, sqltype);
|
|
} else if (mystreq(cmd,"movie_end")) {
|
|
mystrftime(cam, sqlquery, sizeof(sqlquery)
|
|
, cam->conf->sql_movie_end.c_str()
|
|
, ts1, filename, sqltype);
|
|
} else if (mystreq(cmd,"event_start")) {
|
|
mystrftime(cam, sqlquery, sizeof(sqlquery)
|
|
, cam->conf->sql_event_start.c_str()
|
|
, ts1, filename, sqltype);
|
|
} else if (mystreq(cmd,"event_end")) {
|
|
mystrftime(cam, sqlquery, sizeof(sqlquery)
|
|
, cam->conf->sql_event_end.c_str()
|
|
, ts1, filename, sqltype);
|
|
}
|
|
|
|
if (strlen(sqlquery) <= 0) {
|
|
MOTION_LOG(WRN, TYPE_DB, NO_ERRNO, "Ignoring empty sql query");
|
|
return;
|
|
}
|
|
|
|
if (cam->conf->database_type == "mysql") {
|
|
dbse_mysql_exec(sqlquery, cam, 0);
|
|
} else if (cam->conf->database_type == "mariadb") {
|
|
dbse_mariadb_exec(sqlquery, cam, 0);
|
|
} else if (cam->conf->database_type == "postgresql") {
|
|
dbse_pgsql_exec(sqlquery, cam, 0);
|
|
} else if (cam->conf->database_type == "sqlite3") {
|
|
dbse_sqlite3_exec(sqlquery, cam, 0);
|
|
}
|
|
|
|
}
|
|
|
|
/* Execute query against the motionplus database */
|
|
void dbse_motpls_exec(const char *sqlquery, struct ctx_cam *cam)
|
|
{
|
|
int retcd;
|
|
char *errmsg = 0;
|
|
|
|
if (cam->dbsemp == NULL) {
|
|
return;
|
|
}
|
|
if (cam->dbsemp->database_sqlite3 == NULL) {
|
|
return;
|
|
}
|
|
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3, sqlquery, NULL, 0, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("SQLite error was %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
}
|
|
}
|
|
|
|
/* sqlite query result call back */
|
|
static int dbse_motpls_cb(
|
|
void *ptr, int arg_nb, char **arg_val, char **col_nm)
|
|
{
|
|
ctx_cam *cam = (ctx_cam *)ptr;
|
|
int indx;
|
|
|
|
(void)col_nm;
|
|
|
|
if (cam->dbsemp->dbse_action == DBSE_ACT_CHKTBL) {
|
|
for (indx=0; indx < arg_nb; indx++) {
|
|
if (mystrceq(arg_val[indx],"motionplus")) {
|
|
cam->dbsemp->table_ok = true;
|
|
}
|
|
}
|
|
} else if (cam->dbsemp->dbse_action == DBSE_ACT_GETCNT) {
|
|
for (indx=0; indx < arg_nb; indx++) {
|
|
if (mystrceq(col_nm[indx],"movie_cnt")) {
|
|
cam->dbsemp->movie_cnt =atoi(arg_val[indx]);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Process query records for movie list */
|
|
static int dbse_motpls_cb_movies(
|
|
void *ptr, int arg_nb, char **arg_val, char **col_nm)
|
|
{
|
|
ctx_cam *cam = (ctx_cam *)ptr;
|
|
struct stat statbuf;
|
|
int indx, rnbr, flen;
|
|
|
|
if (cam->dbsemp->dbse_action == DBSE_ACT_GETTBL) {
|
|
rnbr = cam->dbsemp->rec_indx;
|
|
if (rnbr < cam->dbsemp->movie_cnt) {
|
|
cam->dbsemp->movie_list[rnbr].found = false;
|
|
|
|
cam->dbsemp->movie_list[rnbr].rowid = -1;
|
|
cam->dbsemp->movie_list[rnbr].camid = -1;
|
|
cam->dbsemp->movie_list[rnbr].movie_nm = NULL;
|
|
cam->dbsemp->movie_list[rnbr].full_nm = NULL;
|
|
cam->dbsemp->movie_list[rnbr].movie_sz = 0;
|
|
cam->dbsemp->movie_list[rnbr].movie_dtl = 0;
|
|
cam->dbsemp->movie_list[rnbr].movie_tmc = NULL;
|
|
cam->dbsemp->movie_list[rnbr].movie_tmc = NULL;
|
|
cam->dbsemp->movie_list[rnbr].diff_avg = 0;
|
|
cam->dbsemp->movie_list[rnbr].sdev_min = 0;
|
|
cam->dbsemp->movie_list[rnbr].sdev_max = 0;
|
|
cam->dbsemp->movie_list[rnbr].sdev_avg = 0;
|
|
|
|
for (indx=0; indx < arg_nb; indx++) {
|
|
if (arg_val[indx] != NULL) {
|
|
if (mystreq(col_nm[indx],"rowid")) {
|
|
cam->dbsemp->movie_list[rnbr].rowid = atoi(arg_val[indx]);
|
|
|
|
} else if (mystreq(col_nm[indx],"camid")) {
|
|
cam->dbsemp->movie_list[rnbr].camid = atoi(arg_val[indx]);
|
|
|
|
} else if (mystreq(col_nm[indx],"movie_nm")) {
|
|
flen = strlen(arg_val[indx]);
|
|
cam->dbsemp->movie_list[rnbr].movie_nm =
|
|
(char*)mymalloc(flen + 1);
|
|
snprintf(cam->dbsemp->movie_list[rnbr].movie_nm
|
|
,flen+1,"%s",arg_val[indx]);
|
|
flen += cam->conf->target_dir.length() + 2;
|
|
cam->dbsemp->movie_list[rnbr].full_nm =
|
|
(char*)mymalloc(flen + 1);
|
|
snprintf(cam->dbsemp->movie_list[rnbr].full_nm
|
|
, flen, "%s/%s", cam->conf->target_dir.c_str()
|
|
, arg_val[indx]);
|
|
if (stat(cam->dbsemp->movie_list[rnbr].full_nm,
|
|
&statbuf) == 0) {
|
|
cam->dbsemp->movie_list[rnbr].found = true;
|
|
}
|
|
|
|
} else if (mystreq(col_nm[indx],"movie_sz")) {
|
|
cam->dbsemp->movie_list[rnbr].movie_sz =atoi(arg_val[indx]);
|
|
|
|
} else if (mystreq(col_nm[indx],"movie_dtl")) {
|
|
cam->dbsemp->movie_list[rnbr].movie_dtl =atoi(arg_val[indx]);
|
|
|
|
} else if (mystreq(col_nm[indx],"movie_tmc")) {
|
|
flen = strlen(arg_val[indx]);
|
|
cam->dbsemp->movie_list[rnbr].movie_tmc =
|
|
(char*)mymalloc(flen + 1);
|
|
snprintf(cam->dbsemp->movie_list[rnbr].movie_tmc
|
|
,flen+1,"%s",arg_val[indx]);
|
|
|
|
} else if (mystreq(col_nm[indx],"diff_avg")) {
|
|
cam->dbsemp->movie_list[rnbr].diff_avg =atoi(arg_val[indx]);
|
|
} else if (mystreq(col_nm[indx],"sdev_min")) {
|
|
cam->dbsemp->movie_list[rnbr].sdev_min =atoi(arg_val[indx]);
|
|
} else if (mystreq(col_nm[indx],"sdev_max")) {
|
|
cam->dbsemp->movie_list[rnbr].sdev_max =atoi(arg_val[indx]);
|
|
} else if (mystreq(col_nm[indx],"sdev_avg")) {
|
|
cam->dbsemp->movie_list[rnbr].sdev_avg =atoi(arg_val[indx]);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cam->dbsemp->rec_indx++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Process query list of columns in motionplus table*/
|
|
static int dbse_motpls_cb_cols(
|
|
void *ptr, int arg_nb, char **arg_val, char **col_nm)
|
|
{
|
|
ctx_cam *cam = (ctx_cam *)ptr;
|
|
int indx, indx2;
|
|
|
|
if (cam->dbsemp->dbse_action == DBSE_ACT_GETCOLS) {
|
|
for (indx=0; indx < arg_nb; indx++) {
|
|
if (mystreq(col_nm[indx],"col_nm")) {
|
|
for (indx2=0; indx2 < cam->dbsemp->cols_cnt; indx2++) {
|
|
if (mystreq(arg_val[indx]
|
|
, cam->dbsemp->cols_list[indx2].col_nm)) {
|
|
cam->dbsemp->cols_list[indx2].found = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Free the movies lists*/
|
|
static void dbse_motpls_free_movies(struct ctx_cam *cam)
|
|
{
|
|
int indx;
|
|
|
|
if (cam->dbsemp == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (cam->dbsemp->movie_list != NULL) {
|
|
for (indx=0; indx<cam->dbsemp->movie_cnt; indx++) {
|
|
myfree(&cam->dbsemp->movie_list[indx].movie_nm);
|
|
myfree(&cam->dbsemp->movie_list[indx].full_nm);
|
|
myfree(&cam->dbsemp->movie_list[indx].movie_tmc);
|
|
}
|
|
myfree(&cam->dbsemp->movie_list);
|
|
}
|
|
cam->dbsemp->movie_cnt = 0;
|
|
|
|
}
|
|
|
|
/* Free the cols lists*/
|
|
static void dbse_motpls_free_cols(struct ctx_cam *cam)
|
|
{
|
|
int indx;
|
|
|
|
if (cam->dbsemp == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (cam->dbsemp->cols_list != NULL) {
|
|
for (indx=0; indx<cam->dbsemp->cols_cnt; indx++) {
|
|
myfree(&cam->dbsemp->cols_list[indx].col_nm);
|
|
myfree(&cam->dbsemp->cols_list[indx].col_typ);
|
|
}
|
|
myfree(&cam->dbsemp->cols_list);
|
|
}
|
|
cam->dbsemp->cols_cnt = 0;
|
|
|
|
}
|
|
|
|
/* Create array of all the columns in current version */
|
|
static void dbse_motpls_col_list(struct ctx_cam *cam)
|
|
{
|
|
int indx;
|
|
|
|
dbse_motpls_free_cols(cam);
|
|
|
|
cam->dbsemp->cols_cnt = 9;
|
|
|
|
cam->dbsemp->cols_list =(ctx_dbsemp_col *)
|
|
mymalloc(sizeof(ctx_dbsemp_col) * cam->dbsemp->cols_cnt);
|
|
|
|
/* The size of 30 is arbitrary */
|
|
for (indx=0; indx<cam->dbsemp->cols_cnt; indx++) {
|
|
cam->dbsemp->cols_list[indx].col_nm = (char*)mymalloc(30);
|
|
cam->dbsemp->cols_list[indx].col_typ = (char*)mymalloc(30);
|
|
cam->dbsemp->cols_list[indx].found = false;
|
|
}
|
|
|
|
snprintf(cam->dbsemp->cols_list[0].col_nm, 30, "%s", "camid");
|
|
snprintf(cam->dbsemp->cols_list[0].col_typ, 30, "%s", "int");
|
|
|
|
snprintf(cam->dbsemp->cols_list[1].col_nm, 30, "%s", "movie_nm");
|
|
snprintf(cam->dbsemp->cols_list[1].col_typ, 30, "%s", "text");
|
|
|
|
snprintf(cam->dbsemp->cols_list[2].col_nm, 30, "%s", "movie_sz");
|
|
snprintf(cam->dbsemp->cols_list[2].col_typ, 30, "%s", "int");
|
|
|
|
snprintf(cam->dbsemp->cols_list[3].col_nm, 30, "%s", "movie_dtl");
|
|
snprintf(cam->dbsemp->cols_list[3].col_typ, 30, "%s", "int");
|
|
|
|
snprintf(cam->dbsemp->cols_list[4].col_nm, 30, "%s", "movie_tmc");
|
|
snprintf(cam->dbsemp->cols_list[4].col_typ, 30, "%s", "text");
|
|
|
|
snprintf(cam->dbsemp->cols_list[5].col_nm, 30, "%s", "diff_avg");
|
|
snprintf(cam->dbsemp->cols_list[5].col_typ, 30, "%s", "int");
|
|
|
|
snprintf(cam->dbsemp->cols_list[6].col_nm, 30, "%s", "sdev_min");
|
|
snprintf(cam->dbsemp->cols_list[6].col_typ, 30, "%s", "int");
|
|
|
|
snprintf(cam->dbsemp->cols_list[7].col_nm, 30, "%s", "sdev_max");
|
|
snprintf(cam->dbsemp->cols_list[7].col_typ, 30, "%s", "int");
|
|
|
|
snprintf(cam->dbsemp->cols_list[8].col_nm, 30, "%s", "sdev_avg");
|
|
snprintf(cam->dbsemp->cols_list[8].col_typ, 30, "%s", "int");
|
|
|
|
}
|
|
|
|
/* Validate table has our cols. If not add the cols */
|
|
static int dbse_motpls_validate_cols(struct ctx_cam *cam)
|
|
{
|
|
int retcd, indx;
|
|
char *errmsg = 0;
|
|
std::string sqlquery;
|
|
|
|
dbse_motpls_col_list(cam);
|
|
|
|
sqlquery =
|
|
" select name as col_nm "
|
|
" from pragma_table_info('motionplus');";
|
|
cam->dbsemp->dbse_action = DBSE_ACT_GETCOLS;
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3
|
|
, sqlquery.c_str(), dbse_motpls_cb_cols, cam, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
, _("Error retrieving table columns: %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
return -1;
|
|
}
|
|
|
|
for (indx=0; indx<cam->dbsemp->cols_cnt; indx++) {
|
|
if (cam->dbsemp->cols_list[indx].found == false) {
|
|
sqlquery = "Alter table motionplus add column ";
|
|
sqlquery += std::string(cam->dbsemp->cols_list[indx].col_nm) + " ";
|
|
sqlquery += std::string(cam->dbsemp->cols_list[indx].col_typ) + " ;";
|
|
dbse_motpls_exec(sqlquery.c_str(), cam);
|
|
}
|
|
}
|
|
|
|
dbse_motpls_free_cols(cam);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Validate database has our required table, if not create it */
|
|
static int dbse_motpls_validate(struct ctx_cam *cam)
|
|
{
|
|
int retcd;
|
|
char *errmsg = 0;
|
|
std::string sqlquery;
|
|
|
|
sqlquery =
|
|
"select name from sqlite_master"
|
|
" where type='table' "
|
|
" and name='motionplus';";
|
|
cam->dbsemp->table_ok = false;
|
|
cam->dbsemp->dbse_action = DBSE_ACT_CHKTBL;
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3
|
|
, sqlquery.c_str(), dbse_motpls_cb, cam, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
, _("Error checking table: %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
return -1;
|
|
}
|
|
|
|
if (cam->dbsemp->table_ok == false) {
|
|
sqlquery =
|
|
"create table motionplus ("
|
|
" camid int"
|
|
");";
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3
|
|
, sqlquery.c_str(), 0, 0, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
, _("Error creating table: %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
retcd = dbse_motpls_validate_cols(cam);
|
|
|
|
return retcd;
|
|
|
|
}
|
|
|
|
/* Open and validate the motionplus database*/
|
|
void dbse_motpls_init(struct ctx_cam *cam)
|
|
{
|
|
std::string dbname;
|
|
|
|
cam->dbsemp = new ctx_dbsemp;
|
|
cam->dbsemp->movie_cnt = 0;
|
|
cam->dbsemp->movie_list = NULL;
|
|
cam->dbsemp->cols_cnt = 0;
|
|
cam->dbsemp->cols_list = NULL;
|
|
|
|
dbname = cam->conf->target_dir + "/dbcam" +
|
|
std::to_string(cam->camera_id)+".db";
|
|
|
|
MOTION_LOG(NTC, TYPE_DB, NO_ERRNO, "%s", dbname.c_str());
|
|
|
|
if (sqlite3_open(dbname.c_str(), &cam->dbsemp->database_sqlite3) != SQLITE_OK) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
,_("Can't open database %s : %s")
|
|
,dbname.c_str(), sqlite3_errmsg(cam->dbsemp->database_sqlite3));
|
|
sqlite3_close(cam->dbsemp->database_sqlite3);
|
|
cam->dbsemp->database_sqlite3 = NULL;
|
|
return;
|
|
}
|
|
|
|
if (dbse_motpls_validate(cam) != 0) {
|
|
sqlite3_close(cam->dbsemp->database_sqlite3);
|
|
cam->dbsemp->database_sqlite3 = NULL;
|
|
return;
|
|
};
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* Close the motionplus database */
|
|
void dbse_motpls_deinit(struct ctx_cam *cam)
|
|
{
|
|
if (cam->dbsemp != NULL) {
|
|
if (cam->dbsemp->database_sqlite3 != NULL) {
|
|
sqlite3_close(cam->dbsemp->database_sqlite3);
|
|
}
|
|
cam->dbsemp->database_sqlite3 = NULL;
|
|
dbse_motpls_free_movies(cam);
|
|
dbse_motpls_free_cols(cam);
|
|
delete cam->dbsemp;
|
|
}
|
|
}
|
|
|
|
/* Populate the list of the movies from the database*/
|
|
int dbse_motpls_getlist(struct ctx_cam *cam)
|
|
{
|
|
int retcd, indx;
|
|
char *errmsg = 0;
|
|
std::string sqlquery;
|
|
|
|
if (cam->dbsemp == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
dbse_motpls_free_movies(cam);
|
|
|
|
if (cam->dbsemp->database_sqlite3 == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
sqlquery =
|
|
"select count(*) as movie_cnt "
|
|
" from motionplus "
|
|
" where camid = " + std::to_string(cam->camera_id) + ";";
|
|
cam->dbsemp->dbse_action = DBSE_ACT_GETCNT;
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3
|
|
, sqlquery.c_str(), dbse_motpls_cb, cam, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
, _("Error counting table: %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
return -1;
|
|
}
|
|
|
|
if (cam->dbsemp->movie_cnt > 0) {
|
|
cam->dbsemp->movie_list =(ctx_dbsemp_rec *)
|
|
mymalloc(sizeof(ctx_dbsemp_rec)*cam->dbsemp->movie_cnt);
|
|
cam->dbsemp->rec_indx = 0;
|
|
sqlquery =
|
|
" select rowid, * from motionplus "
|
|
" where camid = " + std::to_string(cam->camera_id) + ";";
|
|
cam->dbsemp->dbse_action = DBSE_ACT_GETTBL;
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3
|
|
, sqlquery.c_str(), dbse_motpls_cb_movies, cam, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO
|
|
, _("Error retrieving table: %s"), errmsg);
|
|
sqlite3_free(errmsg);
|
|
return -1;
|
|
}
|
|
/* Clean the database of files that were removed*/
|
|
for (indx=0; indx<cam->dbsemp->movie_cnt; indx++) {
|
|
if (cam->dbsemp->movie_list[indx].found == false) {
|
|
sqlquery =
|
|
" delete from motionplus "
|
|
" where camid = " + std::to_string(cam->camera_id) +
|
|
" and rowid = " + std::to_string(
|
|
cam->dbsemp->movie_list[indx].rowid)+";";
|
|
dbse_motpls_exec(sqlquery.c_str(),cam);
|
|
}
|
|
/*since we run vacuum after this, the rowids will no longer be valid*/
|
|
cam->dbsemp->movie_list[indx].rowid = -1;
|
|
}
|
|
sqlquery ="vacuum";
|
|
dbse_motpls_exec(sqlquery.c_str(),cam);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Add a record for new movies */
|
|
void dbse_motpls_addrec(struct ctx_cam *cam,char *fname, struct timespec *ts1)
|
|
{
|
|
std::string sqlquery;
|
|
struct stat statbuf;
|
|
char *errmsg = 0;
|
|
int retcd, dirlen;
|
|
int64_t bsz;
|
|
char dtl[12];
|
|
char tmc[12];
|
|
uint64_t diff_avg, sdev_avg;
|
|
|
|
struct tm timestamp_tm;
|
|
|
|
if (cam->dbsemp == NULL) {
|
|
return;
|
|
}
|
|
if (cam->dbsemp->database_sqlite3 == NULL) {
|
|
return;
|
|
}
|
|
|
|
/* Movie file times */
|
|
if (stat(fname, &statbuf) == 0) {
|
|
bsz = statbuf.st_size;
|
|
} else {
|
|
bsz = 0;
|
|
}
|
|
localtime_r(&ts1->tv_sec, ×tamp_tm);
|
|
strftime(dtl, 11, "%G%m%d", ×tamp_tm);
|
|
strftime(tmc, 11, "%I:%M%p", ×tamp_tm);
|
|
|
|
/* Add 1 for last slash */
|
|
dirlen = cam->conf->target_dir.length() + 1;
|
|
if (dirlen >= (int)strlen(fname)) {
|
|
return;
|
|
}
|
|
|
|
if (cam->info_diff_cnt != 0) {
|
|
diff_avg = (cam->info_diff_tot / cam->info_diff_cnt);
|
|
} else {
|
|
diff_avg =0;
|
|
}
|
|
if (cam->info_diff_cnt != 0) {
|
|
sdev_avg = (cam->info_sdev_tot / cam->info_diff_cnt);
|
|
} else {
|
|
sdev_avg =0;
|
|
}
|
|
|
|
sqlquery = "insert into motionplus ";
|
|
sqlquery += " (camid, movie_nm, movie_sz, movie_dtl, movie_tmc ";
|
|
sqlquery += " , diff_avg, sdev_min, sdev_max, sdev_avg)";
|
|
sqlquery += " values ("+std::to_string(cam->camera_id);
|
|
sqlquery += " ,'" + std::string(fname + dirlen) + "'";
|
|
sqlquery += " ," + std::to_string(bsz);
|
|
sqlquery += " ," + std::string(dtl);
|
|
sqlquery += " ,'" + std::string(tmc)+ "'";
|
|
sqlquery += " ," + std::to_string(diff_avg);
|
|
sqlquery += " ," + std::to_string(cam->info_sdev_min);
|
|
sqlquery += " ," + std::to_string(cam->info_sdev_max);
|
|
sqlquery += " ," + std::to_string(sdev_avg);
|
|
sqlquery += ")";
|
|
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3, sqlquery.c_str(), NULL, 0, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("SQLite error %d was %s"),retcd, errmsg);
|
|
dbse_motpls_deinit(cam);
|
|
dbse_motpls_init(cam);
|
|
retcd = sqlite3_exec(cam->dbsemp->database_sqlite3, sqlquery.c_str(), NULL, 0, &errmsg);
|
|
if (retcd != SQLITE_OK ) {
|
|
MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("Serious error %d was %s"),retcd, errmsg);
|
|
dbse_motpls_deinit(cam);
|
|
}
|
|
}
|
|
}
|