From 0eebeb8d79614e07a1ea59bbeeb607ff0b89bd00 Mon Sep 17 00:00:00 2001 From: Sang Woo Kim Date: Fri, 22 May 2026 11:53:56 +0900 Subject: [PATCH] fix(qgroup): non-atomic group get must read channel-less Const fields A non-atomic group get (record[atomic=false]) gated each field read on `pDbChannel && leafNode`, so fields with no dbChannel were silently skipped. MappingInfo::Const fields carry a constant value rather than a channel, so a non-atomic get returned them at their cloneEmpty() defaults (0 / 0.0 / ""), while the atomic get and monitor paths return the constant. Mirror the atomic branch's field selection in the non-atomic branch: skip only Proc/Structure and read every other field, taking the per-field DBLocker only when a channel is present. getGroupField() already handles channel-less fields via field.info, so Const fields populate correctly. --- ioc/groupsource.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ioc/groupsource.cpp b/ioc/groupsource.cpp index 4527fdf..98a4cb5 100644 --- a/ioc/groupsource.cpp +++ b/ioc/groupsource.cpp @@ -510,17 +510,20 @@ void onGet(Group& group, const std::unique_ptr& getOperation) { // Loop through all fields for (auto& field: group.fields) { - dbChannel* pDbChannel = field.value; + if(field.info.type == MappingInfo::Proc || field.info.type==MappingInfo::Structure) + continue; // find the leaf node in which to set the value auto leafNode = field.findIn(returnValue); - if (pDbChannel && leafNode) { + if (dbChannel* pDbChannel = field.value) { // Lock this field DBLocker F(pDbChannel->addr.precord); - if (!getGroupField(field, leafNode, group.name, getOperation)) { + if(!getGroupField(field, leafNode, group.name, getOperation)) + return; + } else { + if(!getGroupField(field, leafNode, group.name, getOperation)) return; - } } } }