Merge ~dirk.zimoch/epics-base:fix_zero_size_arrays into ~epics-core/epics-base/+git/epics-base:7.0

Proposed by Dirk Zimoch
Status: Merged
Approved by: Andrew Johnson
Approved revision: d1491e0860efc2ea3bd85a9f68cd83f18b575ae0
Merged at revision: d108a1ff113319aed89fd1c5ef7f397a82eca707
Proposed branch: ~dirk.zimoch/epics-base:fix_zero_size_arrays
Merge into: ~epics-core/epics-base/+git/epics-base:7.0
Diff against target: 349 lines (+102/-40)
12 files modified
documentation/RELEASE_NOTES.md (+36/-0)
modules/ca/src/client/db_access.h (+1/-1)
modules/ca/src/client/nciu.cpp (+2/-2)
modules/database/src/ioc/db/dbAccess.c (+16/-15)
modules/database/src/ioc/db/dbCa.c (+7/-1)
modules/database/src/ioc/db/dbTest.c (+21/-10)
modules/database/src/std/dev/devAaiSoft.c (+8/-3)
modules/database/src/std/dev/devAiSoft.c (+2/-1)
modules/database/src/std/dev/devSASoft.c (+2/-2)
modules/database/src/std/dev/devWfSoft.c (+5/-2)
modules/database/src/std/rec/aSubRecord.c (+1/-2)
modules/database/test/std/rec/regressTest.c (+1/-1)
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
mdavidsaver Approve
Review via email: mp+386175@code.launchpad.net
To post a comment you must log in.
Revision history for this message
mdavidsaver (mdavidsaver) wrote :

Looks good.

wrt. dbpf. So this would look like:

> dbpf "some:pv" "1 2 3 4"

Did you consider switching dbpf() to use iocshArgArgv to capture the value element(s)?
This doesn't have to be the only argument. This seems more natural to me, and potentially
avoids some of the added string parsing code. I suppose this would be a disadvantage for
vxworks though?

Also, an example of this should be added to the help message for dbpf.
This is in dbIocRegister.c. I can do this after merge if needed.

review: Approve
Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

Yes, 'dbpf some:pv 1 2 3 4' would look more natural. For VxWorks this would be limited to 9 array elements though. RTEMS? Let's see what I can do.

field (INP, "empty:array CP") does not give the desired result yet. I am still working on that. Maybe it will change the output of 'caget partially_filled:array" though (which would them become compatible with camonitor partially_filled:array). As I said, still working on it ...

Revision history for this message
Andrew Johnson (anj) wrote :

Speculating here I admit so this comment is probably going a bit far for this MR: I wonder how hard it would be to integrate yajl into iocsh and add an iocshArgJSON type? The yajl JSON-5 parser would make that slightly easier to use (no need to "quote":"keys").

I'm not too concerned about trying to keep compatibility with the VxWorks target shell, there are enough places where we already have to accept arguments as strings (for float and double values), and VxWorks users can and often do switch to using iocsh anyway.

However my point is this could change the dbpf of arrays to become 'dbpf some:pv [1,2,3,4]' which is in line with our use of JSON in the database files.

Revision history for this message
Andrew Johnson (anj) wrote :

On changing the semantics of passing pnRequest=NULL to dbGet(): I like this as a solution, it probably just clarifies existing practice but I haven't thought through if and how any other code might have to change (if at all). Presumably similar changes apply to the semantics of the dbGetField(), dbGetLink(), lset::getValue() etc. since they normally pass that argument through to dbGet().

Has anyone done a search through the epics-modules repo's on GitHub to see if there is any code there which might need changing? Hopefully there isn't any such code, but I would like to be proactive about that just in case. If there might need to be any changes to external code we should create a HAS_EMPTY_ARRAY_SUPPORT macro in dbAccessDefs.h to allow for easy compile-time detection.

Do recent versions of autosave properly save & restore an empty array field? There are other tools out there for doing the same thing, but I believe the synapps autosave module has the widest usage.

I see the change to modules/ca to allow the ca_array_put() API to write a 0-length array, do we need to make any changes to the caput program to allow that to be exercised from the command-line? That might be reasonable as a separate development for later, but we should support it.

Finally a minor code complaint: I don't like the use of the epicsOldString type. I know it's just a typedef but it isn't by accident that there is only one existing use of this data type in the IOC code and that's in newer code where sizeof(epicsOldString) should be replaced by MAX_STRING_SIZE anyway. The epicsTypes.h header even has a comment block above tye typedef which says "Dont use this - it may vanish in the future". I read that imperative as applying to the typedef and not so much to the MAX_STRING_SIZE macro (which would be much harder to get rid of) but there are several other ancient typedefs, enums and arrays in epicsTypes.h which should really get dumped.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

