MpDatabaseQuery with multiple mappView clients: literal array index in target PV silently drops rows

Background

We wanted several mappView clients to run database queries independently and see only their own results, so the natural design was one MpDatabaseQuery config with a shared result type, and a single array indexed per client slot — something like:

gDbClientData : ARRAY\[0..2] OF DbClientData_typ;

with the query’s target PV pointing at a specific slot, e.g.:

<Property ID="PV" Value="::gDbClientData[0].Rows[].number" />

That way each client’s data would live in its own array element, and per-client mappView bindings (via clientInfo.slotId) would just read/write the matching index. Simple, and it’s how you’d normally handle “N instances of the same thing.”

The problem

It doesn’t work — but it fails silently. With a literal index in the target path (gDbClientData[0].Rows[]), mapp still reports success: Error = FALSE, correct ArraySize, correct Rows.Total. But every row gets written to element [0] of the Rows array — the row index never advances — so all you see is the last row repeated, no error anywhere in the logbook or logger.

Root cause: the target PV path may contain struct members, but only one [] and no literal index. Any literal index anywhere in the path breaks the internal row-counter mapping, without any diagnostic.

Confirmed with a small test matrix:

PV path Result
gDbTestNumber[] correct
gDbClient0.RowsNumber[] (struct member, no literal index) correct
gDbClient1.Rows[] (array of struct) correct
gDbClientData[1].RowsNumber[] (literal index) wrong — all rows on [0]

The fix

Since the slot index can’t appear in the PV path, per-client results have to be separate named variables instead of one indexed array:

gDbClient0 : DbClientData_typ;
gDbClient1 : DbClientData_typ;
gDbClient2 : DbClientData_typ;

Each has its own query entry pointing at its own variable (::gDbClient0.Rows[], etc.). mappView’s per-client binding still works the same way via clientInfo.slotId — only the bound refIds change from gDbClientData[N]… to gDbClientN…. In ST, since these are separate variables rather than an array, we rebind a reference per iteration (CASE i OF 0: pRef ACCESS ADR(gDbClient0); ...).

2 Likes

Thanks for sharing @tomas.miculka :wink:

Hi! That’s an interesting thing to read, but I do have a question (or two)…

Are you using the Database Widget, or do you somehow bind the PV to a Table-Widget/…? Because if you only use the Database Widget (and don’t need the data for the application itself), there is no need to specify a PV. Queries executed directly from the Widget are supposed to only hand over data to that widget (if I remember correctly).

Otherwise I’d be interested in why you need the data on the PLC / the application itself? Because maybe MpDatabase can be improved.

Either way, I’d consider the behavior of MpDatabase a bug (without having tried it myself right now). Because MpDatabase is built to work (primarily) with arrays, but it seems it is too eager to accept the first [] as the array it should handle. Which is fine (and expected) if there is no index provided, but if there is an index, it should probably continue searching if there is a different [] without index. :thinking: And if there is no [] without index, then it should only return a single row (same as if no array was specified at all).

I’d recommend to contact support and open a ticket for further investigation (and yes, I know this topic is not a question, but still, possibly incorrect behavior should still be investigated/corrected).