26#include <unordered_map>
54#define FREE(x) { if (x) free(x); (x) = NULL; }
68 const char* sign =
"";
84 char c =
'0' + (char)(tt%10);
107 char c =
'0' + (char)(
i%10);
121 bool newStyleEventName = (strchr(var_event_name,
'/')!=NULL);
125 if (strcasecmp(event_name, var_event_name) == 0) {
127 }
else if (newStyleEventName) {
132 const char* s = event_name;
133 for (
int j=0; s[
j];
j++) {
135 if ((var_event_name[
j]==0) && (s[
j]==
'/')) {
140 if ((var_event_name[
j]==0) && (s[
j]==
'_')) {
145 if (var_event_name[
j]==0) {
150 if (tolower(var_event_name[
j]) != tolower(s[
j])) {
160static bool MatchTagName(
const char* tag_name,
int n_data,
const char* var_tag_name,
const int var_tag_index)
162 char alt_tag_name[1024];
163 sprintf(alt_tag_name,
"%s[%d]", var_tag_name, var_tag_index);
167 if (strcasecmp(tag_name, var_tag_name) == 0)
168 if (var_tag_index >= 0 && var_tag_index < n_data)
171 if (strcasecmp(tag_name, alt_tag_name) == 0)
179 for (
int i=0;
i<ntags;
i++)
189 for (
int i=0; s[
i]!=0;
i++) {
191 if (isalpha(
c) || isdigit(
c))
206 for (
int i=0; s[
i]!=0;
i++) {
208 if (isalpha(
c) || isdigit(
c))
221 return strcasecmp(e1.c_str(), e2);
228 return strcasecmp(v1.c_str(), v2);
236static const char *sql_type_sqlite[
TID_LAST] = {
250 "xxxINVALIDxxxARRAY",
251 "xxxINVALIDxxxSTRUCT",
258static const char *sql_type_pgsql[
TID_LAST] = {
272 "xxxINVALIDxxxARRAY",
273 "xxxINVALIDxxxSTRUCT",
294 "xxxINVALIDxxxARRAY",
295 "xxxINVALIDxxxSTRUCT",
303 if (*col_type == index_type)
306 if (*col_type ==
"bigint" && strcmp(index_type,
"int8")==0) {
307 *col_type = index_type;
311 if (*col_type ==
"integer" && strcmp(index_type,
"int4")==0) {
312 *col_type = index_type;
316 if (*col_type ==
"smallint" && strcmp(index_type,
"int2")==0) {
317 *col_type = index_type;
321 cm_msg(
MERROR,
"SqlHistory",
"Cannot use this SQL database, incompatible column names: created column type [%s] is reported with column type [%s]", index_type, col_type->c_str());
328 if (*col_type == index_type)
331 if (*col_type ==
"int(10) unsigned" && strcmp(index_type,
"integer unsigned")==0) {
332 *col_type = index_type;
336 if (*col_type ==
"int(11)" && strcmp(index_type,
"integer")==0) {
337 *col_type = index_type;
341 if (*col_type ==
"integer" && strcmp(index_type,
"int(11)")==0) {
342 *col_type = index_type;
348 if (*col_type ==
"int" && strcmp(index_type,
"integer")==0) {
349 *col_type = index_type;
353 if (*col_type ==
"int unsigned" && strcmp(index_type,
"integer unsigned")==0) {
354 *col_type = index_type;
358 cm_msg(
MERROR,
"SqlHistory",
"Cannot use this SQL database, incompatible column names: created column type [%s] is reported with column type [%s]", index_type, col_type->c_str());
364static int sql2midasType_mysql(
const char*
name)
366 for (
int tid=0; tid<
TID_LAST; tid++)
370 printf(
"sql2midasType: Cannot convert SQL data type \'%s\' to a MIDAS data type!\n",
name);
376static int sql2midasType_sqlite(
const char*
name)
378 if (strcmp(
name,
"INTEGER") == 0)
380 if (strcmp(
name,
"REAL") == 0)
382 if (strcmp(
name,
"TEXT") == 0)
385 printf(
"sql2midasType: Cannot convert SQL data type \'%s\' to a MIDAS data type!\n",
name);
432 virtual void print(
bool print_tags =
true)
const;
436 virtual int write_event(
const time_t t,
const char*
data,
const size_t data_size) = 0;
440 time_t* last_written) = 0;
442 const time_t end_time,
443 const int num_var,
const std::vector<int>& var_schema_index,
const int var_index[],
470 for (
size_t i=0;
i<
fData.size();
i++)
478 void print(
bool print_tags =
true)
const {
479 for (
size_t i=0;
i<
fData.size();
i++)
512 for (
auto it =
fData.begin(); it !=
fData.end(); it++) {
538 for (
auto it =
fData.begin(); it !=
fData.end(); it++) {
541 time_to = (*it)->fTimeFrom;
553 printf(
"find_event: All schema for event %s: (total %zu)\n", event_name,
fData.size());
555 for (
size_t i=0;
i<
fData.size();
i++) {
557 printf(
"find_event: schema %zu name [%s]\n",
i, s->
fEventName.c_str());
564 printf(
"find_event: Found %d schemas for event %s\n", found, event_name);
570 for (
size_t i=0;
i<
fData.size();
i++) {
591 for (
size_t i=0;
i<
fData.size();
i++) {
613 printf(
"find_event: for time %s, returning:\n",
TimeToString(t).c_str());
616 printf(
"find_event: for time %s, nothing found:\n",
TimeToString(t).c_str());
650 virtual int ListColumns(
const char* table_name, std::vector<std::string> *plist) = 0;
653 virtual int Exec(
const char* table_name,
const char* sql) = 0;
657 virtual int Prepare(
const char* table_name,
const char* sql) = 0;
675 virtual std::string
QuoteId(
const char* s) = 0;
710 void print(
bool print_tags =
true)
const;
717 int write_event(
const time_t t,
const char*
data,
const size_t data_size);
721 time_t* last_written);
723 const time_t end_time,
724 const int num_var,
const std::vector<int>& var_schema_index,
const int var_index[],
754 return (
int)it->second;
796 void print(
bool print_tags =
true)
const;
799 int write_event(
const time_t t,
const char*
data,
const size_t data_size);
802 time_t* last_written);
804 const time_t end_time,
805 const int num_var,
const std::vector<int>& var_schema_index,
const int var_index[],
820 for (
size_t j=0;
j<nv;
j++)
821 printf(
" %zu: name [%s], type [%s] tid %d, n_data %d, n_bytes %d, offset %d\n",
j, this->
fVariables[
j].name.c_str(),
rpc_tid_name(this->
fVariables[
j].
type), this->
fVariables[
j].type, this->
fVariables[
j].n_data, this->
fVariables[
j].n_bytes, this->
fOffsets[
j]);
827 printf(
"event [%s], sql_table [%s], time %s..%s, %zu variables, %zu bytes\n", this->
fEventName.c_str(), this->fTableName.c_str(),
TimeToString(this->
fTimeFrom).c_str(),
TimeToString(this->
fTimeTo).c_str(), nv,
fNumBytes);
829 for (
size_t j=0;
j<nv;
j++) {
841 printf(
"event [%s], file_name [%s], time %s..%s, %zu variables, %zu bytes, dat_offset %jd, record_size %zu\n", this->
fEventName.c_str(), this->fFileName.c_str(),
TimeToString(this->
fTimeFrom).c_str(),
TimeToString(this->
fTimeTo).c_str(), nv,
fNumBytes, (intmax_t)
fDataOffset,
fRecordSize);
843 for (
size_t j=0;
j<nv;
j++)
844 printf(
" %zu: name [%s], type [%s] tid %d, n_data %d, n_bytes %d, offset %d\n",
j, this->
fVariables[
j].name.c_str(),
rpc_tid_name(this->
fVariables[
j].
type), this->
fVariables[
j].type, this->
fVariables[
j].n_data, this->
fVariables[
j].n_bytes, this->
fOffsets[
j]);
866 std::string fConnectString;
867 MYSQL* fMysql = NULL;
870 MYSQL_RES* fResult = NULL;
871 MYSQL_ROW fRow = NULL;
875 size_t fMaxDisconnected = 0;
876 std::list<std::string> fDisconnectedBuffer;
877 time_t fNextReconnect = 0;
878 int fNextReconnectDelaySec = 0;
879 int fDisconnectedLost = 0;
888 int ConnectTable(
const char* table_name);
890 int ListTables(std::vector<std::string> *plist);
891 int ListColumns(
const char* table_name, std::vector<std::string> *plist);
893 int Exec(
const char* table_name,
const char* sql);
896 int Prepare(
const char* table_name,
const char* sql);
898 const char*
GetText(
int column);
910 std::string
QuoteId(
const char* s);
920 fMaxDisconnected = 1000;
922 fNextReconnectDelaySec = 0;
923 fDisconnectedLost = 0;
924 fTransactionPerTable =
false;
934 if (fDisconnectedBuffer.size() > 0) {
935 cm_msg(
MINFO,
"Mysql::~Mysql",
"Lost %zu history entries accumulated while disconnected from the database", fDisconnectedBuffer.size());
940int Mysql::Connect(
const char* connect_string)
945 fConnectString = connect_string;
948 cm_msg(
MINFO,
"Mysql::Connect",
"Connecting to Mysql database specified by \'%s\'", connect_string);
953 std::string user_name;
954 std::string user_password;
957 std::string unix_socket;
960 FILE*
fp = fopen(connect_string,
"r");
962 cm_msg(
MERROR,
"Mysql::Connect",
"Cannot read MYSQL connection parameters from \'%s\', fopen() error %d (%s)", connect_string, errno, strerror(errno));
968 char* s = fgets(buf,
sizeof(buf),
fp);
974 ss = strchr(s,
'\n');
976 ss = strchr(s,
'\r');
981 if (strncasecmp(s,
"server=", 7)==0)
983 if (strncasecmp(s,
"port=", 5)==0)
985 if (strncasecmp(s,
"database=", 9)==0)
987 if (strncasecmp(s,
"socket=", 7)==0)
989 if (strncasecmp(s,
"user=", 5)==0)
991 if (strncasecmp(s,
"password=", 9)==0)
993 if (strncasecmp(s,
"buffer=", 7)==0)
999 int buffer_int = atoi(buffer.c_str());
1001 if (buffer_int > 0 && buffer_int < 1000000)
1002 fMaxDisconnected = buffer_int;
1005 printf(
"Mysql::Connect: connecting to server [%s] port %d, unix socket [%s], database [%s], user [%s], password [%s], buffer [%zu]\n",
host_name.c_str(), tcp_port, unix_socket.c_str(), db_name.c_str(), user_name.c_str(), user_password.c_str(), fMaxDisconnected);
1008 fMysql = mysql_init(NULL);
1014 int client_flag = 0|CLIENT_IGNORE_SIGPIPE;
1016 if (mysql_real_connect(fMysql,
host_name.c_str(), user_name.c_str(), user_password.c_str(), db_name.c_str(), tcp_port, unix_socket.c_str(), client_flag) == NULL) {
1017 cm_msg(
MERROR,
"Mysql::Connect",
"mysql_real_connect() to host [%s], port %d, unix socket [%s], database [%s], user [%s], password [%s]: error %d (%s)",
host_name.c_str(), tcp_port, unix_socket.c_str(), db_name.c_str(), user_name.c_str(),
"xxx", mysql_errno(fMysql), mysql_error(fMysql));
1028 status = Exec(
"(notable)",
"SET SESSION sql_mode='ANSI'");
1030 cm_msg(
MERROR,
"Mysql::Connect",
"Cannot set ANSI mode, nothing will work");
1036 cm_msg(
MINFO,
"Mysql::Connect",
"Connected to a MySQL database on host [%s], port %d, unix socket [%s], database [%s], user [%s], password [%s], buffer %zu",
host_name.c_str(), tcp_port, unix_socket.c_str(), db_name.c_str(), user_name.c_str(),
"xxx", fMaxDisconnected);
1040 fIsConnected =
true;
1043 while (fDisconnectedBuffer.size() > 0) {
1044 status = Exec(
"(flush)", fDisconnectedBuffer.front().c_str());
1048 fDisconnectedBuffer.pop_front();
1053 cm_msg(
MINFO,
"Mysql::Connect",
"Saved %d, lost %d history events accumulated while disconnected from the database",
count, fDisconnectedLost);
1057 assert(fDisconnectedBuffer.size() == 0);
1058 fDisconnectedLost = 0;
1063int Mysql::Disconnect()
1070 mysql_free_result(fResult);
1073 mysql_close(fMysql);
1079 fIsConnected =
false;
1083bool Mysql::IsConnected()
1085 return fIsConnected;
1088int Mysql::OpenTransaction(
const char* table_name)
1090 return Exec(table_name,
"START TRANSACTION");
1094int Mysql::CommitTransaction(
const char* table_name)
1096 Exec(table_name,
"COMMIT");
1100int Mysql::RollbackTransaction(
const char* table_name)
1102 Exec(table_name,
"ROLLBACK");
1106int Mysql::ListTables(std::vector<std::string> *plist)
1112 printf(
"Mysql::ListTables!\n");
1116 fResult = mysql_list_tables(fMysql, NULL);
1118 if (fResult == NULL) {
1119 cm_msg(
MERROR,
"Mysql::ListTables",
"mysql_list_tables() error %d (%s)", mysql_errno(fMysql), mysql_error(fMysql));
1123 fNumFields = mysql_num_fields(fResult);
1129 std::string tn = GetText(0);
1130 plist->push_back(tn);
1138int Mysql::ListColumns(
const char* table_name, std::vector<std::string> *plist)
1144 printf(
"Mysql::ListColumns for table \'%s\'\n", table_name);
1149 cmd +=
"SHOW COLUMNS FROM ";
1150 cmd += QuoteId(table_name);
1153 status = Prepare(table_name, cmd.c_str());
1157 fNumFields = mysql_num_fields(fResult);
1163 std::string cn = GetText(0);
1164 std::string ct = GetText(1);
1165 plist->push_back(cn);
1166 plist->push_back(ct);
1177int Mysql::Exec(
const char* table_name,
const char* sql)
1180 printf(
"Mysql::Exec(%s, %s)\n", table_name, sql);
1192 assert(fResult == NULL);
1193 assert(fRow == NULL);
1195 if (mysql_query(fMysql, sql)) {
1196 if (mysql_errno(fMysql) == 1050) {
1199 if (mysql_errno(fMysql) == 1146) {
1202 cm_msg(
MERROR,
"Mysql::Exec",
"mysql_query(%s) error %d (%s)", sql, mysql_errno(fMysql), mysql_error(fMysql));
1203 if (mysql_errno(fMysql) == 1060)
1205 if (mysql_errno(fMysql) == 2006) {
1207 return ExecDisconnected(table_name, sql);
1215int Mysql::ExecDisconnected(
const char* table_name,
const char* sql)
1218 printf(
"Mysql::ExecDisconnected(%s, %s)\n", table_name, sql);
1220 if (fDisconnectedBuffer.size() < fMaxDisconnected) {
1221 fDisconnectedBuffer.push_back(sql);
1222 if (fDisconnectedBuffer.size() >= fMaxDisconnected) {
1223 cm_msg(
MERROR,
"Mysql::ExecDisconnected",
"Error: Disconnected database buffer overflow, size %zu, subsequent events are lost", fDisconnectedBuffer.size());
1226 fDisconnectedLost++;
1229 time_t now = time(NULL);
1231 if (fNextReconnect == 0 || now >= fNextReconnect) {
1232 int status = Connect(fConnectString.c_str());
1235 fNextReconnectDelaySec = 0;
1237 if (fNextReconnectDelaySec == 0) {
1238 fNextReconnectDelaySec = 5;
1239 }
else if (fNextReconnectDelaySec < 10*60) {
1240 fNextReconnectDelaySec *= 2;
1243 cm_msg(
MINFO,
"Mysql::ExecDisconnected",
"Next reconnect attempt in %d sec, history events buffered %zu, lost %d", fNextReconnectDelaySec, fDisconnectedBuffer.size(), fDisconnectedLost);
1246 fNextReconnect = now + fNextReconnectDelaySec;
1253int Mysql::Prepare(
const char* table_name,
const char* sql)
1256 printf(
"Mysql::Prepare(%s, %s)\n", table_name, sql);
1262 assert(fResult == NULL);
1263 assert(fRow == NULL);
1271 int status = mysql_query(fMysql, sql);
1273 if (mysql_errno(fMysql) == 2006 || mysql_errno(fMysql) == 2013) {
1275 status = Connect(fConnectString.c_str());
1278 status = mysql_query(fMysql, sql);
1280 cm_msg(
MERROR,
"Mysql::Prepare",
"mysql_query(%s) - MySQL server has gone away, and couldn't reconnect - %d", sql,
status);
1285 cm_msg(
MERROR,
"Mysql::Prepare",
"mysql_query(%s) error %d (%s)", sql, mysql_errno(fMysql), mysql_error(fMysql));
1288 cm_msg(
MINFO,
"Mysql::Prepare",
"Reconnected to MySQL after long inactivity.");
1291 fResult = mysql_store_result(fMysql);
1295 cm_msg(
MERROR,
"Mysql::Prepare",
"mysql_store_result(%s) returned NULL, error %d (%s)", sql, mysql_errno(fMysql), mysql_error(fMysql));
1299 fNumFields = mysql_num_fields(fResult);
1309 printf(
"Mysql::Step()\n");
1314 fRow = mysql_fetch_row(fResult);
1319 if (mysql_errno(fMysql) == 0)
1322 cm_msg(
MERROR,
"Mysql::Step",
"mysql_fetch_row() error %d (%s)", mysql_errno(fMysql), mysql_error(fMysql));
1327const char* Mysql::GetText(
int column)
1332 assert(fNumFields > 0);
1333 assert(column >= 0);
1334 assert(column < fNumFields);
1335 if (fRow[column] == NULL)
1337 return fRow[column];
1340double Mysql::GetDouble(
int column)
1342 return atof(GetText(column));
1345time_t Mysql::GetTime(
int column)
1347 return strtoul(GetText(column), NULL, 0);
1350int Mysql::Finalize()
1355 mysql_free_result(fResult);
1363const char* Mysql::ColumnType(
int midas_tid)
1365 assert(midas_tid>=0);
1370bool Mysql::TypesCompatible(
int midas_tid,
const char*
sql_type)
1373 printf(
"compare types midas \'%s\'=\'%s\' and sql \'%s\'\n",
rpc_tid_name(midas_tid), ColumnType(midas_tid),
sql_type);
1378 if (strcasecmp(ColumnType(midas_tid),
sql_type) == 0)
1400 printf(
"type mismatch!\n");
1405std::string Mysql::QuoteId(
const char* s)
1414std::string Mysql::QuoteString(
const char* s)
1420 while (
int c = *s++) {
1425 }
else if (isprint(
c)) {
1429 sprintf(buf,
"\\\\x%02x",
c&0xFF);
1448#include <libpq-fe.h>
1453 std::string fConnectString;
1454 int fDownsample = 0;
1455 PGconn* fPgsql = NULL;
1458 PGresult *fResult = NULL;
1463 size_t fMaxDisconnected = 0;
1464 std::list<std::string> fDisconnectedBuffer;
1465 time_t fNextReconnect = 0;
1466 int fNextReconnectDelaySec = 0;
1467 int fDisconnectedLost = 0;
1472 int Connect(
const char* path);
1476 int ConnectTable(
const char* table_name);
1478 int ListTables(std::vector<std::string> *plist);
1479 int ListColumns(
const char* table_name, std::vector<std::string> *plist);
1481 int Exec(
const char* table_name,
const char* sql);
1484 int Prepare(
const char* table_name,
const char* sql);
1485 std::string BuildDownsampleQuery(
const time_t start_time,
const time_t end_time,
const int npoints,
const char* table_name,
const char* column_name);
1487 const char*
GetText(
int column);
1499 std::string
QuoteId(
const char* s);
1510 fMaxDisconnected = 1000;
1512 fNextReconnectDelaySec = 0;
1513 fDisconnectedLost = 0;
1514 fTransactionPerTable =
false;
1524 if (fDisconnectedBuffer.size() > 0) {
1525 cm_msg(
MINFO,
"Pgsql::~Pgsql",
"Lost %zu history entries accumulated while disconnected from the database", fDisconnectedBuffer.size());
1530int Pgsql::Connect(
const char* connect_string)
1535 fConnectString = connect_string;
1538 cm_msg(
MINFO,
"Pgsql::Connect",
"Connecting to PostgreSQL database specified by \'%s\'", connect_string);
1543 std::string user_name;
1544 std::string user_password;
1545 std::string db_name;
1546 std::string tcp_port;
1547 std::string unix_socket;
1550 FILE*
fp = fopen(connect_string,
"r");
1552 cm_msg(
MERROR,
"Pgsql::Connect",
"Cannot read PostgreSQL connection parameters from \'%s\', fopen() error %d (%s)", connect_string, errno, strerror(errno));
1558 char* s = fgets(buf,
sizeof(buf),
fp);
1564 ss = strchr(s,
'\n');
1566 ss = strchr(s,
'\r');
1571 if (strncasecmp(s,
"server=", 7)==0)
1573 if (strncasecmp(s,
"port=", 5)==0)
1575 if (strncasecmp(s,
"database=", 9)==0)
1577 if (strncasecmp(s,
"socket=", 7)==0)
1579 if (strncasecmp(s,
"user=", 5)==0)
1581 if (strncasecmp(s,
"password=", 9)==0)
1583 if (strncasecmp(s,
"buffer=", 7)==0)
1589 int buffer_int = atoi(buffer.c_str());
1591 if (buffer_int > 0 && buffer_int < 1000000)
1592 fMaxDisconnected = buffer_int;
1595 printf(
"Pgsql::Connect: connecting to server [%s] port %s, unix socket [%s], database [%s], user [%s], password [%s], buffer [%zu]\n",
host_name.c_str(), tcp_port.c_str(), unix_socket.c_str(), db_name.c_str(), user_name.c_str(), user_password.c_str(), fMaxDisconnected);
1597 fPgsql = PQsetdbLogin(
host_name.c_str(), tcp_port.c_str(), NULL, NULL, db_name.c_str(), user_name.c_str(), user_password.c_str());
1598 if (PQstatus(fPgsql) != CONNECTION_OK) {
1599 std::string msg(PQerrorMessage(fPgsql));
1600 msg.erase(std::remove(msg.begin(), msg.end(),
'\n'), msg.end());
1601 cm_msg(
MERROR,
"Pgsql::Connect",
"PQsetdbLogin() to host [%s], port %s, unix socket [%s], database [%s], user [%s], password [%s]: error (%s)",
host_name.c_str(), tcp_port.c_str(), unix_socket.c_str(), db_name.c_str(), user_name.c_str(),
"xxx", msg.c_str());
1609 cm_msg(
MINFO,
"Pgsql::Connect",
"Connected to a PostgreSQL database on host [%s], port %s, unix socket [%s], database [%s], user [%s], password [%s], buffer %zu",
host_name.c_str(), tcp_port.c_str(), unix_socket.c_str(), db_name.c_str(), user_name.c_str(),
"xxx", fMaxDisconnected);
1613 fIsConnected =
true;
1616 while (fDisconnectedBuffer.size() > 0) {
1617 status = Exec(
"(flush)", fDisconnectedBuffer.front().c_str());
1621 fDisconnectedBuffer.pop_front();
1626 cm_msg(
MINFO,
"Pgsql::Connect",
"Saved %d, lost %d history events accumulated while disconnected from the database",
count, fDisconnectedLost);
1630 assert(fDisconnectedBuffer.size() == 0);
1631 fDisconnectedLost = 0;
1634 status = Prepare(
"pg_extensions",
"select extname from pg_extension where extname = 'timescaledb';");
1637 cm_msg(
MERROR,
"Pgsql::Connect",
"TimescaleDB extension not installed");
1642 status = Prepare(
"pg_extensions",
"select extname from pg_extension where extname = 'timescaledb_toolkit';");
1645 cm_msg(
MERROR,
"Pgsql::Connect",
"TimescaleDB_toolkit extension not installed");
1650 cm_msg(
MINFO,
"Pgsql::Connect",
"TimescaleDB extensions found - downsampling enabled");
1656int Pgsql::Disconnect()
1664 fIsConnected =
false;
1668bool Pgsql::IsConnected()
1670 return fIsConnected;
1673int Pgsql::OpenTransaction(
const char* table_name)
1675 return Exec(table_name,
"BEGIN TRANSACTION;");
1678int Pgsql::CommitTransaction(
const char* table_name)
1680 return Exec(table_name,
"COMMIT;");
1683int Pgsql::RollbackTransaction(
const char* table_name)
1685 return Exec(table_name,
"ROLLBACK;");
1688int Pgsql::ListTables(std::vector<std::string> *plist)
1694 printf(
"Pgsql::ListTables!\n");
1696 int status = Prepare(
"pg_tables",
"select tablename from pg_tables where schemaname = 'public';");
1699 cm_msg(
MERROR,
"Pgsql::ListTables",
"error %s (%s)", PQresStatus(PQresultStatus(fResult)), PQresultErrorMessage(fResult));
1706 std::string tn = GetText(0);
1707 plist->push_back(tn);
1715int Pgsql::ListColumns(
const char* table_name, std::vector<std::string> *plist)
1721 printf(
"Pgsql::ListColumns for table \'%s\'\n", table_name);
1724 cmd +=
"SELECT column_name, data_type FROM information_schema.columns WHERE table_name = ";
1725 cmd += QuoteString(table_name);
1728 int status = Prepare(table_name, cmd.c_str());
1732 fNumFields = PQnfields(fResult);
1737 std::string cn = GetText(0);
1738 std::string ct = GetText(1);
1739 plist->push_back(cn);
1740 plist->push_back(ct);
1748int Pgsql::Exec(
const char* table_name,
const char* sql)
1751 printf(
"Pgsql::Exec(%s, %s)\n", table_name, sql);
1759 fResult = PQexec(fPgsql, sql);
1760 ExecStatusType err = PQresultStatus(fResult);
1761 if(err != PGRES_TUPLES_OK) {
1762 if(err == PGRES_FATAL_ERROR) {
1764 if(strstr(PQresultErrorMessage(fResult),
"already exists"))
1769 if(PQstatus(fPgsql) == CONNECTION_BAD) {
1771 return ExecDisconnected(table_name, sql);
1778int Pgsql::ExecDisconnected(
const char* table_name,
const char* sql)
1781 printf(
"Pgsql::ExecDisconnected(%s, %s)\n", table_name, sql);
1783 if (fDisconnectedBuffer.size() < fMaxDisconnected) {
1784 fDisconnectedBuffer.push_back(sql);
1785 if (fDisconnectedBuffer.size() >= fMaxDisconnected) {
1786 cm_msg(
MERROR,
"Pgsql::ExecDisconnected",
"Error: Disconnected database buffer overflow, size %zu, subsequent events are lost", fDisconnectedBuffer.size());
1789 fDisconnectedLost++;
1792 time_t now = time(NULL);
1794 if (fNextReconnect == 0 || now >= fNextReconnect) {
1795 int status = Connect(fConnectString.c_str());
1798 fNextReconnectDelaySec = 0;
1800 if (fNextReconnectDelaySec == 0) {
1801 fNextReconnectDelaySec = 5;
1802 }
else if (fNextReconnectDelaySec < 10*60) {
1803 fNextReconnectDelaySec *= 2;
1806 cm_msg(
MINFO,
"Pgsql::ExecDisconnected",
"Next reconnect attempt in %d sec, history events buffered %zu, lost %d", fNextReconnectDelaySec, fDisconnectedBuffer.size(), fDisconnectedLost);
1809 fNextReconnect = now + fNextReconnectDelaySec;
1816int Pgsql::Prepare(
const char* table_name,
const char* sql)
1819 printf(
"Pgsql::Prepare(%s, %s)\n", table_name, sql);
1828 fResult = PQexec(fPgsql, sql);
1829 if (PQstatus(fPgsql) == CONNECTION_BAD) {
1831 int status = Connect(fConnectString.c_str());
1834 fResult = PQexec(fPgsql, sql);
1836 cm_msg(
MERROR,
"Pgsql::Prepare",
"PQexec(%s) PostgreSQL server has gone away, and couldn't reconnect - %d", sql,
status);
1840 cm_msg(
MERROR,
"Pgsql::Prepare",
"PQexec(%s) error %s", sql, PQresStatus(PQresultStatus(fResult)));
1843 cm_msg(
MINFO,
"Pgsql::Prepare",
"Reconnected to PostgreSQL after long inactivity.");
1846 fNumFields = PQnfields(fResult);
1851std::string Pgsql::BuildDownsampleQuery(
const time_t start_time,
const time_t end_time,
const int npoints,
1852 const char* table_name,
const char* column_name)
1855 cmd +=
"SELECT extract(epoch from time::TIMESTAMPTZ) as _i_time, value ";
1857 cmd +=
" FROM unnest(( SELECT lttb";
1858 cmd +=
"(_t_time, ";
1861 cmd += std::to_string(npoints);
1864 cmd += QuoteId(table_name);
1865 cmd +=
" WHERE _t_time BETWEEN ";
1866 cmd +=
"to_timestamp(";
1868 cmd +=
") AND to_timestamp(";
1870 cmd +=
") )) ORDER BY time;";
1882 if (fRow == PQntuples(fResult))
1888const char* Pgsql::GetText(
int column)
1892 assert(fNumFields > 0);
1893 assert(column >= 0);
1894 assert(column < fNumFields);
1896 return PQgetvalue(fResult, fRow, column);
1899double Pgsql::GetDouble(
int column)
1901 return atof(GetText(column));
1904time_t Pgsql::GetTime(
int column)
1906 return strtoul(GetText(column), NULL, 0);
1909int Pgsql::Finalize()
1920const char* Pgsql::ColumnType(
int midas_tid)
1922 assert(midas_tid>=0);
1924 return sql_type_pgsql[midas_tid];
1927bool Pgsql::TypesCompatible(
int midas_tid,
const char*
sql_type)
1930 printf(
"compare types midas \'%s\'=\'%s\' and sql \'%s\'\n",
rpc_tid_name(midas_tid), ColumnType(midas_tid),
sql_type);
1935 if (strcasecmp(ColumnType(midas_tid),
sql_type) == 0)
1953 printf(
"type mismatch!\n");
1958std::string Pgsql::QuoteId(
const char* s)
1967std::string Pgsql::QuoteString(
const char* s)
1986typedef std::map<std::string, sqlite3*> DbMap;
1997 sqlite3_stmt* fTempStmt;
2002 int Connect(
const char* path);
2006 int ConnectTable(
const char* table_name);
2007 sqlite3* GetTable(
const char* table_name);
2009 int ListTables(std::vector<std::string> *plist);
2010 int ListColumns(
const char* table_name, std::vector<std::string> *plist);
2012 int Exec(
const char* table_name,
const char* sql);
2015 int Prepare(
const char* table_name,
const char* sql);
2017 const char*
GetText(
int column);
2029 std::string
QuoteId(
const char* s);
2033std::string Sqlite::QuoteId(
const char* s)
2042std::string Sqlite::QuoteString(
const char* s)
2051const char* Sqlite::ColumnType(
int midas_tid)
2053 assert(midas_tid>=0);
2055 return sql_type_sqlite[midas_tid];
2058bool Sqlite::TypesCompatible(
int midas_tid,
const char*
sql_type)
2061 printf(
"compare types midas \'%s\'=\'%s\' and sql \'%s\'\n",
rpc_tid_name(midas_tid), ColumnType(midas_tid),
sql_type);
2066 if (strcasecmp(ColumnType(midas_tid),
sql_type) == 0)
2076const char* Sqlite::GetText(
int column)
2078 return (
const char*)sqlite3_column_text(fTempStmt, column);
2081time_t Sqlite::GetTime(
int column)
2083 return sqlite3_column_int64(fTempStmt, column);
2086double Sqlite::GetDouble(
int column)
2088 return sqlite3_column_double(fTempStmt, column);
2093 fIsConnected =
false;
2104const char* xsqlite3_errstr(sqlite3* db,
int errcode)
2107 return sqlite3_errmsg(db);
2110int Sqlite::ConnectTable(
const char* table_name)
2112 std::string fname = fPath +
"mh_" + table_name +
".sqlite3";
2116 int status = sqlite3_open(fname.c_str(), &db);
2118 if (
status != SQLITE_OK) {
2119 cm_msg(
MERROR,
"Sqlite::Connect",
"Table %s: sqlite3_open(%s) error %d (%s)", table_name, fname.c_str(),
status, xsqlite3_errstr(db,
status));
2125#if SQLITE_VERSION_NUMBER >= 3006020
2126 status = sqlite3_extended_result_codes(db, 1);
2127 if (
status != SQLITE_OK) {
2128 cm_msg(
MERROR,
"Sqlite::Connect",
"Table %s: sqlite3_extended_result_codes(1) error %d (%s)", table_name,
status, xsqlite3_errstr(db,
status));
2131#warning Missing sqlite3_extended_result_codes()!
2134 fMap[table_name] = db;
2136 Exec(table_name,
"PRAGMA journal_mode=persist;");
2137 Exec(table_name,
"PRAGMA synchronous=normal;");
2139 Exec(table_name,
"PRAGMA journal_size_limit=-1;");
2142 Exec(table_name,
"PRAGMA legacy_file_format;");
2143 Exec(table_name,
"PRAGMA synchronous;");
2144 Exec(table_name,
"PRAGMA journal_mode;");
2145 Exec(table_name,
"PRAGMA journal_size_limit;");
2148#ifdef SQLITE_LIMIT_COLUMN
2150 int max_columns = sqlite3_limit(db, SQLITE_LIMIT_COLUMN, -1);
2151 printf(
"Sqlite::Connect: SQLITE_LIMIT_COLUMN=%d\n", max_columns);
2156 cm_msg(
MINFO,
"Sqlite::Connect",
"Table %s: connected to Sqlite file \'%s\'", table_name, fname.c_str());
2161sqlite3* Sqlite::GetTable(
const char* table_name)
2163 sqlite3* db = fMap[table_name];
2168 int status = ConnectTable(table_name);
2172 return fMap[table_name];
2175int Sqlite::Connect(
const char* path)
2183 if (fPath.length() > 0) {
2189 cm_msg(
MINFO,
"Sqlite::Connect",
"Connected to Sqlite database in \'%s\'", fPath.c_str());
2191 fIsConnected =
true;
2196int Sqlite::Disconnect()
2201 for (DbMap::iterator iter = fMap.begin(); iter != fMap.end(); ++iter) {
2202 const char* table_name = iter->first.c_str();
2203 sqlite3* db = iter->second;
2204 int status = sqlite3_close(db);
2205 if (
status != SQLITE_OK) {
2206 cm_msg(
MERROR,
"Sqlite::Disconnect",
"sqlite3_close(%s) error %d (%s)", table_name,
status, xsqlite3_errstr(db,
status));
2212 fIsConnected =
false;
2217bool Sqlite::IsConnected()
2219 return fIsConnected;
2222int Sqlite::OpenTransaction(
const char* table_name)
2224 int status = Exec(table_name,
"BEGIN TRANSACTION");
2228int Sqlite::CommitTransaction(
const char* table_name)
2230 int status = Exec(table_name,
"COMMIT TRANSACTION");
2234int Sqlite::RollbackTransaction(
const char* table_name)
2236 int status = Exec(table_name,
"ROLLBACK TRANSACTION");
2240int Sqlite::Prepare(
const char* table_name,
const char* sql)
2242 sqlite3* db = GetTable(table_name);
2247 printf(
"Sqlite::Prepare(%s, %s)\n", table_name, sql);
2249 assert(fTempDB==NULL);
2252#if SQLITE_VERSION_NUMBER >= 3006020
2253 int status = sqlite3_prepare_v2(db, sql, strlen(sql), &fTempStmt, NULL);
2255#warning Missing sqlite3_prepare_v2()!
2256 int status = sqlite3_prepare(db, sql, strlen(sql), &fTempStmt, NULL);
2262 std::string sqlstring = sql;
2263 cm_msg(
MERROR,
"Sqlite::Prepare",
"Table %s: sqlite3_prepare_v2(%s...) error %d (%s)", table_name, sqlstring.substr(0,60).c_str(),
status, xsqlite3_errstr(db,
status));
2273 printf(
"Sqlite::Step()\n");
2278 int status = sqlite3_step(fTempStmt);
2280 if (
status == SQLITE_DONE)
2283 if (
status == SQLITE_ROW)
2291int Sqlite::Finalize()
2294 printf(
"Sqlite::Finalize()\n");
2299 int status = sqlite3_finalize(fTempStmt);
2301 if (
status != SQLITE_OK) {
2315int Sqlite::ListTables(std::vector<std::string> *plist)
2321 printf(
"Sqlite::ListTables at path [%s]\n", fPath.c_str());
2325 const char* cmd =
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;";
2327 DIR *dir = opendir(fPath.c_str());
2329 cm_msg(
MERROR,
"Sqlite::ListTables",
"Cannot opendir(%s), errno %d (%s)", fPath.c_str(), errno, strerror(errno));
2334 const struct dirent*
de = readdir(dir);
2338 const char* dn =
de->d_name;
2345 s = strstr(dn,
"mh_");
2349 s = strstr(dn,
".sqlite3");
2353 char table_name[256];
2354 mstrlcpy(table_name, dn+3,
sizeof(table_name));
2356 char* ss = strstr(table_name,
".sqlite3");
2363 status = Prepare(table_name, cmd);
2372 const char* tn = GetText(0);
2374 plist->push_back(tn);
2386int Sqlite::ListColumns(
const char* table, std::vector<std::string> *plist)
2392 printf(
"Sqlite::ListColumns for table \'%s\'\n", table);
2395 cmd =
"PRAGMA table_info(";
2401 status = Prepare(table, cmd.c_str());
2410 const char* colname = GetText(1);
2411 const char* coltype = GetText(2);
2413 plist->push_back(colname);
2414 plist->push_back(coltype);
2422static int callback_debug = 0;
2424static int callback(
void *NotUsed,
int argc,
char **argv,
char **azColName){
2425 if (callback_debug) {
2426 printf(
"history_sqlite::callback---->\n");
2427 for (
int i=0;
i<argc;
i++){
2428 printf(
"history_sqlite::callback[%d] %s = %s\n",
i, azColName[
i], argv[
i] ? argv[
i] :
"NULL");
2434int Sqlite::Exec(
const char* table_name,
const char* sql)
2444 sqlite3* db = GetTable(table_name);
2449 printf(
"Sqlite::Exec(%s, %s)\n", table_name, sql);
2453 callback_debug = fDebug;
2454 char* errmsg = NULL;
2457 if (
status != SQLITE_OK) {
2458 if (
status == SQLITE_ERROR && strstr(errmsg,
"duplicate column name"))
2460 if (
status == SQLITE_ERROR && strstr(errmsg,
"already exists"))
2462 std::string sqlstring = sql;
2463 cm_msg(
MERROR,
"Sqlite::Exec",
"Table %s: sqlite3_exec(%s...) error %d (%s)", table_name, sqlstring.substr(0,60).c_str(),
status, errmsg);
2464 sqlite3_free(errmsg);
2471int Sqlite::ExecDisconnected(
const char* table_name,
const char* sql)
2473 cm_msg(
MERROR,
"Sqlite::Exec",
"sqlite driver does not support disconnected operations");
2492 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot write to \'%s\', open() errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2506 off64_t file_size = ::lseek64(s->
fWriterFd, 0, SEEK_END);
2508 if (file_size < 0) {
2509 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot read file size of \'%s\', lseek64(SEEK_END) errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2526 if (data_end != file_size) {
2528 cm_msg(
MERROR,
"FileHistory::write_event",
"File \'%s\' may be truncated, data offset %jd, record size %zu, file size: %jd, should be %jd, making it so", s->
fFileName.c_str(), (intmax_t)s->
fDataOffset, s->
fRecordSize, (intmax_t)file_size, (intmax_t)data_end);
2530 off64_t status64 = ::lseek64(s->
fWriterFd, data_end, SEEK_SET);
2533 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot seek \'%s\' to offset %jd, lseek64() errno %d (%s)", s->
fFileName.c_str(), (intmax_t)data_end, errno, strerror(errno));
2540 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot truncate \'%s\' to size %jd, ftruncate64() errno %d (%s)", s->
fFileName.c_str(), (intmax_t)data_end, errno, strerror(errno));
2558 cm_msg(
MERROR,
"FileHistory::write_event",
"Event \'%s\' data size mismatch, expected %zu bytes, got %zu bytes, previously %zu bytes", s->
fEventName.c_str(), expected_size, data_size, s->
fLastSize);
2562 if (data_size < expected_size)
2570 size_t size = 4 + expected_size;
2582 if ((
size_t)wr != size) {
2583 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot write to \'%s\', write(%zu) returned %zd, errno %d (%s)", s->
fFileName.c_str(), size, wr, errno, strerror(errno));
2592 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot write to \'%s\', write(timestamp) errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2597 if (
status != expected_size) {
2598 cm_msg(
MERROR,
"FileHistory::write_event",
"Cannot write to \'%s\', write(%d) errno %d (%s)", s->
fFileName.c_str(), data_size, errno, strerror(errno));
2617 off64_t fpos =
offset + irec*recsize;
2619 off64_t status64 = ::lseek64(fd, fpos, SEEK_SET);
2622 cm_msg(
MERROR,
"FileHistory::ReadRecord",
"Cannot read \'%s\', lseek64(%jd) errno %d (%s)",
file_name, (intmax_t)fpos, errno, strerror(errno));
2626 ssize_t rd =
::read(fd, rec, recsize);
2629 cm_msg(
MERROR,
"FileHistory::ReadRecord",
"Cannot read \'%s\', read() errno %d (%s)",
file_name, errno, strerror(errno));
2634 cm_msg(
MERROR,
"FileHistory::ReadRecord",
"Cannot read \'%s\', unexpected end of file on read()",
file_name);
2638 if ((
size_t)rd != recsize) {
2639 cm_msg(
MERROR,
"FileHistory::ReadRecord",
"Cannot read \'%s\', short read() returned %zd instead of %zu bytes",
file_name, rd, recsize);
2646static int FindTime(
const char*
file_name,
int fd, off64_t
offset,
size_t recsize, off64_t nrec, time_t timestamp, off64_t* i1p, time_t* t1p, off64_t* i2p, time_t* t2p, time_t* tstart, time_t* tend,
int debug)
2667 char* buf =
new char[recsize];
2672 off64_t rec2 = nrec-1;
2680 time_t t1 = *(
DWORD*)buf;
2685 if (timestamp <= t1) {
2695 assert(t1 < timestamp);
2713 time_t t2 = *(
DWORD*)buf;
2718 if (t2 < timestamp) {
2727 assert(t1 < timestamp);
2728 assert(timestamp <= t2);
2731 printf(
"FindTime: rec %jd..(x)..%jd, time %s..(%s)..%s\n", (intmax_t)rec1, (intmax_t)rec2,
TimeToString(t1).c_str(),
TimeToString(timestamp).c_str(),
TimeToString(t2).c_str());
2736 off64_t rec = (rec1+rec2)/2;
2747 time_t t = *(
DWORD*)buf;
2749 if (timestamp <= t) {
2762 }
while (rec2 - rec1 > 1);
2764 assert(rec1+1 == rec2);
2765 assert(t1 < timestamp);
2766 assert(timestamp <= t2);
2769 printf(
"FindTime: rec %jd..(x)..%jd, time %s..(%s)..%s, this is the result.\n", (intmax_t)rec1, (intmax_t)rec2,
TimeToString(t1).c_str(),
TimeToString(timestamp).c_str(),
TimeToString(t2).c_str());
2783 time_t* last_written)
2791 int fd = open(s->
fFileName.c_str(), O_RDONLY);
2793 cm_msg(
MERROR,
"FileHistory::read_last_written",
"Cannot read \'%s\', open() errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2797 off64_t file_size = ::lseek64(fd, 0, SEEK_END);
2799 if (file_size < 0) {
2800 cm_msg(
MERROR,
"FileHistory::read_last_written",
"Cannot read file size of \'%s\', lseek64(SEEK_END) errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2845 if (lw >= timestamp) {
2848 off64_t iunused = 0;
2853 status =
FindTime(s->
fFileName.c_str(), fd, s->
fDataOffset, s->
fRecordSize, nrec, timestamp, &irec, &trec, &iunused, &tunused, &tstart, &tend, 0*
debug);
2859 assert(trec < timestamp);
2870 assert(lw < timestamp);
2878 const time_t end_time,
2879 const int num_var,
const std::vector<int>& var_schema_index,
const int var_index[],
2898 printf(
"FileHistory::read_data: file %s map", s->
fFileName.c_str());
2899 for (
size_t i=0;
i<var_schema_index.size();
i++) {
2900 printf(
" %2d", var_schema_index[
i]);
2905 int fd = ::open(s->
fFileName.c_str(), O_RDONLY);
2907 cm_msg(
MERROR,
"FileHistory::read_data",
"Cannot read \'%s\', open() errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2911 off64_t file_size = ::lseek64(fd, 0, SEEK_END);
2913 if (file_size < 0) {
2914 cm_msg(
MERROR,
"FileHistory::read_data",
"Cannot read file size of \'%s\', lseek64(SEEK_END) errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
2937 off64_t iunused = 0;
2944 int istatus =
FindTime(s->
fFileName.c_str(), fd, s->
fDataOffset, s->
fRecordSize, nrec, start_time, &iunused, &tunused, &irec, &trec, &tstart, &tend, 0*
debug);
2952 printf(
"FindTime %d, nrec %jd, (%jd, %s) (%jd, %s), tstart %s, tend %s, want %s\n", istatus, (intmax_t)nrec, (intmax_t)iunused,
TimeToString(tunused).c_str(), (intmax_t)irec,
TimeToString(trec).c_str(),
TimeToString(tstart).c_str(),
TimeToString(tend).c_str(),
TimeToString(start_time).c_str());
2955 if (irec < 0 || irec >= nrec) {
2961 printf(
"FileHistory::read: file %s, schema time %s..%s, read time %s..%s, file time %s..%s, data in this file is too old\n", s->
fFileName.c_str(),
TimeToString(s->
fTimeFrom).c_str(),
TimeToString(s->
fTimeTo).c_str(),
TimeToString(start_time).c_str(),
TimeToString(end_time).c_str(),
TimeToString(tstart).c_str(),
TimeToString(tend).c_str());
2986 for (
int i=0;
i<num_var;
i++) {
2987 int si = var_schema_index[
i];
3004 off64_t xpos = ::lseek64(fd, fpos, SEEK_SET);
3009 cm_msg(
MERROR,
"FileHistory::read_data",
"Cannot read \'%s\', lseek64(%jd) errno %d (%s)", s->
fFileName.c_str(), (intmax_t)fpos, errno, strerror(errno));
3016 off64_t prec = irec;
3022 cm_msg(
MERROR,
"FileHistory::read_data",
"Cannot read \'%s\', read() errno %d (%s)", s->
fFileName.c_str(), errno, strerror(errno));
3038 bool past_end_of_last_file = (s->
fTimeTo == 0) && (prec > nrec);
3040 time_t t = *(
DWORD*)buf;
3052 if (tend && (t > tend) && !past_end_of_last_file) {
3062 char*
data = buf + 4;
3064 for (
int i=0;
i<num_var;
i++) {
3065 int si = var_schema_index[
i];
3081 int ii = var_index[
i];
3091 v = ((
unsigned char*)ptr)[ii];
3094 v = ((
signed char *)ptr)[ii];
3097 v = ((
char*)ptr)[ii];
3100 v = ((
unsigned short *)ptr)[ii];
3103 v = ((
signed short *)ptr)[ii];
3106 v = ((
unsigned int *)ptr)[ii];
3109 v = ((
int *)ptr)[ii];
3112 v = ((
unsigned int *)ptr)[ii];
3115 v = ((
float*)ptr)[ii];
3118 v = ((
double*)ptr)[ii];
3122 buffer[
i]->
Add(t, v);
3133 printf(
"FileHistory::read_data: file %s map", s->
fFileName.c_str());
3134 for (
size_t i=0;
i<var_schema_index.size();
i++) {
3135 printf(
" %2d", var_schema_index[
i]);
3137 printf(
" read %d rows\n",
count);
3141 printf(
"FileHistory::read: file %s, schema time %s..%s, read time %s..%s, %d vars, read %d rows\n", s->
fFileName.c_str(),
TimeToString(s->
fTimeFrom).c_str(),
TimeToString(s->
fTimeTo).c_str(),
TimeToString(start_time).c_str(),
TimeToString(end_time).c_str(), num_var,
count);
3210 int hs_define_event(
const char* event_name, time_t timestamp,
int ntags,
const TAG tags[]);
3211 int hs_write_event(
const char* event_name, time_t timestamp,
int buffer_size,
const char* buffer);
3219 int hs_get_events(time_t t, std::vector<std::string> *pevents);
3220 int hs_get_tags(
const char* event_name, time_t t, std::vector<TAG> *ptags);
3221 int hs_get_last_written(time_t timestamp,
int num_var,
const char*
const event_name[],
const char*
const var_name[],
const int var_index[], time_t last_written[]);
3223 int num_var,
const char*
const event_name[],
const char*
const var_name[],
const int var_index[],
3272 if (newalloc <= 1000)
3273 newalloc = wantalloc + 1000;
3300 (*fTimeBuffer)[pos] = t;
3301 (*fDataBuffer)[pos] = v;
3303 (*fNumEntries) = pos + 1;
3317 int hs_read(time_t start_time, time_t end_time, time_t interval,
3319 const char*
const event_name[],
const char*
const var_name[],
const int var_index[],
3321 time_t* time_buffer[],
double* data_buffer[],
3326 int hs_read_binned(time_t start_time, time_t end_time,
int num_bins,
3327 int num_var,
const char*
const event_name[],
const char*
const var_name[],
const int var_index[],
3329 int* count_bins[],
double* mean_bins[],
double* rms_bins[],
double* min_bins[],
double* max_bins[],
3330 time_t* bins_first_time[],
double* bins_first_value[],
3331 time_t* bins_last_time[],
double* bins_last_value[],
3332 time_t
last_time[],
double last_value[],
3344 fSum0 =
new double[num_bins];
3345 fSum1 =
new double[num_bins];
3346 fSum2 =
new double[num_bins];
3348 for (
int i=0;
i<num_bins;
i++) {
3376 for (
int ibin = 0; ibin <
fNumBins; ibin++) {
3409 int ibin = (int)fbin;
3416 if (
fSum0[ibin] == 0) {
3466 double variance = 0;
3469 variance =
fSum2[
i]/num-mean*mean;
3473 rms = sqrt(variance);
3496 printf(
"hs_define_event: event name [%s] with %d tags\n", event_name, ntags);
3506 printf(
"deleting exising event %s\n", event_name);
3513 for (
int i=0;
i<ntags;
i++) {
3514 if (strlen(tags[
i].
name) < 1) {
3515 cm_msg(
MERROR,
"hs_define_event",
"Error: History event \'%s\' has empty name at index %d", event_name,
i);
3518 if (tags[
i].
name[0] ==
' ') {
3519 cm_msg(
MERROR,
"hs_define_event",
"Error: History event \'%s\' has name \'%s\' starting with a blank", event_name, tags[
i].
name);
3523 cm_msg(
MERROR,
"hs_define_event",
"Error: History event \'%s\' tag \'%s\' at index %d has invalid type %d",
3529 "Error: History event \'%s\' tag \'%s\' at index %d has forbidden type TID_STRING", event_name,
3533 if (tags[
i].n_data <= 0) {
3534 cm_msg(
MERROR,
"hs_define_event",
"Error: History event \'%s\' tag \'%s\' at index %d has invalid n_data %d",
3535 event_name, tags[
i].
name,
i, tags[
i].n_data);
3541 std::vector<std::string> names;
3542 for (
int i=0;
i<ntags;
i++) {
3544 std::transform(
str.begin(),
str.end(),
str.begin(), ::toupper);
3545 names.push_back(
str);
3547 std::sort(names.begin(), names.end());
3548 for (
int i=0;
i<ntags-1;
i++) {
3549 if (names[
i] == names[
i + 1]) {
3551 "Error: History event \'%s\' has duplicate tag name \'%s\'", event_name,
3583 printf(
"hs_write_event: write event \'%s\', time %d, size %d\n", event_name, (
int)timestamp, xbuffer_size);
3585 assert(xbuffer_size > 0);
3587 size_t buffer_size = xbuffer_size;
3625 cm_msg(
MERROR,
"hs_write_event",
"Event \'%s\' data size mismatch: expected %zu bytes, got %zu bytes", s->
fEventName.c_str(), s->
fNumBytes, buffer_size);
3631 }
else if (buffer_size < s->fNumBytes) {
3635 cm_msg(
MERROR,
"hs_write_event",
"Event \'%s\' data size mismatch: expected %zu bytes, got %zu bytes", s->
fEventName.c_str(), s->
fNumBytes, buffer_size);
3640 else if (buffer_size < s->fWriteMinSize)
3642 char* tmp = (
char*)malloc(s->
fNumBytes);
3643 memcpy(tmp, buffer, buffer_size);
3644 memset(tmp + buffer_size, 0, s->
fNumBytes - buffer_size);
3655 cm_msg(
MERROR,
"hs_write_event",
"Event \'%s\' disabled after write error %d", event_name,
status);
3667 printf(
"hs_flush_buffers!\n");
3686 printf(
"SchemaHistoryBase::hs_clear_cache!\n");
3697 printf(
"hs_get_events, time %s\n",
TimeToString(t).c_str());
3704 printf(
"hs_get_events: available schema:\n");
3715 for (
size_t j=0;
j<pevents->size();
j++)
3725 std::sort(pevents->begin(), pevents->end());
3728 printf(
"hs_get_events: returning %zu events\n", pevents->size());
3729 for (
size_t i=0;
i<pevents->size();
i++) {
3730 printf(
" %zu: [%s]\n",
i, (*pevents)[
i].c_str());
3740 printf(
"hs_get_tags: event [%s], time %s\n", event_name,
TimeToString(t).c_str());
3748 bool found_event =
false;
3760 const char* tagname = s->
fVariables[
i].name.c_str();
3765 for (
size_t k=0;
k<ptags->size();
k++)
3766 if (strcasecmp((*ptags)[
k].
name, tagname) == 0) {
3773 mstrlcpy(t.
name, tagname,
sizeof(t.
name));
3777 ptags->push_back(t);
3786 printf(
"hs_get_tags: event [%s], returning %zu tags\n", event_name, ptags->size());
3787 for (
size_t i=0;
i<ptags->size();
i++) {
3788 printf(
" tag[%zu]: %s[%d] type %d\n",
i, (*ptags)[
i].
name, (*ptags)[
i].n_data, (*ptags)[
i].
type);
3798 printf(
"hs_get_last_written: timestamp %s, num_var %d\n",
TimeToString(timestamp).c_str(), num_var);
3801 for (
int j=0;
j<num_var;
j++) {
3802 last_written[
j] = 0;
3805 for (
int i=0;
i<num_var;
i++) {
3813 for (
int i=0;
i<num_var;
i++) {
3832 for (
int j=0;
j<num_var;
j++) {
3837 if (lw > last_written[
j])
3838 last_written[
j] = lw;
3845 printf(
"hs_get_last_written: timestamp time %s, num_var %d, result:\n",
TimeToString(timestamp).c_str(), num_var);
3846 for (
int i=0;
i<num_var;
i++) {
3847 printf(
" event [%s] tag [%s] index [%d] last_written %s\n", event_name[
i],
var_name[
i], var_index[
i],
TimeToString(last_written[
i]).c_str());
3855 int num_var,
const char*
const event_name[],
const char*
const var_name[],
const int var_index[],
3860 printf(
"hs_read_buffer: %d variables, start time %s, end time %s\n", num_var,
TimeToString(start_time).c_str(),
TimeToString(end_time).c_str());
3862 for (
int i=0;
i<num_var;
i++) {
3873 for (
int i=0;
i<num_var;
i++) {
3908 cm_msg(
MERROR,
"SchemaHistoryBase::hs_read_buffer",
"History internal error, schema is not ordered by time. Please report this error to the midas forum.");
3915 std::vector<HsSchema*> slist;
3916 std::vector<std::vector<int>> smap;
3927 std::vector<int> sm;
3929 for (
int i=0;
i<num_var;
i++) {
3936 for (
int i=0;
i<num_var;
i++) {
3951 printf(
"Found %zu matching schema:\n", slist.size());
3953 for (
size_t i=0;
i<slist.size();
i++) {
3956 for (
int k=0;
k<num_var;
k++)
3957 printf(
" tag %s[%d] sindex %d\n",
var_name[
k], var_index[
k], smap[
i][
k]);
3972 for (
size_t ss=1; ss<slist.size(); ss++) {
3974 printf(
"Check schema %zu/%zu: prev from %s, this from %s to %s, compare %d\n", ss, slist.size(),
3978 slist[ss-1]->fTimeFrom >= slist[ss]->fTimeFrom);
3980 if (slist[ss-1]->fTimeFrom >= slist[ss]->fTimeFrom) {
3983 cm_msg(
MERROR,
"SchemaHistoryBase::hs_read_buffer",
"History internal error, selected schema is not ordered by time. Please report this error to the midas forum.");
3990 for (
int i=0;
i<num_var;
i++) {
3994 if (slist.size() > 0) {
3995 for (
size_t i=slist.size()-1; ;
i--) {
4001 for (
int j=0;
j<num_var;
j++) {
4002 if (smap[
i][
j] >= 0)
4017 const char*
const event_name[],
const char*
const var_name[],
const int var_index[],
4019 time_t* time_buffer[],
double* data_buffer[],
4027 for (
int i=0;
i<num_var;
i++) {
4028 buffer[
i] =
new ReadBuffer(start_time, end_time, interval);
4035 time_buffer[
i] = NULL;
4037 data_buffer[
i] = NULL;
4050 num_var, event_name,
var_name, var_index,
4053 for (
int i=0;
i<num_var;
i++) {
4065 int num_var,
const char*
const event_name[],
const char*
const var_name[],
const int var_index[],
4067 int* count_bins[],
double* mean_bins[],
double* rms_bins[],
double* min_bins[],
double* max_bins[],
4068 time_t* bins_first_time[],
double* bins_first_value[],
4069 time_t* bins_last_time[],
double* bins_last_value[],
4070 time_t
last_time[],
double last_value[],
4078 for (
int i=0;
i<num_var;
i++) {
4080 xbuffer[
i] = buffer[
i];
4085 buffer[
i]->
fMean = mean_bins[
i];
4087 buffer[
i]->
fRms = rms_bins[
i];
4089 buffer[
i]->
fMin = min_bins[
i];
4091 buffer[
i]->
fMax = max_bins[
i];
4092 if (bins_first_time)
4094 if (bins_first_value)
4098 if (bins_last_value)
4109 num_var, event_name,
var_name, var_index,
4113 for (
int i=0;
i<num_var;
i++) {
4118 for (
int j=0;
j<num_bins;
j++) {
4119 printf(
"var %d bin %d count %d, first %s last %s value first %f last %f\n",
i,
j, count_bins[
i][
j],
TimeToString(bins_first_time[
i][
j]).c_str(),
TimeToString(bins_last_time[
i][
j]).c_str(), bins_first_value[
i][
j], bins_last_value[
i][
j]);
4185 for (
size_t i=0;
i<sv->
size();
i++) {
4236 cm_msg(
MERROR,
"NewSqlSchema",
"Error: Unexpected ordering of schema for table \'%s\', good luck!", table_name);
4250 cm_msg(
MERROR,
"NewSqlSchema",
"Error: Cannot clone schema for table \'%s\', good luck!", table_name);
4261 size_t count_active = 0;
4262 size_t count_inactive = 0;
4266 count_inactive += 1;
4274 if (count_inactive > 0) {
4295 assert(
j == count_active);
4331 cm_msg(
MERROR,
"HsSqlSchema::write_event",
"Internal error, unexpected inactive column %zu",
i);
4342 cm_msg(
MERROR,
"HsSqlSchema::write_event",
"Internal error, unexpected negative offset %d for column %zu",
offset,
i);
4347 assert(n_data == 1);
4348 assert(strlen(column_name) > 0);
4350 assert((
size_t)
offset < data_size);
4364 sprintf(buf,
"unknownType%d",
type);
4367 sprintf(buf,
"%u",((
unsigned char *)ptr)[
j]);
4370 sprintf(buf,
"%d",((
signed char*)ptr)[
j]);
4374 sprintf(buf,
"\'%c\'",((
char*)ptr)[
j]);
4377 sprintf(buf,
"%u",((
unsigned short *)ptr)[
j]);
4380 sprintf(buf,
"%d",((
short *)ptr)[
j]);
4383 sprintf(buf,
"%u",((
unsigned int *)ptr)[
j]);
4386 sprintf(buf,
"%d",((
int *)ptr)[
j]);
4389 sprintf(buf,
"%u",((
unsigned int *)ptr)[
j]);
4393 sprintf(buf,
"\'%.8g\'",((
float*)ptr)[
j]);
4397 sprintf(buf,
"\'%.16g\'",((
double*)ptr)[
j]);
4406 localtime_r(&t, &tms);
4408 strftime(buf,
sizeof(buf)-1,
"%Y-%m-%d %H:%M:%S.0", &tms);
4411 cmd =
"INSERT INTO ";
4413 cmd +=
" (_t_time, _i_time";
4415 cmd +=
") VALUES (";
4455 time_t* last_written)
4458 printf(
"SqlHistory::read_last_written: table [%s], timestamp %s\n",
fTableName.c_str(),
TimeToString(timestamp).c_str());
4461 cmd +=
"SELECT _i_time FROM ";
4463 cmd +=
" WHERE _i_time < ";
4465 cmd +=
" ORDER BY _i_time DESC LIMIT 2;";
4501 const time_t end_time,
4502 const int num_var,
const std::vector<int>& var_schema_index,
const int var_index[],
4507 bool bad_last_time =
false;
4512 std::string collist;
4514 for (
int i=0;
i<num_var;
i++) {
4515 int j = var_schema_index[
i];
4518 if (collist.length() > 0)
4524 cmd +=
"SELECT _i_time, ";
4528 cmd +=
" WHERE _i_time>=";
4530 cmd +=
" and _i_time<=";
4532 cmd +=
" ORDER BY _i_time;";
4552 if (t < start_time || t > end_time)
4557 for (
int i=0;
i<num_var;
i++) {
4558 int j = var_schema_index[
i];
4563 bad_last_time =
true;
4569 buffer[
i]->
Add(t, v);
4579 if (bad_last_time) {
4619 if (*have_transaction)
4626 *have_transaction =
true;
4630static int CreateSqlTable(
SqlBase* sql,
const char* table_name,
bool* have_transaction,
bool set_default_timestamp =
false)
4640 cmd =
"CREATE TABLE ";
4641 cmd += sql->
QuoteId(table_name);
4642 if (set_default_timestamp) {
4643 cmd +=
" (_t_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, _i_time INTEGER NOT NULL DEFAULT 0);";
4645 cmd +=
" (_t_time TIMESTAMP NOT NULL, _i_time INTEGER NOT NULL);";
4652 cm_msg(
MINFO,
"CreateSqlTable",
"Adding SQL table \"%s\", but it already exists", table_name);
4658 cm_msg(
MINFO,
"CreateSqlTable",
"Adding SQL table \"%s\", error status %d", table_name,
status);
4663 cm_msg(
MINFO,
"CreateSqlTable",
"Adding SQL table \"%s\"", table_name);
4666 std::string i_index_name;
4667 i_index_name = table_name;
4668 i_index_name +=
"_i_time_index";
4670 std::string t_index_name;
4671 t_index_name = table_name;
4672 t_index_name +=
"_t_time_index";
4674 cmd =
"CREATE INDEX ";
4675 cmd += sql->
QuoteId(i_index_name.c_str());
4677 cmd += sql->
QuoteId(table_name);
4678 cmd +=
" (_i_time ASC);";
4684 cmd =
"CREATE INDEX ";
4685 cmd += sql->
QuoteId(t_index_name.c_str());
4687 cmd += sql->
QuoteId(table_name);
4688 cmd +=
" (_t_time);";
4706 cmd =
"CREATE TABLE ";
4707 cmd += sql->
QuoteId(table_name);
4708 cmd +=
" (_t_time TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, _i_time INTEGER NOT NULL DEFAULT 0);";
4713 cm_msg(
MINFO,
"CreateSqlHyperTable",
"Adding SQL table \"%s\", but it already exists", table_name);
4719 cm_msg(
MINFO,
"CreateSqlHyperTable",
"Adding SQL table \"%s\", error status %d", table_name,
status);
4724 cm_msg(
MINFO,
"CreateSqlHyperTable",
"Adding SQL table \"%s\"", table_name);
4727 cmd =
"SELECT create_hypertable(";
4729 cmd +=
", '_t_time');";
4735 cm_msg(
MINFO,
"CreateSqlHyperTable",
"Converting SQL table to hypertable \"%s\", error status %d", table_name,
status);
4740 std::string i_index_name;
4741 i_index_name = table_name;
4742 i_index_name +=
"_i_time_index";
4744 std::string t_index_name;
4745 t_index_name = table_name;
4746 t_index_name +=
"_t_time_index";
4748 cmd =
"CREATE INDEX ";
4749 cmd += sql->
QuoteId(i_index_name.c_str());
4751 cmd += sql->
QuoteId(table_name);
4752 cmd +=
" (_i_time ASC);";
4758 cmd =
"CREATE INDEX ";
4759 cmd += sql->
QuoteId(t_index_name.c_str());
4761 cmd += sql->
QuoteId(table_name);
4762 cmd +=
" (_t_time);";
4774 printf(
"CreateSqlColumn: table [%s], column [%s], type [%s]\n", table_name, column_name, column_type);
4781 cmd =
"ALTER TABLE ";
4782 cmd += sql->
QuoteId(table_name);
4783 cmd +=
" ADD COLUMN ";
4784 cmd += sql->
QuoteId(column_name);
4791 cm_msg(
MINFO,
"CreateSqlColumn",
"Adding column \"%s\" to SQL table \"%s\", status %d", column_name, table_name,
status);
4838 virtual int update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction) = 0;
4841 int update_schema1(
HsSqlSchema* s,
const time_t timestamp,
const int ntags,
const TAG tags[],
bool write_enable,
bool* have_transaction);
4847 printf(
"hs_connect [%s]!\n", connect_string);
4857 if (!connect_string || strlen(connect_string) < 1) {
4859 connect_string =
".";
4865 printf(
"hs_connect: connecting to SQL database \'%s\'\n",
fConnectString.c_str());
4877 printf(
"hs_disconnect!\n");
4891 printf(
"SqlHistory::new_event: event [%s], timestamp %s, ntags %d\n", event_name,
TimeToString(timestamp).c_str(), ntags);
4913 cm_msg(
MERROR,
"SqlHistory::new_event",
"Error: Cannot create schema for event \'%s\', see previous messages", event_name);
4928 cm_msg(
MERROR,
"SqlHistory::new_event",
"Error: Cannot update schema database for event \'%s\', see previous messages", event_name);
4933 printf(
"SqlHistory::new_event: schema for [%s] is %p\n", event_name, s);
4940 cm_msg(
MERROR,
"SqlHistory::new_event",
"Error: Cannot create schema for event \'%s\', see previous messages", event_name);
4951 cm_msg(
MERROR,
"SqlHistory::new_event",
"Error: Cannot update schema database for event \'%s\', see previous messages", event_name);
4956 printf(
"SqlHistory::new_event: schema for [%s] is %p\n", event_name, s);
4965 cm_msg(
MERROR,
"SqlHistory::new_event",
"Error: Cannot create schema for event \'%s\', see previous messages", event_name);
4982 printf(
"SqlHistory::read_schema: loading schema for event [%s] at time %s\n", event_name,
TimeToString(timestamp).c_str());
4986 if (sv->
size() == 0) {
4994 if (event_name == NULL)
4997 for (
size_t i=0;
i<sv->
size();
i++) {
5006 size_t nn = sv->
size();
5011 if (sv->
size() != nn)
5023 bool have_transaction =
false;
5027 if (have_transaction) {
5038 have_transaction =
false;
5049 printf(
"update_schema1\n");
5053 bool schema_ok =
true;
5056 for (
int i=0;
i<ntags;
i++) {
5057 for (
unsigned int j=0;
j<tags[
i].
n_data;
j++) {
5058 int tagtype = tags[
i].
type;
5059 std::string tagname = tags[
i].
name;
5062 if (tags[
i].n_data > 1) {
5064 sprintf(s,
"[%d]",
j);
5067 sprintf(s,
"_%d",
j);
5092 printf(
"Incompatible column!\n");
5109 printf(
"No column for tag %s!\n", tagname.c_str());
5111 bool found_column =
false;
5130 found_column =
true;
5141 if (!found_column && write_enable) {
5142 std::string col_name = maybe_colname;
5152 time_t now = time(NULL);
5155 for (
int t=0; t<20; t++) {
5158 if (dupe || retry) {
5159 col_name = maybe_colname;
5164 sprintf(s,
"_%d", t);
5170 printf(
"SqlHistory::update_schema: table [%s], add column [%s] type [%s] for tag [%s]\n", s->
fTableName.c_str(), col_name.c_str(), col_type, tagname.c_str());
5176 printf(
"SqlHistory::update_schema: table [%s], add column [%s] type [%s] for tag [%s] failed: duplicate column name\n", s->
fTableName.c_str(), col_name.c_str(), col_type, tagname.c_str());
5199 cm_msg(
MERROR,
"SqlHistory::update_schema",
"Duplicate tags or SQL columns for history event \"%s\" tag \"%s\"", s->
fEventName.c_str(), tagname.c_str());
5211 for (
int i=0;
i<ntags;
i++) {
5212 for (
unsigned int j=0;
j<tags[
i].
n_data;
j++) {
5213 std::string tagname = tags[
i].
name;
5215 if (tags[
i].n_data > 1) {
5217 sprintf(s,
"[%d]",
j);
5250 printf(
"Return error!\n");
5264 printf(
"ReadSqliteTableNames: table [%s]\n", table_name);
5270 cmd =
"SELECT event_name, _i_time FROM \'_event_name_";
5272 cmd +=
"\' WHERE table_name='";
5287 std::string xevent_name = sql->
GetText(0);
5288 time_t xevent_time = sql->
GetTime(1);
5309 printf(
"ReadSqliteTableSchema: table [%s]\n", table_name);
5334 fSql =
new Sqlite();
5341 int update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction);
5349 printf(
"SqliteHistory::read_table_and_event_names!\n");
5353 std::vector<std::string> tables;
5358 for (
size_t i=0;
i<tables.size();
i++) {
5359 const char* table_name = tables[
i].c_str();
5362 s = strstr(table_name,
"_event_name_");
5363 if (s == table_name)
5365 s = strstr(table_name,
"_column_names_");
5366 if (s == table_name)
5378 printf(
"SqliteHistory::read_column_names: table [%s], event [%s]\n", table_name, event_name);
5382 std::vector<std::string> columns;
5387 for (
size_t i=0;
i<sv->
size();
i++) {
5396 for (
size_t j=0;
j<columns.size();
j+=2) {
5397 const char* cn = columns[
j+0].c_str();
5398 const char* ct = columns[
j+1].c_str();
5400 if (strcmp(cn,
"_t_time") == 0)
5402 if (strcmp(cn,
"_i_time") == 0)
5428 tn +=
"_column_names_";
5432 cmd =
"SELECT column_name, tag_name, tag_type, _i_time FROM ";
5434 cmd +=
" WHERE table_name=";
5436 cmd +=
" ORDER BY _i_time ASC;";
5466 for (
size_t i=0;
i<sv->
size();
i++) {
5493 printf(
"SqliteHistory::create_table: event [%s], timestamp %s\n", event_name,
TimeToString(timestamp).c_str());
5496 bool have_transaction =
false;
5515 en +=
"_event_name_";
5518 cmd =
"CREATE TABLE ";
5520 cmd +=
" (table_name TEXT NOT NULL, event_name TEXT NOT NULL, _i_time INTEGER NOT NULL);";
5524 cmd =
"INSERT INTO ";
5526 cmd +=
" (table_name, event_name, _i_time) VALUES (";
5537 cn +=
"_column_names_";
5540 cmd =
"CREATE TABLE ";
5542 cmd +=
" (table_name TEXT NOT NULL, column_name TEXT NOT NULL, tag_name TEXT NOT NULL, tag_type TEXT NOT NULL, column_type TEXT NOT NULL, _i_time INTEGER NOT NULL);";
5554int SqliteHistory::update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction)
5557 printf(
"SqliteHistory::update_column: event [%s], table [%s], column [%s], new name [%s], timestamp %s\n", event_name, table_name, column_name, tag_name,
TimeToString(timestamp).c_str());
5565 cmd =
"INSERT INTO \'_column_names_";
5567 cmd +=
"\' (table_name, column_name, tag_name, tag_type, column_type, _i_time) VALUES (\'";
5601 int update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction);
5607 printf(
"ReadMysqlTableNames: table [%s], must have event [%s] table [%s]\n", table_name, must_have_event_name, must_have_table_name);
5613 cmd =
"SELECT event_name, table_name, itimestamp FROM _history_index WHERE table_name='";
5622 cmd =
"SELECT event_name, table_name, itimestamp FROM _history_index WHERE table_name!='' AND column_name IS NULL;";
5623 table_name =
"_history_index";
5631 bool found_must_have_table =
false;
5640 const char* xevent_name = sql->
GetText(0);
5641 const char* xtable_name = sql->
GetText(1);
5642 time_t xevent_time = sql->
GetTime(2);
5645 printf(
"entry %d event name [%s] table name [%s] time %s\n",
count, xevent_name, xtable_name,
TimeToString(xevent_time).c_str());
5648 if (must_have_table_name && (strcmp(xtable_name, must_have_table_name) == 0)) {
5649 assert(must_have_event_name != NULL);
5651 found_must_have_table =
true;
5670 if (must_have_table_name && !found_must_have_table) {
5671 cm_msg(
MERROR,
"ReadMysqlTableNames",
"Error: Table [%s] for event [%s] missing from the history index\n", must_have_table_name, must_have_event_name);
5675 ReadMysqlTableNames(sql, sv, table_name, 999, must_have_event_name, must_have_table_name);
5676 cm_msg(
MERROR,
"ReadMysqlTableNames",
"Error: Cannot continue, nothing will work after this error\n");
5684 printf(
"ReadMysqlTableNames: table_name [%s] event_name [%s] table_name [%s]\n", table_name, must_have_event_name, must_have_table_name);
5694 printf(
"MysqlHistory::read_column_names: table [%s], event [%s]\n", table_name, event_name);
5698 std::vector<std::string> columns;
5703 for (
size_t i=0;
i<sv->
size();
i++) {
5712 for (
size_t j=0;
j<columns.size();
j+=2) {
5713 const char* cn = columns[
j+0].c_str();
5714 const char* ct = columns[
j+1].c_str();
5716 if (strcmp(cn,
"_t_time") == 0)
5718 if (strcmp(cn,
"_i_time") == 0)
5746 cmd =
"SELECT column_name, column_type, tag_name, tag_type, itimestamp, active FROM _history_index WHERE event_name=";
5768 int iactive = atoi(active);
5776 if (strlen(col_name) < 1)
5784 for (
size_t i=0;
i<sv->
size();
i++) {
5827 printf(
"ReadMysqlTableSchema: table [%s]\n", table_name);
5849 printf(
"MysqlHistory::read_table_and_event_names!\n");
5853 std::vector<std::string> tables;
5858 for (
size_t i=0;
i<tables.size();
i++) {
5859 const char* table_name = tables[
i].c_str();
5862 s = strstr(table_name,
"_history_index");
5863 if (s == table_name)
5880 printf(
"read_table_and_event_names:\n");
5892 printf(
"MysqlHistory::create_table: event [%s], timestamp %s\n", event_name,
TimeToString(timestamp).c_str());
5898 if (table_name.length() > 40) {
5899 table_name.resize(40);
5903 time_t now = time(NULL);
5905 int max_attempts = 10;
5906 for (
int i=0;
i<max_attempts;
i++) {
5912 bool have_transaction =
true;
5914 std::string xtable_name = table_name;
5922 sprintf(buf,
"%d",
i);
5939 cm_msg(
MERROR,
"MysqlHistory::create_table",
"Could not create table [%s] for event [%s], timestamp %s, please fix the SQL database configuration and try again", table_name.c_str(), event_name,
TimeToString(timestamp).c_str());
5947 for (
int j=0;
j<2;
j++) {
5949 cmd +=
"INSERT INTO _history_index (event_name, table_name, itimestamp, active) VALUES (";
5955 sprintf(buf,
"%.0f", (
double)timestamp);
5985 cm_msg(
MERROR,
"MysqlHistory::create_table",
"Could not create table [%s] for event [%s], timestamp %s, after %d attempts", table_name.c_str(), event_name,
TimeToString(timestamp).c_str(), max_attempts);
5990int MysqlHistory::update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction)
5993 printf(
"MysqlHistory::update_column: event [%s], table [%s], column [%s], type [%s] new name [%s], timestamp %s\n", event_name, table_name, column_name, column_type, tag_name,
TimeToString(timestamp).c_str());
5996 cmd +=
"INSERT INTO _history_index (event_name, table_name, tag_name, tag_type, column_name, column_type, itimestamp, active) VALUES (";
6010 sprintf(buf,
"%.0f", (
double)timestamp);
6035 Pgsql *fPgsql = NULL;
6038 fPgsql =
new Pgsql();
6045 int update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction);
6048static int ReadPgsqlTableNames(
SqlBase* sql,
HsSchemaVector *sv,
const char* table_name,
int debug,
const char* must_have_event_name,
const char* must_have_table_name)
6051 printf(
"ReadPgsqlTableNames: table [%s], must have event [%s] table [%s]\n", table_name, must_have_event_name, must_have_table_name);
6057 cmd =
"SELECT event_name, table_name, itimestamp FROM _history_index WHERE table_name='";
6066 cmd =
"SELECT event_name, table_name, itimestamp FROM _history_index WHERE table_name!='' AND column_name IS NULL;";
6067 table_name =
"_history_index";
6075 bool found_must_have_table =
false;
6084 const char* xevent_name = sql->
GetText(0);
6085 const char* xtable_name = sql->
GetText(1);
6086 time_t xevent_time = sql->
GetTime(2);
6089 printf(
"entry %d event name [%s] table name [%s] time %s\n",
count, xevent_name, xtable_name,
TimeToString(xevent_time).c_str());
6092 if (must_have_table_name && (strcmp(xtable_name, must_have_table_name) == 0)) {
6093 assert(must_have_event_name != NULL);
6095 found_must_have_table =
true;
6114 if (must_have_table_name && !found_must_have_table) {
6115 cm_msg(
MERROR,
"ReadPgsqlTableNames",
"Error: Table [%s] for event [%s] missing from the history index\n", must_have_table_name, must_have_event_name);
6119 ReadPgsqlTableNames(sql, sv, table_name, 999, must_have_event_name, must_have_table_name);
6120 cm_msg(
MERROR,
"ReadPgsqlTableNames",
"Error: Cannot continue, nothing will work after this error\n");
6128 printf(
"ReadPgsqlTableNames: table_name [%s] event_name [%s] table_name [%s]\n", table_name, must_have_event_name, must_have_table_name);
6135int PgsqlHistory::read_column_names(
HsSchemaVector *sv,
const char* table_name,
const char* event_name)
6138 printf(
"PgsqlHistory::read_column_names: table [%s], event [%s]\n", table_name, event_name);
6142 std::vector<std::string> columns;
6143 fSql->ListColumns(table_name, &columns);
6147 for (
size_t i=0;
i<sv->
size();
i++) {
6156 for (
size_t j=0;
j<columns.size();
j+=2) {
6157 const char* cn = columns[
j+0].c_str();
6158 const char* ct = columns[
j+1].c_str();
6160 if (strcmp(cn,
"_t_time") == 0)
6162 if (strcmp(cn,
"_i_time") == 0)
6188 cmd =
"SELECT column_name, column_type, tag_name, tag_type, itimestamp, active FROM _history_index WHERE event_name=";
6189 cmd += fSql->QuoteString(event_name);
6192 int status = fSql->Prepare(table_name, cmd.c_str());
6204 const char* col_name = fSql->GetText(0);
6205 const char* col_type = fSql->GetText(1);
6206 const char* tag_name = fSql->GetText(2);
6207 const char* tag_type = fSql->GetText(3);
6208 time_t schema_time = fSql->GetTime(4);
6209 const char* active = fSql->GetText(5);
6210 int iactive = atoi(active);
6218 if (strlen(col_name) < 1)
6225 for (
size_t i=0;
i<sv->
size();
i++) {
6259 status = fSql->Finalize();
6269 printf(
"PgsqlHistory::read_table_and_event_names!\n");
6273 std::vector<std::string> tables;
6274 status = fSql->ListTables(&tables);
6278 for (
size_t i=0;
i<tables.size();
i++) {
6279 const char* table_name = tables[
i].c_str();
6282 s = strstr(table_name,
"_history_index");
6283 if (s == table_name)
6300 printf(
"read_table_and_event_names:\n");
6304 status = ReadPgsqlTableNames(fSql, sv, NULL, fDebug, NULL, NULL);
6309int PgsqlHistory::create_table(
HsSchemaVector* sv,
const char* event_name, time_t timestamp)
6312 printf(
"PgsqlHistory::create_table: event [%s], timestamp %s\n", event_name,
TimeToString(timestamp).c_str());
6318 if (table_name.length() > 40) {
6319 table_name.resize(40);
6323 time_t now = time(NULL);
6325 int max_attempts = 10;
6326 for (
int i=0;
i<max_attempts;
i++) {
6327 status = fSql->OpenTransaction(table_name.c_str());
6332 bool have_transaction =
true;
6334 std::string xtable_name = table_name;
6342 sprintf(buf,
"%d",
i);
6347 if (fPgsql->fDownsample)
6356 fSql->RollbackTransaction(table_name.c_str());
6361 fSql->RollbackTransaction(table_name.c_str());
6365 fSql->Exec(table_name.c_str(),
"SAVEPOINT t0");
6367 for (
int j=0;
j<2;
j++) {
6369 cmd +=
"INSERT INTO _history_index (event_name, table_name, itimestamp, active) VALUES (";
6370 cmd += fSql->QuoteString(event_name);
6372 cmd += fSql->QuoteString(xtable_name.c_str());
6375 sprintf(buf,
"%.0f", (
double)timestamp);
6378 cmd += fSql->QuoteString(
"1");
6381 int status = fSql->Exec(table_name.c_str(), cmd.c_str());
6387 fSql->Exec(table_name.c_str(),
"ROLLBACK TO SAVEPOINT t0");
6390 status =
CreateSqlColumn(fSql,
"_history_index",
"event_name",
"text not null", &have_transaction, fDebug);
6396 status =
CreateSqlColumn(fSql,
"_history_index",
"itimestamp",
"integer not null", &have_transaction, fDebug);
6399 status = fSql->CommitTransaction(table_name.c_str());
6406 return ReadPgsqlTableNames(fSql, sv, xtable_name.c_str(), fDebug, event_name, xtable_name.c_str());
6409 cm_msg(
MERROR,
"PgsqlHistory::create_table",
"Could not create table [%s] for event [%s], timestamp %s, after %d attempts", table_name.c_str(), event_name,
TimeToString(timestamp).c_str(), max_attempts);
6414int PgsqlHistory::update_column(
const char* event_name,
const char* table_name,
const char* column_name,
const char* column_type,
const char* tag_name,
const char* tag_type,
const time_t timestamp,
bool active,
bool* have_transaction)
6417 printf(
"PgsqlHistory::update_column: event [%s], table [%s], column [%s], type [%s] new name [%s], timestamp %s\n", event_name, table_name, column_name, column_type, tag_name,
TimeToString(timestamp).c_str());
6420 cmd +=
"INSERT INTO _history_index (event_name, table_name, tag_name, tag_type, column_name, column_type, itimestamp, active) VALUES (";
6421 cmd += fSql->QuoteString(event_name);
6423 cmd += fSql->QuoteString(table_name);
6425 cmd += fSql->QuoteString(tag_name);
6427 cmd += fSql->QuoteString(tag_type);
6429 cmd += fSql->QuoteString(column_name);
6431 cmd += fSql->QuoteString(column_type);
6434 sprintf(buf,
"%.0f", (
double)timestamp);
6438 cmd += fSql->QuoteString(
"1");
6440 cmd += fSql->QuoteString(
"0");
6443 int status = fSql->Exec(table_name, cmd.c_str());
6486 int create_file(
const char* event_name, time_t timestamp,
const std::vector<HsSchemaEntry>& vars, std::string* filenamep);
6497 printf(
"hs_connect [%s]!\n", connect_string);
6502 fPath = connect_string;
6505 if (
fPath.length() > 0) {
6516 printf(
"FileHistory::hs_clear_cache!\n");
6524 printf(
"FileHistory::hs_disconnect!\n");
6547 struct stat stat_buf;
6550 cm_msg(
MERROR,
"FileHistory::read_file_list",
"Cannot stat(%s), errno %d (%s)",
fPath.c_str(), errno, strerror(errno));
6558 printf(
"FileHistory::read_file_list: history directory \"%s\" mtime %d did not change\n",
fPath.c_str(),
int(stat_buf.st_mtime));
6565 printf(
"FileHistory::read_file_list: reading list of history files in \"%s\"\n",
fPath.c_str());
6567 std::vector<std::string> flist;
6572 double ls_elapsed = ls_time - start_time;
6573 if (ls_elapsed > 5.000) {
6574 cm_msg(
MINFO,
"FileHistory::read_file_list",
"\"ls -l\" of \"%s\" took %.1f sec",
fPath.c_str(), ls_elapsed);
6579 std::sort(flist.rbegin(), flist.rend());
6583 printf(
"file names sorted by time:\n");
6584 for (
size_t i=0;
i<flist.size();
i++) {
6585 printf(
"%d: %s\n",
i, flist[
i].c_str());
6590 std::vector<bool> fread;
6591 fread.resize(flist.size());
6598 for (
size_t i=0;
i<flist.size();
i++) {
6619 printf(
"FileHistory::read_schema: event [%s] at time %s\n", event_name,
TimeToString(timestamp).c_str());
6621 if (sv->
size() == 0) {
6623 printf(
"FileHistory::read_schema: schema is empty, do a full reload from disk\n");
6628 DWORD old_timeout = 0;
6632 bool changed =
false;
6642 if ((*sv).find_event(event_name, timestamp)) {
6644 printf(
"FileHistory::read_schema: event [%s] at time %s, no new history files, already have this schema\n", event_name,
TimeToString(timestamp).c_str());
6689 double read_elapsed = end_time - start_time;
6690 if (read_elapsed > 5.000) {
6691 cm_msg(
MINFO,
"FileHistory::read_schema",
"Loading schema for event \"%s\" timestamp %s, reading %d history files took %.1f sec", event_name,
TimeToString(timestamp).c_str(), count_read, read_elapsed);
6702 for (
int i=0;
i<ntags;
i++) {
6707 e.tag_name = tags[
i].
name;
6714 variables.push_back(
e);
6721 printf(
"FileHistory::new_event: event [%s], timestamp %s, ntags %d\n", event_name,
TimeToString(timestamp).c_str(), ntags);
6737 bool xdebug =
false;
6745 printf(
"AAA: [%s] [%s]!\n", s->
fEventName.c_str(), event_name);
6753 printf(
"BBB: event [%s]: ntags: %zu -> %d!\n", event_name, s->
fVariables.size(), ntags);
6762 printf(
"CCC: event [%s] index %zu: name [%s] -> [%s]!\n", event_name,
i, s->
fVariables[
i].name.c_str(), tags[
i].
name);
6767 printf(
"DDD: event [%s] index %zu: type %d -> %d!\n", event_name,
i, s->
fVariables[
i].type, tags[
i].
type);
6772 printf(
"EEE: event [%s] index %zu: n_data %d -> %d!\n", event_name,
i, s->
fVariables[
i].n_data, tags[
i].
n_data);
6782 printf(
"*** Schema for event %s has changed!\n", event_name);
6784 printf(
"*** Old schema for event [%s] time %s:\n", event_name,
TimeToString(timestamp).c_str());
6786 printf(
"*** New tags:\n");
6791 printf(
"FileHistory::new_event: event [%s], timestamp %s, ntags %d: schema mismatch, starting a new file.\n", event_name,
TimeToString(timestamp).c_str(), ntags);
6803 printf(
"FileHistory::new_event: event [%s], timestamp %s, ntags %d: schema is too old, age %.1f months, starting a new file.\n", event_name,
TimeToString(timestamp).c_str(), ntags, (
double)age/(
double)
kMonth);
6816 printf(
"FileHistory::new_event: event [%s], timestamp %s, ntags %d: file too big, size %.1f MiBytes, max size %.1f MiBytes, starting a new file.\n", event_name,
TimeToString(timestamp).c_str(), ntags, size/
MiB,
fConfMaxFileSize/
MiB);
6824 std::string filename;
6826 std::vector<HsSchemaEntry> vars;
6836 cm_msg(
MERROR,
"FileHistory::new_event",
"Error: Cannot create schema for event \'%s\', see previous messages", event_name);
6845 cm_msg(
MERROR,
"FileHistory::new_event",
"Error: Cannot create schema for event \'%s\', see previous messages", event_name);
6850 printf(
"*** New schema for event [%s] time %s:\n", event_name,
TimeToString(timestamp).c_str());
6859 printf(
"schema for [%s] is %p\n", event_name, s);
6875 printf(
"FileHistory::create_file: event [%s]\n", event_name);
6882 localtime_r(×tamp, &
tm);
6885 strftime(buf,
sizeof(buf),
"%Y%m%d", &
tm);
6887 std::string filename;
6896 std::string try_filename = filename +
".dat";
6899 for (
int itry=0; itry<10; itry++) {
6902 sprintf(s,
"_%d", rand());
6903 try_filename = filename + s +
".dat";
6906 fp = fopen(try_filename.c_str(),
"r");
6913 fp = fopen(try_filename.c_str(),
"w");
6916 cm_msg(
MERROR,
"FileHistory::create_file",
"Error: Cannot create file \'%s\' for event \'%s\', fopen() errno %d (%s)", try_filename.c_str(), event_name, errno, strerror(errno));
6926 cm_msg(
MERROR,
"FileHistory::create_file",
"Error: Cannot create file \'%s\' for event \'%s\'", filename.c_str(), event_name);
6932 ss +=
"version: 2.0\n";
6933 ss +=
"event_name: ";
6942 ss +=
"tag: /DWORD 1 4 /timestamp\n";
6945 bool padded =
false;
6948 bool xdebug =
false;
6950 for (
size_t i=0;
i<vars.size();
i++) {
6952 int n_bytes = vars[
i].n_data*tsize;
6953 int xalign = (
offset % tsize);
6956 printf(
"tag %zu, tsize %d, n_bytes %d, xalign %d\n",
i, tsize, n_bytes, xalign);
6962 int pad_bytes = tsize - xalign;
6963 assert(pad_bytes > 0);
6977 recsize += pad_bytes;
6979 assert((
offset % tsize) == 0);
6980 fprintf(stderr,
"FIXME: need to debug padding!\n");
6999 ss +=
"record_size: ";
7004 int sslength = ss.length() + 127;
7007 int nb = (sslength + block - 1)/block;
7008 int data_offset = block * nb;
7010 ss +=
"data_offset: ";
7014 fprintf(
fp,
"%s", ss.c_str());
7019 printf(
"Schema in file %s has padding:\n", try_filename.c_str());
7020 printf(
"%s", ss.c_str());
7024 *filenamep = try_filename;
7032 printf(
"FileHistory::read_file_schema: file %s\n", filename);
7034 FILE*
fp = fopen(filename,
"r");
7036 cm_msg(
MERROR,
"FileHistory::read_file_schema",
"Cannot read \'%s\', fopen() errno %d (%s)", filename, errno, strerror(errno));
7053 size_t rd_recsize = 0;
7058 char* b = fgets(buf,
sizeof(buf),
fp);
7068 bb = strchr(b,
'\n');
7072 bb = strchr(b,
'\r');
7076 bb = strstr(b,
"version: 2.0");
7090 bb = strstr(b,
"event_name: ");
7096 bb = strstr(b,
"time: ");
7098 s->
fTimeFrom = strtoul(bb + 6, NULL, 10);
7111 bb = strstr(b,
"tag: ");
7114 const char* midas_type = bb;
7115 char* bbb = strchr(bb,
' ');
7119 if (midas_type[0] ==
'/') {
7124 cm_msg(
MERROR,
"FileHistory::read_file_schema",
"Unknown MIDAS data type \'%s\' in history file \'%s\'", midas_type, filename);
7135 t.
n_data = strtoul(bbb, &bbb, 10);
7139 t.
n_bytes = strtoul(bbb, &bbb, 10);
7146 if (midas_type[0] !=
'/') {
7157 bb = strstr(b,
"record_size: ");
7163 bb = strstr(b,
"data_offset: ");
7174 cm_msg(
MERROR,
"FileHistory::read_file_schema",
"Malformed history schema in \'%s\', maybe it is not a history file", filename);
7179 cm_msg(
MERROR,
"FileHistory::read_file_schema",
"Record size mismatch in history schema from \'%s\', file says %zu while total of all tags is %zu", filename, s->
fRecordSize, rd_recsize);
7186 cm_msg(
MERROR,
"FileHistory::read_file_schema",
"Could not read history schema from \'%s\', maybe it is not a history file", filename);
7219 std::string new_filename;
7238 *new_fs_copy = *new_fs;
7271 cm_msg(
MERROR,
"MakeMidasHistorySqlite",
"Error: Cannot initialize SQLITE history - this MIDAS was built without SQLITE support - HAVE_SQLITE is not defined");
7281 cm_msg(
MERROR,
"MakeMidasHistoryMysql",
"Error: Cannot initialize MySQL history - this MIDAS was built without MySQL support - HAVE_MYSQL is not defined");
7289 return new PgsqlHistory();
7291 cm_msg(
MERROR,
"MakeMidasHistoryPgsql",
"Error: Cannot initialize PgSQL history - this MIDAS was built without PostgreSQL support - HAVE_PGSQL is not defined");
HsSchema * maybe_reopen(const char *event_name, time_t timestamp, HsSchema *s)
HsFileSchema * read_file_schema(const char *filename)
std::vector< std::string > fSortedFiles
HsSchema * new_event(const char *event_name, time_t timestamp, int ntags, const TAG tags[])
std::vector< bool > fSortedRead
int hs_connect(const char *connect_string)
returns HS_SUCCESS
void tags_to_variables(int ntags, const TAG tags[], std::vector< HsSchemaEntry > &variables)
int create_file(const char *event_name, time_t timestamp, const std::vector< HsSchemaEntry > &vars, std::string *filenamep)
int hs_clear_cache()
clear internal cache, returns HS_SUCCESS
int read_schema(HsSchemaVector *sv, const char *event_name, const time_t timestamp)
int read_file_list(bool *pchanged)
int hs_disconnect()
disconnect from history, returns HS_SUCCESS
void remove_inactive_columns()
int read_data(const time_t start_time, const time_t end_time, const int num_var, const std::vector< int > &var_schema_index, const int var_index[], const int debug, std::vector< time_t > &last_time, MidasHistoryBufferInterface *buffer[])
void print(bool print_tags=true) const
int write_event(const time_t t, const char *data, const size_t data_size)
int read_last_written(const time_t timestamp, const int debug, time_t *last_written)
virtual void print(bool print_tags=true) const
std::vector< int > fOffsets
virtual void remove_inactive_columns()=0
std::vector< HsSchemaEntry > fVariables
virtual int read_data(const time_t start_time, const time_t end_time, const int num_var, const std::vector< int > &var_schema_index, const int var_index[], const int debug, std::vector< time_t > &last_time, MidasHistoryBufferInterface *buffer[])=0
virtual int write_event(const time_t t, const char *data, const size_t data_size)=0
virtual int read_last_written(const time_t timestamp, const int debug, time_t *last_written)=0
virtual int flush_buffers()=0
virtual int match_event_var(const char *event_name, const char *var_name, const int var_index)
void print(bool print_tags=true) const
std::vector< HsSchema * > fData
HsSchema * find_event(const char *event_name, const time_t timestamp, int debug=0)
HsSchema * operator[](int index) const
int get_transaction_count()
int read_last_written(const time_t timestamp, const int debug, time_t *last_written)
int read_data(const time_t start_time, const time_t end_time, const int num_var, const std::vector< int > &var_schema_index, const int var_index[], const int debug, std::vector< time_t > &last_time, MidasHistoryBufferInterface *buffer[])
std::vector< std::string > fColumnNames
void print(bool print_tags=true) const
void remove_inactive_columns()
std::vector< std::string > fColumnTypes
int fTableTransactionCount
std::unordered_map< std::string, size_t > fColumnIndexCache
int find_column_index(const std::string &column_name)
std::vector< bool > fColumnInactive
void increment_transaction_count()
int match_event_var(const char *event_name, const char *var_name, const int var_index)
static std::map< SqlBase *, int > gfTransactionCount
void reset_transaction_count()
int write_event(const time_t t, const char *data, const size_t data_size)
MidasHistoryBinnedBuffer(time_t first_time, time_t last_time, int num_bins)
~MidasHistoryBinnedBuffer()
void Add(time_t t, double v)
virtual void Add(time_t time, double value)=0
char type[NAME_LENGTH]
history channel name
int update_column(const char *event_name, const char *table_name, const char *column_name, const char *column_type, const char *tag_name, const char *tag_type, const time_t timestamp, bool active, bool *have_transaction)
int read_table_and_event_names(HsSchemaVector *sv)
int create_table(HsSchemaVector *sv, const char *event_name, time_t timestamp)
int read_column_names(HsSchemaVector *sv, const char *table_name, const char *event_name)
void Add(time_t t, double v)
ReadBuffer(time_t first_time, time_t last_time, time_t interval)
void Realloc(int wantalloc)
int hs_get_tags(const char *event_name, time_t t, std::vector< TAG > *ptags)
get list of history variables for given event (use event names returned by hs_get_events()) that exis...
virtual int hs_connect(const char *connect_string)=0
returns HS_SUCCESS
virtual ~SchemaHistoryBase()
int hs_write_event(const char *event_name, time_t timestamp, int buffer_size, const char *buffer)
see hs_write_event(), returns HS_SUCCESS or HS_FILE_ERROR
int hs_read_buffer(time_t start_time, time_t end_time, int num_var, const char *const event_name[], const char *const var_name[], const int var_index[], MidasHistoryBufferInterface *buffer[], int hs_status[])
returns HS_SUCCESS
virtual HsSchema * maybe_reopen(const char *event_name, time_t timestamp, HsSchema *s)=0
int hs_define_event(const char *event_name, time_t timestamp, int ntags, const TAG tags[])
see hs_define_event(), returns HS_SUCCESS or HS_FILE_ERROR
int hs_read_binned(time_t start_time, time_t end_time, int num_bins, int num_var, const char *const event_name[], const char *const var_name[], const int var_index[], int num_entries[], int *count_bins[], double *mean_bins[], double *rms_bins[], double *min_bins[], double *max_bins[], time_t *bins_first_time[], double *bins_first_value[], time_t *bins_last_time[], double *bins_last_value[], time_t last_time[], double last_value[], int st[])
returns HS_SUCCESS
HsSchemaVector fWriterSchema
virtual HsSchema * new_event(const char *event_name, time_t timestamp, int ntags, const TAG tags[])=0
int hs_get_events(time_t t, std::vector< std::string > *pevents)
get list of events that exist(ed) at given time and later (value 0 means "return all events from begi...
std::vector< HsSchema * > fWriterEvents
int hs_get_last_written(time_t timestamp, int num_var, const char *const event_name[], const char *const var_name[], const int var_index[], time_t last_written[])
virtual int hs_set_debug(int debug)
set debug level, returns previous debug level
virtual int hs_disconnect()=0
disconnect from history, returns HS_SUCCESS
HsSchemaVector fReaderSchema
int hs_read(time_t start_time, time_t end_time, time_t interval, int num_var, const char *const event_name[], const char *const var_name[], const int var_index[], int num_entries[], time_t *time_buffer[], double *data_buffer[], int st[])
see hs_read(), returns HS_SUCCESS
int hs_clear_cache()
clear internal cache, returns HS_SUCCESS
std::string fConnectString
int hs_flush_buffers()
flush buffered data to storage where it is visible to mhttpd
virtual int read_schema(HsSchemaVector *sv, const char *event_name, const time_t timestamp)=0
virtual int ListColumns(const char *table_name, std::vector< std::string > *plist)=0
virtual int Connect(const char *path)=0
virtual int ListColumns(const char *table, std::vector< std::string > *plist)=0
virtual double GetDouble(int column)=0
virtual int RollbackTransaction(const char *table_name)=0
virtual bool IsConnected()=0
virtual int CommitTransaction(const char *table_name)=0
virtual int ListTables(std::vector< std::string > *plist)=0
virtual std::string QuoteId(const char *s)=0
virtual int Disconnect()=0
virtual bool TypesCompatible(int midas_tid, const char *sql_type)=0
virtual int Prepare(const char *table_name, const char *sql)=0
virtual int Exec(const char *sql)=0
virtual int Connect(const char *dsn=0)=0
virtual int Exec(const char *table_name, const char *sql)=0
virtual std::string QuoteString(const char *s)=0
bool fTransactionPerTable
virtual time_t GetTime(int column)=0
virtual const char * GetText(int column)=0
virtual int ExecDisconnected(const char *table_name, const char *sql)=0
virtual int OpenTransaction(const char *table_name)=0
virtual const char * ColumnType(int midas_tid)=0
int update_schema1(HsSqlSchema *s, const time_t timestamp, const int ntags, const TAG tags[], bool write_enable, bool *have_transaction)
int hs_disconnect()
disconnect from history, returns HS_SUCCESS
int hs_set_debug(int debug)
set debug level, returns previous debug level
int read_schema(HsSchemaVector *sv, const char *event_name, const time_t timestamp)
HsSchema * maybe_reopen(const char *event_name, time_t timestamp, HsSchema *s)
virtual ~SqlHistoryBase()
virtual int create_table(HsSchemaVector *sv, const char *event_name, time_t timestamp)=0
virtual int update_column(const char *event_name, const char *table_name, const char *column_name, const char *column_type, const char *tag_name, const char *tag_type, const time_t timestamp, bool active, bool *have_transaction)=0
virtual int read_column_names(HsSchemaVector *sv, const char *table_name, const char *event_name)=0
virtual int read_table_and_event_names(HsSchemaVector *sv)=0
int hs_connect(const char *connect_string)
returns HS_SUCCESS
HsSchema * new_event(const char *event_name, time_t timestamp, int ntags, const TAG tags[])
int update_schema(HsSqlSchema *s, const time_t timestamp, const int ntags, const TAG tags[], bool write_enable)
int update_column(const char *event_name, const char *table_name, const char *column_name, const char *column_type, const char *tag_name, const char *tag_type, const time_t timestamp, bool active, bool *have_transaction)
int read_column_names(HsSchemaVector *sv, const char *table_name, const char *event_name)
int create_table(HsSchemaVector *sv, const char *event_name, time_t timestamp)
int read_table_and_event_names(HsSchemaVector *sv)
INT cm_get_watchdog_params(BOOL *call_watchdog, DWORD *timeout)
INT cm_set_watchdog_params(BOOL call_watchdog, DWORD timeout)
#define DB_NO_MORE_SUBKEYS
#define HS_UNDEFINED_EVENT
double ss_file_size(const char *path)
INT ss_file_find(const char *path, const char *pattern, char **plist)
INT cm_msg_flush_buffer()
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
const char * rpc_tid_name(INT id)
int rpc_name_tid(const char *name)
static std::string q(const char *s)
static const int tid_size[]
static const char * sql_type_mysql[]
static const char ** sql_type
static std::string MidasNameToSqlName(const char *s)
static int CreateSqlColumn(SqlBase *sql, const char *table_name, const char *column_name, const char *column_type, bool *have_transaction, int debug)
static int ReadSqliteTableNames(SqlBase *sql, HsSchemaVector *sv, const char *table_name, int debug)
void DoctorPgsqlColumnType(std::string *col_type, const char *index_type)
static int ReadRecord(const char *file_name, int fd, off64_t offset, size_t recsize, off64_t irec, char *rec)
static int CreateSqlHyperTable(SqlBase *sql, const char *table_name, bool *have_transaction)
void DoctorSqlColumnType(std::string *col_type, const char *index_type)
static bool MatchTagName(const char *tag_name, int n_data, const char *var_tag_name, const int var_tag_index)
static int var_name_cmp(const std::string &v1, const char *v2)
static std::string TimeToString(time_t t)
MidasHistoryInterface * MakeMidasHistorySqlite()
static void PrintTags(int ntags, const TAG tags[])
static char * skip_spaces(char *s)
static bool MatchEventName(const char *event_name, const char *var_event_name)
static HsSqlSchema * NewSqlSchema(HsSchemaVector *sv, const char *table_name, time_t t)
static int StartSqlTransaction(SqlBase *sql, const char *table_name, bool *have_transaction)
MidasHistoryInterface * MakeMidasHistoryMysql()
static int ReadSqliteTableSchema(SqlBase *sql, HsSchemaVector *sv, const char *table_name, int debug)
static int event_name_cmp(const std::string &e1, const char *e2)
MidasHistoryInterface * MakeMidasHistoryPgsql()
MidasHistoryInterface * MakeMidasHistoryFile()
static int ReadMysqlTableNames(SqlBase *sql, HsSchemaVector *sv, const char *table_name, int debug, const char *must_have_event_name, const char *must_have_table_name)
static std::string SmallIntToString(int i)
static int CreateSqlTable(SqlBase *sql, const char *table_name, bool *have_transaction, bool set_default_timestamp=false)
static std::string MidasNameToFileName(const char *s)
static int FindTime(const char *file_name, int fd, off64_t offset, size_t recsize, off64_t nrec, time_t timestamp, off64_t *i1p, time_t *t1p, off64_t *i2p, time_t *t2p, time_t *tstart, time_t *tend, int debug)
BOOL debug
debug printouts
char host_name[HOST_NAME_LENGTH]
#define DIR_SEPARATOR_STR
#define write(n, a, f, d)
struct callback_addr callback
BOOL match(char *pat, char *str)