Project

General

Profile

Bug #11191

ChUI: COMBO-BOX raises error 4058 on valid SCREEN-VALUE assignment

Added by Vladimir Tsichevski 6 months ago. Updated 16 days ago.

Status:
Review
Priority:
Normal
Target version:
-
Start date:
Due date:
% Done:

100%

billable:
No
vendor_id:
GCD
case_num:
version_reported:
16409
version_resolved:
reviewer:
production:
No
env_name:
topics:

History

#2 Updated by Vladimir Tsichevski 6 months ago

Run this example in CHARACTER mode:

DEFINE VARIABLE id AS CHARACTER FORMAT "x(3)".
DEFINE FRAME f id VIEW-AS COMBO-BOX
   LIST-ITEM-PAIRS "123456789qwe", "123456789abc" 
   DROP-DOWN-LIST.
ENABLE ALL WITH FRAME f.
id:SCREEN-VALUE = "123456789abc".
WAIT-FOR WINDOW-CLOSE OF CURRENT-WINDOW.

  • In OE: code runs without error.
  • In FWD: error 4058 raised ("**Attribute SCREEN-VALUE for the %s has an invalid value of 123.").

This problem was initially reported as #11126-11.

#3 Updated by Razvan-Nicolae Chichirau 5 months ago

  • Status changed from New to WIP
Analyzed the error handling from 4GL related to setting the SCREEN-VALUE attribute. I'll use the following messages for reference:
  1. Any message that results from the fact that a value could not be converted to the combo-box format.
  2. **Attribute SCREEN-VALUE for the <widget_type> <widget_name> has an invalid value of <unformatted_value>. (4058)

For GUI combo boxes of type DROP-DOWN or SIMPLE, the value assigned to SCREEN-VALUE is not validated (i.e., whether it can be formatted or whether the formatted value exists among the items) and is simply accepted, so no errors are thrown. The following is true for DROP-DOWN-LIST on GUI and all types (SIMPLE, DROP-DOWN, DROP-DOWN-LIST) on ChUI:

  • Value can not be formatted: 1 (ERROR) + 2 (WARNING)
  • Value can be formatted, but does not exist in the items: 2 (WARNING)
  • Value is empty string
    • no items: no error
    • has items: no error
  • Value is unknown value:
    • no items: no error
    • has items: no error

#4 Updated by Razvan-Nicolae Chichirau 5 months ago

  • Assignee set to Razvan-Nicolae Chichirau

#5 Updated by Razvan-Nicolae Chichirau 5 months ago

Did some extensive testing for the following control set entities: radio-set, combo-box and selection-list. Consider the error messages from #11191-3.

COMBO-BOX

The following data-types were tested: character, logical, integer, decimal, date, datetime, datetime-tz, recid
  • GUI
    • The SIMPLE and DROP-DOWN combos does not throw any errors and accept the input as is.
    • For DROP-DOWN-LIST:
      1. Widget is not realized
        • Can not format the screen-value: 1 + 2
        • Can format, but does not exist among the current items: no errors, silent exit
      2. Widget is realized
        • Can not format the screen-value: 1 + 2
        • Can format, but does not exist among the current items: 2
  • CHUI
    • The following is true for all combo-box types:
      1. Widget is not realized
        • Can not format the screen-value: 1 + 2
        • Can format, but does not exist among the current items: no errors, silent exit
      2. Widget is realized
        • Can not format the screen-value: 1 + 2
        • Can format, but does not exist among the current items: 2

RADIO-SET

The following data-types were tested: character, logical, integer, decimal, date, datetime, datetime-tz, recid
  • GUI + CHUI
    • Widget is not realized or it is realized: 2

SELECTION-LIST

Only character data-type was tested as it was the only one permitted for this widget.
  • GUI + CHUI:
    • Widget is not realized or it is realized: 2

The browse column widget has another behavior compared with the widgets listed above. This can be treated in another task and the functionality of combo-box, radio-set and selection-list can be grouped and treated in this issue.

#6 Updated by Razvan-Nicolae Chichirau 3 months ago

  • % Done changed from 0 to 100
  • Status changed from WIP to Review

Hynek: Please review 11191a/rev. 16549.

#7 Updated by Hynek Cihlar 3 months ago

  • % Done changed from 100 to 90
  • Status changed from Review to WIP

