history_odbc.h File Reference


Detailed Description

Definition in file history_odbc.h.

Go to the source code of this file.

Functions

int hs_connect_odbc (const char *odbc_dsn)
int hs_disconnect_odbc ()
int hs_debug_odbc (int debug)
int hs_set_alarm_odbc (const char *alarm_name)
int hs_define_event_odbc (const char *event_name, const TAG tags[], int tags_size)
int hs_write_event_odbc (const char *event_name, time_t timestamp, const char *buffer, int buffer_size)
int hs_get_tags_odbc (const char *event_name, int *n_tags, TAG **tags)
int hs_read_odbc (time_t start_time, time_t end_time, time_t interval, const char *event_name, const char *tag_name, int var_index, int *num_entries, time_t **time_buffer, double **data_buffer)


Function Documentation

int hs_connect_odbc ( const char *  odbc_dsn  ) 

connect to given ODBC DSN, defined in $HOME/.odbc.ini, returns HS_SUCCESS

Definition at line 848 of file history_odbc.cxx.

00849 {
00850    int status;
00851 
00852    if (gSql && gSql->IsConnected())
00853       if (strcmp(gOdbcDsn.c_str(), odbc_dsn) == 0)
00854          return HS_SUCCESS;
00855    
00856    if (gSql)
00857       hs_disconnect_odbc();
00858    
00859    assert(!gSql);
00860 
00861    gOdbcDsn = odbc_dsn;
00862    
00863    if (gTrace)
00864       printf("hs_connect_odbc: set DSN to \'%s\'\n", gOdbcDsn.c_str());
00865 
00866    if (gOdbcDsn[0] == '/')
00867       gSql = new SqlStdout();
00868    else
00869       gSql = new SqlODBC();
00870    
00871    status = gSql->Connect(gOdbcDsn.c_str());
00872    if (status != 0)
00873       return HS_FILE_ERROR;
00874    
00875    return HS_SUCCESS;
00876 }

int hs_debug_odbc ( int  debug  ) 

set debug level, returns previous debug level

Definition at line 832 of file history_odbc.cxx.

00833 {
00834    int old = gTrace;
00835    gTrace = debug;
00836    return old;
00837 }

int hs_define_event_odbc ( const char *  event_name,
const TAG  tags[],
int  tags_size 
)

see hs_define_event(), returns HS_SUCCESS or HS_FILE_ERROR

Definition at line 922 of file history_odbc.cxx.

00923 {
00924    assert(gSql);
00925 
00926    int ntags = tags_size/sizeof(TAG);
00927 
00928    if (gTrace) {
00929       printf("define event [%s] with %d tags:\n", event_name, ntags);
00930       PrintTags(ntags, tags);
00931    }
00932 
00933    // delete all events with the same name
00934    for (unsigned int i=0; i<gEvents.size(); i++)
00935       if (gEvents[i])
00936          if (gEvents[i]->event_name == event_name) {
00937             printf("deleting exising event %s\n", event_name);
00938             delete gEvents[i];
00939             gEvents[i] = NULL;
00940          }
00941 
00942    Event* e = new Event();
00943 
00944    e->event_name = event_name;
00945    e->table_name = eventName2tableName(event_name);
00946    e->active = true;
00947    e->create = false;
00948 
00949    int offset = 0;
00950    for (int i=0; i<ntags; i++) {
00951       for (unsigned int j=0; j<tags[i].n_data; j++) {
00952          Tag t;
00953          t.create = false;
00954          if (tags[i].n_data == 1)
00955             t.column_name = tagName2columnName(tags[i].name);
00956          else {
00957             char s[256];
00958             sprintf(s, "_%d", j);
00959             t.column_name = tagName2columnName(tags[i].name) + s;
00960          }
00961          t.offset = offset;
00962          t.tag = tags[i];
00963          t.tag.n_data = 1;
00964          e->tags.push_back(t);
00965          int size = tid_size[tags[i].type];
00966          offset += size;
00967       }
00968    }
00969 
00970    std::vector<std::string> columns = gSql->ListColumns(e->table_name.c_str());
00971 
00972    if (columns.size() <= 0)
00973       e->create = true;
00974 
00975    for (size_t i=0; i<e->tags.size(); i++) {
00976       // check for duplicate column names
00977       for (size_t j=i+1; j<e->tags.size(); j++)
00978          if (e->tags[i].column_name == e->tags[j].column_name) {
00979             cm_msg(MERROR, "hs_define_event_odbc", "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);
00980             e->active = false;
00981             break;
00982          }
00983 
00984       // check if new column needs to be created
00985       bool found = false;
00986       for (size_t j=0; j<columns.size(); j+=2) {
00987          if (e->tags[i].column_name == columns[j]) {
00988             // column exists, check data type
00989             //printf("column \'%s\', data type %s\n", e->tags[i].column_name.c_str(), columns[j+1].c_str());
00990 
00991             if (!isCompatible(e->tags[i].tag.type, columns[j+1].c_str())) {
00992                cm_msg(MERROR, "hs_define_event_odbc", "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());
00993                e->active = false;
00994             }
00995 
00996             found = true;
00997             break;
00998          }
00999       }
01000 
01001       if (!found) {
01002          // create it
01003          //printf("column \'%s\', data type %s  --- create!\n", e->tags[i].column_name.c_str(), midasTypeName(e->tags[i].tag.type));
01004          e->tags[i].create = true;
01005       }
01006    }
01007 
01008    int status = CreateEvent(gSql, e);
01009 
01010    if (status != 0) {
01011       // if cannot create event in SQL database, disable this event and carry on.
01012 
01013       e->active = false;
01014 
01015       if (gAlarmName.length() > 0) {
01016          char buf[256];
01017          sprintf(buf, "%s cannot define history event \'%s\', see messages", gAlarmName.c_str(), e->event_name.c_str());
01018          al_trigger_alarm(gAlarmName.c_str(), buf, "Alarm", "", AT_INTERNAL);
01019       }
01020    }
01021 
01022    // find empty slot in events list
01023    for (unsigned int i=0; i<gEvents.size(); i++)
01024       if (!gEvents[i]) {
01025          gEvents[i] = e;
01026          e = NULL;
01027          break;
01028       }
01029 
01030    // if no empty slots, add at the end
01031    if (e)
01032       gEvents.push_back(e);
01033 
01034    return HS_SUCCESS;
01035 }

int hs_disconnect_odbc (  ) 

disconnect from ODBC, returns HS_SUCCESS

Definition at line 878 of file history_odbc.cxx.

Referenced by hs_connect_odbc().

00879 {
00880    if (gTrace)
00881       printf("hs_disconnect_odbc!\n");
00882 
00883    if (gSql) {
00884       gSql->Disconnect();
00885       delete gSql;
00886       gSql = NULL;
00887    }
00888 
00889    return HS_SUCCESS;
00890 }

int hs_get_tags_odbc ( const char *  event_name,
int *  n_tags,
TAG **  tags 
)

use event names returned by hs_get_events_odbc(), see hs_get_tags(), returns HS_SUCCESS

Definition at line 1125 of file history_odbc.cxx.

01126 {
01127    assert(gSql);
01128 
01129    *n_tags = 0;
01130    *tags = NULL;
01131 
01132    std::string tname = eventName2tableName(event_name);
01133 
01134    std::vector<std::string> columns = gSql->ListColumns(tname.c_str());
01135 
01136    if (columns.size() < 1) {
01137       cm_msg(MERROR, "hs_get_tags_odbc", "Cannot get columns for table \'%s\', try to reconnect to the database", tname.c_str());
01138 
01139       gSql->Disconnect();
01140       gSql->Connect(gOdbcDsn.c_str());
01141       if (!gSql->IsConnected()) {
01142 
01143          if (gAlarmName.length() > 0) {
01144             char buf[256];
01145             sprintf(buf, "%s lost connection to the history database", gAlarmName.c_str());
01146             al_trigger_alarm(gAlarmName.c_str(), buf, "Alarm", "", AT_INTERNAL);
01147          }
01148 
01149          return HS_FILE_ERROR;
01150       }
01151 
01152       columns = gSql->ListColumns(tname.c_str());      
01153    }
01154 
01155    TAG* t = (TAG*)malloc(sizeof(TAG)*columns.size());
01156    assert(t);
01157 
01158    int n=0;
01159    for (unsigned int j=0; j<columns.size(); j+=2) {
01160       if (columns[j] == "_t_time")
01161          continue;
01162       if (columns[j] == "_i_time")
01163          continue;
01164       STRLCPY(t[n].name, columns[j].c_str());
01165       t[n].type = sql2midasType(columns[j+1].c_str());
01166       t[n].n_data = 1;
01167       n++;
01168    }
01169 
01170    if (0) {
01171       printf("event [%s] table [%s], tags: %d\n", event_name, tname.c_str(), n);
01172       PrintTags(n, t);
01173    }
01174 
01175    *n_tags = n;
01176    *tags = t;
01177 
01178    return HS_SUCCESS;
01179 }

int hs_read_odbc ( time_t  start_time,
time_t  end_time,
time_t  interval,
const char *  event_name,
const char *  tag_name,
int  var_index,
int *  num_entries,
time_t **  time_buffer,
double **  data_buffer 
)

see hs_read(), returns HS_SUCCESS

Definition at line 1181 of file history_odbc.cxx.

01185 {
01186    assert(gSql);
01187 
01188    *num_entries = 0;
01189    *time_buffer = NULL;
01190    *data_buffer = NULL;
01191 
01192    //printf("start %d, end %d, dt %d, interval %d, max points %d\n", start_time, end_time, end_time-start_time, interval, (end_time-start_time)/interval);
01193 
01194    std::string ename = eventName2tableName(event_name);
01195    std::string tname = tagName2columnName(tag_name);
01196 
01197    int status = 1;
01198 
01199    std::vector<std::string> tables = gSql->ListTables();
01200 
01201    if (tables.size() <= 1) {
01202         cm_msg(MERROR, "hs_read_odbc", "ListTables() returned nothing, trying to reconnect to the database");
01203 
01204         gSql->Disconnect();
01205         gSql->Connect(gOdbcDsn.c_str());
01206         if (!gSql->IsConnected()) {
01207 
01208            if (gAlarmName.length() > 0) {
01209               char buf[256];
01210               sprintf(buf, "%s lost connection to the history database", gAlarmName.c_str());
01211               al_trigger_alarm(gAlarmName.c_str(), buf, "Alarm", "", AT_INTERNAL);
01212            }
01213 
01214            return HS_FILE_ERROR;
01215         }
01216 
01217         tables = gSql->ListTables();
01218    }
01219 
01220    int len = strlen(event_name);
01221    for (unsigned int i=0; i<tables.size(); i++) {
01222       //printf("table %s\n", tables[i].c_str());
01223 
01224       const char* t = tables[i].c_str();
01225       const char* s = strstr(t, ename.c_str());
01226 
01227       if (s==t && (t[len]=='_'||t[len]==0)) {
01228 
01229          bool found = false;
01230          std::vector<std::string> columns = gSql->ListColumns(tables[i].c_str());
01231          for (unsigned int j=0; j<columns.size(); j+=2) {
01232             //printf("column %s\n", columns[j].c_str());
01233             if (columns[j] == tname) {
01234                found = true;
01235                break;
01236             }
01237          }
01238 
01239          if (found) {
01240             char cmd[256];
01241             sprintf(cmd, "SELECT _i_time, %s FROM %s where _i_time>=%d and _i_time<=%d;",
01242                     tname.c_str(), tables[i].c_str(),
01243                     (int)start_time, (int)end_time);
01244            
01245             status = gSql->Exec(cmd);
01246 
01247             if (gTrace) {
01248                printf("hs_read_odbc: event %s, name %s, index %d: Read table %s: status %d, nrows: %d\n",
01249                       event_name, tag_name, var_index,
01250                       tables[i].c_str(),
01251                       status,
01252                       gSql->GetNumRows());
01253             }
01254 
01255             if (status)
01256                continue;
01257 
01258             if (gSql->GetNumRows() == 0) {
01259                gSql->Done();
01260                status = SQL_NO_DATA;
01261                continue;
01262             }
01263 
01264             break;
01265          }
01266       }
01267    }
01268 
01269    if (status == SQL_NO_DATA)
01270       return HS_SUCCESS;
01271 
01272    if (status) {
01273       if (gTrace)
01274          printf("hs_read_odbc: event %s, name %s, index %d, could not find the right table? status %d\n",
01275                 event_name, tag_name, var_index,
01276                 status);
01277       
01278       return HS_FILE_ERROR;
01279    }
01280 
01281    int nrows = gSql->GetNumRows();
01282    int ncols = gSql->GetNumColumns();
01283 
01284    if (nrows == 0)
01285       return HS_SUCCESS;
01286 
01287    if (gTrace)
01288       printf("hs_read_odbc: event %s, name %s, index %d, nrows: %d, ncols: %d\n",
01289              event_name, tag_name, var_index,
01290              nrows, ncols);
01291 
01292    if (nrows < 0)
01293       return HS_FILE_ERROR;
01294 
01295    if (ncols < 1)
01296       return HS_FILE_ERROR;
01297 
01298    *num_entries = 0;
01299    *time_buffer = (time_t*)malloc(nrows * sizeof(time_t));
01300    *data_buffer = (double*)malloc(nrows * sizeof(double));
01301   
01302    /* Loop through the rows in the result-set */
01303    int row = 0;
01304    time_t tt = 0;
01305    int ann = 0;
01306    double att = 0;
01307    double avv = 0;
01308    while (gSql->Fetch()) {
01309       time_t t = 0;
01310       double v = 0;
01311      
01312       const char* timedata = gSql->GetColumn(1);
01313       if (timedata)
01314          t = atoi(timedata);
01315      
01316       const char* valuedata = gSql->GetColumn(2);
01317       if (valuedata)
01318          v = atof(valuedata);
01319      
01320       if (t < start_time || t > end_time)
01321          continue;
01322      
01323       //printf("Row %d, time %d, value %f\n", row, t, v);
01324       //printf("tt: %d, ann: %d\n", tt, ann);
01325      
01326       if (tt == 0 || t >= tt + interval) {
01327         
01328          if (ann > 0) {
01329             assert(row < nrows);
01330            
01331             (*time_buffer)[row] = (time_t)(att/ann);
01332             (*data_buffer)[row] = avv/ann;
01333            
01334             row++;
01335             (*num_entries) = row;
01336          }
01337 
01338          ann = 0;
01339          att = 0;
01340          avv = 0;
01341          tt  = t;
01342          
01343       }
01344 
01345       ann++;
01346       att += t;
01347       avv += v;
01348    }
01349 
01350    if (ann > 0) {
01351       assert(row < nrows);
01352 
01353       (*time_buffer)[row] = (time_t)(att/ann);
01354       (*data_buffer)[row] = avv/ann;
01355      
01356       row++;
01357       (*num_entries) = row;
01358    }
01359 
01360    gSql->Done();
01361 
01362    if (gTrace)
01363       printf("hs_read_odbc: return %d events\n", *num_entries);
01364 
01365    return HS_SUCCESS;
01366 }

int hs_set_alarm_odbc ( const char *  alarm_name  ) 

set alarm name for history failures. Use NULL to disable alarms

Definition at line 839 of file history_odbc.cxx.

00840 {
00841    if (alarm_name)
00842       gAlarmName = alarm_name;
00843    else
00844       gAlarmName = "";
00845    return HS_SUCCESS;
00846 }

int hs_write_event_odbc ( const char *  event_name,
time_t  timestamp,
const char *  buffer,
int  buffer_size 
)

see hs_write_event(), returns HS_SUCCESS or HS_FILE_ERROR

Definition at line 1037 of file history_odbc.cxx.

01038 {
01039    if (gTrace)
01040       printf("write event [%s] size %d\n", event_name, buffer_size);
01041 
01042    assert(gSql);
01043 
01044    // if disconnected, try to reconnect
01045 
01046    if (!gSql->IsConnected()) {
01047       time_t now = time(NULL);
01048 
01049       // too early to try reconnecting?
01050       if (gConnectRetry!=0 && now < gNextConnect) {
01051          return HS_FILE_ERROR;
01052       }
01053 
01054       int status = gSql->Connect(gOdbcDsn.c_str());
01055 
01056       if (status != 0) {
01057 
01058          // first retry in 5 seconds
01059          if (gConnectRetry == 0)
01060             gConnectRetry = 5;
01061 
01062          gNextConnect = now + gConnectRetry;
01063 
01064          // exponential backoff
01065          gConnectRetry *= 2;
01066 
01067          // but no more than every 10 minutes
01068          if (gConnectRetry > 10*60)
01069             gConnectRetry = 10*60;
01070 
01071          return HS_FILE_ERROR;
01072       }
01073    }
01074 
01075    gNextConnect = 0;
01076    gConnectRetry = 0;
01077 
01078    Event *e = NULL;
01079 
01080    // find this event
01081    for (size_t i=0; i<gEvents.size(); i++)
01082       if (gEvents[i]->event_name == event_name) {
01083          e = gEvents[i];
01084          break;
01085       }
01086 
01087    // not found
01088    if (!e)
01089       return HS_FILE_ERROR;
01090 
01091    // deactivated because of error?
01092    if (!e->active)
01093       return HS_FILE_ERROR;
01094 
01095    int status = WriteEvent(gSql, e, timestamp, buffer, buffer_size);
01096 
01097    // if could not write to SQL?
01098    if (status != 0) {
01099 
01100       // if lost SQL connection, try again later
01101       if (!gSql->IsConnected()) {
01102          return HS_FILE_ERROR;
01103       }
01104 
01105       // otherwise, deactivate this event, raise alarm
01106 
01107       e->active = 0;
01108 
01109       if (gAlarmName.length() > 0) {
01110          char buf[256];
01111          sprintf(buf, "%s cannot write history event \'%s\', see messages", gAlarmName.c_str(), e->event_name.c_str());
01112          al_trigger_alarm(gAlarmName.c_str(), buf, "Alarm", "", AT_INTERNAL);
01113       }
01114 
01115       return HS_FILE_ERROR;
01116    }
01117 
01118    return HS_SUCCESS;
01119 }


Midas DOC Version 3.0.0 ---- PSI Stefan Ritt ----
Contributions: Pierre-Andre Amaudruz - Sergio Ballestrero - Suzannah Daviel - Doxygen - Peter Green - Qing Gu - Greg Hackman - Gertjan Hofman - Paul Knowles - Exaos Lee - Rudi Meier - Glenn Moloney - Dave Morris - John M O'Donnell - Konstantin Olchanski - Renee Poutissou - Tamsen Schurman - Andreas Suter - Jan M.Wouters - Piotr Adam Zolnierczuk