/* ** ZABBIX ** Copyright (C) 2000-2005 SIA Zabbix ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **/ #include "common.h" #include "log.h" #include "zlog.h" #include "zbxodbc.h" static char zbx_last_odbc_strerror[255]; char* get_last_odbc_strerror(void) { return zbx_last_odbc_strerror; } #ifdef HAVE___VA_ARGS__ # define set_last_odbc_strerror(fmt, ...) __zbx_set_last_odbc_strerror(ZBX_CONST_STRING(fmt), ##__VA_ARGS__) #else # define set_last_odbc_strerror __zbx_set_last_odbc_strerror #endif /* HAVE___VA_ARGS__ */ static void __zbx_set_last_odbc_strerror(const char *fmt, ...) { va_list args; va_start(args, fmt); zbx_vsnprintf(zbx_last_odbc_strerror, sizeof(zbx_last_odbc_strerror), fmt, args); va_end(args); } #define clean_odbc_strerror() zbx_last_odbc_strerror[0]='\0' static void odbc_free_row_data(ZBX_ODBC_DBH *pdbh) { SQLSMALLINT i; if(pdbh->row_data) { for(i = 0; i < pdbh->col_num; i++) zbx_free(pdbh->row_data[i]); zbx_free(pdbh->row_data); pdbh->row_data = NULL; } if(pdbh->data_len) { zbx_free(pdbh->data_len); pdbh->data_len = NULL; } pdbh->col_num = 0; } void odbc_DBclose(ZBX_ODBC_DBH *pdbh) { if(pdbh->hstmt) { SQLFreeHandle(SQL_HANDLE_STMT, pdbh->hstmt); pdbh->hstmt = NULL; } if(pdbh->hdbc) { if(pdbh->connected) { SQLDisconnect(pdbh->hdbc); } SQLFreeHandle(SQL_HANDLE_DBC, pdbh->hdbc); pdbh->hdbc = NULL; } if(pdbh->henv) { SQLFreeHandle(SQL_HANDLE_ENV, pdbh->henv); pdbh->henv = NULL; } odbc_free_row_data(pdbh); } int odbc_DBconnect(ZBX_ODBC_DBH *pdbh, const char *db_dsn, const char *user, const char *pass) { SQLCHAR err_stat[10], err_msg[100]; SQLINTEGER err_int; SQLSMALLINT err_msg_len; SQLRETURN retcode; clean_odbc_strerror(); memset(pdbh, 0 , sizeof(ZBX_ODBC_DBH)); zabbix_log(LOG_LEVEL_DEBUG, "ODBC connect [%s] [%s]", db_dsn, user); /*Allocate environment handle */ retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &(pdbh->henv)); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { set_last_odbc_strerror("%s","failed environment handle allocation."); } else { /* Set the ODBC version environment attribute */ retcode = SQLSetEnvAttr(pdbh->henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { set_last_odbc_strerror("%s","failed ODBC version setting."); } else { /* Allocate connection handle */ retcode = SQLAllocHandle(SQL_HANDLE_DBC, pdbh->henv, &(pdbh->hdbc)); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { set_last_odbc_strerror("%s","failed connection handle allocation."); } else { /* Set login timeout to 5 seconds. */ SQLSetConnectAttr(pdbh->hdbc, (SQLINTEGER)SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, (SQLINTEGER)0); /* Connect to data source */ retcode = SQLConnect(pdbh->hdbc, (SQLCHAR*) db_dsn, SQL_NTS, (SQLCHAR*) user, SQL_NTS, (SQLCHAR*) pass, SQL_NTS ); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) { SQLGetDiagRec(SQL_HANDLE_DBC, pdbh->hdbc, 1, err_stat, &err_int, err_msg, sizeof(err_msg), &err_msg_len ); set_last_odbc_strerror("failed connection [%s] (%d)", err_msg, err_int); } else { pdbh->connected = 1; /* Allocate statement handle */ retcode = SQLAllocHandle(SQL_HANDLE_STMT, pdbh->hdbc, &(pdbh->hstmt)); if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) { return SUCCEED; } else { SQLFreeHandle(SQL_HANDLE_STMT, pdbh->hstmt); pdbh->hstmt = NULL; } SQLDisconnect(pdbh->hdbc); } SQLFreeHandle(SQL_HANDLE_DBC, pdbh->hdbc); pdbh->hdbc = NULL; } } SQLFreeHandle(SQL_HANDLE_ENV, pdbh->henv); pdbh->henv = NULL; } zabbix_log(LOG_LEVEL_ERR, "Failed to connect to DSN '%s' : Error: %s", db_dsn, get_last_odbc_strerror()); return FAIL; /* error */ } int odbc_DBexecute(ZBX_ODBC_DBH *pdbh, const char *query) { SQLCHAR err_stat[10], err_msg[100]; SQLINTEGER err_int; SQLSMALLINT err_msg_len; SQLRETURN retcode; clean_odbc_strerror(); odbc_free_row_data(pdbh); retcode = SQLExecDirect(pdbh->hstmt, (SQLCHAR*) query, SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) goto lbl_err_exit; return SUCCEED; lbl_err_exit: SQLGetDiagRec(SQL_HANDLE_STMT, pdbh->hstmt, 1, err_stat, &err_int, err_msg, sizeof(err_msg), &err_msg_len ); set_last_odbc_strerror("Failed select execution [%s] (%d)", err_msg, err_int); zabbix_log(LOG_LEVEL_ERR, "%s", get_last_odbc_strerror()); return FAIL; } ZBX_ODBC_ROW odbc_DBfetch(ZBX_ODBC_RESULT pdbh) { SQLCHAR err_stat[10], err_msg[100]; SQLINTEGER err_int; SQLSMALLINT err_msg_len; SQLRETURN retcode; SQLSMALLINT i; if(pdbh == NULL) return NULL; clean_odbc_strerror(); zabbix_log(LOG_LEVEL_DEBUG, "ODBC fetch"); retcode = SQLFetch(pdbh->hstmt); if (retcode == SQL_ERROR) goto lbl_err_exit; if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO ) { zabbix_log(LOG_LEVEL_DEBUG, "odbc_DBfetch [end of rows received]"); return NULL; } for(i=0; i < pdbh->col_num; i++) { rtrim_spaces(pdbh->row_data[i]); zabbix_log(LOG_LEVEL_DEBUG, "Featched [%i col]: %s", i, pdbh->row_data[i]); } return pdbh->row_data; lbl_err_exit: SQLGetDiagRec(SQL_HANDLE_STMT, pdbh->hstmt, 1, err_stat, &err_int, err_msg, sizeof(err_msg), &err_msg_len ); set_last_odbc_strerror("Failed data fetching [%s] (%d)", err_msg, err_int); zabbix_log(LOG_LEVEL_ERR, "%s", get_last_odbc_strerror()); return NULL; } ZBX_ODBC_RESULT odbc_DBselect(ZBX_ODBC_DBH *pdbh, const char *query) { SQLCHAR err_stat[10], err_msg[100]; SQLINTEGER err_int; SQLSMALLINT err_msg_len; SQLRETURN retcode; SQLSMALLINT i = 0, col_num = 0; clean_odbc_strerror(); odbc_free_row_data(pdbh); zabbix_log(LOG_LEVEL_DEBUG, "ODBC select [%s]", query); retcode = SQLExecDirect(pdbh->hstmt, (SQLCHAR*) query, SQL_NTS); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) goto lbl_err_exit; retcode = SQLNumResultCols(pdbh->hstmt, &col_num); if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) goto lbl_err_exit; pdbh->col_num = col_num; pdbh->row_data = zbx_malloc(pdbh->row_data, sizeof(char*) * col_num); memset(pdbh->row_data, 0, sizeof(char*) * col_num); pdbh->data_len = zbx_malloc(pdbh->data_len, sizeof(SQLINTEGER) * col_num); memset(pdbh->data_len, 0, sizeof(SQLINTEGER) * col_num); for(i=0; i < col_num; i++) { pdbh->row_data[i] = zbx_malloc(pdbh->row_data[i], MAX_STRING_LEN); SQLBindCol(pdbh->hstmt, i+1, SQL_C_CHAR, pdbh->row_data[i], MAX_STRING_LEN, &pdbh->data_len[i]); } zabbix_log(LOG_LEVEL_DEBUG, "selected %i cols", col_num); return (ZBX_ODBC_RESULT) pdbh; lbl_err_exit: SQLGetDiagRec(SQL_HANDLE_STMT, pdbh->hstmt, 1, err_stat, &err_int, err_msg, sizeof(err_msg), &err_msg_len ); set_last_odbc_strerror("Failed selection [%s] (%d)", err_msg, err_int); zabbix_log(LOG_LEVEL_ERR, "%s", get_last_odbc_strerror()); return NULL; }