I had checked EPICS base for uses of pnRequest and found no problems. All scalar records use NULL.

I have not checked autosave yet.

Caput „just works“ writing zero size arrays.

I willchange the code which uses epicsOldString and will use MAX_STRING_SIZE instead.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

I have removed epicsOldString.

From looking at the code, I would say autosave saves as scalar if curr_elements<=1. This may even now produce problematic results and should be fixed. It better always saves arrays as arrays, even with 0 or 1 elements. I need to do some actual tests.

But first I would like to find out if I can do something about CA links.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

CA links now work as well. It was not necessary to change anything in CA, thus caget did not change.

In dbCa.c dbCaGetLink() are several occations where sevr/stat is set to INVALID/LINK alarm in case of errors. I think that is not necessary. Returning -1 is sufficient. The calling function dbGetLink() already sets INVALID/LINK alarm on error.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

Writing empty arrays to scalars via output links still needs to be fixed.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

Finally put is fixed as well. I changed dbPut to set the target to INVALID/LINK if the target is a scalar and 0 elements are put. Only the target record goes to alarm state, not the sending record.
The target is then processed normally if the link is PP, as before only that before if was processed with no alarm and value 0.

If the target happens to be an array of max length 1, it is set to an empty array and not to alarm. For that I always use now the array implementation if the target is a SPC_DBADDR field with array_info(), even if the target has only 1 element. That allowed me to streamline the dbPut code a bit.

This change works for db links, CA links and as well for `caput -a 0` (empty array put) to a scalar field. Is it ok to call this case a "LINK_ALARM"? I cannot really distinguish between caput and any other put in dbPut. An alternative would be to check the target in the CA server and report an error to the caller when trying to put an empty array into a scalar. But that would probably affect CA links as well and generate an error in the sending record.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

For the record: I consider this work complete. Any opinions on the final version?

Revision history for this message
Andrew Johnson (anj) wrote :

Thanks for working on this Dirk. The Core group will need some time to review it again, and I suspect we won't want to merge it before the 7.0.4.1 patch release, which will be coming out soon to fix some problems discovered in 7.0.4

Revision history for this message
Andrew Johnson (anj) wrote :

Some comments inline, not quite ready. We aren't 100% sure about the dbpf change but it's probably Okay. The code change in dbPut() needs fixing.

review: Needs Fixing
Revision history for this message
Andrew Johnson (anj) wrote :

The previous comment was from a Core Group review of this code, sorry for not making that clear.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

Replies inline.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

more inline comment.

Revision history for this message
Andrew Johnson (anj) wrote :

Replies inline.

Revision history for this message
Dirk Zimoch (dirk.zimoch) :
Revision history for this message
Andrew Johnson (anj) :
Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

Ah, now I got it. I always mixed up get_array_info and put_array_info. I must have been blind.

Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

epics> dbpf array_of_numbers "[1,2,3]"
DBF_DOUBLE[3]: 1 2 3
epics> dbpf string "[1,2,3]"
DBF_STRING: "[1,2,3]"
epics> dbpf array_of_strings "[1,2,3]"
DBF_STRING[3]: "1" "2" "3"
epics> dbpf array_of_strings '"[1,2,3]"'
DBF_STRING: "[1,2,3]"
epics> dbpf string "bla"
DBF_STRING: "bla"
epics> dbpf array_of_strings "bla"
dbConvertJSON: lexical error: invalid char in json text.
                                       bla
                     (right here) ------^
epics> dbpf array_of_strings '"bla"'
DBF_STRING: "bla"
epics> dbpf array_of_chars "bla"
DBF_CHAR[4]: "bla"
epics> dbpf array_of_chars "[0x41,0x42,0x43]"
DBF_CHAR[17]: "[0x41,0x42,0x43]"

Should I support
1) writing plain strings into arrays of string?
2) writing arrays of integers into arrays of char?

Revision history for this message
Andrew Johnson (anj) wrote :

I have developed some updates to this branch, for dbgf and the Release Notes, which I will apply after merging.

Looks good to me now.

review: Approve
Revision history for this message
Andrew Johnson (anj) wrote :
Download full text (5.9 KiB)

My changes:

