Upgrade Compatibility Checklist for Health Connect 2020.1
The purpose of this chapter is to highlight those features of the 2020.1 release of HealthShare® Health Connect that, because of their difference in this version, affect the administration, operation, or development activities of existing systems. Some of the items discussed apply to the underlying InterSystems IRIS technology and might not apply to Health Connect users.
This document addresses the differences between the 2019.1.0 and 2020.1 versions of Health Connect. Customers upgrading their applications from earlier releases are strongly urged to read the upgrade checklist for the intervening versions as well.
This section highlights information of interest to those who are familiar with administering prior versions of Health Connect and wish to learn what is new or different in this area for version 2019.4. The items listed here are brief descriptions. More complete descriptions are in the following section.
Improved Container with Nonroot Default User Requires Installation Change
In this release, the distribution container has a nonroot default user. This improves the security of your container. However, if you are using a durable %SYS from an Health Connect 2019.1 instance, you need to change some file ownerships in the host’s durable directory before running Health Connect 2020.1. Please contact your InterSystems sales engineer or the InterSystems Worldwide Response Center for instructions on changing the file ownerships. If you do not make these changes, the container will encounter an error starting Health Connect.
Changes for Dejournaling
There are several dejournaling changes, which have some impact on system administration:
On systems configured with a database cache larger than 128GB, a dejournaling task (which applies database updates in the journal to databases during a journal restore or when the backup failover member of a mirror is synchronized with the primary) may employ more updater processes than in previous versions, and therefore use more system resources. If your instance is close to resource limits, this may cause problems.
Previous versions of Caché or InterSystems IRIS allowed fewer databases to be mounted at one time than the current version. Any journal files created after an instance has passed the old limit are therefore incompatible with previous versions of Caché or Health Connect. For example, they could not be used to run a journal restore after restoring databases from backup to an instance of a previous version. However, journal files created by previous versions are compatible with this version.
Parallel Dejournaling has been enhanced to allow multiple jobs to process separate globals within a single database rather than being restricted to processing only separate databases in parallel. This affects the ordering of updates that can be seen when dejournaling has been started but not yet completed. For details, see “Restore Globals From Journal Files Using ^JRNRESTO” in the description of Data Integrity Journaling and “Configuring Parallel Dejournaling” in the description of Configuring Mirroring for high availability.
(first in 2019.4)
Change in Location of Container changePassword.sh Script
In this release, the container changePassword.sh script is in usr/irissys/dev/Container/. In previous releases, it was in /usr/irissys/dev/Cloud/ICM/. If you have any scripts that explicitly specify the location of this script, you should update the script. (first in 2019.3)
Cloud Manager Changes
In this release, there are two changes to the InterSystems Cloud Manager (ICM) that can impact upgrades:
ICM now supports Docker Community only on CentOS and Ubuntu. If you are using ICM with Red Hat Enterprise Linux or SUSE Linux and Docker Community, you must either switch to Docker Enterprise or switch to the CentOS or Ubuntu operating system.
ICM now stores the state directory in a different location. It now uses a default state subdirectory named “state”. If you have scripts or custom code that reference the state directory, you should update the references to the new location.
This section contains information of interest to those who have designed, developed and maintained applications running on prior versions of Health Connect. Since developers typically administer development system, developers should also read the previous section for administrators.
The items listed here are brief descriptions. In most cases, more complete descriptions are available elsewhere in the documentation.
Legacy FHIR — Name Change of HSFHIRErr
The domain name (global name) for FHIR® error message localization has changed from HSFHIRErr to HSFHIRXErr for our legacy FHIR DSTU2/STU3 implementation. If existing custom code for FHIR includes logic for evaluating method calls to find specific error codes in errors in the HSFHIRErr domain, that code will need to be modified to account for the name change from HSFHIRErr to HSFHRXErr.
Business Intelligence Analytics — Change in ResultSet Timing
To ensure consistency, this release has changes in the timing of setting the %DeepSee.ResultSet. Consequently, code that previously worked may be accessing the ResultSet before the operation completes. To ensure that the ResultSet has been set, test that ResultSetObj.%GetStatus() has a value of 100 before accessing the ResultSet value. (first in 2019.3)
Business Intelligence Analytics — Change in Advance Filter Editor
Containers — Custom Code Cannot Assume Root Privileges Running in Docker Containers
In release 2019.1 and earlier, the Docker container had a default root user, but in this release the container has a nonroot default user (irisuser, UID 52773) to improve container security. Consequently, any custom code that assumes that the default user has root privileges running in Docker containers will fail in this release. Processes which connect to an IRIS container (such as via JDBC) should not be affected unless they execute code that makes assumptions about rootlike privileges when dealing with files. Note that container-root already lacks, by default, many of the kernel capabilities usually held by host-root in noncontainer systems. (first in 2019.3)
This change only applies to Docker images provided by InterSystems. If you create a Docker image using a noncontainer install, you can control the default user.
Interoperability Productions — Changes in Display of Host Status in Interoperability Productions
The meaning of the running status display in the Production Configuration page has changed because the changes to support source control for productions has involved a slightly different possible state. The status in the production configuration diagram for items that are enabled but not running, either because the item has a schedule and is currently stopped or if the item has been temporarily stopped, has changed. These items now have the status stopped which means that the item dot is shown light green as per the existing legend: Not running, enabled. Therefore 'Not running' can apply if the production is stopped or if the item is not running but the production is running. (first in 2019.4)
Interoperability Productions — Changes in X12 Validation Schema Paths
To enhance the validation feature, this release changes the validation schema paths for hierarchical structures. If you have code specifying these paths, you will need to update them to correspond to these changes.For example, a segment in the 2000B loop of HIPAA_5010:837 would have had path 2000B.segName before, but is now 2000A.2000B.segName.
Interoperability Productions — Changes in X12 Acknowledgement Documents in Interoperability Productions
In previous releases, X12 acknowledgement documents had many wrong field values in them. This release corrects these values, but if custom code is expecting those incorrect values, you need to make modifications to accept the corrected values or implement OnConstructReply() in your Business Service instead. (first in 2019.4)
Interoperability Productions — Changes in syncresponses Array in BPLs for Interoperability Productions
The syncresponses array was not being correctly populated with the callresponses. Instead the process's response object was being used. It is unlikely that custom code will relies on syncresponses containing the response object. However, if this is the case then reworking of the code will be necessary. (first in 2019.4)
Interoperability Productions — Changes to EnsLib.EDI.Segment Class for Interoperability Productions
If you have subclassed EnsLib.EDI.Segment and are making use of the RawContent property (this would require creating the getter method RawContentGet()), then you now have to add RawContent to the list of properties in your custom class since it would no longer be inheriting this property from EnsLib.EDI.Segment. (first in 2019.4)
Interoperability Productions — Changes in HIPAA Schema for Interoperability Productions
This change fixes the name of the ISA:11 field for HIPAA_5010. The old name of Interchange Control Standards Identifier was correct for older versions, but the purpose of this field changed in version 403 to now be the Repetition Separator. If you have used the HIPAA_5010 schema and are getting or setting this field using the property path, ISA:InterchangeControlStandardsIdentifier, you will need to switch to using ISA:RepetitionSeparator or ISA:11. This change is relevant for IRIS for Health and Health Connect. (first in 2019.4)
Interoperability Production — Changes in Handling Unexpected HL7 Names in Interoperability Productions
In order to see information about unexpected HL7 Segment names you must now set ^Ens.Debug("TraceCat","parse") to 1 - this replaces possible event log warnings. Message validation can still be used to enforce schema segment names. (first in 2019.4)
Interoperability Production — New X12 Validation May Impact Previously Ignored Flags
The behavior for existing X12 validation flags in routers is unchanged. However, in the unlikely event that you have specified extra validation flags that were not previously valid, the behavior may change. If you specified a nonexistent validation flag, it would have been ignored, but if the flag now matches a new validation flag, the specified validation will be performed.
For a list of the new validation flags, see “Validation” in Routing X12 Documents in Productions. (first in 2019.3)
Interoperability Production — Interoperability Production HTTP Generic Message Changes
The EnsLib.HTTP.GenericMessage class now explicitly defines XMLNAME and XMLTYPE parameters. Any custom subclasses of EnsLib.HTTP.GenericMessage need to account for XMLNAME parameter now being inherited and, if necessary, override it. (first in 2019.2)
JSON Adapter %Status Value Changes
For some conditions the value returned in %Status has changed. Under some circumstances, where the JSON adapter previously set the %status value to <METHOD DOES NOT EXIST> system error returned by the %JSONExport method, it now sets %status to "ERROR #9411: A class referenced by a %JSONENABLED class must be a subclass of %JSON.Adaptor".
Language Bindings — Changes for Existing Applications that will Use Dynamic Gateway in Place of Legacy Gateway
This change allows existing applications that use the legacy gateway to switch to the new Dynamic Gateway by regenerating the proxy classes. Proxy classes generated with this new style is called Recast Gateway. Proxy classes generated with the old style is now called Legacy Gateway.
To generate Recast Gateway proxy classes for a specific namespace, set the following global:
Or to generate Recast Gateway proxy classes for all namespaces, set the following global:
Then re-import all the proxy classes. The first global governs Recast behavior for one namespace only while the second global governs Recast behavior for all namespaces that don't have their own setting. The import utility will automatically mark all the no-recast generated classes as out-of-date and re-import all the classes in the inheritance hierarchy.
All of the proxy classes have to be regenerated together. The Recast Gateway proxy classes can not be mixed with Legacy Gateway proxy classes.
The Recast Gateway generated proxy classes have the same generated interface as the Legacy Gateway proxy classes. Run-time behavior are compatible. Only known differences are in the area of fixing erroneous behaviors in Legacy Gateway, Dynamic Gateway enhancements, and in handling of run-time type mismatches. The following are the run-time differences:
Difference in dispatching overloaded method of the same argument count. Recast Gateway uses a new method overloading resolution algorithm that's in Dynamic Gateway. The detailed behavior is:
In Dynamic Gateway, when dispatching a method, first look for the method under the number of runtime parameters. If the number of methods found is unique, gateway has found thetarget.
If there are more than one method that match the runtime parameter count, then disambiguate further on parameter types.
Only use the $list type for runtime type. don't use runtime values.
$list only gives three primitive types, STRING ($list type 01, 02), INTEGER ($list type 04, 05) and DOUBLE ($list type 06, 07, 08) , plus OREF ($list type 25, 26) type.
Divide all Java/.NET primitive types (and their boxed types) into 3 type families based on $list types.
Check to see if each actual type is a match for the corresponding formal type.
In this check, an actual type can match more than one formal type. For example, runtime type INTEGER is a match for formal type short, int, long or boolean.
At the end of the process, if there is only one method left that matches with all actual types, then the search is successful. If none is left, search has failed to find an overloaded method. If more than one is left, then there is a unresolvable ambiguity.
Same algorithm applies to constructors.
Currently, when overloading is not involved, ignore runtime types. Just convert parameters (of any actual type) to their corresponding formal type. In order to have a consistent behavior, logic says, if a particular formal parameter has no type variations, then the actual type check is skipped. In another word, only use actual type to disambiguate if there is any ambiguity to begin with, and this applies on each parameter independently.
Any missing or undefined parameter (which results in UNDEFINED in $list) is a match for any formal type.
Non-primitive formal types are matched to actual parameter objects (OREF type in $list) using "instanceof" check.
At runtime, users can coerce a parameter's $list type in order to influence overloading resolution. Usually, a straight-up literal has the $list type of what it appears, for example m("ABC") is a STRING type, m(123) is an INTEGER type and m(3.14) is a DOUBLE type. To force a particular type on a variable with unknown type, do the following:
m(x_"") forces the parameter to be a STRING.
forces the parameter to be an INTEGER.
m($double(x)) forces the parameter to be a DOUBLE.
Note, this algorithm is different from how Legacy Gateway works. Legacy Gateway parses the actual value of the parameters in order to guess the runtime type. This guessing is inherently inaccurate. Sometimes, Legacy Gateway failed to dispatch because the guess is wrong, other times, Legacy Gateway dispatches successfully even when clear ambiguities exist.
Difference in support for pass-by-reference. Recast Gateway uses pass-by-reference support implemented in Dynamic Gateway, which makes it somewhat different from the limited support of pass-by-reference in Legacy Gateway.
Pass-by-reference works in the Dynamic Gateway and recast Gateway as follows:
C# method declares method parameter pass-by-reference with "ref" or "out" keywords
At runtime, IRIS user calls the corresponding proxy method with .variable syntax (IRIS pass-by-reference syntax)
Modified values of the C# pass-by-reference parameters will be sent back to IRIS and assigned into user's pass-by-reference variable.
This is only in .NET as Java doesn't support pass-by-reference.
This works for primitive datatypes as well we objects.
When the parameter is an object, this support is for "pass-by-reference" in .NET per se, which means when the parameter variable is assigned a new object, that new assignment is passed back to IRIS variable.
The different behavior in the Legacy Gateway is:
Legacy pass-by-reference doesn't support datatypes - objects only.
Legacy pass-by-reference doesn't support "ref" keyword - "out" keyword only.
Legacy pass-by-reference doesn't require .variable syntax
At runtime, Legacy pass-by-reference variable must not be null OREF.
Callee code cannot change the pass-by-reference parameter to a different type - i.e. cannot change to an object of a subclass.
With all the difference described above, what works the same is the basic simple case. For example, variable x is a proxy of a Person object in .NET, say with firstName equals to "Isabella". Then call a method in .NET that declares this parameter with "out" keyword and the method changes the parameter assignment to a new Person object with firstName equals to "Mia". IRIS user calls the method with (.x), and after the call, x.firstName will equal to "Mia".
But these gateway work very differently internally. After a pass-by-reference parameter is changed, instead of sending the modified value back to IRIS, Legacy Gateway simply changes the oref-registry. This implementation has some unexpected side-effects: Using the above example, if we set y=x before the call. After calling m(.x), not only x.firstName is changed, y.firstName is also changed to "Mia". This side-effect is highly undesirable. Fixing the behavior of this side-effect in Recast is one of difference in behavior.
Constructor with array arguments are not working properly in Legacy Gateway. It is working properly in Recast Gateway, together with updating array contents just like any other methods.
Properties with underscore in the name as prefix or suffix are not working properly in Legacy Gateway. It is working properly in Recast Gateway.
Methods with varargs work mostly the same. In Legacy Gateway, overloaded method with varargs do not work properly. Recast Gateway works properly on all vararg and overload combinations.
Array of Objects do not work properly in Legacy Gateway, It works properly in Recast Gateway.
Recast Gateway is more dynamic. In most cases, modification to Java code doesn't require the proxy classes to be regenerated. For example, after generating Recast proxy classes, user can modify the Java class to add methods or change signature of Java methods. The existing Recast proxy classes will work with the new Java classes without being regenerated. In fact, most of the generated methods in Recast Gateway proxy class don't need to be there at all. The proxy class works just fine without them. The methods are there mostly for documentation purposes, as Legacy Gateway users are used to looking at the proxy class to see which methods are there.
Recast Gateway supports Reverse Proxy which comes with Dynamic Gateway. In Recast Gateway, IRIS objects passed to Java/.NET methods will arrive as objects of IRISObject which are reverse proxy objects on which users can access properties and methods on the IRIS side. In Legacy Gateway, IRIS objects arrive in Java/.NET, sometimes as Strings, sometimes as null, but overall, was not a supported behavior.
Language Bindings — IRISList and DBList Changes
Custom code using construct like createIRISList() or IRIS.createIRISList() should be changed to IRISList.createIRISList()
Behavior of DBList::toString has beeen modified. Before this change both 01 and 02 01 was displayed as "null", now 02 01 displayed as "empty". Since toString is intended as a debugging tool, this change is unlikely to impact custom code. (first in 2019.4)
Language Bindings — Change in Handling of Nullable Types
This release changes the way the gateway handles nullable types so that they are handled correctly. For example, in .NET, if you declare a parameter to be of type long? and the gateway receives an empty string, it now sets the parameter to null, where in previous releases it set it to a 0 value. If your code does not handle null values, you can fix it by changing the parameter type to one that does not include null values, such as long.
Security — Changes to %SYS.PhoneProvider
In this release, you cannot delete a %SYS.PhoneProvider if it is in use. Some deleted operations that previously succeeded will now fail. This is an intentional feature but could cause some unexpected behavior in unusual cases. (first in 2019.4)
SQL — Universal Cached Queries
This release improves SQL performance by caching all SQL queries. To achieve this, queries are compiled when they are first used, not when the class or routine containing the query is compiled. The environment at runtime when the SQL query is compiled can be slightly different from the class or routine compile-time environment. The compiler stores information when the class or routine is compiled that allows it to compile the SQL query in most cases without error. In rare cases, SQL queries can contain macros defined in include files. If the class or routine was compiled in one namespace and the SQL query is compiled in a second namespace and the second does not contain the include file, the compilation will encounter an error. If this occurs then you must add the include file to the second namespace.
SQL — Queries from Management Portal Run in Background
Starting with this release, if you issue a query from the SQL explorer page in the Management Portal, the query is executed in the background. While this enables query cancellation and avoids web request timeouts, it also means certain legacy stored procedures that depend on foreground execution and write to the current device may no longer display this logging information properly. (first in 2019.3)
SQL — Sybase TSQL Dialect Variable Names are now Case Sensitive
Sybase TSQL dialect now properly supports case sensitive variable names in procedure code. For example:
declare @myvariable varchar(255) declare @MyVariable varchar(255)
In this code myvariable and MyVariable are two different variables. Prior to this change, in TSQL Sybase dialect, if you declared a variable in once case, and referenced it in another, it would work. For example, the following did work but no longer works in the Sybase dialect:
@declare @A int select @a = 1
When using MSSQL dialect, variable names are case insensitive. The code defining myvariable and MyVariable will produce an error in compiled with MSSQL dialect, but the code declaring variable A and referencing variable a will work in MSSQL dialect.
SQL — Changes in TRUNCATE TABLE Transactions
TRUNCATE TABLE no longer initiates transactions when executed in AUTOCOMMIT_ON or AUTOCOMMIT_OFF mode. If you need the ability to rollback a truncate table command, you must start you own transaction prior to executing the truncate table. (first in 2019.4)
SQL — TSQL Parser Changes
Prior to this change, if you had defined:
The TSQL parser would have behaved as if these settings were ON. Now that this has been corrected, if your code was really relying on either of these settings being ON, and not they are OFF because of the ^%SYS("tsql","SET","ANSI_NULLS") or ^%SYS("tsql","SET","QUOTED_IDENTIFIER") global setting, the run-time behavior of your procedure may be different. (first in 2019.4)
System — Changes to TCP /BINDTO Behavior
If your application uses TCP device with /BINDTO option for outgoing connection, you may find the OPEN will fail if the IP does not exist in local system. (first in 2019.4)
System — Changes to Accessing Global’s Characteristics
This release requires write access in order to modify the keep flag or growth block of a global. If your code attempts to modify these characteristics without write access, it will fail with a <PROTECT> error.
Utilities — Changes to %File.TempFilename Method
The ##class(%File).TempFilename method now returns an empty string instead of a negative return code when there is an error. The new third argument receives the error code in case of an error. If your code is checking the return value for a negative error code you must change it to check for an empty string and use the third argument to report the error code.
System — Class Compiler Validates Global Name Length Limit
This release adds compiler validation to ensure that the global names defined for DataLocation, IdLocation, IndexLocation, StreamLocation, CounterLocation, and VersionLocation are all within the global name length supported by the system (currently 31 characters). In previous releases, these global names were silently truncated to 31 characters. This could cause collisions between global names in the same class. These collisions would cause what appears to be references to separate globals to actually reference the same global.
During class compilation, an error will be reported if any of the global names used for the class are longer than the supported length. For example:
Compiling class %UnitTest.Result.TestInstance ERROR #9101: Global name 'UnitTest.Result.TestInstanceStream' for 'StreamLocation' is too long, must be no more than 31 characters in length. [ConstructAddresses+60^%ocsExtentCache:BUILDSYS] > ERROR #5030: An error occurred while compiling class '%UnitTest.Result.TestInstance' [compile+59^%occClass:BUILDSYS]
This change will most likely result in classes that need to be modified upon upgrade. This more commonly occurs on systems that were converted from Caché or Ensemble using the in-place conversion if the classes were first defined using %CacheStorage and the class names were fairly long. (first in 2019.3)