/****************************************************************************** * * * Function: process_record * * * * Purpose: process record update * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occured * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static int process_record(int nodeid, const char *record, int sender_nodetype) { char fieldname[ZBX_FIELDNAME_LEN_MAX]; zbx_uint64_t recid; int op, res = SUCCEED; int valuetype; char *value_esc; const ZBX_TABLE *table; DB_RESULT result; DB_ROW row; const char *r; char *buffer = NULL, *tmp = NULL, *fields_update = NULL, *fields = NULL, *values = NULL; int buffer_allocated = 16*1024, buffer_len, fieldname_len; int tmp_allocated = 16*1024, tmp_offset = 0; int fields_update_allocated = 16*1024, fields_update_offset = 0; int fields_allocated = 4*1024, fields_offset = 0; int values_allocated = 16*1024, values_offset = 0; zabbix_log( LOG_LEVEL_DEBUG, "In process_record [%s]", record); r = record; buffer = zbx_malloc(buffer, buffer_allocated); zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); if (NULL == (table = DBget_table(buffer))) { zabbix_log(LOG_LEVEL_WARNING, "Cannot find table [%s]", buffer); res = FAIL; goto out; } zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); ZBX_STR2UINT64(recid, buffer); zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); op = atoi(buffer); if (op == NODE_CONFIGLOG_OP_DELETE) { DBexecute("delete from %s where %s=" ZBX_FS_UI64, table->table, table->recid, recid); goto out; } tmp = zbx_malloc(tmp, tmp_allocated); fields_update = zbx_malloc(fields_update, fields_update_allocated); fields = zbx_malloc(fields, fields_allocated); values = zbx_malloc(values, values_allocated); zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, 128, "%s,", table->recid); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 128, ZBX_FS_UI64",", recid); while (NULL != r) { fieldname_len = zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); zbx_strlcpy(fieldname, buffer, sizeof(fieldname)); zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); valuetype=atoi(buffer); buffer_len = zbx_get_next_field(&r, &buffer, &buffer_allocated, ZBX_DM_DELIMITER); if (op == NODE_CONFIGLOG_OP_UPDATE) { if (0 == strcmp(buffer, "NULL")) { zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + 8, "%s=NULL,", fieldname); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 8, "NULL,"); } else { if (valuetype == ZBX_TYPE_INT || valuetype == ZBX_TYPE_UINT || valuetype == ZBX_TYPE_ID || valuetype == ZBX_TYPE_FLOAT) { zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 4, "%s=%s,", fieldname, buffer); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 4, "%s,", buffer); } else if (valuetype == ZBX_TYPE_BLOB) { if (*buffer == '\0') { zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + 8, "%s='',", fieldname); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, 8, "'',"); } else { #if defined(HAVE_POSTGRESQL) buffer_len = zbx_hex2binary(buffer); buffer_len = zbx_pg_escape_bytea((u_char *)buffer, buffer_len, &tmp, &tmp_allocated); zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 8, "%s='%s',", fieldname, tmp); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 8, "'%s',", tmp); #else zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 8, "%s=0x%s,", fieldname, buffer); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 8, "0x%s,", buffer); #endif } } else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ { zbx_hex2binary(buffer); value_esc = DBdyn_escape_string(buffer); buffer_len = strlen(value_esc); zbx_snprintf_alloc(&fields_update, &fields_update_allocated, &fields_update_offset, fieldname_len + buffer_len + 8, "%s='%s',", fieldname, value_esc); zbx_snprintf_alloc(&values, &values_allocated, &values_offset, buffer_len + 8, "'%s',", value_esc); zbx_free(value_esc) } } zbx_snprintf_alloc(&fields, &fields_allocated, &fields_offset, fieldname_len + 4, "%s,", fieldname); } else { zabbix_log( LOG_LEVEL_WARNING, "Unknown record operation [%d]", op); res = FAIL; goto out; } }
/****************************************************************************** * * * Function: process_record * * * * Purpose: process record update * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: Alexei Vladishev * * * * Comments: * * * ******************************************************************************/ static int process_record(char **sql, size_t *sql_alloc, size_t *sql_offset, int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, int lastrecord, int acknowledges, zbx_vector_uint64_t *ack_eventids) { const char *r; int f, res = FAIL; char *value_esc; zabbix_log(LOG_LEVEL_DEBUG, "In process_record()"); if (0 == *sql_offset) { DBbegin_multiple_update(sql, sql_alloc, sql_offset); #ifdef HAVE_MULTIROW_INSERT begin_history_sql(sql, sql_alloc, sql_offset, table); #endif } #if !defined(HAVE_MULTIROW_INSERT) begin_history_sql(sql, sql_alloc, sql_offset, table); #endif zbx_chrcpy_alloc(sql, sql_alloc, sql_offset, '('); if (0 != (table->flags & ZBX_HISTORY_SYNC)) zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%d,", nodeid); for (r = record, f = 0; table->fields[f].name != 0; f++) { if (0 != (table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) continue; if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); if (0 != acknowledges && 0 == strcmp(table->fields[f].name, "eventid")) { zbx_uint64_t eventid; ZBX_STR2UINT64(eventid, buffer); zbx_vector_uint64_append(ack_eventids, eventid); } if (table->fields[f].type == ZBX_TYPE_INT || table->fields[f].type == ZBX_TYPE_UINT || table->fields[f].type == ZBX_TYPE_ID || table->fields[f].type == ZBX_TYPE_FLOAT) { zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "%s,", buffer); } else if (table->fields[f].type == ZBX_TYPE_BLOB) { if ('\0' == *buffer) zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "'',"); else { #ifdef HAVE_POSTGRESQL size_t len; len = zbx_hex2binary(buffer); zbx_pg_escape_bytea((u_char *)buffer, len, &tmp, &tmp_alloc); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "'%s',", tmp); #else zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "0x%s,", buffer); #endif } } else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ { zbx_hex2binary(buffer); value_esc = DBdyn_escape_string(buffer); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, "'%s',", value_esc); zbx_free(value_esc); } } (*sql_offset)--; #ifdef HAVE_MULTIROW_INSERT zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "),"); #else zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ");\n"); #endif if (0 != lastrecord || *sql_offset > ZBX_MAX_SQL_SIZE) { #ifdef HAVE_MULTIROW_INSERT (*sql_offset)--; zbx_strcpy_alloc(sql, sql_alloc, sql_offset, ";\n"); #endif DBend_multiple_update(sql, sql_alloc, sql_offset); if (ZBX_DB_OK <= DBexecute("%s", *sql)) res = SUCCEED; *sql_offset = 0; if (SUCCEED == res && 0 != lastrecord && 0 != acknowledges && 0 != ack_eventids->values_num) { zbx_vector_uint64_sort(ack_eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); zbx_vector_uint64_uniq(ack_eventids, ZBX_DEFAULT_UINT64_COMPARE_FUNC); zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update events" " set acknowledged=1" " where"); DBadd_condition_alloc(sql, sql_alloc, sql_offset, "eventid", ack_eventids->values, ack_eventids->values_num); if (ZBX_DB_OK > DBexecute("%s", *sql)) res = FAIL; *sql_offset = 0; } } else res = SUCCEED; return res; error: zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", CONFIG_NODEID, sender_nodeid, nodeid, record); return FAIL; }
/****************************************************************************** * * * Function: update_items * * * * Purpose: process record update * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: * * * * Comments: * * * ******************************************************************************/ static int process_items(char **sql, size_t *sql_alloc, size_t *sql_offset, int sender_nodeid, int nodeid, const ZBX_TABLE *table, const char *record, int lastrecord) { const char *r; int f, res = FAIL; zbx_uint64_t itemid = 0; char *value_esc; int clock, value_type = -1; double value_double; zbx_uint64_t value_uint64; zabbix_log(LOG_LEVEL_DEBUG, "In process_items()"); if (*sql_offset == 0) DBbegin_multiple_update(sql, sql_alloc, sql_offset); zbx_strcpy_alloc(sql, sql_alloc, sql_offset, "update items set prevvalue=lastvalue"); for (r = record, f = 0; table->fields[f].name != 0; f++) { if (0 != (table->flags & ZBX_HISTORY_SYNC) && 0 == (table->fields[f].flags & ZBX_HISTORY_SYNC)) continue; if (NULL == r) goto error; zbx_get_next_field(&r, &buffer, &buffer_alloc, ZBX_DM_DELIMITER); if (0 == strcmp(table->fields[f].name, "itemid")) ZBX_STR2UINT64(itemid, buffer); if (table->fields[f].type == ZBX_TYPE_INT || table->fields[f].type == ZBX_TYPE_UINT || table->fields[f].type == ZBX_TYPE_ID || table->fields[f].type == ZBX_TYPE_FLOAT) { if (0 == strcmp(table->fields[f].name, "clock")) { zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ",lastclock=%s", buffer); clock = atoi(buffer); } else if (0 == strcmp(table->fields[f].name, "value")) { zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ",lastvalue=%s", buffer); value_type = table->fields[f].type; if (value_type == ZBX_TYPE_FLOAT) value_double = atof(buffer); else if (value_type == ZBX_TYPE_UINT) ZBX_STR2UINT64(value_uint64, buffer); } } else /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ { if (0 == strcmp(table->fields[f].name, "value")) { zbx_hex2binary(buffer); value_esc = DBdyn_escape_string_len(buffer, ITEM_LASTVALUE_LEN); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, ",lastvalue='%s'", value_esc); zbx_free(value_esc); } } } if (value_type == ZBX_TYPE_FLOAT) DBadd_trend(itemid, value_double, clock); else if (value_type == ZBX_TYPE_UINT) DBadd_trend_uint(itemid, value_uint64, clock); zbx_snprintf_alloc(sql, sql_alloc, sql_offset, " where itemid=" ZBX_FS_UI64 ";\n", itemid); if (lastrecord || *sql_offset > ZBX_MAX_SQL_SIZE) { DBend_multiple_update(sql, sql_alloc, sql_offset); if (DBexecute("%s", *sql) >= ZBX_DB_OK) res = SUCCEED; *sql_offset = 0; } else res = SUCCEED; return res; error: zabbix_log(LOG_LEVEL_ERR, "NODE %d: Received invalid record from node %d for node %d [%s]", CONFIG_NODEID, sender_nodeid, nodeid, record); return FAIL; }
/****************************************************************************** * * * Function: process_updated_records * * * * Purpose: * * * * Parameters: * * * * Return value: * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ static void process_updated_records(int nodeid, char *data) { const char *__function_name = "process_updated_records"; char *r, *lf, *value_esc; int op, dnum; const ZBX_TABLE *table = NULL; const ZBX_FIELD *field = NULL; zbx_uint64_t recid; char *dsql = NULL, *isql = NULL, *ifld = NULL, *ival = NULL, *usql = NULL, *ufld = NULL; size_t dsql_alloc = 4 * ZBX_KIBIBYTE, dsql_offset = 0, dtmp_offset = 0, isql_alloc = 4 * ZBX_KIBIBYTE, isql_offset = 0, ifld_alloc = 4 * ZBX_KIBIBYTE, ifld_offset = 0, ival_alloc = 4 * ZBX_KIBIBYTE, ival_offset = 0, usql_alloc = 4 * ZBX_KIBIBYTE, usql_offset = 0, ufld_alloc = 4 * ZBX_KIBIBYTE, ufld_offset = 0; DB_RESULT result; DB_ROW row; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name); dsql = zbx_malloc(dsql, dsql_alloc); isql = zbx_malloc(isql, isql_alloc); ifld = zbx_malloc(ifld, ifld_alloc); ival = zbx_malloc(ival, ival_alloc); usql = zbx_malloc(usql, usql_alloc); ufld = zbx_malloc(ufld, ufld_alloc); #ifdef HAVE_ORACLE DBbegin_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBbegin_multiple_update(&isql, &isql_alloc, &isql_offset); DBbegin_multiple_update(&usql, &usql_alloc, &usql_offset); #endif for (r = data; '\0' != *r;) { if (NULL != (lf = strchr(r, '\n'))) *lf = '\0'; /* table name */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (NULL == table || 0 != strcmp(table->table, buf)) { if (NULL == (table = DBget_table(buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find table [%s]", __function_name, buf); goto next; } } /* record id */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); ZBX_STR2UINT64(recid, buf); if (NULL == r) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): invalid record", __function_name); goto next; } if ('0' == *r) /* NODE_CONFIGLOG_OP_UPDATE */ { result = DBselect("select 0 from %s where %s=" ZBX_FS_UI64, table->table, table->recid, recid); if (NULL == (row = DBfetch(result))) op = NODE_CONFIGLOG_OP_ADD; else op = NODE_CONFIGLOG_OP_UPDATE; DBfree_result(result); zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); ifld_offset = 0; ival_offset = 0; ufld_offset = 0; dtmp_offset = dsql_offset; dnum = 0; if (op == NODE_CONFIGLOG_OP_ADD && NULL != table->uniq) { zbx_snprintf_alloc(&dsql, &dsql_alloc, &dsql_offset, "delete from %s where ", table->table); } while (NULL != r) { /* field name */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (NULL == (field = DBget_field(table, buf))) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): cannot find field [%s.%s]", __function_name, table->table, buf); goto next; } if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "%s=", buf); else /* NODE_CONFIGLOG_OP_ADD */ zbx_snprintf_alloc(&ifld, &ifld_alloc, &ifld_offset, "%s,", buf); /* value type (ignored) */ zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); zbx_get_next_field((const char **)&r, &buf, &buf_alloc, ZBX_DM_DELIMITER); if (0 == strcmp(buf, "NULL")) { if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_strcpy_alloc(&ufld, &ufld_alloc, &ufld_offset, "NULL,"); else /* NODE_CONFIGLOG_OP_ADD */ zbx_strcpy_alloc(&ival, &ival_alloc, &ival_offset, "NULL,"); continue; } switch (field->type) { case ZBX_TYPE_ID: /* if the field relates the same table * for example: host.proxy_hostid relates with host.hostid */ if (NODE_CONFIGLOG_OP_ADD == op && NULL != field->fk_table && 0 == strcmp(table->table, field->fk_table)) { zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "%s=%s,", field->name, buf); zbx_strcpy_alloc(&ival, &ival_alloc, &ival_offset, "NULL,"); break; } case ZBX_TYPE_INT: case ZBX_TYPE_UINT: case ZBX_TYPE_FLOAT: if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "%s,", buf); else /* NODE_CONFIGLOG_OP_ADD */ { zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "%s,", buf); if (NULL != table->uniq && SUCCEED == str_in_list(table->uniq, field->name, ',')) { zbx_snprintf_alloc(&dsql, &dsql_alloc, &dsql_offset, "%s=%s and ", field->name, buf); dnum++; } } break; case ZBX_TYPE_BLOB: if ('\0' == *buf) { if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_strcpy_alloc(&ufld, &ufld_alloc, &ufld_offset, "'',"); else /* NODE_CONFIGLOG_OP_ADD */ zbx_strcpy_alloc(&ival, &ival_alloc, &ival_offset, "'',"); } else { #if defined(HAVE_POSTGRESQL) size_t len; len = zbx_hex2binary(buf); DBbytea_escape((u_char *)buf, len, &tmp, &tmp_alloc); if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "'%s',", tmp); else /* NODE_CONFIGLOG_OP_ADD */ zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "'%s',", tmp); #else if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "0x%s,", buf); else /* NODE_CONFIGLOG_OP_ADD */ zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "0x%s,", buf); #endif } break; default: /* ZBX_TYPE_TEXT, ZBX_TYPE_CHAR */ zbx_hex2binary(buf); value_esc = DBdyn_escape_string(buf); if (NODE_CONFIGLOG_OP_UPDATE == op) zbx_snprintf_alloc(&ufld, &ufld_alloc, &ufld_offset, "'%s',", value_esc); else /* NODE_CONFIGLOG_OP_ADD */ { zbx_snprintf_alloc(&ival, &ival_alloc, &ival_offset, "'%s',", value_esc); if (NULL != table->uniq && SUCCEED == str_in_list(table->uniq, field->name, ',')) { zbx_snprintf_alloc(&dsql, &dsql_alloc, &dsql_offset, "%s='%s' and ", field->name, value_esc); dnum++; } } zbx_free(value_esc); } } if (dsql_offset != dtmp_offset) { if (dnum != num_param(table->uniq)) { zabbix_log(LOG_LEVEL_DEBUG, "%s(): missing required fields [%s][%s]", __function_name, table->table, table->uniq); dsql_offset = dtmp_offset; goto next; } dsql_offset -= 5; zbx_strcpy_alloc(&dsql, &dsql_alloc, &dsql_offset, ";\n"); } if (0 != ifld_offset) { ifld[--ifld_offset] = '\0'; ival[--ival_offset] = '\0'; zbx_snprintf_alloc(&isql, &isql_alloc, &isql_offset, "insert into %s (%s,%s) values (" ZBX_FS_UI64 ",%s);\n", table->table, table->recid, ifld, recid, ival); } if (0 != ufld_offset) { ufld[--ufld_offset] = '\0'; zbx_snprintf_alloc(&usql, &usql_alloc, &usql_offset, "update %s set %s where %s=" ZBX_FS_UI64 ";\n", table->table, ufld, table->recid, recid); } if (dsql_offset > ZBX_MAX_SQL_SIZE || isql_offset > ZBX_MAX_SQL_SIZE || usql_offset > ZBX_MAX_SQL_SIZE) { DBend_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBend_multiple_update(&isql, &isql_alloc, &isql_offset); DBend_multiple_update(&usql, &usql_alloc, &usql_offset); if (dsql_offset > 16) DBexecute("%s", dsql); if (isql_offset > 16) DBexecute("%s", isql); if (usql_offset > 16) DBexecute("%s", usql); dsql_offset = 0; isql_offset = 0; usql_offset = 0; #ifdef HAVE_ORACLE DBbegin_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBbegin_multiple_update(&isql, &isql_alloc, &isql_offset); DBbegin_multiple_update(&usql, &usql_alloc, &usql_offset); #endif } } next: if (lf != NULL) { *lf++ = '\n'; r = lf; } else break; } DBend_multiple_update(&dsql, &dsql_alloc, &dsql_offset); DBend_multiple_update(&isql, &isql_alloc, &isql_offset); DBend_multiple_update(&usql, &usql_alloc, &usql_offset); if (dsql_offset > 16) DBexecute("%s", dsql); if (isql_offset > 16) DBexecute("%s", isql); if (usql_offset > 16) DBexecute("%s", usql); zbx_free(ufld); zbx_free(usql); zbx_free(ival); zbx_free(ifld); zbx_free(isql); zbx_free(dsql); zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name); }