commit 297f04bddc6765d7fc2b5941e16054b448fc994e
Author: Andrew Johnson <email address hidden>
Date: Fri Oct 30 13:37:50 2020 -0500

    Make dbgf display something for an empty array

    Also significantly expands on Dirk's Release Notes entries.

diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md
index 0a54dc67f..f21fbdcec 100644
--- a/documentation/RELEASE_NOTES.md
+++ b/documentation/RELEASE_NOTES.md
@@ -17,42 +17,84 @@ should also be read to understand what has changed since earlier releases.

 <!-- Insert new items immediately below here ... -->

-### Support for empty arrays
+### Support for zero-length arrays

-Several problems with empty arrays have been fixed.
+Several modifications have been made to properly support zero-length
+array values inside the IOC and over Channel Access. Some of these changes
+may affect external code that interfaces with the IOC, either directly or
+over the CA client API so we recommend thorough testing of any external
+code that handles array fields when upgrading to this release.

-#### Changed dbr_size_n(TYPE,COUNT) macro
+Since these changes affect the Channel Access client-side API they will
+require rebuilding any CA Gateways against this version or Base to
+properly handle zero-length arrays. The `caget`, `caput` and `camonitor`
+client programs are known to work with empty arrays as long as they were
+built with this or a later version of EPICS.

-When called with COUNT=0 the macro no longer returns the number of bytes
+#### Change to the db_access.h `dbr_size_n(TYPE, COUNT)` macro
+
+When called with COUNT=0 this macro no longer returns the number of bytes
 required for a scalar (1 element) but for an empty array (0 elements).
-Make sure you don't call it with COUNT=0 when you really mean COUNT=1.
+Make sure code that uses this doesn't call it with COUNT=0 when it really
+means COUNT=1.
+
+Note that the db_access.h header file is included by cadef.h so the change
+can impact Channel Access client programs that use this macro.
+
+#### Channel Access support for zero-length arrays
+
+The `ca_array_put()` and `ca_array_put_callback()` routines now accept an
+element count of zero, and will write a zero-length array to the PV if
+possible. No error will be raised if the target is a scalar field though,
+and the field's value will not be changed.
+
+The `ca_array_get_callback()` and `ca_create_subscription()` routines
+still accept a count of zero to mean fetch as many elements as the PV
+currently holds.
+
+Client programs should be prepared for the `count` fields of any
+`struct event_handler_args` or `struct exception_handler_args` passed to
+their callback routines to be zero.

 #### Array records

-The soft supports of array records aai, waveform, and subArray as well as
-the aSub record type have been fixed to correctly report 0 elements read
-when reading empty arrays from an input link.
+The soft device support for the array records aai, waveform, and subArray
+as well as the aSub record type now correctly report reading 0 elements
+when getting an empty array from an input link.

 #### Array support for dbpf

-The dbpf function now accepts arrays...

Read more...

Revision history for this message
Andrew Johnson (anj) wrote :

Core Group 11/4: Approved.

review: Approve
Revision history for this message
Dirk Zimoch (dirk.zimoch) wrote :

+The `ca_array_put()` and `ca_array_put_callback()` routines now accept an
+element count of zero, and will write a zero-length array to the PV if
+possible. No error will be raised if the target is a scalar field though,
+and the field's value will not be changed.

I thought I set the target scalar record to INVALID/LINK.

Revision history for this message
Andrew Johnson (anj) wrote :

