28#define FREE(x) { if (x) free(x); (x) = NULL; }
98 "xxxINVALIDxxxSTRUCT",
118 "xxxINVALIDxxxARRAY",
119 "xxxINVALIDxxxSTRUCT",
146 for (
int tid=0; tid<15; tid++)
149 printf(
"sql2midasType: Cannot convert SQL data type \'%s\' to a MIDAS data type!\n",
name);
193 virtual int Exec(
const char* sql) = 0;
240 filename =
"/dev/fd/1";
283#define DWORD DWORD_xxx
324 int Exec(
const char* sql);
339 fIsConnected =
false;
348int SqlODBC::Connect(
const char*
dsn)
358 cm_msg(
MERROR,
"SqlODBC::Connect",
"SQLAllocHandle(SQL_HANDLE_ENV) error %d",
status);
374 cm_msg(
MERROR,
"SqlODBC::Connect",
"SQLAllocHandle(SQL_HANDLE_DBC) error %d",
status);
414 cm_msg(
MINFO,
"SqlODBC::Connect",
"Connected to ODBC database DSN \'%s\'",
dsn);
421int SqlODBC::Disconnect()
432 fIsConnected =
false;
437bool SqlODBC::IsConnected()
447 for (
int i=1; ;
i++) {
472 if (1 || (error == 2006) ) {
476 }
else if (1 || ((error != 1060) && (error != 1050))) {
484int SqlODBC::DecodeError()
491 for (
int i=1; ;
i++) {
519int SqlODBC::ListTables(std::vector<std::string> *
plist)
524 for (
int i=0;
i<2;
i++) {
526 printf(
"SqlODBC::ListTables!\n");
535 printf(
"SqlODBC::ListTables: SQLTables() error %d\n",
status);
547 cm_msg(
MINFO,
"SqlODBC::ListTables",
"Reconnecting to ODBC database DSN \'%s\'",
fDSN.c_str());
555 cm_msg(
MERROR,
"SqlODBC::ListTables",
"Cannot reconnect to ODBC database DSN \'%s\', status %d. Database is down?",
fDSN.c_str(),
status);
559 cm_msg(
MINFO,
"SqlODBC::ListTables",
"Reconnected to ODBC database DSN \'%s\'",
fDSN.c_str());
562 int ncols = GetNumColumns();
563 int nrows = GetNumRows();
566 cm_msg(
MERROR,
"SqlODBC::ListTables",
"Error: SQLTables() returned unexpected number of columns %d or number of rows %d",
ncols,
nrows);
578 const char* s = GetColumn(
i);
585 plist->push_back(GetColumn(3));
593int SqlODBC::ListColumns(
const char* table, std::vector<std::string> *
plist)
598 for (
int i=0;
i<2;
i++) {
600 printf(
"SqlODBC::ListColumns for table \'%s\'\n", table);
609 printf(
"SqlODBC::ListColumns: SQLColumns(%s) error %d\n", table,
status);
621 cm_msg(
MINFO,
"SqlODBC::ListColumns",
"Reconnecting to ODBC database DSN \'%s\'",
fDSN.c_str());
629 cm_msg(
MERROR,
"SqlODBC::ListColumns",
"Cannot reconnect to ODBC database DSN \'%s\', status %d. Database is down?",
fDSN.c_str(),
status);
633 cm_msg(
MINFO,
"SqlODBC::ListColumns",
"Reconnected to ODBC database DSN \'%s\'",
fDSN.c_str());
636 int ncols = GetNumColumns();
637 int nrows = GetNumRows();
640 cm_msg(
MERROR,
"SqlODBC::ListColumns",
"Error: SQLColumns(\'%s\') returned unexpected number of columns %d or number of rows %d", table,
ncols,
nrows);
654 const char* s = GetColumn(
i);
661 plist->push_back(GetColumn(4));
662 plist->push_back(GetColumn(6));
670int SqlODBC::Exec(
const char* sql)
682 for (
int i=0;
i<2;
i++) {
684 printf(
"SqlODBC::Exec: %s\n", sql);
693 printf(
"SqlODBC::Exec: SQLExecDirect() error %d: SQL command: \"%s\"\n",
status, sql);
705 cm_msg(
MINFO,
"SqlODBC::Exec",
"Reconnecting to ODBC database DSN \'%s\'",
fDSN.c_str());
713 cm_msg(
MERROR,
"SqlODBC::Exec",
"Cannot reconnect to ODBC database DSN \'%s\', status %d. Database is down?",
fDSN.c_str(),
status);
717 cm_msg(
MINFO,
"SqlODBC::Exec",
"Reconnected to ODBC database DSN \'%s\'",
fDSN.c_str());
723int SqlODBC::GetNumRows()
735int SqlODBC::GetNumColumns()
772const char* SqlODBC::GetColumn(
int icol)
774 static char buf[1024];
834 int n =
e->tags.size();
842 for (
int i=0;
i<
n;
i++) {
843 const Tag*t = &
e->tags[
i];
847 void* ptr = (
void*)(buf+
offset);
851 for (
int j=0;
j<arraySize;
j++) {
871 sprintf(s,
"%u",((
unsigned char*)ptr)[
j]);
874 sprintf(s,
"%d",((
signed char*)ptr)[
j]);
877 sprintf(s,
"\'%c\'",((
char*)ptr)[
j]);
880 sprintf(s,
"%u",((
unsigned short*)ptr)[
j]);
883 sprintf(s,
"%d",((
signed short*)ptr)[
j]);
886 sprintf(s,
"%u",((
unsigned int*)ptr)[
j]);
892 sprintf(s,
"%u",((
unsigned int*)ptr)[
j]);
895 sprintf(s,
"\'%.8g\'",((
float*)ptr)[
j]);
898 sprintf(s,
"\'%.16g\'",((
double*)ptr)[
j]);
911 strftime(s,
sizeof(s)-1,
"%Y-%m-%d %H:%M:%S.0",&
tms);
914 sprintf(
sss,
"INSERT INTO %s (_t_time, _i_time%s) VALUES (\'%s\', \'%d\'%s);",
915 e->table_name.c_str(),
936 for (
int i=0; s[
i]!=0;
i++) {
959 std::vector<IndexEntryTag>
tags;
971 printf(
"entry %d: [%s] [%s], time %d, tags\n",
i,
e->event_name.c_str(),
e->table_name.c_str(),
e->timestamp);
973 for (
unsigned j=0;
j<
e->tags.size();
j++)
974 printf(
" tag %d: [%s] [%s], time %d\n",
j,
e->tags[
j].tag_name.c_str(),
e->tags[
j].column_name.c_str(),
e->tags[
j].timestamp);
999 for (
unsigned i=0;
i<
ie->tags.size();
i++)
1001 return &
ie->tags[
i];
1008 for (
unsigned i=0;
i<
ie->tags.size();
i++)
1010 return &
ie->tags[
i];
1023 printf(
"ReadIndex [%s]\n", event_name);
1032 printf(
"ReadIndex: reading index for event [%s]\n", event_name);
1039 sprintf(cmd,
"SELECT event_name, table_name, tag_name, column_name, itimestamp FROM _history_index where event_name=\'%s\';", event_name);
1041 sprintf(cmd,
"SELECT event_name, table_name, tag_name, column_name, itimestamp FROM _history_index;");
1051 printf(
"ReadIndex: event %s, Read status %d, nrows: %d\n",
1072 printf(
"ReadIndex: event %s, nrows: %d, ncols: %d\n",
1103 if (timestamp >
ie->timestamp) {
1106 ie->timestamp = timestamp;
1129 for (
unsigned j=0;
j<
ie->tags.size();
j++)
1131 if (timestamp >
ie->tags[
j].timestamp) {
1132 ie->tags[
j].timestamp = timestamp;
1143 it.timestamp = timestamp;
1144 ie->tags.push_back(
it);
1157 if (event_name ==
NULL)
1230 std::vector<std::string>
tables;
1236 for (
unsigned i=0;
i<
tables.size();
i++) {
1237 if (
tables[
i] ==
"_history_index") {
1249 printf(
"hs_disconnect!\n");
1261 printf(
"Reconnect to SQL database!\n");
1279 printf(
"hs_clear_cache!\n");
1304 std::vector<std::string>
tables;
1310 for (
unsigned i=0;
i<
tables.size();
i++) {
1311 if (
tables[
i] ==
"_history_index")
1320 ie->event_name =
ie->table_name;
1325 std::vector<std::string>
columns;
1331 for (
unsigned int j=0;
j<
columns.size();
j+=2) {
1342 ie->tags.push_back(t);
1362 printf(
"define event [%s] with %d tags:\n", event_name,
ntags);
1367 for (
unsigned int i=0;
i<
fEvents.size();
i++)
1369 if (
fEvents[
i]->event_name == event_name) {
1371 printf(
"deleting exising event %s\n", event_name);
1378 e->event_name = event_name;
1382 sprintf(buf,
"CREATE TABLE _history_index (event_name VARCHAR(256) NOT NULL, table_name VARCHAR(256), tag_name VARCHAR(256), column_name VARCHAR(256), itimestamp INTEGER NOT NULL);");
1402 sprintf(
sss,
"INSERT INTO _history_index (event_name, table_name, itimestamp) VALUES (\'%s\', \'%s\', \'%.0f\');",
1416 cm_msg(
MERROR,
"hs_define_event",
"could not add event name to SQL history index table, see messages");
1420 e->table_name =
ie->table_name;
1427 for (
unsigned int j=0;
j<tags[
i].
n_data;
j++) {
1431 if (tags[
i].n_data > 1) {
1447 for (
unsigned i=0;
i<
e->tags.size();
i++) {
1448 if (
colname ==
e->tags[
i].column_name) {
1466 sprintf(
sss,
"INSERT INTO _history_index (event_name, tag_name, column_name, itimestamp) VALUES (\'%s\', \'%s\', \'%s\', \'%.0f\');",
1485 cm_msg(
MERROR,
"hs_define_event",
"could not add event tags to SQL history index table, see messages");
1495 e->tags.push_back(t);
1501 std::vector<std::string>
columns;
1510 for (
unsigned i=0;
i<
e->tags.size();
i++) {
1512 for (
unsigned j=
i+1;
j<
e->tags.size();
j++)
1513 if (
e->tags[
i].column_name ==
e->tags[
j].column_name) {
1514 cm_msg(
MERROR,
"hs_define_event",
"Error: History event \'%s\': Duplicated column name \'%s\' from tags %d \'%s\' and %d \'%s\'", event_name,
e->tags[
i].column_name.c_str(),
i,
e->tags[
i].tag.name,
j,
e->tags[
j].tag.name);
1527 cm_msg(
MERROR,
"hs_define_event",
"Error: History event \'%s\': Incompatible data type for tag \'%s\' type \'%s\', SQL column \'%s\' type \'%s\'", event_name,
e->tags[
i].tag.name,
midasTypeName(
e->tags[
i].tag.type),
columns[
j].c_str(),
columns[
j+1].c_str());
1539 e->tags[
i].create =
true;
1545 sprintf(buf,
"CREATE TABLE %s (_t_time TIMESTAMP NOT NULL, _i_time INTEGER NOT NULL, INDEX (_i_time), INDEX (_t_time));",
e->table_name.c_str());
1553 for (
size_t i=0;
i<
e->tags.size();
i++)
1554 if (
e->tags[
i].create) {
1557 sprintf(buf,
"ALTER TABLE %s ADD COLUMN %s %s;",
1558 e->table_name.c_str(),
1559 e->tags[
i].column_name.c_str(),
1571 for (
unsigned int i=0;
i<
fEvents.size();
i++)
1588 printf(
"hs_write_event: write event \'%s\', time %d, size %d\n", event_name, (
int)timestamp, buffer_size);
1632 if (
fEvents[
i]->event_name == event_name) {
1671 printf(
"hs_flush_buffers!\n");
1682 printf(
"hs_get_events!\n");
1687 printf(
"hs_get_events: reading event names!\n");
1691 std::vector<std::string>
tables;
1696 for (
unsigned i=0;
i<
tables.size();
i++) {
1697 if (
tables[
i] ==
"_history_index")
1722 printf(
"hs_get_tags for [%s]\n", event_name);
1741 if (
ie->tags_cache.size() == 0) {
1743 printf(
"hs_get_tags reading tags for [%s]\n", event_name);
1745 std::string
tname =
ie->table_name;
1747 std::vector<std::string>
columns;
1754 cm_msg(
MERROR,
"hs_get_tags",
"Cannot get columns for table \'%s\', try to reconnect to the database",
tname.c_str());
1769 for (
unsigned int j=0;
j<
columns.size();
j+=2) {
1785 ie->tags_cache.push_back(t);
1789 for (
unsigned i=0;
i<
ie->tags_cache.size();
i++)
1790 ptags->push_back(
ie->tags_cache[
i]);
1798 last_written[
i] = 0;
1803 const char* event_name,
const char* tag_name,
int var_index,
1808 printf(
"hs_read_old_style: event \"%s\", tag \"%s\"\n", event_name, tag_name);
1818 for (
int j=0; s[
j];
j++) {
1820 if ((event_name[
j]==0) && (s[
j]==
'/')) {
1825 if ((event_name[
j]==0) && (s[
j]==
'_')) {
1830 if (event_name[
j]==0) {
1846 for (
unsigned v=0; v<
ie->tags.size(); v++) {
1860 printf(
"hs_read_old_style: event \"%s\", tag \"%s\", try matching event \'%s\'\n", event_name, tag_name, s);
1863 s, tag_name, var_index,
1876 const char* event_name,
const char* tag_name,
int tag_index,
1885 printf(
"hs_read: event [%s], tag [%s], index %d, start %f, end %f, dt %f, interval %f, max points %f\n",
1887 start_time, end_time, end_time-start_time,
interval, (end_time-start_time)/
interval);
1889 if (event_name==
NULL)
1933 std::string
tname =
ie->table_name;
1934 std::string
cname =
it->column_name;
1937 sprintf(cmd,
"SELECT _i_time, %s FROM %s WHERE _i_time>=%.0f and _i_time<=%.0f ORDER BY _i_time;",
1939 start_time, end_time);
1944 printf(
"hs_read: event \"%s\", tag \"%s\", index %d: Read table \"%s\" column \"%s\": status %d, nrows: %d, ncolumns: %d\n",
2021 (*num_entries) =
row;
2043 (*num_entries) =
row;
2049 printf(
"hs_read: return %d entries\n", *num_entries);
2056 const char*
const event_name[],
const char*
const tag_name[],
const int tag_index[],
2069 if (event_name[
i]==
NULL) {
2088 const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
2097 int status =
hs_read(start_time, end_time,
interval,
num_var, event_name, tag_name, var_index, num_entries,
time_buffer,
mean_buffer,
read_status);
2100 int num = num_entries[
i];
2105 for (
int j=0;
j<
num;
j++) {
2118 int num_var,
const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
2128 int num_var,
const char*
const event_name[],
const char*
const tag_name[],
const int var_index[],
virtual int ListColumns(const char *table, std::vector< std::string > *plist)=0
virtual bool IsConnected()=0
virtual int SetDebug(int debug)=0
virtual const char * GetColumn(int icol)=0
virtual int ListTables(std::vector< std::string > *plist)=0
virtual int Disconnect()=0
virtual int Exec(const char *sql)=0
virtual int Connect(const char *dsn=0)=0
virtual int GetNumColumns()=0
virtual int GetNumRows()=0
int Connect(const char *filename=NULL)
int Exec(const char *sql)
int ListColumns(const char *table, std::vector< std::string > *plist)
const char * GetColumn(int icol)
int ListTables(std::vector< std::string > *plist)
int hs_read_old_style(double start_time, double end_time, double interval, const char *event_name, const char *tag_name, int var_index, int *num_entries, time_t **time_buffer, double **data_buffer)
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 tag_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 status[])
returns HS_SUCCESS
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_get_last_written(time_t start_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], time_t last_written[])
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_flush_buffers()
flush buffered data to storage where it is visible to mhttpd
int hs_clear_cache()
clear internal cache, returns HS_SUCCESS
int hs_disconnect()
disconnect from history, returns HS_SUCCESS
int hs_read_buffer(time_t start_time, time_t end_time, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], MidasHistoryBufferInterface *buffer[], int status[])
returns HS_SUCCESS
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 tag_name[], const int tag_index[], int num_entries[], time_t *time_buffer[], double *data_buffer[], int st[])
see hs_read(), returns HS_SUCCESS
int hs_connect(const char *connect_string)
returns HS_SUCCESS
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...
int hs_read(double start_time, double end_time, double interval, const char *event_name, const char *tag_name, int tag_index, int *num_entries, time_t **time_buffer, double **data_buffer)
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...
int hs_set_debug(int debug)
set debug level, returns previous debug level
int hs_read2(time_t start_time, time_t end_time, time_t interval, int num_var, const char *const event_name[], const char *const tag_name[], const int var_index[], int num_entries[], time_t *time_buffer[], double *mean_buffer[], double *rms_buffer[], double *min_buffer[], double *max_buffer[], int read_status[])
std::vector< Event * > fEvents
std::string fConnectString
std::vector< std::string > fIndexEvents
#define DB_NO_MORE_SUBKEYS
#define HS_UNDEFINED_EVENT
INT cm_msg(INT message_type, const char *filename, INT line, const char *routine, const char *format,...)
BOOL equal_ustring(const char *str1, const char *str2)
static IndexEntry * FindIndexByTableName(const char *table_name)
static std::string MidasNameToSqlName(const char *s)
int WriteEvent(SqlBase *sql, Event *e, time_t t, const char *buf, int size)
static const int tid_size[]
static int sql2midasType(const char *name)
static const char * midasTypeName(int tid)
static IndexEntry * FindIndexByEventName(const char *event_name)
static const char * sql_type_mysql[]
static IndexEntryTag * FindIndexByColumnName(IndexEntry *ie, const char *column_name)
MidasHistoryInterface * MakeMidasHistoryODBC()
static IndexEntryTag * FindIndexByTagName(IndexEntry *ie, const char *tag_name)
static bool isCompatible(int tid, const char *sqlType)
static const char * tid_name[]
static void PrintTags(int ntags, const TAG tags[])
MidasHistoryInterface * MakeMidasHistorySqlDebug()
static std::vector< IndexEntry * > gHistoryIndex
static const char * midas2sqlType(int tid)
static int ReadIndex(SqlBase *sql, const char *event_name)
static const char ** sql_type
BOOL debug
debug printouts
#define message(type, str)
BOOL match(char *pat, char *str)
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
std::vector< TAG > tags_cache
std::vector< IndexEntryTag > tags