/****************************************************************************** * * * Function: zbx_db_rollback * * * * Purpose: rollback transaction * * * * Author: Eugene Grigorjev * * * * Comments: do nothing if DB does not support transactions * * * ******************************************************************************/ int zbx_db_rollback() { int rc = ZBX_DB_OK, last_txn_error; if (0 == txn_level) { zabbix_log(LOG_LEVEL_CRIT, "ERROR: rollback without transaction." " Please report it to Job Arranger Team."); assert(0); } last_txn_error = txn_error; /* allow rollback of failed transaction */ txn_error = 0; #if defined(HAVE_IBM_DB2) if (SUCCEED != zbx_ibm_db2_success(SQLEndTran(SQL_HANDLE_DBC, ibm_db2.hdbc, SQL_ROLLBACK))) rc = ZBX_DB_DOWN; if (SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS))) rc = ZBX_DB_DOWN; if (ZBX_DB_OK != rc) { zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); rc = (SQL_CD_TRUE == IBM_DB2server_status() ? ZBX_DB_FAIL : ZBX_DB_DOWN); } #elif defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) rc = zbx_db_execute("%s", "rollback;"); #elif defined(HAVE_ORACLE) OCITransRollback(oracle.svchp, oracle.errhp, OCI_DEFAULT); #elif defined(HAVE_SQLITE3) rc = zbx_db_execute("%s", "rollback;"); php_sem_release(&sqlite_access); #endif if (ZBX_DB_DOWN != rc) /* ZBX_DB_FAIL or ZBX_DB_OK or number of changes */ txn_level--; else txn_error = last_txn_error; /* in case of DB down we will repeat this operation */ return rc; }
/****************************************************************************** * * * Function: zbx_db_commit * * * * Purpose: commit transaction * * * * Author: Eugene Grigorjev * * * * Comments: do nothing if DB does not support transactions * * * ******************************************************************************/ int zbx_db_commit() { int rc = ZBX_DB_OK; if (0 == txn_level) { zabbix_log(LOG_LEVEL_CRIT, "ERROR: commit without transaction." " Please report it to Job Arranger Team."); assert(0); } if (1 == txn_error) { zabbix_log(LOG_LEVEL_DEBUG, "commit called on failed transaction, doing a rollback instead"); return zbx_db_rollback(); } #if defined(HAVE_IBM_DB2) if (SUCCEED != zbx_ibm_db2_success(SQLEndTran(SQL_HANDLE_DBC, ibm_db2.hdbc, SQL_COMMIT))) rc = ZBX_DB_DOWN; if (SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS))) rc = ZBX_DB_DOWN; if (ZBX_DB_OK != rc) { zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); rc = (SQL_CD_TRUE == IBM_DB2server_status() ? ZBX_DB_FAIL : ZBX_DB_DOWN); } #elif defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) rc = zbx_db_execute("%s", "commit;"); #elif defined(HAVE_ORACLE) OCITransCommit(oracle.svchp, oracle.errhp, OCI_DEFAULT); #elif defined(HAVE_SQLITE3) rc = zbx_db_execute("%s", "commit;"); php_sem_release(&sqlite_access); #endif if (ZBX_DB_DOWN != rc) /* ZBX_DB_FAIL or ZBX_DB_OK or number of changes */ txn_level--; return rc; }
/* server status: SQL_CD_TRUE or SQL_CD_FALSE */ int IBM_DB2server_status() { int server_status = SQL_CD_TRUE; if (SUCCEED != zbx_ibm_db2_success(SQLGetConnectAttr(ibm_db2.hdbc, SQL_ATTR_CONNECTION_DEAD, &server_status, SQL_IS_POINTER, NULL))) { zabbix_log(LOG_LEVEL_WARNING, "cannot determine IBM DB2 server status, assuming not connected"); } return (SQL_CD_FALSE == server_status ? SQL_CD_TRUE : SQL_CD_FALSE); }
/****************************************************************************** * * * Function: zbx_db_begin * * * * Purpose: start transaction * * * * Author: Eugene Grigorjev * * * * Comments: do nothing if DB does not support transactions * * * ******************************************************************************/ int zbx_db_begin() { int rc = ZBX_DB_OK; if (txn_level > 0) { zabbix_log(LOG_LEVEL_CRIT, "ERROR: nested transaction detected." " Please report it to Zabbix Team."); assert(0); } txn_level++; #if defined(HAVE_IBM_DB2) if (SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS))) rc = ZBX_DB_DOWN; if (ZBX_DB_OK != rc) { zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); rc = (SQL_CD_TRUE == IBM_DB2server_status() ? ZBX_DB_FAIL : ZBX_DB_DOWN); } #elif defined(HAVE_MYSQL) || defined(HAVE_POSTGRESQL) rc = zbx_db_execute("%s", "begin;"); #elif defined(HAVE_SQLITE3) if (PHP_MUTEX_OK != php_sem_acquire(&sqlite_access)) { zabbix_log(LOG_LEVEL_CRIT, "ERROR: Unable to create lock" " on SQLite database."); assert(0); } rc = zbx_db_execute("%s", "begin;"); #endif if (ZBX_DB_DOWN == rc) txn_level--; return rc; }
/****************************************************************************** * * * Function: zbx_db_connect * * * * Purpose: connect to the database * * * * Return value: ZBX_DB_OK - succefully connected * * ZBX_DB_DOWN - database is down * * ZBX_DB_FAIL - failed to connect * * * ******************************************************************************/ int zbx_db_connect(char *host, char *user, char *password, char *dbname, char *dbschema, char *dbsocket, int port) { int ret = ZBX_DB_OK; #if defined(HAVE_IBM_DB2) char *connect = NULL; #elif defined(HAVE_ORACLE) char *connect = NULL; sword err = OCI_SUCCESS; #elif defined(HAVE_POSTGRESQL) char *cport = NULL; DB_RESULT result; DB_ROW row; #endif txn_init = 1; assert(NULL != host); #if defined(HAVE_IBM_DB2) connect = zbx_strdup(connect, "PROTOCOL=TCPIP;"); if ('\0' != *host) connect = zbx_strdcatf(connect, "HOSTNAME=%s;", host); if (NULL != dbname && '\0' != *dbname) connect = zbx_strdcatf(connect, "DATABASE=%s;", dbname); if (0 != port) connect = zbx_strdcatf(connect, "PORT=%d;", port); if (NULL != user && '\0' != *user) connect = zbx_strdcatf(connect, "UID=%s;", user); if (NULL != password && '\0' != *password) connect = zbx_strdcatf(connect, "PWD=%s;", password); memset(&ibm_db2, 0, sizeof(ibm_db2)); /* allocate an environment handle */ if (SUCCEED != zbx_ibm_db2_success(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &ibm_db2.henv))) ret = ZBX_DB_FAIL; /* set attribute to enable application to run as ODBC 3.0 application; */ /* recommended for pure IBM DB2 CLI, but not required */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLSetEnvAttr(ibm_db2.henv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0))) ret = ZBX_DB_FAIL; /* allocate a database connection handle */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLAllocHandle(SQL_HANDLE_DBC, ibm_db2.henv, &ibm_db2.hdbc))) ret = ZBX_DB_FAIL; /* connect to the database */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLDriverConnect(ibm_db2.hdbc, NULL, (SQLCHAR *)connect, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT))) ret = ZBX_DB_FAIL; /* set autocommit on */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_NTS))) ret = ZBX_DB_DOWN; /* we do not generate vendor escape clause sequences */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLSetConnectAttr(ibm_db2.hdbc, SQL_ATTR_NOSCAN, (SQLPOINTER)SQL_NOSCAN_ON, SQL_NTS))) ret = ZBX_DB_DOWN; /* set current schema */ if (NULL != dbschema && '\0' != *dbschema && ZBX_DB_OK == ret) { char *dbschema_esc; dbschema_esc = DBdyn_escape_string(dbschema); DBexecute("set current schema='%s'", dbschema_esc); zbx_free(dbschema_esc); } /* output error information */ if (ZBX_DB_OK != ret) { zbx_ibm_db2_log_errors(SQL_HANDLE_ENV, ibm_db2.henv); zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); zbx_db_close(); } zbx_free(connect); #elif defined(HAVE_MYSQL) conn = mysql_init(NULL); if (!mysql_real_connect(conn, host, user, password, dbname, port, dbsocket, CLIENT_MULTI_STATEMENTS)) { zabbix_errlog(ERR_Z3001, dbname, mysql_errno(conn), mysql_error(conn)); ret = ZBX_DB_FAIL; } if (ZBX_DB_OK == ret) { if (0 != mysql_select_db(conn, dbname)) { zabbix_errlog(ERR_Z3001, dbname, mysql_errno(conn), mysql_error(conn)); ret = ZBX_DB_FAIL; } } if (ZBX_DB_OK == ret) { DBexecute("set names utf8"); } if (ZBX_DB_FAIL == ret) { switch (mysql_errno(conn)) { case CR_CONN_HOST_ERROR: case CR_SERVER_GONE_ERROR: case CR_CONNECTION_ERROR: case CR_SERVER_LOST: case CR_UNKNOWN_HOST: case ER_SERVER_SHUTDOWN: case ER_ACCESS_DENIED_ERROR: /* wrong user or password */ case ER_ILLEGAL_GRANT_FOR_TABLE: /* user without any privileges */ case ER_TABLEACCESS_DENIED_ERROR: /* user without some privilege */ case ER_UNKNOWN_ERROR: ret = ZBX_DB_DOWN; break; default: break; } } #elif defined(HAVE_ORACLE) #if defined(HAVE_GETENV) && defined(HAVE_PUTENV) if (NULL == getenv("NLS_LANG")) putenv("NLS_LANG=.UTF8"); #endif memset(&oracle, 0, sizeof(oracle)); /* connection string format: [//]host[:port][/service name] */ if ('\0' != *host) { connect = zbx_strdcatf(connect, "//%s", host); if (0 != port) connect = zbx_strdcatf(connect, ":%d", port); if (NULL != dbname && '\0' != *dbname) connect = zbx_strdcatf(connect, "/%s", dbname); } else ret = ZBX_DB_FAIL; if (ZBX_DB_OK == ret) { /* initialize environment */ err = OCIEnvCreate((OCIEnv **)&oracle.envhp, (ub4)OCI_DEFAULT, (dvoid *)0, (dvoid * (*)(dvoid *,size_t))0, (dvoid * (*)(dvoid *, dvoid *, size_t))0, (void (*)(dvoid *, dvoid *))0, (size_t)0, (dvoid **)0); if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3001, connect, err, zbx_oci_error(err)); ret = ZBX_DB_FAIL; } } if (ZBX_DB_OK == ret) { /* allocate an error handle */ (void)OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&oracle.errhp, OCI_HTYPE_ERROR, (size_t)0, (dvoid **)0); /* get the session */ err = OCILogon2(oracle.envhp, oracle.errhp, &oracle.svchp, (text *)user, (ub4)(NULL != user ? strlen(user) : 0), (text *)password, (ub4)(NULL != password ? strlen(password) : 0), (text *)connect, (ub4)strlen(connect), OCI_DEFAULT); if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3001, connect, err, zbx_oci_error(err)); ret = ZBX_DB_DOWN; } else { err = OCIAttrGet((void *)oracle.svchp, OCI_HTYPE_SVCCTX, (void *)&oracle.srvhp, (ub4 *)0, OCI_ATTR_SERVER, oracle.errhp); if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3001, connect, err, zbx_oci_error(err)); ret = ZBX_DB_DOWN; } } } zbx_free(connect); if (ZBX_DB_OK != ret) zbx_db_close(); #elif defined(HAVE_POSTGRESQL) if (0 != port) cport = zbx_dsprintf(cport, "%d", port); conn = PQsetdbLogin(host, cport, NULL, NULL, dbname, user, password); zbx_free(cport); /* check to see that the backend connection was successfully made */ if (CONNECTION_OK != PQstatus(conn)) { zabbix_errlog(ERR_Z3001, dbname, 0, PQerrorMessage(conn)); ret = ZBX_DB_DOWN; } else { result = DBselect("select oid from pg_type where typname='bytea'"); if (NULL != (row = DBfetch(result))) ZBX_PG_BYTEAOID = atoi(row[0]); DBfree_result(result); } #ifdef HAVE_FUNCTION_PQSERVERVERSION ZBX_PG_SVERSION = PQserverVersion(conn); zabbix_log(LOG_LEVEL_DEBUG, "PostgreSQL Server version: %d", ZBX_PG_SVERSION); #endif if (80100 <= ZBX_PG_SVERSION) { /* disable "nonstandard use of \' in a string literal" warning */ DBexecute("set escape_string_warning to off"); result = DBselect("show standard_conforming_strings"); if (NULL != (row = DBfetch(result))) ZBX_PG_ESCAPE_BACKSLASH = (0 == strcmp(row[0], "off")); DBfree_result(result); } if (90000 <= ZBX_PG_SVERSION) { /* change the output format for values of type bytea from hex (the default) to escape */ DBexecute("set bytea_output=escape"); } #elif defined(HAVE_SQLITE3) #ifdef HAVE_FUNCTION_SQLITE3_OPEN_V2 if (SQLITE_OK != sqlite3_open_v2(dbname, &conn, SQLITE_OPEN_READWRITE, NULL)) #else if (SQLITE_OK != sqlite3_open(dbname, &conn)) #endif { zabbix_errlog(ERR_Z3001, dbname, 0, sqlite3_errmsg(conn)); sqlite3_close(conn); ret = ZBX_DB_DOWN; } else { char *p, *path; /* do not return SQLITE_BUSY immediately, wait for N ms */ sqlite3_busy_timeout(conn, SEC_PER_MIN * 1000); path = strdup(dbname); if (NULL != (p = strrchr(path, '/'))) *++p = '\0'; else *path = '\0'; DBexecute("PRAGMA synchronous = 0"); /* OFF */ DBexecute("PRAGMA temp_store = 2"); /* MEMORY */ DBexecute("PRAGMA temp_store_directory = '%s'", path); zbx_free(path); } #endif /* HAVE_SQLITE3 */ txn_init = 0; return ret; }
/****************************************************************************** * * * Function: zbx_db_vselect * * * * Purpose: execute a select statement * * * * Return value: data, NULL (on error) or (DB_RESULT)ZBX_DB_DOWN * * * ******************************************************************************/ DB_RESULT zbx_db_vselect(const char *fmt, va_list args) { char *sql = NULL; DB_RESULT result = NULL; double sec = 0; #if defined(HAVE_IBM_DB2) int i; SQLRETURN ret = SQL_SUCCESS; #elif defined(HAVE_ORACLE) sword err = OCI_SUCCESS; ub4 counter; #elif defined(HAVE_POSTGRESQL) char *error = NULL; #elif defined(HAVE_SQLITE3) int ret = FAIL; char *error = NULL; #endif if (0 != CONFIG_LOG_SLOW_QUERIES) sec = zbx_time(); sql = zbx_dvsprintf(sql, fmt, args); if (1 == txn_error) { zabbix_log(LOG_LEVEL_DEBUG, "ignoring query [txnlev:%d] [%s] within failed transaction", txn_level, sql); goto clean; } zabbix_log(LOG_LEVEL_DEBUG, "query [txnlev:%d] [%s]", txn_level, sql); #if defined(HAVE_IBM_DB2) result = zbx_malloc(result, sizeof(ZBX_IBM_DB2_RESULT)); memset(result, 0, sizeof(ZBX_IBM_DB2_RESULT)); /* allocate a statement handle */ if (SUCCEED != zbx_ibm_db2_success(ret = SQLAllocHandle(SQL_HANDLE_STMT, ibm_db2.hdbc, &result->hstmt))) goto error; /* directly execute the statement */ if (SUCCEED != zbx_ibm_db2_success(ret = SQLExecDirect(result->hstmt, (SQLCHAR *)sql, SQL_NTS))) goto error; /* identify the number of output columns */ if (SUCCEED != zbx_ibm_db2_success(ret = SQLNumResultCols(result->hstmt, &result->ncolumn))) goto error; if (0 == result->ncolumn) goto error; result->nalloc = 0; result->values = zbx_malloc(result->values, sizeof(char *) * result->ncolumn); result->values_cli = zbx_malloc(result->values_cli, sizeof(char *) * result->ncolumn); result->values_len = zbx_malloc(result->values_len, sizeof(SQLINTEGER) * result->ncolumn); for (i = 0; i < result->ncolumn; i++) { /* get the display size for a column */ if (SUCCEED != zbx_ibm_db2_success(ret = SQLColAttribute(result->hstmt, (SQLSMALLINT)(i + 1), SQL_DESC_DISPLAY_SIZE, NULL, 0, NULL, &result->values_len[i]))) { goto error; } result->values_len[i] += 1; /* '\0'; */ /* allocate memory to bind a column */ result->values_cli[i] = zbx_malloc(NULL, result->values_len[i]); result->nalloc++; /* bind columns to program variables, converting all types to CHAR */ if (SUCCEED != zbx_ibm_db2_success(ret = SQLBindCol(result->hstmt, (SQLSMALLINT)(i + 1), SQL_C_CHAR, result->values_cli[i], result->values_len[i], &result->values_len[i]))) { goto error; } } error: if (SUCCEED != zbx_ibm_db2_success(ret) || 0 == result->ncolumn) { zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); zbx_ibm_db2_log_errors(SQL_HANDLE_STMT, result->hstmt); IBM_DB2free_result(result); result = (SQL_CD_TRUE == IBM_DB2server_status() ? NULL : (DB_RESULT)ZBX_DB_DOWN); } #elif defined(HAVE_MYSQL) if (NULL == conn) { zabbix_errlog(ERR_Z3003); result = NULL; } else { if (0 != mysql_query(conn, sql)) { zabbix_errlog(ERR_Z3005, mysql_errno(conn), mysql_error(conn), sql); switch (mysql_errno(conn)) { case CR_CONN_HOST_ERROR: case CR_SERVER_GONE_ERROR: case CR_CONNECTION_ERROR: case CR_SERVER_LOST: case ER_SERVER_SHUTDOWN: case ER_ACCESS_DENIED_ERROR: /* wrong user or password */ case ER_ILLEGAL_GRANT_FOR_TABLE: /* user without any privileges */ case ER_TABLEACCESS_DENIED_ERROR:/* user without some privilege */ case ER_UNKNOWN_ERROR: result = (DB_RESULT)ZBX_DB_DOWN; break; default: result = NULL; break; } } else result = mysql_store_result(conn); } #elif defined(HAVE_ORACLE) result = zbx_malloc(NULL, sizeof(ZBX_OCI_DB_RESULT)); memset(result, 0, sizeof(ZBX_OCI_DB_RESULT)); err = OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&result->stmthp, OCI_HTYPE_STMT, (size_t)0, (dvoid **)0); if (OCI_SUCCESS == err) { err = OCIStmtPrepare(result->stmthp, oracle.errhp, (text *)sql, (ub4)strlen((char *)sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT); } if (OCI_SUCCESS == err) { err = OCIStmtExecute(oracle.svchp, result->stmthp, oracle.errhp, (ub4)0, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_COMMIT_ON_SUCCESS); } if (OCI_SUCCESS == err) { /* get the number of columns in the query */ err = OCIAttrGet((void *)result->stmthp, OCI_HTYPE_STMT, (void *)&result->ncolumn, (ub4 *)0, OCI_ATTR_PARAM_COUNT, oracle.errhp); } if (OCI_SUCCESS != err) goto error; assert(0 < result->ncolumn); result->values = zbx_malloc(NULL, result->ncolumn * sizeof(char *)); memset(result->values, 0, result->ncolumn * sizeof(char *)); for (counter = 1; OCI_SUCCESS == err && counter <= result->ncolumn; counter++) { OCIParam *parmdp = NULL; OCIDefine *defnp = NULL; ub4 char_semantics; ub2 col_width; /* request a parameter descriptor in the select-list */ err = OCIParamGet((void *)result->stmthp, OCI_HTYPE_STMT, oracle.errhp, (void **)&parmdp, (ub4)counter); if (OCI_SUCCESS == err) { /* retrieve the length semantics for the column */ char_semantics = 0; err = OCIAttrGet((void *)parmdp, (ub4)OCI_DTYPE_PARAM, (void *)&char_semantics, (ub4 *)0, (ub4)OCI_ATTR_CHAR_USED, (OCIError *)oracle.errhp); } if (OCI_SUCCESS == err) { col_width = 0; if (char_semantics) { /* retrieve the column width in characters */ err = OCIAttrGet((void *)parmdp, (ub4)OCI_DTYPE_PARAM, (void *)&col_width, (ub4 *)0, (ub4)OCI_ATTR_CHAR_SIZE, (OCIError *)oracle.errhp); } else { /* retrieve the column width in bytes */ err = OCIAttrGet((void *)parmdp, (ub4)OCI_DTYPE_PARAM, (void *)&col_width, (ub4 *)0, (ub4)OCI_ATTR_DATA_SIZE, (OCIError *)oracle.errhp); } } col_width++; result->values[counter - 1] = zbx_malloc(NULL, col_width); memset(result->values[counter - 1], 0, col_width); if (OCI_SUCCESS == err) { /* represent any data as characters */ err = OCIDefineByPos(result->stmthp, &defnp, oracle.errhp, counter, (dvoid *)result->values[counter - 1], col_width, SQLT_STR, (dvoid *)0, (ub2 *)0, (ub2 *)0, OCI_DEFAULT); } /* free cell descriptor */ OCIDescriptorFree(parmdp, OCI_DTYPE_PARAM); parmdp = NULL; } error: if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3005, err, zbx_oci_error(err), sql); OCI_DBfree_result(result); result = (OCI_SERVER_NORMAL == OCI_DBserver_status() ? NULL : (DB_RESULT)ZBX_DB_DOWN); } #elif defined(HAVE_POSTGRESQL) result = zbx_malloc(NULL, sizeof(ZBX_PG_DB_RESULT)); result->pg_result = PQexec(conn, sql); result->values = NULL; result->cursor = 0; result->row_num = 0; if (NULL == result->pg_result) zabbix_errlog(ERR_Z3005, 0, "result is NULL", sql); if (PGRES_TUPLES_OK != PQresultStatus(result->pg_result)) { error = zbx_dsprintf(error, "%s:%s", PQresStatus(PQresultStatus(result->pg_result)), PQresultErrorMessage(result->pg_result)); zabbix_errlog(ERR_Z3005, 0, error, sql); zbx_free(error); PG_DBfree_result(result); result = (CONNECTION_OK == PQstatus(conn) ? NULL : (DB_RESULT)ZBX_DB_DOWN); } else /* init rownum */ result->row_num = PQntuples(result->pg_result); #elif defined(HAVE_SQLITE3) if (0 == txn_level && PHP_MUTEX_OK != php_sem_acquire(&sqlite_access)) { zabbix_log(LOG_LEVEL_CRIT, "ERROR: cannot create lock on SQLite3 database"); exit(FAIL); } result = zbx_malloc(NULL, sizeof(ZBX_SQ_DB_RESULT)); result->curow = 0; lbl_get_table: if (SQLITE_OK != (ret = sqlite3_get_table(conn,sql, &result->data, &result->nrow, &result->ncolumn, &error))) { if (SQLITE_BUSY == ret) goto lbl_get_table; zabbix_errlog(ERR_Z3005, 0, error, sql); sqlite3_free(error); SQ_DBfree_result(result); switch (ret) { case SQLITE_ERROR: /* SQL error or missing database; assuming SQL error, because if we are this far into execution, zbx_db_connect() was successful */ case SQLITE_NOMEM: /* a malloc() failed */ case SQLITE_MISMATCH: /* data type mismatch */ result = NULL; break; default: result = (DB_RESULT)ZBX_DB_DOWN; break; } } if (0 == txn_level) php_sem_release(&sqlite_access); #endif /* HAVE_SQLITE3 */ if (0 != CONFIG_LOG_SLOW_QUERIES) { sec = zbx_time() - sec; if (sec > (double)CONFIG_LOG_SLOW_QUERIES / 1000.0) zabbix_log(LOG_LEVEL_WARNING, "slow query: " ZBX_FS_DBL " sec, \"%s\"", sec, sql); } if (NULL == result && 0 < txn_level) { zabbix_log(LOG_LEVEL_DEBUG, "query [%s] failed, setting transaction as failed", sql); txn_error = 1; } clean: zbx_free(sql); return result; }
/* * Execute SQL statement. For non-select statements only. */ int zbx_db_vexecute(const char *fmt, va_list args) { char *sql = NULL; int ret = ZBX_DB_OK; double sec = 0; #if defined(HAVE_IBM_DB2) SQLHANDLE hstmt = 0; SQLRETURN ret1; SQLLEN row1; SQLLEN rows = 0; #elif defined(HAVE_MYSQL) int status; #elif defined(HAVE_ORACLE) OCIStmt *stmthp = NULL; sword err = OCI_SUCCESS; #elif defined(HAVE_POSTGRESQL) PGresult *result; char *error = NULL; #elif defined(HAVE_SQLITE3) int err; char *error = NULL; #endif if (0 != CONFIG_LOG_SLOW_QUERIES) sec = zbx_time(); sql = zbx_dvsprintf(sql, fmt, args); if (0 == txn_init && 0 == txn_level) zabbix_log(LOG_LEVEL_DEBUG, "query without transaction detected"); if (1 == txn_error) { zabbix_log(LOG_LEVEL_DEBUG, "ignoring query [txnlev:%d] [%s] within failed transaction", txn_level, sql); ret = ZBX_DB_FAIL; goto clean; } zabbix_log(LOG_LEVEL_DEBUG, "query [txnlev:%d] [%s]", txn_level, sql); #if defined(HAVE_IBM_DB2) /* allocate a statement handle */ if (SUCCEED != zbx_ibm_db2_success(SQLAllocHandle(SQL_HANDLE_STMT, ibm_db2.hdbc, &hstmt))) ret = ZBX_DB_DOWN; /* directly execute the statement; returns SQL_NO_DATA_FOUND when no rows were affected */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success_ext(SQLExecDirect(hstmt, (SQLCHAR *)sql, SQL_NTS))) ret = ZBX_DB_DOWN; /* get number of affected rows */ if (ZBX_DB_OK == ret && SUCCEED != zbx_ibm_db2_success(SQLRowCount(hstmt, &rows))) ret = ZBX_DB_DOWN; /* process other SQL statements in the batch */ while (ZBX_DB_OK == ret && SUCCEED == zbx_ibm_db2_success(ret1 = SQLMoreResults(hstmt))) { if (SUCCEED != zbx_ibm_db2_success(SQLRowCount(hstmt, &row1))) ret = ZBX_DB_DOWN; else rows += row1; } if (ZBX_DB_OK == ret && SQL_NO_DATA_FOUND != ret1) ret = ZBX_DB_DOWN; if (ZBX_DB_OK != ret) { zbx_ibm_db2_log_errors(SQL_HANDLE_DBC, ibm_db2.hdbc); zbx_ibm_db2_log_errors(SQL_HANDLE_STMT, hstmt); ret = (SQL_CD_TRUE == IBM_DB2server_status() ? ZBX_DB_FAIL : ZBX_DB_DOWN); } else if (0 <= rows) { ret = (int)rows; } if (hstmt) SQLFreeHandle(SQL_HANDLE_STMT, hstmt); #elif defined(HAVE_MYSQL) if (NULL == conn) { zabbix_errlog(ERR_Z3003); ret = ZBX_DB_FAIL; } else { if (0 != (status = mysql_query(conn, sql))) { zabbix_errlog(ERR_Z3005, mysql_errno(conn), mysql_error(conn), sql); switch (mysql_errno(conn)) { case CR_CONN_HOST_ERROR: case CR_SERVER_GONE_ERROR: case CR_CONNECTION_ERROR: case CR_SERVER_LOST: case ER_SERVER_SHUTDOWN: case ER_ACCESS_DENIED_ERROR: /* wrong user or password */ case ER_ILLEGAL_GRANT_FOR_TABLE: /* user without any privileges */ case ER_TABLEACCESS_DENIED_ERROR:/* user without some privilege */ case ER_UNKNOWN_ERROR: ret = ZBX_DB_DOWN; break; default: ret = ZBX_DB_FAIL; break; } } else { do { if (0 != mysql_field_count(conn)) { zabbix_log(LOG_LEVEL_DEBUG, "cannot retrieve result set"); break; } else ret += (int)mysql_affected_rows(conn); /* more results? -1 = no, >0 = error, 0 = yes (keep looping) */ if (0 < (status = mysql_next_result(conn))) zabbix_errlog(ERR_Z3005, mysql_errno(conn), mysql_error(conn), sql); } while (0 == status); } } #elif defined(HAVE_ORACLE) err = OCIHandleAlloc((dvoid *)oracle.envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, (size_t)0, (dvoid **)0); if (OCI_SUCCESS == err) { err = OCIStmtPrepare(stmthp, oracle.errhp, (text *)sql, (ub4)strlen((char *)sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT); } if (OCI_SUCCESS == err) { err = OCIStmtExecute(oracle.svchp, stmthp, oracle.errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_COMMIT_ON_SUCCESS); if (OCI_SUCCESS == err) { ub4 nrows = 0; err = OCIAttrGet((void *)stmthp, OCI_HTYPE_STMT, (ub4 *)&nrows, (ub4 *)0, OCI_ATTR_ROW_COUNT, oracle.errhp); ret = nrows; } } if (OCI_SUCCESS != err) { zabbix_errlog(ERR_Z3005, err, zbx_oci_error(err), sql); ret = (OCI_SERVER_NORMAL == OCI_DBserver_status() ? ZBX_DB_FAIL : ZBX_DB_DOWN); } if (NULL != stmthp) { (void)OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT); stmthp = NULL; } #elif defined(HAVE_POSTGRESQL) result = PQexec(conn,sql); if (NULL == result) { zabbix_errlog(ERR_Z3005, 0, "result is NULL", sql); ret = (CONNECTION_OK == PQstatus(conn) ? ZBX_DB_FAIL : ZBX_DB_DOWN); } else if (PGRES_COMMAND_OK != PQresultStatus(result)) { error = zbx_dsprintf(error, "%s:%s", PQresStatus(PQresultStatus(result)), PQresultErrorMessage(result)); zabbix_errlog(ERR_Z3005, 0, error, sql); zbx_free(error); ret = (CONNECTION_OK == PQstatus(conn) ? ZBX_DB_FAIL : ZBX_DB_DOWN); } if (ZBX_DB_OK == ret) ret = atoi(PQcmdTuples(result)); PQclear(result); #elif defined(HAVE_SQLITE3) if (0 == txn_level && PHP_MUTEX_OK != php_sem_acquire(&sqlite_access)) { zabbix_log(LOG_LEVEL_CRIT, "ERROR: cannot create lock on SQLite3 database"); exit(FAIL); } lbl_exec: if (SQLITE_OK != (err = sqlite3_exec(conn, sql, NULL, 0, &error))) { if (SQLITE_BUSY == err) goto lbl_exec; zabbix_errlog(ERR_Z3005, 0, error, sql); sqlite3_free(error); switch (err) { case SQLITE_ERROR: /* SQL error or missing database; assuming SQL error, because if we are this far into execution, zbx_db_connect() was successful */ case SQLITE_NOMEM: /* A malloc() failed */ case SQLITE_TOOBIG: /* String or BLOB exceeds size limit */ case SQLITE_CONSTRAINT: /* Abort due to constraint violation */ case SQLITE_MISMATCH: /* Data type mismatch */ ret = ZBX_DB_FAIL; break; default: ret = ZBX_DB_DOWN; break; } } if (ZBX_DB_OK == ret) ret = sqlite3_changes(conn); if (0 == txn_level) php_sem_release(&sqlite_access); #endif /* HAVE_SQLITE3 */ if (0 != CONFIG_LOG_SLOW_QUERIES) { sec = zbx_time() - sec; if (sec > (double)CONFIG_LOG_SLOW_QUERIES / 1000.0) zabbix_log(LOG_LEVEL_WARNING, "slow query: " ZBX_FS_DBL " sec, \"%s\"", sec, sql); } if (ZBX_DB_FAIL == ret && 0 < txn_level) { zabbix_log(LOG_LEVEL_DEBUG, "query [%s] failed, setting transaction as failed", sql); txn_error = 1; } clean: zbx_free(sql); return ret; }
DB_ROW zbx_db_fetch(DB_RESULT result) { #if defined(HAVE_IBM_DB2) int i; #elif defined(HAVE_ORACLE) sword rc; static char errbuf[512]; sb4 errcode; #endif if (NULL == result) return NULL; #if defined(HAVE_IBM_DB2) if (SUCCEED != zbx_ibm_db2_success(SQLFetch(result->hstmt))) /* e.g., SQL_NO_DATA_FOUND */ return NULL; for (i = 0; i < result->ncolumn; i++) { result->values[i] = (SQL_NULL_DATA == result->values_len[i] ? NULL : result->values_cli[i]); } return result->values; #elif defined(HAVE_MYSQL) return mysql_fetch_row(result); #elif defined(HAVE_ORACLE) if (OCI_NO_DATA == (rc = OCIStmtFetch2(result->stmthp, oracle.errhp, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT))) return NULL; if (OCI_SUCCESS == rc) return result->values; if (OCI_SUCCESS != (rc = OCIErrorGet((dvoid *)oracle.errhp, (ub4)1, (text *)NULL, &errcode, (text *)errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR))) { zabbix_errlog(ERR_Z3006, rc, zbx_oci_error(rc)); return NULL; } switch (errcode) { case 3113: /* ORA-03113: end-of-file on communication channel */ case 3114: /* ORA-03114: not connected to ORACLE */ zabbix_errlog(ERR_Z3006, errcode, errbuf); return NULL; } return result->values; #elif defined(HAVE_POSTGRESQL) /* free old data */ if (NULL != result->values) zbx_free(result->values); /* EOF */ if (result->cursor == result->row_num) return NULL; /* init result */ result->fld_num = PQnfields(result->pg_result); if (result->fld_num > 0) { int i; result->values = zbx_malloc(result->values, sizeof(char *) * result->fld_num); for (i = 0; i < result->fld_num; i++) { if (PQgetisnull(result->pg_result, result->cursor, i)) { result->values[i] = NULL; } else { result->values[i] = PQgetvalue(result->pg_result, result->cursor, i); if (PQftype(result->pg_result, i) == ZBX_PG_BYTEAOID) /* binary data type BYTEAOID */ zbx_pg_unescape_bytea((u_char *)result->values[i]); } } } result->cursor++; return result->values; #elif defined(HAVE_SQLITE3) /* EOF */ if (result->curow >= result->nrow) return NULL; if (NULL == result->data) return NULL; result->curow++; /* NOTE: first row == header row */ return &(result->data[result->curow * result->ncolumn]); #endif }