Code review 11191a revisions 16548..16549

  • [CRITICAL] style RadioSetWidget: Copyright year in the file header is still 2005-2025, but the file is modified in 2026. Update to 2005-2026, Golden Code Development Corporation.
  • [CRITICAL] functional ControlSetEntity.invalidScreenValueWarning: Method dereferences unparsedValue via unparsedValue.isUnknown() with no null check. Concrete trigger: the 3-arg GenericWidget.setScreenValue(ScreenBuffer, Object, boolean) forwards unparsedValue=null to the 4-arg overload; this is exercised on the standard frame realization / DISPLAY path via GenericFrame.copyToScreenBuffer (around line 11301) on a RADIO-SET, SELECTION-LIST or already-realized COMBO-BOX whose value fails isValidScreenValue. The chain reaches validateScreenValue(value, null) which calls invalidScreenValueWarning(null, ...); for RADIO-SET / SELECTION-LIST the realizeCheck=false guard does not bail out, and the method NPEs on unparsedValue.isUnknown(). The old inline implementation referenced only the parsed value (never null), so this is a regression. Add a null guard or fall back to the parsed value when unparsedValue is null.
  • [CRITICAL] functional RadioSetWidget.validateScreenValue: Calls invalidScreenValueWarning(unparsedValue, false) when validation fails. Same trigger as above — unparsedValue can be null on the 3-arg setScreenValue path (used during frame realization). With realizeCheck=false and a non-null frame, invalidScreenValueWarning(null, false) immediately NPEs on unparsedValue.isUnknown().
  • [MAJOR] functional ControlSetEntity.invalidScreenValueWarning: Replaces ErrorManager.recordOrShowWarning(...) with ErrorManager.displayWarning(...). The two are not equivalent: (a) recordOrShowWarning short-circuits on isSuppressWarnings() and on per-code suppressWarningsSet.contains(num), while displayWarning never consults the per-code suppression set and adds the condition to _MSG even under SESSION:SUPPRESS-WARNINGS; (b) recordOrShowWarning delegates to recordOrShowError which throws DeferredLegacyErrorException when hasLegacyError()/mustManageLegacyError() is true, allowing an enclosing 4GL CATCH Progress.Lang.SysError to capture the condition — displayWarning never throws. Reachable from straightforward 4GL: ASSIGN cb:SCREEN-VALUE = "<invalid>" inside SESSION:SUPPRESS-WARNINGS, with SUPPRESS-WARNINGS-LIST naming 4056/4058, or inside a CATCH block. Verify against OE behavior; if displayWarning is the intended API, the previously suppressed/catchable cases need explicit handling.
  • [MINOR] style RadioSetWidget.setScreenValueInt: Continuation lines of the multi-line if condition are indented one column short of the opening condition character, breaking project convention for multi-line condition alignment.
  • [MINOR] style GenericFrame.setScreenValue: Newly added Javadoc \@param widget description reads "The widget for which the value is to be retrieved". This is a setter; description must say "set".
  • [MINOR] style ControlSetEntity.invalidScreenValueWarning: Both \@param tags use 3 spaces after the tag keyword. All other Javadoc \@param tags in this file and in the same diff use 4 spaces — adjust for consistency.
  • [MINOR] style ControlSetEntity.shouldParseScreenValue / ComboBoxWidget.shouldParseScreenValue: Both newly added Javadoc blocks use \@return with 2 spaces. Existing \@return tags in these files use 3 spaces — adjust for consistency.

Instead of getSubType().getValue().equals("DROP-DOWN-LIST") compare the enum value returned by ComboBoxConfig.getMode.

In setScreenValueInt catching ErrorConditionException is used for the happy path. The catch block here is part of the expected flow, not an exceptional condition. Let's turn this into a predicate (e.g. tryParseScreenValue returning a boolean) and reserve the exception for genuinely unexpected failures (or the error condition in this case).

Is the 'UNKNOWN' in invalidScreenValueWarning also displayed in OpenEdge? OpenEdge AFAIK typically represents unknown values as '?' in the messages.

#8 Updated by Razvan-Nicolae Chichirau 3 months ago

  • Status changed from WIP to Review
  • % Done changed from 90 to 100

Hynek Cihlar wrote:

Code review 11191a revisions 16548..16549

  • [CRITICAL] style RadioSetWidget: Copyright year in the file header is still 2005-2025, but the file is modified in 2026. Update to 2005-2026, Golden Code Development Corporation.
  • [CRITICAL] functional ControlSetEntity.invalidScreenValueWarning: Method dereferences unparsedValue via unparsedValue.isUnknown() with no null check. Concrete trigger: the 3-arg GenericWidget.setScreenValue(ScreenBuffer, Object, boolean) forwards unparsedValue=null to the 4-arg overload; this is exercised on the standard frame realization / DISPLAY path via GenericFrame.copyToScreenBuffer (around line 11301) on a RADIO-SET, SELECTION-LIST or already-realized COMBO-BOX whose value fails isValidScreenValue. The chain reaches validateScreenValue(value, null) which calls invalidScreenValueWarning(null, ...); for RADIO-SET / SELECTION-LIST the realizeCheck=false guard does not bail out, and the method NPEs on unparsedValue.isUnknown(). The old inline implementation referenced only the parsed value (never null), so this is a regression. Add a null guard or fall back to the parsed value when unparsedValue is null.
  • [CRITICAL] functional RadioSetWidget.validateScreenValue: Calls invalidScreenValueWarning(unparsedValue, false) when validation fails. Same trigger as above — unparsedValue can be null on the 3-arg setScreenValue path (used during frame realization). With realizeCheck=false and a non-null frame, invalidScreenValueWarning(null, false) immediately NPEs on unparsedValue.isUnknown().
  • [MINOR] style RadioSetWidget.setScreenValueInt: Continuation lines of the multi-line if condition are indented one column short of the opening condition character, breaking project convention for multi-line condition alignment.
  • [MINOR] style GenericFrame.setScreenValue: Newly added Javadoc \@param widget description reads "The widget for which the value is to be retrieved". This is a setter; description must say "set".
  • [MINOR] style ControlSetEntity.invalidScreenValueWarning: Both \@param tags use 3 spaces after the tag keyword. All other Javadoc \@param tags in this file and in the same diff use 4 spaces — adjust for consistency.
  • [MINOR] style ControlSetEntity.shouldParseScreenValue / ComboBoxWidget.shouldParseScreenValue: Both newly added Javadoc blocks use \@return with 2 spaces. Existing \@return tags in these files use 3 spaces — adjust for consistency.

Instead of getSubType().getValue().equals("DROP-DOWN-LIST") compare the enum value returned by ComboBoxConfig.getMode.

In setScreenValueInt catching ErrorConditionException is used for the happy path. The catch block here is part of the expected flow, not an exceptional condition. Let's turn this into a predicate (e.g. tryParseScreenValue returning a boolean) and reserve the exception for genuinely unexpected failures (or the error condition in this case).

Fixed.

  • [MAJOR] functional ControlSetEntity.invalidScreenValueWarning: Replaces ErrorManager.recordOrShowWarning(...) with ErrorManager.displayWarning(...). The two are not equivalent: (a) recordOrShowWarning short-circuits on isSuppressWarnings() and on per-code suppressWarningsSet.contains(num), while displayWarning never consults the per-code suppression set and adds the condition to _MSG even under SESSION:SUPPRESS-WARNINGS; (b) recordOrShowWarning delegates to recordOrShowError which throws DeferredLegacyErrorException when hasLegacyError()/mustManageLegacyError() is true, allowing an enclosing 4GL CATCH Progress.Lang.SysError to capture the condition — displayWarning never throws. Reachable from straightforward 4GL: ASSIGN cb:SCREEN-VALUE = "<invalid>" inside SESSION:SUPPRESS-WARNINGS, with SUPPRESS-WARNINGS-LIST naming 4056/4058, or inside a CATCH block. Verify against OE behavior; if displayWarning is the intended API, the previously suppressed/catchable cases need explicit handling.
Raising a warning for the invalid screen-value in 4GL will:
  • Make the warning be unconditionally added to _MSG, whether SESSION:SUPPRESS-WARNINGS or set or not
  • Not display the warning in case of SESSION:SUPPRESS-WARNINGS
  • Not throw an actual 4GL legacy error which can be caught by a CATCH block.

As such, displayWarning is the correct API to use here.

Is the 'UNKNOWN' in invalidScreenValueWarning also displayed in OpenEdge? OpenEdge AFAIK typically represents unknown values as '?' in the messages.

Check this testcase:

def var rs as char view-as radio-set radio-buttons "a", "b".
def frame f rs.

rs:screen-value = ?.

Please review 11191a/rev. 16550.

#9 Updated by Hynek Cihlar 3 months ago

  • Status changed from Review to Internal Test

Code review 11191a revisions 16548..16550

The changes look good. Please go ahead with regression testing. Also run ChUI regression tests.

#10 Updated by Razvan-Nicolae Chichirau about 1 month ago

  • Status changed from Internal Test to Review

Small regression detected on the testcases project:

define variable rs as logical initial ? format 'one/two' view-as radio-set radio-buttons "first", true, "second", true.
def frame f rs.

rs:screen-value = "".
display rs with frame f.
wait-for window-close of current-window. 

Trunk and 4GL do not raise a warning, meanwhile 11191a does, GUI + ChUI.

Hynek: Please review 11191a/rev. 16624.

#11 Updated by Hynek Cihlar 20 days ago

  • % Done changed from 100 to 90
  • Status changed from Review to WIP

Code review 11191a revisions 16621..16624

Intsead of this instanceof BrowseColumnWidget override recoverFromParsingError.

