Skip to content

Remote push uses the local server's upsert syntax against the main server #603

Description

@somethingwithproof

poller_push_data_to_main() picks its upsert syntax from set.dbonupdate, which describes the local database, but every statement it builds is sent to the main database. When the two are different vendors the statement is rejected and the whole batch is lost.

util.c:984 and util.c:1146 (develop), util.c:855 and util.c:990 (1.2.x):

if (set.dbonupdate == 0) {
    snprintf(suffix, BUFSIZE, " ON DUPLICATE KEY UPDATE snmp_sysDescr=VALUES(snmp_sysDescr), ...");
} else {
    snprintf(suffix, BUFSIZE, " AS rs ON DUPLICATE KEY UPDATE snmp_sysDescr=rs.snmp_sysDescr, ...");
}

Three facts make this always the wrong connection:

  1. set.dbonupdate is derived from the local server's banner (util.c:550-556), in the same function that calls get_cacti_version(&mysql, LOCAL). It is 1 for MySQL 8.x, 0 for MariaDB.
  2. poller_push_data_to_main() is called from exactly one place, under if (set.poller_id > 1 && set.mode == REMOTE_ONLINE && !set.SQL_readonly) (spine.c:1071). It only ever runs on a remote poller.
  3. Both suffixes are appended to sqlbuf and sent with db_insert(&mysqlr, REMOTE, sqlbuf) (util.c:1114, 1124, 1193, 1203). Every insert in the function goes to the main server.

So on a remote poller running MySQL 8 against a MariaDB main server, set.dbonupdate is 1, the row-alias form is selected, and MariaDB rejects VALUES ... AS rs as a syntax error. Host status and poller_item sync fail on every push cycle. The symptom a user sees is stale device status and graphs that stop advancing for everything behind that poller, not a message about SQL.

The reverse pairing is harmless today: a MariaDB remote poller against a MySQL 8 main server picks VALUES(), which MySQL 8 still accepts but has deprecated. That is the same deprecation #590 describes for poll_host(), and it is a warning rather than a failure.

config_t already carries rdbversion and rdbonupdate for exactly this distinction and nothing ever populates them. Populating rdbonupdate from the remote connection's banner is the real fix. Until then the portable VALUES() form is correct in this function, because it is the only one both vendors accept.

Note that putsetting() at util.c:238 keeps the branch correctly. It takes the connection as a parameter and its one caller passes LOCAL, so there set.dbonupdate really does describe the target.

Present on develop and 1.2.x. A fix and a structural regression test are in #597.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions