diff --git a/doc/motion_config.html b/doc/motion_config.html index 530ba9f1..a85d05e9 100644 --- a/doc/motion_config.html +++ b/doc/motion_config.html @@ -2159,8 +2159,8 @@ threshold %Q Number of labels from despeckle - %{dbeventid} - See sql_query_start + %{eventid} + Unique identifier for event (cam id + date/time) %$ @@ -5499,20 +5499,6 @@ The sql_log_* options do not impact sql_query_start, which, if specified, is always executed at event start.

- Configuration option sql_query_start allows motion-detected - events to be assigned unique event IDs and recorded in the database independently from - Motion's recording of images and movies. - When this SQL statement and the related database table schema are so configured, the - database assigns an event ID that is globally unique within its table and returns the ID - to the motion thread that recorded the event. - The conversion specifier %{dbeventid} may then be included in subsequently executed - sql_query and sql_query_stop - statements to insert that event ID into database records created for associated files or - to control updates of event-related records. - For example, sql_query_stop may specify a SQL UPDATE statement - that inserts event end time into a recently-started event's record. (Note that Motion's "event" - data item, conversion specifier %v, is unique only within a given camera and Motion run). -

Motion does not provide for deletion of the database records it creates nor for the images and movies they catalog. Other user-provided scripts or software may analyze, search, display, @@ -5530,28 +5516,6 @@ time_stamp TIMESTAMP NOT NULL, frame INTEGER, motion_event INTEGER, movie_end TIMESTAMP);

- Sample SQL defining a table for Motion-recognized events, each with a unique %{dbeventid} ID: -

- MySQL; MariaDB : CREATE TABLE event (event_id INTEGER PRIMARY KEY AUTO_INCREMENT, - camera INTEGER NOT NULL, event_start DATETIME NOT NULL, event_stop DATETIME, - motion_event INTEGER NOT NULL, event_text VARCHAR(255)); -

- SQLite3 : CREATE TABLE event (event_id INTEGER PRIMARY KEY AUTOINCREMENT, - camera INTEGER NOT NULL, event_start REAL NOT NULL, event_stop REAL, - motion_event INTEGER NOT NULL, event_text TEXT); - (SQLite3 has no native timestamp data type; REAL supports timestamps down to microsecond precision.) -

- PostgreSQL : - CREATE TABLE event (event_id SERIAL PRIMARY KEY, camera INTEGER NOT NULL, - event_start TIMESTAMP NOT NULL, event_stop TIMESTAMP, motion_event INTEGER NOT NULL, - motion_pixels INTEGER, motion_x INTEGER, motion_y INTEGER, event_text VARCHAR);
- sql_query_start INSERT INTO event values (DEFAULT, %t, '%Y-%m-%d %T', NULL, %v, - %D, %K, %L, %C) RETURNING event_id
- sql_query_stop UPDATE event SET event_stop='%Y-%m-%d %T' WHERE %n=8 AND - event_id=%{dbeventid} AND event_stop IS NULL - (assumes movie_output and - sql_log_movie are enabled) -

database_type

@@ -5704,8 +5668,6 @@ VALUES(%t, '%f', %q, %n, '%Y-%m-%d %T', '%C')
INSERT IGNORE INTO security(camera, file_name, year, month, day, hour, minute) VALUES (8, '%f', %Y, %m,%d, %H, %M)
- INSERT INTO security(camera, event_id, filename, frame, file_type, time_stamp) - VALUES(%t, %{dbeventid}, '%f', %q, %n, '%Y-%m-%d %T')

@@ -5723,26 +5685,6 @@ You can use Conversion Specifiers in this statement.