Please check the following functional points.

  • [MAJOR] functional RadioSetWidget.setScreenValueInt/isValidScreenValue: The rev-16624 savedValue recovery that suppresses the false-positive 4058 warning is captured only inside the GUI branch (!LogicalTerminal.isChui()), so the ChUI arm of the reproducer regresses. In ChUI, setScreenValueInt leaves "" untouched and savedValue stays null; parseScreenValue(logical, "", "one/two") yields an unknown logical (empty value, format not delimited by /), which ControlSetEntity.setScreenValue re-derives as an unknown character; isValidScreenValue then has no savedValue to restore the original "", returns false on !value.isUnknown(), and validateScreenValue fires a spurious 4058. GUI works only because it captures savedValue = "" and swaps it back. Trigger: the redmine section-3 reproducer (rs as logical initial ? format 'one/two' view-as radio-set ...; rs:screen-value = "") run in CHARACTER mode — redmine states the false positive appeared in both GUI and ChUI on 11191a. Capture savedValue (or otherwise preserve the original value for validation) on the ChUI path as well.
  • [MINOR] functional ControlSetEntity.invalidScreenValueWarning: The switch from ErrorManager.recordOrShowWarning to ErrorManager.displayWarning(id, msg, true) drops honoring of SESSION:SUPPRESS-WARNINGS-LIST. recordOrShowWarning suppresses when either the global SUPPRESS-WARNINGS boolean or the per-number set suppressWarningsSet matches (ErrorManager ~line 1452-1454); displayWarning checks only the global boolean (~line 3441) and never consults suppressWarningsSet. Trigger: a program sets SESSION:SUPPRESS-WARNINGS-LIST = "4058" (or "4056") then assigns an invalid SCREEN-VALUE to a realized control-set widget — previously suppressed entirely, now displayed and added to _MSG. Redmine section 2 mandates only the global SUPPRESS-WARNINGS for this case and requires the warning to unconditionally reach _MSG, so this may be acceptable; verify the per-number-list behavior against OE.
  • [MINOR] style ComboBoxWidget (header history entry #057): Typo in the new history description — "Overriden 'shouldParseScreenValue()'." should be "Overridden".

#12 Updated by Razvan-Nicolae Chichirau 16 days ago

  • % Done changed from 90 to 100
  • Status changed from WIP to Review

Hynek Cihlar wrote:

Intsead of this instanceof BrowseColumnWidget override recoverFromParsingError.

  • [MAJOR] functional RadioSetWidget.setScreenValueInt/isValidScreenValue: The rev-16624 savedValue recovery that suppresses the false-positive 4058 warning is captured only inside the GUI branch (!LogicalTerminal.isChui()), so the ChUI arm of the reproducer regresses. In ChUI, setScreenValueInt leaves "" untouched and savedValue stays null; parseScreenValue(logical, "", "one/two") yields an unknown logical (empty value, format not delimited by /), which ControlSetEntity.setScreenValue re-derives as an unknown character; isValidScreenValue then has no savedValue to restore the original "", returns false on !value.isUnknown(), and validateScreenValue fires a spurious 4058. GUI works only because it captures savedValue = "" and swaps it back. Trigger: the redmine section-3 reproducer (rs as logical initial ? format 'one/two' view-as radio-set ...; rs:screen-value = "") run in CHARACTER mode — redmine states the false positive appeared in both GUI and ChUI on 11191a. Capture savedValue (or otherwise preserve the original value for validation) on the ChUI path as well.
  • [MINOR] style ComboBoxWidget (header history entry #057): Typo in the new history description — "Overriden 'shouldParseScreenValue()'." should be "Overridden".

Solved.

  • [MINOR] functional ControlSetEntity.invalidScreenValueWarning: The switch from ErrorManager.recordOrShowWarning to ErrorManager.displayWarning(id, msg, true) drops honoring of SESSION:SUPPRESS-WARNINGS-LIST. recordOrShowWarning suppresses when either the global SUPPRESS-WARNINGS boolean or the per-number set suppressWarningsSet matches (ErrorManager ~line 1452-1454); displayWarning checks only the global boolean (~line 3441) and never consults suppressWarningsSet. Trigger: a program sets SESSION:SUPPRESS-WARNINGS-LIST = "4058" (or "4056") then assigns an invalid SCREEN-VALUE to a realized control-set widget — previously suppressed entirely, now displayed and added to _MSG. Redmine section 2 mandates only the global SUPPRESS-WARNINGS for this case and requires the warning to unconditionally reach _MSG, so this may be acceptable; verify the per-number-list behavior against OE.

4GL suppresses the warning message if either SESSION:SUPPRESS-WARNINGS is used or the message number is in the SESSION:SUPPRESS-WARNINGS-LIST value. Additionally, it adds it to _MSG() only if silent error is disabled and the process is not running in headless mode. As such, the correct method is recordOrShowWarning(), but with a slight modification. If the warning is suppressed and silent mode is disabled + not running in headless mode, append the message number to _MSG().

Note that I've verified all usages of this method, and the behavior is the same in every case. Please check rev. 16625.

Also available in: Atom PDF