That is possible with a DB link and that's probably what you're remembering, but not via the CA API. CA clients can't set record alarms, look at the code in dbChannel_put() in db_access.c which is what would do that.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md
2index e78bb64..1b4e78d 100644
3--- a/documentation/RELEASE_NOTES.md
4+++ b/documentation/RELEASE_NOTES.md
5@@ -17,6 +17,42 @@ should also be read to understand what has changed since earlier releases.
6
7 <!-- Insert new items immediately below here ... -->
8
9+### Support for empty arrays
10+
11+Several problems with empty arrays have been fixed.
12+
13+#### Changed dbr_size_n(TYPE,COUNT) macro
14+
15+When called with COUNT=0 the macro no longer returns the number of bytes
16+required for a scalar (1 element) but for an empty array (0 elements).
17+Make sure you don't call it with COUNT=0 when you really mean COUNT=1.
18+
19+#### Array records
20+
21+The soft supports of array records aai, waveform, and subArray as well as
22+the aSub record type have been fixed to correctly report 0 elements read
23+when reading empty arrays from an input link.
24+
25+#### Array support for dbpf
26+
27+The dbpf function now accepts arrays, including empty arrays as a JSON string.
28+
29+#### Scalar records reading from empty arrays
30+
31+Records reading scalar fields from empty arrays are now set to INVALID/LINK
32+alarm status.
33+Links have to call dbGetLink with pnRequest=NULL to be recognized as requests
34+for scalars.
35+This changes the semantics of pnRequest=NULL. It is now different from
36+requesting up to 1 array element, which may return a valid empty array.
37+
38+### Writing empty arrays to scalar records
39+
40+Witing an empty array to a scalar field now sets the target record to
41+INVALID/LINK alarm but does not modify the value. Before, the value used
42+to be set to 0 (without any alarm).
43+A target field needs to have the SPC_DBADDR tag to be recognized as an array
44+field and the record support must define a put_array_info method.
45
46 ## EPICS Release 7.0.4
47
48diff --git a/modules/ca/src/client/db_access.h b/modules/ca/src/client/db_access.h
49index 810f82f..ad10a88 100644
50--- a/modules/ca/src/client/db_access.h
51+++ b/modules/ca/src/client/db_access.h
52@@ -516,7 +516,7 @@ struct dbr_ctrl_double{
53 };
54
55 #define dbr_size_n(TYPE,COUNT)\
56-((unsigned)((COUNT)<=0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
57+((unsigned)((COUNT)<0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE]))
58
59 /* size for each type - array indexed by the DBR_ type code */
60 LIBCA_API extern const unsigned short dbr_size[];
61diff --git a/modules/ca/src/client/nciu.cpp b/modules/ca/src/client/nciu.cpp
62index 0a7e708..ebf30fe 100644
63--- a/modules/ca/src/client/nciu.cpp
64+++ b/modules/ca/src/client/nciu.cpp
65@@ -328,7 +328,7 @@ void nciu::write (
66 if ( ! this->accessRightState.writePermit() ) {
67 throw cacChannel::noWriteAccess();
68 }
69- if ( countIn > this->count || countIn == 0 ) {
70+ if ( countIn > this->count) {
71 throw cacChannel::outOfBounds();
72 }
73 if ( type == DBR_STRING ) {
74@@ -349,7 +349,7 @@ cacChannel::ioStatus nciu::write (
75 if ( ! this->accessRightState.writePermit() ) {
76 throw cacChannel::noWriteAccess();
77 }
78- if ( countIn > this->count || countIn == 0 ) {
79+ if ( countIn > this->count) {
80 throw cacChannel::outOfBounds();
81 }
82 if ( type == DBR_STRING ) {
83diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c
84index 9cda401..28273f6 100644
85--- a/modules/database/src/ioc/db/dbAccess.c
86+++ b/modules/database/src/ioc/db/dbAccess.c
87@@ -945,6 +945,11 @@ long dbGet(DBADDR *paddr, short dbrType,
88 if (offset == 0 && (!nRequest || no_elements == 1)) {
89 if (nRequest)
90 *nRequest = 1;
91+ else if (no_elements < 1) {
92+ status = S_db_onlyOne;
93+ goto done;
94+ }
95+
96 if (!pfl || pfl->type == dbfl_type_rec) {
97 status = dbFastGetConvertRoutine[field_type][dbrType]
98 (paddr->pfield, pbuf, paddr);
99@@ -1329,25 +1334,21 @@ long dbPut(DBADDR *paddr, short dbrType,
100 status = prset->get_array_info(paddr, &dummy, &offset);
101 /* paddr->pfield may be modified */
102 if (status) goto done;
103- } else
104- offset = 0;
105-
106- if (no_elements <= 1) {
107- status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
108- paddr->pfield, paddr);
109- nRequest = 1;
110- } else {
111 if (no_elements < nRequest)
112 nRequest = no_elements;
113 status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
114 nRequest, no_elements, offset);
115- }
116-
117- /* update array info */
118- if (!status &&
119- paddr->pfldDes->special == SPC_DBADDR &&
120- prset && prset->put_array_info) {
121- status = prset->put_array_info(paddr, nRequest);
122+ /* update array info */
123+ if (!status && prset->put_array_info)
124+ status = prset->put_array_info(paddr, nRequest);
125+ } else {
126+ if (nRequest < 1) {
127+ recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
128+ } else {
129+ status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer,
130+ paddr->pfield, paddr);
131+ nRequest = 1;
132+ }
133 }
134
135 /* Always do special processing if needed */
136diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c
137index 4ae39bb..28e0df6 100644
138--- a/modules/database/src/ioc/db/dbCa.c
139+++ b/modules/database/src/ioc/db/dbCa.c
140@@ -410,9 +410,15 @@ long dbCaGetLink(struct link *plink, short dbrType, void *pdest,
141 goto done;
142 }
143 newType = dbDBRoldToDBFnew[pca->dbrType];
144- if (!nelements || *nelements == 1) {
145+ if (!nelements) {
146 long (*fConvert)(const void *from, void *to, struct dbAddr *paddr);
147
148+ if (pca->usedelements < 1) {
149+ pca->sevr = INVALID_ALARM;
150+ pca->stat = LINK_ALARM;
151+ status = -1;
152+ goto done;
153+ }
154 fConvert = dbFastGetConvertRoutine[newType][dbrType];
155 assert(pca->pgetNative);
156 status = fConvert(pca->pgetNative, pdest, 0);
157diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c
158index 1193954..9368bfc 100644
159--- a/modules/database/src/ioc/db/dbTest.c
160+++ b/modules/database/src/ioc/db/dbTest.c
161@@ -40,6 +40,7 @@
162 #include "recGbl.h"
163 #include "recSup.h"
164 #include "special.h"
165+#include "dbConvertJSON.h"
166
167 #define MAXLINE 80
168 #define MAXMESS 128
169@@ -363,8 +364,9 @@ long dbpf(const char *pname,const char *pvalue)
170 {
171 DBADDR addr;
172 long status;
173- short dbrType;
174- size_t n = 1;
175+ short dbrType = DBR_STRING;
176+ long n = 1;
177+ char *array = NULL;
178
179 if (!pname || !*pname || !pvalue) {
180 printf("Usage: dbpf \"pv name\", \"value\"\n");
181@@ -379,16 +381,25 @@ long dbpf(const char *pname,const char *pvalue)
182 return -1;
183 }
184
185- if (addr.no_elements > 1 &&
186- (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR)) {
187+ if (addr.no_elements > 1) {
188 dbrType = addr.dbr_field_type;
189- n = strlen(pvalue) + 1;
190- }
191- else {
192- dbrType = DBR_STRING;
193+ if (addr.dbr_field_type == DBR_CHAR || addr.dbr_field_type == DBR_UCHAR) {
194+ n = (long)strlen(pvalue) + 1;
195+ } else {
196+ n = addr.no_elements;
197+ array = calloc(n, dbValueSize(dbrType));
198+ if (!array) {
199+ printf("Out of memory\n");
200+ return -1;
201+ }
202+ status = dbPutConvertJSON(pvalue, dbrType, array, &n);
203+ if (status)
204+ return status;
205+ pvalue = array;
206+ }
207 }
208-
209- status = dbPutField(&addr, dbrType, pvalue, (long) n);
210+ status = dbPutField(&addr, dbrType, pvalue, n);
211+ free(array);
212 dbgf(pname);
213 return status;
214 }
215diff --git a/modules/database/src/std/dev/devAaiSoft.c b/modules/database/src/std/dev/devAaiSoft.c
216index 1f57656..0fbb114 100644
217--- a/modules/database/src/std/dev/devAaiSoft.c
218+++ b/modules/database/src/std/dev/devAaiSoft.c
219@@ -60,9 +60,10 @@ static long init_record(dbCommon *pcommon)
220 }
221
222 status = dbLoadLinkArray(plink, prec->ftvl, prec->bptr, &nRequest);
223- if (!status && nRequest > 0) {
224+ if (!status) {
225 prec->nord = nRequest;
226 prec->udf = FALSE;
227+ return status;
228 }
229 }
230 return 0;
231@@ -74,7 +75,7 @@ static long readLocked(struct link *pinp, void *dummy)
232 long nRequest = prec->nelm;
233 long status = dbGetLink(pinp, prec->ftvl, prec->bptr, 0, &nRequest);
234
235- if (!status && nRequest > 0) {
236+ if (!status) {
237 prec->nord = nRequest;
238 prec->udf = FALSE;
239
240@@ -89,8 +90,12 @@ static long read_aai(aaiRecord *prec)
241 {
242 epicsUInt32 nord = prec->nord;
243 struct link *pinp = prec->simm == menuYesNoYES ? &prec->siol : &prec->inp;
244- long status = dbLinkDoLocked(pinp, readLocked, NULL);
245+ long status;
246
247+ if (dbLinkIsConstant(pinp))
248+ return 0;
249+
250+ status = dbLinkDoLocked(pinp, readLocked, NULL);
251 if (status == S_db_noLSET)
252 status = readLocked(pinp, NULL);
253
254diff --git a/modules/database/src/std/dev/devAiSoft.c b/modules/database/src/std/dev/devAiSoft.c
255index e41d9fe..a9b32a3 100644
256--- a/modules/database/src/std/dev/devAiSoft.c
257+++ b/modules/database/src/std/dev/devAiSoft.c
258@@ -85,9 +85,10 @@ static long read_ai(aiRecord *prec)
259
260 prec->udf = FALSE;
261 prec->dpvt = &devAiSoft; /* Any non-zero value */
262+ return 2;
263 }
264 else
265 prec->dpvt = NULL;
266
267- return 2;
268+ return status;
269 }
270diff --git a/modules/database/src/std/dev/devSASoft.c b/modules/database/src/std/dev/devSASoft.c
271index be32af4..8db192f 100644
272--- a/modules/database/src/std/dev/devSASoft.c
273+++ b/modules/database/src/std/dev/devSASoft.c
274@@ -65,7 +65,7 @@ static long init_record(dbCommon *pcommon)
275
276 status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nRequest);
277
278- if (!status && nRequest > 0)
279+ if (!status)
280 subset(prec, nRequest);
281
282 return status;
283@@ -115,7 +115,7 @@ static long read_sa(subArrayRecord *prec)
284 status = readLocked(&prec->inp, &rt);
285 }
286
287- if (!status && rt.nRequest > 0) {
288+ if (!status) {
289 subset(prec, rt.nRequest);
290
291 if (nord != prec->nord)
292diff --git a/modules/database/src/std/dev/devWfSoft.c b/modules/database/src/std/dev/devWfSoft.c
293index 0a089b8..29a617b 100644
294--- a/modules/database/src/std/dev/devWfSoft.c
295+++ b/modules/database/src/std/dev/devWfSoft.c
296@@ -41,7 +41,7 @@ static long init_record(dbCommon *pcommon)
297 long nelm = prec->nelm;
298 long status = dbLoadLinkArray(&prec->inp, prec->ftvl, prec->bptr, &nelm);
299
300- if (!status && nelm > 0) {
301+ if (!status) {
302 prec->nord = nelm;
303 prec->udf = FALSE;
304 }
305@@ -77,11 +77,14 @@ static long read_wf(waveformRecord *prec)
306 rt.ptime = (dbLinkIsConstant(&prec->tsel) &&
307 prec->tse == epicsTimeEventDeviceTime) ? &prec->time : NULL;
308
309+ if (dbLinkIsConstant(&prec->inp))
310+ return 0;
311+
312 status = dbLinkDoLocked(&prec->inp, readLocked, &rt);
313 if (status == S_db_noLSET)
314 status = readLocked(&prec->inp, &rt);
315
316- if (!status && rt.nRequest > 0) {
317+ if (!status) {
318 prec->nord = rt.nRequest;
319 prec->udf = FALSE;
320 if (nord != prec->nord)
321diff --git a/modules/database/src/std/rec/aSubRecord.c b/modules/database/src/std/rec/aSubRecord.c
322index 666558b..1bcbb63 100644
323--- a/modules/database/src/std/rec/aSubRecord.c
324+++ b/modules/database/src/std/rec/aSubRecord.c
325@@ -277,10 +277,9 @@ static long fetch_values(aSubRecord *prec)
326 long nRequest = (&prec->noa)[i];
327 status = dbGetLink(&(&prec->inpa)[i], (&prec->fta)[i], (&prec->a)[i], 0,
328 &nRequest);
329- if (nRequest > 0)
330- (&prec->nea)[i] = nRequest;
331 if (status)
332 return status;
333+ (&prec->nea)[i] = nRequest;
334 }
335 return 0;
336 }
337diff --git a/modules/database/test/std/rec/regressTest.c b/modules/database/test/std/rec/regressTest.c
338index 6614639..fd4f0a8 100644
339--- a/modules/database/test/std/rec/regressTest.c
340+++ b/modules/database/test/std/rec/regressTest.c
341@@ -132,7 +132,7 @@ void testCADisconn(void)
342
343 startRegressTestIoc("badCaLink.db");
344
345- testdbPutFieldOk("ai:disconn.PROC", DBF_LONG, 1);
346+ testdbPutFieldFail(-1, "ai:disconn.PROC", DBF_LONG, 1);
347 testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM);
348 testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM);
349 }

Subscribers

People subscribed via source and target branches