- Upon successful INSERTion of a record into a database table whose schema generates - a positive integer ID for each new record, the returned mysql_insert_id(), - sqlite3_last_insert_rowid(), or PostgreSQL INSERT ... RETURNING - value is saved until the next sql_query_start is executed - for the same camera. - %{dbeventid} can then be used as a value in sql_query - or sql_query_stop statements. - To obtain %{dbeventid} for PostgreSQL, an INSERT statement must include a - RETURNING clause that yields a single positive integer value. - Absent a valid ID value returned by the database, %{dbeventid} yields zero. -

- Sample Queries (presuming the schema of table event defines a column that generates unique IDs): -

- MySQL; MariaDB; SQLite3: - INSERT INTO event(camera, event_start) VALUES(%t, '%Y-%m-%d %T') -

- PostgreSQL: - INSERT INTO event(camera, event_start) VALUES(%t, '%Y-%m-%d %T') RETURNING event_id
-

-

sql_query_stop

@@ -5766,9 +5708,6 @@ Sample Queries:

UPDATE security SET movie_end='%Y-%m-%d %T' WHERE filename='%f'
- UPDATE event SET event_stop='%Y-%m-%d %T' WHERE %n=8 AND event_id=%{dbeventid} - AND event_stop IS NULL -

diff --git a/src/dbse.c b/src/dbse.c index fef6a46d..a71b9ffa 100644 --- a/src/dbse.c +++ b/src/dbse.c @@ -155,7 +155,6 @@ static int dbse_init_mysql(struct context *cnt) #if defined(HAVE_MYSQL) int dbport; if ((mystreq(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) { - cnt->database_event_id = 0; cnt->database_mysql = mymalloc(sizeof(MYSQL)); mysql_init(cnt->database_mysql); if ((cnt->conf.database_port < 0) || (cnt->conf.database_port > 65535)) { @@ -195,7 +194,6 @@ static int dbse_init_mariadb(struct context *cnt) #if defined(HAVE_MARIADB) int dbport; if ((mystreq(cnt->conf.database_type, "mariadb")) && (cnt->conf.database_dbname)) { - cnt->database_event_id = 0; cnt->database_mariadb = mymalloc(sizeof(MYSQL)); mysql_init(cnt->database_mariadb); if ((cnt->conf.database_port < 0) || (cnt->conf.database_port > 65535)) { @@ -273,11 +271,6 @@ static int dbse_init_pgsql(struct context *cnt) #ifdef HAVE_PGSQL if ((mystreq(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) { 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'", cnt->conf.database_dbname, /* dbname */ @@ -290,12 +283,11 @@ static int dbse_init_pgsql(struct context *cnt) cnt->database_pgsql = PQconnectdb(connstring); if (PQstatus(cnt->database_pgsql) == CONNECTION_BAD) { MOTION_LOG(ERR, TYPE_DB, NO_ERRNO - ,_("Connection to PostgreSQL database '%s' failed: %s") - ,cnt->conf.database_dbname, PQerrorMessage(cnt->database_pgsql)); + ,_("Connection to PostgreSQL database '%s' failed: %s") + ,cnt->conf.database_dbname, PQerrorMessage(cnt->database_pgsql)); return -2; } cnt->eid_db_format = dbeid_undetermined; - cnt->database_event_id = 0; } #else (void)cnt; /* Avoid compiler warnings */ @@ -347,7 +339,6 @@ void dbse_deinit(struct context *cnt) if ( (mystreq(cnt->conf.database_type, "mysql")) && (cnt->conf.database_dbname)) { mysql_thread_end(); mysql_close(cnt->database_mysql); - cnt->database_event_id = 0; } #endif /* HAVE_MYSQL */ @@ -355,7 +346,6 @@ void dbse_deinit(struct context *cnt) if ( (mystreq(cnt->conf.database_type, "mariadb")) && (cnt->conf.database_dbname)) { mysql_thread_end(); mysql_close(cnt->database_mariadb); - cnt->database_event_id = 0; } #endif /* HAVE_MARIADB */ @@ -363,7 +353,6 @@ void dbse_deinit(struct context *cnt) if ((mystreq(cnt->conf.database_type, "postgresql")) && (cnt->conf.database_dbname)) { PQfinish(cnt->database_pgsql); cnt->database_pgsql = NULL; - cnt->database_event_id = 0; } #endif /* HAVE_PGSQL */ @@ -399,7 +388,7 @@ void dbse_sqlmask_update(struct context *cnt) * dbse_exec_mysql * */ -static void dbse_exec_mysql(char *sqlquery, struct context *cnt, int save_id) +static void dbse_exec_mysql(char *sqlquery, struct context *cnt) { #if defined(HAVE_MYSQL) if (mystreq(cnt->conf.database_type, "mysql")) { @@ -440,14 +429,10 @@ static void dbse_exec_mysql(char *sqlquery, struct context *cnt, int save_id) } } } - if (save_id) { - cnt->database_event_id = (unsigned long long) mysql_insert_id(cnt->database_mysql); - } } #else (void)sqlquery; (void)cnt; - (void)save_id; #endif /* HAVE_MYSQL*/ } @@ -455,7 +440,7 @@ static void dbse_exec_mysql(char *sqlquery, struct context *cnt, int save_id) * dbse_exec_mariadb * */ -static void dbse_exec_mariadb(char *sqlquery, struct context *cnt, int save_id) +static void dbse_exec_mariadb(char *sqlquery, struct context *cnt) { #if defined(HAVE_MARIADB) if (mystreq(cnt->conf.database_type, "mariadb")) { @@ -496,14 +481,10 @@ static void dbse_exec_mariadb(char *sqlquery, struct context *cnt, int save_id) } } } - if (save_id) { - cnt->database_event_id = (unsigned long long) mysql_insert_id(cnt->database_mariadb); - } } #else (void)sqlquery; (void)cnt; - (void)save_id; #endif /* HAVE_MYSQL HAVE_MARIADB*/ } @@ -512,7 +493,7 @@ static void dbse_exec_mariadb(char *sqlquery, struct context *cnt, int save_id) * dbse_exec_pgsql * */ -static void dbse_exec_pgsql(char *sqlquery, struct context *cnt, int save_id) +static void dbse_exec_pgsql(char *sqlquery, struct context *cnt) { #ifdef HAVE_PGSQL if (mystreq(cnt->conf.database_type, "postgresql") && cnt->database_pgsql) { @@ -561,47 +542,6 @@ static void dbse_exec_pgsql(char *sqlquery, struct context *cnt, int save_id) } else if (!(estat == PGRES_COMMAND_OK || estat == PGRES_TUPLES_OK)) { MOTION_LOG(ERR, TYPE_DB, SHOW_ERRNO, _("PGSQL query failed: [%s] %s %s"), sqlquery, PQresStatus(PQresultStatus(res)), PQresultErrorMessage(res)); - } else if (save_id) { - /* sqlquery processing is complete unless it potentially returns an event ID value; - * save_id optionally allows SQL INSERT RETURNING a single positive integer value, - * e.g., an auto-incremented unique row ID. */ - if (cnt->eid_db_format < dbeid_undetermined) { - /* A previous successful sqlquery returned nothing or an invalid value. This - * is either intended or a non-transient flaw in a table schema or sqlquery. */ - } else { - if (estat == PGRES_TUPLES_OK) { /* returned DB record set (possibly empty) */ - if (PQntuples(res) == 1 && PQnfields(res) == 1 && !PQgetisnull(res, 0, 0) && \ - ((cnt->eid_db_format=PQfformat(res, 0)) == 0)) { /* got one char string */ - /* PQfformat()==0: null-term string, guaranteed unless DECLARE CURSOR BINARY - * or extended query protocol (PGSQL Doc.sec.51.2.2; PGSQL>v9, 52.2.2) */ - char *eid_db_val; - char *endptr; - eid_db_val = PQgetvalue(res, 0, 0); - MOTION_LOG(DBG, TYPE_DB, NO_ERRNO, _("INSERT ... RETURNING VALUE=\"%s\""), - eid_db_val); - cnt->database_event_id = strtoll(eid_db_val, &endptr, 10); - /* "unsigned" dcl overriden by cast, else "<1" test fails if negative */ - if (*endptr != '\0' || (long long)cnt->database_event_id < 1) { - /* not numeric or not positive or not integer */ - cnt->eid_db_format = dbeid_not_valid; /* abandon event ID retrieval */ - } - } else if (PQntuples(res) < 1) { /* returned empty record set */ - cnt->eid_db_format = dbeid_no_return; - } else { /* returned NULL, BINARY value, multiple values, or muliple records */ - cnt->eid_db_format = dbeid_not_valid; /* abandon event ID retrieval */ - } - } else { /* nothing returned; OK if %{dbeventid} never used */ - cnt->eid_db_format = dbeid_no_return; - } - if (cnt->eid_db_format == dbeid_not_valid) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("Invalid event ID returned by SQL query \"%s\""), - sqlquery); - } - if (cnt->eid_db_format && cnt-> database_event_id) { - /* retrieval failed; nullify any earlier retrieved value */ - cnt->database_event_id = 0; - } - } } if (res) { PQclear(res); @@ -610,7 +550,6 @@ static void dbse_exec_pgsql(char *sqlquery, struct context *cnt, int save_id) #else (void)sqlquery; (void)cnt; - (void)save_id; #endif /* HAVE_PGSQL */ } @@ -619,7 +558,7 @@ static void dbse_exec_pgsql(char *sqlquery, struct context *cnt, int save_id) * dbse_exec_sqlite3 * */ -static void dbse_exec_sqlite3(char *sqlquery, struct context *cnt, int save_id) +static void dbse_exec_sqlite3(char *sqlquery, struct context *cnt) { #ifdef HAVE_SQLITE3 if ((mystreq(cnt->conf.database_type, "sqlite3")) && (cnt->conf.database_dbname)) { @@ -630,18 +569,12 @@ static void dbse_exec_sqlite3(char *sqlquery, struct context *cnt, int save_id) if (res != SQLITE_OK ) { MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, _("SQLite3 error was %s"), errmsg); sqlite3_free(errmsg); - if (save_id) { - cnt->database_event_id = 0; - } - } else if (save_id) { - cnt->database_event_id = sqlite3_last_insert_rowid(cnt->database_sqlite3); } } #else (void)sqlquery; (void)cnt; - (void)save_id; #endif /* HAVE_SQLITE3 */ } @@ -663,13 +596,13 @@ void dbse_firstmotion(struct context *cnt) } if (mystreq(cnt->conf.database_type,"mysql")) { - dbse_exec_mysql(sqlquery, cnt, 1); + dbse_exec_mysql(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"mariadb")) { - dbse_exec_mariadb(sqlquery, cnt, 1); + dbse_exec_mariadb(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"postgresql")) { - dbse_exec_pgsql(sqlquery, cnt, 1); + dbse_exec_pgsql(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"sqlite3")) { - dbse_exec_sqlite3(sqlquery, cnt, 1); + dbse_exec_sqlite3(sqlquery, cnt); } } @@ -691,13 +624,13 @@ void dbse_newfile(struct context *cnt, char *filename, int sqltype, struct timev } if (mystreq(cnt->conf.database_type,"mysql")) { - dbse_exec_mysql(sqlquery, cnt, 0); + dbse_exec_mysql(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"mariadb")) { - dbse_exec_mariadb(sqlquery, cnt, 0); + dbse_exec_mariadb(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"postgresql")) { - dbse_exec_pgsql(sqlquery, cnt, 0); + dbse_exec_pgsql(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"sqlite3")) { - dbse_exec_sqlite3(sqlquery, cnt, 0); + dbse_exec_sqlite3(sqlquery, cnt); } } @@ -718,13 +651,13 @@ void dbse_fileclose(struct context *cnt, char *filename, int sqltype, struct tim } if (mystreq(cnt->conf.database_type,"mysql")) { - dbse_exec_mysql(sqlquery, cnt, 0); + dbse_exec_mysql(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"mariadb")) { - dbse_exec_mariadb(sqlquery, cnt, 0); + dbse_exec_mariadb(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"postgresql")) { - dbse_exec_pgsql(sqlquery, cnt, 0); + dbse_exec_pgsql(sqlquery, cnt); } else if (mystreq(cnt->conf.database_type,"sqlite3")) { - dbse_exec_sqlite3(sqlquery, cnt, 0); + dbse_exec_sqlite3(sqlquery, cnt); } } diff --git a/src/motion.c b/src/motion.c index 4a2c2a71..99a5cc97 100644 --- a/src/motion.c +++ b/src/motion.c @@ -554,7 +554,8 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img cnt->prev_event = cnt->event_nr; cnt->eventtime = img->timestamp_tv.tv_sec; localtime_r(&cnt->eventtime, cnt->eventtime_tm); - + sprintf(cnt->eventid,"%05d",cnt->camera_id); + strftime(cnt->eventid+5, 15,"%Y%m%d%H%M%S", cnt->eventtime_tm); /* * Since this is a new event we create the event_text_string used for * the %C conversion specifier. We may already need it for @@ -563,9 +564,9 @@ static void motion_detected(struct context *cnt, int dev, struct image_data *img mystrftime(cnt, cnt->text_event_string, sizeof(cnt->text_event_string), cnt->conf.text_event, &img->timestamp_tv, NULL, 0); - MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO, _("Motion detected - starting event %d"), - cnt->event_nr); - + MOTION_LOG(NTC, TYPE_ALL, NO_ERRNO + , _("Motion detected - starting event %d.") + , cnt->event_nr); /* EVENT_FIRSTMOTION triggers on_event_start_command and event_ffmpeg_newfile */ indx = cnt->imgs.image_ring_out-1; diff --git a/src/motion.h b/src/motion.h index 6371ea64..35a3fe6c 100644 --- a/src/motion.h +++ b/src/motion.h @@ -372,10 +372,6 @@ struct rotdata { }; -/* -* These used to be global variables but now each thread will have its -* own context -*/ struct context { FILE *extpipe; int extpipe_open; @@ -441,7 +437,7 @@ struct context { int event_nr; int prev_event; - unsigned long long database_event_id; + char eventid[20]; /* Cam ID + Date/Time 99999yyyymmddhhmmss */ unsigned int lightswitch_framecounter; char text_event_string[PATH_MAX]; /* The text for conv. spec. %C - */ int text_scale; diff --git a/src/util.c b/src/util.c index 6ed75341..feb76e34 100644 --- a/src/util.c +++ b/src/util.c @@ -388,20 +388,18 @@ static void mystrftime_long (const struct context *cnt, int width, const char *w return; } if (SPECIFIERWORD("dbeventid")) { - #ifdef HAVE_PGSQL - if (cnt->eid_db_format == dbeid_no_return) { - MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, - _("Used %{dbeventid} but sql_query_start returned no valid event ID")); - ((struct context *)cnt)->eid_db_format = dbeid_use_error; - } - #endif - sprintf(out, "%*llu", width, cnt->database_event_id); + MOTION_LOG(ERR, TYPE_DB, NO_ERRNO, + _("{dbeventid} is not supported. Use eventid.")); return; } if (SPECIFIERWORD("ver")) { sprintf(out, "%*s", width, VERSION); return; } + if (SPECIFIERWORD("eventid")) { + sprintf(out, "%*s", width, cnt->eventid); + return; + } // Not a valid modifier keyword. Log the error and ignore. MOTION_LOG(ERR, TYPE_ALL, NO_ERRNO,