Openedge Abl Datatypes
Openedge Abl Datatypes
Copyright
© 2020 Progress Software Corporation and/or its subsidiaries or affiliates. All rights reserved.
®
These materials and all Progress software products are copyrighted and all rights are reserved by Progress
Software Corporation. The information in these materials is subject to change without notice, and Progress
Software Corporation assumes no responsibility for any errors that may appear therein. The references in
these materials to specific platforms supported are subject to change.
Corticon, DataDirect (and design), DataDirect Cloud, DataDirect Connect, DataDirect Connect64, DataDirect
XML Converters, DataDirect XQuery, DataRPM, Defrag This, Deliver More Than Expected, Icenium, Ipswitch,
iMacros, Kendo UI, Kinvey, MessageWay, MOVEit, NativeChat, NativeScript, OpenEdge, Powered by Progress,
Progress, Progress Software Developers Network, SequeLink, Sitefinity (and Design), Sitefinity, SpeedScript,
Stylus Studio, TeamPulse, Telerik, Telerik (and Design), Test Studio, WebSpeed, WhatsConfigured,
WhatsConnected, WhatsUp, and WS_FTP are registered trademarks of Progress Software Corporation or one
of its affiliates or subsidiaries in the U.S. and/or other countries. Analytics360, AppServer, BusinessEdge,
DataDirect Autonomous REST Connector, DataDirect Spy, SupportLink, DevCraft, Fiddler, iMail, JustAssembly,
JustDecompile, JustMock, NativeScript Sidekick, OpenAccess, ProDataSet, Progress Results, Progress
Software, ProVision, PSE Pro, SmartBrowser, SmartComponent, SmartDataBrowser, SmartDataObjects,
SmartDataView, SmartDialog, SmartFolder, SmartFrame, SmartObjects, SmartPanel, SmartQuery, SmartViewer,
SmartWindow, and WebClient are trademarks or service marks of Progress Software Corporation and/or its
subsidiaries or affiliates in the U.S. and other countries. Java is a registered trademark of Oracle and/or its
affiliates. Any other marks contained herein may be trademarks of their respective owners.
March 2020
Updated: 2020/09/10
Table of Contents
Introduction....................................................................................................9
Data types..............................................................................................................................................9
Data type terminology...........................................................................................................................10
Arrays............................................................................................................45
Arrays as parameters...........................................................................................................................45
Passing indeterminate arrays as parameters.......................................................................................46
Deep copying arrays.............................................................................................................................48
Purpose
This web paper documents new data type support which applies to OpenEdge Releases 10.0B and later
releases.
Organization
Introduction on page 9
INT64 data type on page 11
Large object data types on page 17
Using large objects in ABL on page 25
DATETIME and DATETIME-TZ data types on page 33
Arrays on page 45
Documentation conventions
See Documentation Conventions for an explanation of the terminology, format, and typographical conventions
used throughout the OpenEdge content library.
• Data types
Data types
The data type of a database field, temp-table field, or program variable defines what kind of data the field or
variable can store. To allow better interoperability between OpenEdge applications and external products,
OpenEdge provides additional data types and new features for some existing data types in ABL (Advanced
Business Language).
Note: For a list of all the ABL data types, see ABL Reference.
The new data types and the ability to pass arrays as parameters provides a higher level of interoperability with
products such as SQL92, XML, Open Client, Application Server, and Web services products. When the interface
of an application is defined by a non-ABL application, these new data types ensure that the application executes
properly. In addition, these new data types allow ABL developers to create more data-robust OpenEdge
applications.
This new data type support applies to OpenEdge Releases 10.0B and later releases. It is described in the
following sections:
• Like most other keywords, references to specific built-in data types appear in all UPPERCASE, using a font
that is appropriate to the context; no uppercase reference ever includes or implies any data type other than
itself
• Wherever integer appears, this is a reference to the INTEGER or INT64 data type
• Wherever character appears, this is a reference to the CHARACTER, LONGCHAR, or CLOB data type
• Wherever decimal appears, this is a reference to the DECIMAL data type
• Wherever numeric appears, this is a reference to the INTEGER, INT64, or DECIMAL data type
References to built-in class data types appear in mixed case with initial caps, for example,
Progress.Lang.Object. References to user-defined class data types appear in mixed case, as specified
for a given application example.
Starting with OpenEdge Release 10.1B, ABL includes a 64-bit integer data type, INT64. This data type is
separate from the existing 32-bit data type (INTEGER). The INT64 data type is compatible with all current
functions and statements that currently support the 32-bit integer. That is, INT64 and INTEGER are
interchangeable everywhere in ABL, except in parameters and return types for strongly-typed class-based
methods where you want the type checking and where you control both the caller and callee routines.
• Display Format
Display Format
The default display format for INT64 data type is "->,>>>,>>9" (the same as the default display format for
INTEGER.) You can define an INT64 field or variable to be viewed as (VIEW-AS) a fill-in field, text widget,
combo-box, radio-set, or slider.
Note that if you specify VIEW-AS SLIDER for an INT64 field or variable, the value must still remain within the
-2147483648 to +2147483647 integer range.
• INT64 function — Takes any data type and returns an INT64 value, if the conversion is possible. This
function takes most common data types except for RAW, MEMPTR, or LONGCHAR.
• PUT-INT64 statement — Stores the signed 64-bit value of an INT64 or INTEGER expression at the specified
memory location. The specified memory location can have a RAW or a MEMPTR value.
• GET-INT64 function — Returns the signed 64-bit value at the specified memory location as an INT64
value. The specified memory location can have a RAW or a MEMPTR value.
• PUT-UNSIGNED-LONG statement — Stores an INTEGER or INT64 value as a 32-bit unsigned value to
a MEMPTR or RAW value. This statement is analogous to PUT-UNSIGNED-SHORT, except with a 32-bit value.
• GET-UNSIGNED-LONG function — Returns the unsigned 32-bit value at the specified memory location
as an INT64. This is analogous to GET-UNSIGNED-SHORT, except with a 32-bit value.
In addition, the following functions, which were compiled as returning INTEGER in Release 10.1A and earlier,
are now compiled as returning INT64:
• CURRENT-VALUE
• DYNAMIC-CURRENT-VALUE
• DYNAMIC-NEXT-VALUE
• ETIME
• GET-POINTER-VALUE
• GET-SIZE
• INTERVAL
• NEXT-VALUE
• SEEK
You can override this result and have these functions compile to return INTEGER with either the INTEGER
function or by using the No INT64 (-noint64) startup parameter. For more information on this startup parameter,
see Specifying not to use INT64 on page 15.
Starting with Release 10.1B, all intermediate calculations are carried out in 64-bit arithmetic. With the introduction
of the INT64 data type, any operator or function that used to return an INTEGER can now return a value greater
than 32-bits. This large value is held correctly as an intermediate value and does not generate an error message
unless you assign the final result into an INTEGER database field, temp-table field, program variable, or
parameter. This means that if you try to store a value outside the -2147483648 to +2147483647 range in an
INTEGER, you get an error message. For example, 2,000,000,000 * 100 / 100 gives the correct result whether
the target field is INTEGER or INT64. However, although 2,000,000,000 * 100 does not cause an overflow,
the result must be assigned to an INT64 field. It generates a run-time error if you assign it to an INTEGER field.
If you have an existing field, program variable, or parameter defined with the INTEGER data type, and you want
to make it 64-bit capable, you must change the data type to INT64.You can change the data type of a database
field via the Data Dictionary tool. Note that you can make this change without having to dump and load the
data. However, when you change the data type of a database field, you change the Cyclic Redundancy Check
(CRC) of the database table that contains the field. Therefore, you must recompile your r-code. In addition,
you should review your code for any references to the database field to determine whether there is a possibility
of an overflow with the INTEGER data type.
The following code example demonstrates arithmetic operations using a mix of INTEGER and INT64 expressions:
PROCEDURE myproc:
DEF INPUT PARAMETER mp AS INTEGER.
DISPLAY mp.
END.
Caution: If you specify NO-SCHEMA when you define a temp-table, the INT64/INTEGER parameter matching
is not checked, just as other types of checking are bypassed when you specify NO-SCHEMA.
Note: The -noint64 startup parameter does not affect performance. The arithmetic operations in Release
10.1A and earlier code are calculated using the INTEGER data type while those in Release 10.1B code are
calculated using the INT64 data type.
Before OpenEdge Release 10, all data types, other than MEMPTR, were limited in size to 32K. Release 10
introduces three new large object data types that expand this size limit:
• Binary large object ( BLOB ) — For database and temp-table fields. This data type allows the storage of
large binary data in the database. Data previously stored external to the OpenEdge database can now be
integrated into the OpenEdge database and accessed by ABL. This data type is the database counterpart
of the MEMPTR data type.
• Character large object ( CLOB ) — For database and temp-table fields. This data type allows the storage
of large character strings in the database. It also permits automatic code page translation and null-termination.
CLOB values can be in any code page that is supported by the ABL code page conversion map (convmap.p)
file. The code page information is retained by the CLOB. ABL ensures that all characters are valid with
respect to the code page of the CLOB. This data type is the database counterpart of the LONGHAR data type.
• LONGCHAR data type — For in-memory use. This data type is the program variable counterpart of the CLOB
data type. LONGCHAR allows much of the ABL character handling capabilities to be applied to large strings.
Like CLOB values, LONGCHAR values can be in any code page supported by the OpenEdge convmap.p
file, and the code page information is retained by the LONGCHAR. ABL ensures that all characters are valid
with respect to the code page of the LONGCHAR.
BLOB and CLOB fields can be up to 1GB in size. MEMPTR and LONGCHAR variables can be up to 2GB - 1 byte
in size, but are limited by available memory.
Restrictions
The following restrictions apply to BLOB fields:
Restrictions
The following restrictions apply to CLOB fields:
• DBCODEPAGE (for database tables) or TTCODEPAGE (for temp-tables) — A DBCODEPAGE CLOB is a field
in a database that is in the database's codepage and uses the collation table associated with the database's
codepage. A TTCODEPAGE is a CLOB field in a temp-table that is in the code page set by the Internal Code
Page (-cpinternal) startup parameter. Also, if you define a temp-table field to be LIKE a DBCODEPAGE
database field, the -cpinternal code page is used for the temp-table field.
• COLUMN-CODEPAGE — When you define a CLOB field (either in a database or a temp-table) you can use
COLUMN-CODEPAGE to specify the code page of the CLOB as well as a valid collation for that code page.
If you do not specify a code page for a CLOB field in a temporary table, the default code page is -cpinternal.
In the following example, clopcp and clopdb are CLOB fields defined elsewhere. The clopcp field is a
COLUMN-CODEPAGE type of CLOB with code page 1252. The clopdb field is a DBCODEPAGE type of CLOB
with code page UTF-8. The code page set by -cpinternal is iso8859-1:
In this example, ttab1 is in -cpinternal (iso8859-1) because that is the default code page for CLOB fields
in a temp-table.The code page for ttab2 is UTF-16 because it is specifically set using the COLUMN-CODEPAGE
option. The ttab3 field has the 1252 code page because it is defined as being LIKE clobcp which defines
the code page of that CLOB as 1252.
The ttab4 field has the -cpinternal code page (iso8859-1) since it is defined LIKE clobdb which is a
DBCODEPAGE CLOB. It is therefore converted to the code page of the temp-table, which is always defined by
-cpinternal. (You can use the DBCODEPAGE function to get the name of a connected database's code page.
For more information about the DBCODEPAGE function, see ABL Reference.)
The ttab5 field is in TTCODEPAGE (-cpinternal). It is defined to be LIKE clobcp but the TTCODEPAGE
keyword is specified and that overrides the code page of clobcp.
Operators
Assignment (=) Greater than (GT or >) Less than or equal (LE or >=)
Functions
CAPS LC RIGHT-TRIM
GENERATE-PBE-KEY NORMALIZE
GET-CODEPAGE NUM-ENTRIES
Statements
ENTRY METHOD
Attributes
FRAGMENT SYMMETRIC-ENCRYPTION-KEY
Methods
Methods
NODE-VALUE-TO-LONGCHAR() WRITE-CHARACTERS()
READ-XML() WRITE-COMMENT()
Restrictions
The following restrictions apply to LONGCHAR values:
• Whatever the code page, the LONGCHAR can only contain one string in one code page. It contains only 1
NULL terminator of its own code page. LONGCHAR cannot consist of multiple code pages, with different
character sets in different frames, as an HTML file can.
• The UNDEFINED code page is not allowed for LONGCHAR values.
• You can use only the large editor for viewing a LONGCHAR (VIEW-AS EDITOR LARGE).
• A LONGCHAR program variable cannot be UNDO.
• You cannot use a LONGCHAR program variable in WHERE clauses.
Syntax
You can only use this statement to set the code page for a LONGCHAR variable that is empty. If you try to use
the FIX-CODEPAGE statement for a LONGCHAR variable that already has a value, the ABL Virtual Machine
(AVM) generates an error.
When set to a valid code page, the code page of the specified variable is fixed and overrides any default
behavior in assignment operations. For assignment rules, see ABL Reference.
This section provides details and shows examples for using large objects in ABL.
Syntax
COPY-LOB
[ FROM ]{[ ]source-lob| FILE source-filename }
OBJECT
[ STARTING AT n][ FOR length ]
TO {[ OBJECT ]target-lob[OVERLAY AT n[TRIM ]]|
FILE target-filename[ APPEND ]}
[ NO-CONVERT | CONVERT convert-phrase]
[ NO-ERROR ].
You can copy the entire contents of the source to the target with COPY-LOB. You can also use the COPY-LOB
statement to copy part of a file (for example, using STARTING AT or FOR) to the target. For more information
about the COPY-LOB statement, see ABL Reference
You can also use the ASSIGN statement to copy large object data between the database, temp-table fields,
and memory. For example, the following ASSIGN and COPY-LOB statements (where m2 is a MEMPTR) are
functionally equivalent:
You can assign large object data from one BLOB or MEMPTR to another, and from one CLOB or LONGCHAR to
another. You cannot assign large object data between BLOB and CLOB values or MEMPTR and LONGCHAR
values. However, you can accomplish this indirectly by using the COPY-LOB statement.
Note: COPY-LOB file operations involving LONGCHAR variables are limited to 1GB - 1 byte.
Syntax
{
[ SOURCE CODEPAGE codepage ]
[ TARGET CODEPAGE codepage]
}
Specify SOURCE CODEPAGE to indicate that a source object is in the specified code page. If you specify TARGET
CODEPAGE, the AVM converts the target object to the specified code page.
For details on the default character conversions the AVM performs when copying data between the source
and target objects, see the COPY-LOB statement entry in ABL Reference.
ASSIGN employee.blob = ?.
Note that when you delete a record in a table, any non-null BLOB fields referenced in the record are also deleted.
Note: You can also use the Data Administration tool to IMPORT and EXPORT large objects and to specify a
directory for large object files.
OUTPUT TO blob.txt.
EXPORT table.blob-field.
OUTPUT CLOSE.
Note that if the OUTPUT TO statement in this example included the LOB-DIRdir-name option, then the
blob-field_123456.blb file would be created in the LOB-DIR directory. However, the AVM does not
create the LOB-DIR directory if it does not already exist.
In the following example, the names of the files that contain the BLOB data are written to the customer.d file
in the C:\DumpedData\ directory and the files are written to C:\DumpedData\custblob:
OUTPUT CLOSE.
Note that the third customer had no data in the photo field and therefore is the Unknown value (?). Note
also that the generated filename is always unique. If the LOB-DIR phrase is left off of the OUTPUT TO statement,
the BLOB files are created in the C:\DumpedData directory.
For CLOB values, the code page of the CLOB is part of the filename generated by the EXPORT statement. The
file name consists of the field or variable name, followed by the code page name surrounded by exclamation
marks (!), followed by the unique name and the .blb extension. For example:
Fclob!UTF-8!12345_6.blb
Here is the output showing that the BLOB data was excluded from the data dump and is instead represented
by the Unknown value (?):
This message told the user that not just the subtransaction, but the entire transaction was rolled back.
Starting with Release 10.1A, subtransactions containing changes to large object (LOB) fields can be undone
without undoing the entire transaction. Users no longer get the previous message and, more importantly, the
subtransaction containing the LOB operation is rolled back like any other subtransaction. This feature applies
only to LOB operations in the OpenEdge database. The restrictions on LOB operations in subtransactions still
applies to the Oracle DataServer.
Note that this feature does not apply to temporary tables. Temp-tables must be NO-UNDO if they contain binary
(BLOB) or character large object (CLOB) fields.
/*
Assume that fldClob is a CLOB field in a table.
The code page of this file is eucjis. The CLOB field is in the -cpinternal code page.
*/
DEFINE TEMP-TABLE ttab NO-UNDO
FIELD name AS CHAR
FIELD address AS CHAR
FIELD city AS CHAR
FIELD state AS CHAR
FIELD fldClob as CLOB.
CREATE ttab.
COPY-LOB FROM file "clobfile.txt" TO fldClob
CONVERT SOURCE CODEPAGE "eucjis".
The DATETIME and DATETIME-TZ data types are also new to OpenEdge Release 10. These two ABL data
types provide the following benefits (where datetime refers to DATETIME or DATETIME-TZ):
• You no longer have to manipulate dates and times separately to have datetime types of data.
• If you use DataServers, you can get direct mapping to their datetime data.
• If you do open ABL programming, you can convert your datetime data directly.
• Summary of features
• Display formats
• Datetime arithmetic
• An order entry application that accepts orders from around the world wants the order datetimes stored in
UTC so that they index in absolute time.
• An ABL application communicating with a Web service that includes an XML Schema datetime in its interface
can use DATETIME-TZ parameters to communicate in absolute time, and to preserve time zone information
from the datetime data coming from the Web service.
• An ABL client/application server communication should also use DATETIME-TZ, since the client and the
application server might be in different time zones. For DATETIME-TZ, the value represents an absolute
date and time, and there is no data loss when passing parameters between sessions in different time zones.
Summary of features
The following features apply to the DATETIME and DATETIME-TZ data types:
• ABL supports both DATETIME and DATETIME-TZ in ABL data management statements such as ASSIGN,
UPDATE, DISPLAY, IMPORT/EXPORT; by the dynamic BUFFER-FIELD and TEMP-TABLE objects; and by
ABL functions and conversions that apply to DATE or TIME.
• You can define DATETIME and DATETIME-TZ database and temp-table fields (static and dynamic). The
Data Dictionary supports creating DATETIME and DATETIME-TZ database fields.
• You can define a variable or field AS a DATETIME or DATETIME-TZ variable orLIKE a DATETIME or
DATETIME-TZ database field.
• You can index DATETIME and DATETIME-TZ database and temp-table fields.
• You can reference DATETIME and DATETIME-TZ data in WHERE clauses.
• You can use all of the ABL constructs (BUFFER-COPY, BUFFER-COMPARE, RAW-TRANSFER) that deal with
records containing DATETIME or DATETIME-TZ data.
• You can pass DATETIME and DATETIME-TZ parameters to local or remote procedures and user-defined
functions, and as return values from user-defined functions and methods.
• The default initial value for DATETIME and DATETIME-TZ variables or fields is the Unknown value (?).
The entire value is unknown if any or all of the parts are unknown.
• You can use NOW to initialize both DATETIME and DATETIME-TZ variable or fields to the current system
date and time. The time zone for a DATETIME-TZ initialized to NOW is the time zone of the session creating
the DATETIME-TZ.
• DATETIME — Creates a DATETIME from date and time values or from a character string. The following
example uses the DATETIME function:
• DATETIME-TZ — Creates a DATETIME-TZ from date, time, and time zone values or from a character
string. The following example uses the DATETIME-TZ function:
The ABL functions summarized in the following table support the DATETIME and DATETIME-TZ data types.
For details on each of these functions, see ABL Reference.
Function Description
ADD-INTERVAL Adds or subtracts a specified unit of time (days, months, seconds, etc.) to/from a
DATETIME or DATETIME-TZ value. This function takes the date, time, and time
zone information into account. You can also use this function with a DATE.
DAY Returns the day of the month of the date part of the DATETIME or DATETIME-TZ
value.
1
INTERVAL Returns an integer that represents an interval between two date/times, expressed
in interval-units (days, months, seconds, etc.). This function takes the date, time,
and time zone information into account.You can also use this function with a DATE.
1
ISO-DATE Returns the character representation of a DATE, DATETIME or DATETIME-TZ that
conforms to the ISO 8601 standard for date/time representations - formats are
equivalent to the XML Schema date and dateTime formats.
MONTH Returns an integer value representing the month of the date part of the DATE,
DATETIME, or DATETIME-TZ value.
1
MTIME Returns an integer representing the time part of a DATETIME or DATETIME-TZ in
milliseconds. With no arguments, MTIME returns the number of milliseconds since
midnight.
1
NOW Returns the current system date, time, and time zone as a DATETIME-TZ. If
assigned to a DATETIME, NOW does not include the time zone.
WEEKDAY Returns the weekday of the date part of the DATETIME or DATETIME-TZ value.
YEAR Returns the year of the date part of the DATETIME or DATETIME-TZ value.
• SESSION:DATE-FORMAT ( -d ) — Used to set the display format of the date part of DATETIME and
DATETIME-TZ; for example, month/day/year (mdy) or year/month/day (ymd).
• SESSION:YEAR-OFFSET ( -yy ) — The start date for the two-digit year range of 100 years; used to display
the DATETIMEand DATETIME-TZ when the format specifies a two-digit year.
1
This ABL function is new to OpenEdge Release 10.
• SESSION:TIME-SOURCE — The ABL client/application server or database server machine that serves as
the time source for the TIME, TODAY, NOW, TIMEZONE, and MTIME functions. This source is also used to
generate values for DATE, DATETIME and DATETIME-TZ database and temp-table fields with initial values
of TODAY or NOW. The TIME-SOURCE attribute overrides the SESSION:TIMEZONE attribute.
• SESSION:TIMEZONE — An INTEGER value that specifies the time zone offset from UTC, in minutes, that
ABL uses in the TODAY, TIME, NOW, MTIME and TIMEZONE functions. This source is also used to generate
values for DATE, DATETIME and DATETIME-TZ database and temp-table fields with initial values of TODAY
or NOW. The SESSION:TIME-SOURCE attribute overrides the TIMEZONE attribute.
• SESSION:DISPLAY-TIMEZONE — The time zone for displaying DATETIME-TZ data without a time zone
offset.
• The default time zone of the operating system where the current session is running.
• The time zone offset specified in the TIMEZONE attribute of the SESSION system handle. This attribute can
be changed within the session.
• The time zone of the server specified in the TIME-SOURCE attribute of the SESSION system handle. This
attribute can be changed within the session.
9999-99-99THH:MM:SS.SSS+HH:MM
"99-99-9999 HH:MM:SS.SSS+HH:MM"
The literal must be in quotes because of the space between the date and time. The date part must be in
month/day/year order (like DATE literals).
You can omit all or part of the seconds, as well as the time zone offset.
The AVM evaluates the literals at run time. If a time zone offset is specified for a DATETIME literal, the literal
is converted to the local time of the session. If a time zone offset is not specified for a DATETIME-TZ literal,
the DATETIME-TZ uses the session's time zone offset.
Display formats
The format policy syntax for DATETIME and DATETIME-TZ is similar to the DATE and TIME formats:
Syntax
any-date-format time-with-timezone-format
You can leave off part or all of the time format. The date part is subject to the usual –d or
SESSION:DATE-FORMAT rules.
The default format for DATETIME is:
"99/99/9999 HH:MM:SS.SSS".
"99/99/9999 HH:MM:SS.SSS+HH:MM"
March 5, 2002 at 7:15:03.002 am on a client with a time-source time zone of UTC-05:00 would display as
(assuming -d mdy):
The ABL client in London (time zone UTC+00:00) displays the field as follows:
An ABL client in Bedford, MA (time zone UTC-05:00) displays the same field as follows:
An ABL client in San Diego, CA (time zone UTC-08:00) displays the field as follows:
If you want to display DATETIME-TZ data without a time zone offset in a time zone other than the session's
time zone (a client in Bedford wants to see DATETIME-TZ data in San Diego local time), use the
SESSION:DISPLAY-TIMEZONE attribute.
Datetime arithmetic
You can use the DATETIME, DATETIME-TZ, INTERVAL, and ADD-INTERVAL functions to add and subtract
dates and times in your application.
You can add an integer or decimal to a DATETIME or DATETIME-TZ and get a new DATETIME or DATETIME-TZ.
This adds milliseconds to the original DATETIME or DATETIME-TZ. All functions that manipulate DATETIME
and DATETIME-TZ data ensure that the time part remains within the valid range, adding a day or days to the
date part when the time part goes over the number of milliseconds in a day and subtracting a day or days from
the date part when the time part goes under the number of milliseconds in a day.
Syntax
Syntax
With the subtraction operator, you can subtract milliseconds from a datetime value or subtract a compatible
datetime value from a another datetime value using the following syntax:
The result is either a different DATETIME or DATETIME-TZ value (when subtracting milliseconds) or a
millisecond interval between two DATETIME or DATATIME-TZ values returned as an INT64.
Syntax
The new-datetime value then represents a new DATETIME at a point later (when adding to) or earlier (when
subtracting from) the old-datetime value by the specified number of days and milliseconds.
This is the syntax for adding or subtracting a specific number of days and milliseconds with a DATETIME-TZ:
Syntax
The new-datetime-tz value then represents a new DATETIME-TZ at a point later (when adding to) or earlier
(when subtracting from) the old-datetime-tz value by the specified number of days and milliseconds within
the specified time zone.
Syntax
To subtract dates and times, you use the ADD-INTERVAL function with an INTEGER value for the interval
amount, and a unit of time (such as minutes, days, or weeks) for the interval unit. The result is a different
DATE, DATETIME, or DATETIME-TZ value, depending on the data type of datetime.
Here is an example that adds two days to the order date to determine the estimated ship date:
Starting with Release 10.1B, you can subtract two datetimes, giving an INT64 with the number of milliseconds.
The INTERVAL function returns the time interval between two DATE, DATETIME, or DATETIME-TZ values
using the following syntax:
Syntax
The result is a the number of specified units (for example, minutes, days, or weeks) between the specified
values date or datetime values.
The return data type of INTERVAL is INT64. Here is an example that uses the INTERVAL function to determine
if an order shipped on time:
In this example, the ship datetime should be five days after the order date.
The following example using ADD-INTERVAL and INTERVAL shows time-interval calculations with date and
datetime values that produce results in milliseconds.
/* ADD-INTERVAL() */
DEF VAR mm AS int64.
mm = 200000000000000.
MESSAGE "pos - ADD-INTERVAL with milliseconds - " ADD-INTERVAL(dtz1, mm,
"milliseconds") {&vab}.
mm = -9999999999999.
MESSAGE "neg - ADD-INTERVAL with milliseconds - " ADD-INTERVAL(dtz1, mm,
"milliseconds") {&vab}.
/* INTERVAL() */
dtz1 = 1945-07-30T23:01:02.123+2:00.
dtz2 = 1945-07-01T23:01:02.123+2:00.
MESSAGE "pos DTZ - INTERVAL with milliseconds - " INTERVAL(dtz1, dtz2,
"milliseconds") {&vab}.
dtz2 = 1945-07-01T23:01:03.123+2:00.
MESSAGE "neg DTZ - INTERVAL with milliseconds - " INTERVAL(dtz1, dtz2,
"milliseconds") {&vab}.
dt1 = 1945-07-13T00:59:59.123.
dt2 = 1945-02-13T00:59:59.123.
MESSAGE "pos DT - INTERVAL with milliseconds - " INTERVAL(dt1, dt2,
"milliseconds") {&vab}.
dt2 = 1945-02-13T00:59:59.123.
MESSAGE "neg DT - INTERVAL with milliseconds - " INTERVAL(dt1, dt2,
"milliseconds") {&vab}.
OUTPUT CLOSE.
/* dump_order.p */
OUTPUT TO dump.txt.
OUTPUT CLOSE
For example, assume the OrderDate field in the sports2000.Order table is a DATETIME, and there is an
additional DATETIME-TZ field, OrderDateTZ that contains the same date and time as OrderDate. Here is
the result in dump.txt:
• Arrays as parameters
Arrays as parameters
You can pass arrays as run-time parameters and you can return arrays from class-based methods and
user-defined functions. This feature enables applications developed in ABL to be more compatible with non-ABL
applications which expose arrays in their interfaces.
Class properties and public data members can also be arrays and defining an instance of a class with the
EXTENT option results in an array of handles to that class.
Here is the DEFINE PARAMETER statement syntax for defining an array as a parameter:
Syntax
You can define an array parameter as either determinate (has a defined number of elements) or indeterminate
(has an undefined number of elements). To define a determinate array parameter, specify the EXTENT option
with the expression argument. This optional argument evaluates to an integer value that represents a size
(extent) for the array parameter. To define an indeterminate array parameter, specify the EXTENT option without
the expression argument.
An indeterminate array parameter can be in one of two states: with a size or without a size. An indeterminate
array does not have a size when first defined, unless initial values are provided. You can set the size of an
indeterminate array parameter by:
• Passing the array parameter to a routine whose corresponding parameter is a determinate array
• Setting the number of elements in the array parameter using the EXTENT statement
ABL treats an indeterminate array parameter with a size as a determinate array parameter; that is, its size is
set. ABL determines the size at runtime.
The EXTENT function returns the size of (the number of elements in) an array field or variable. For example,
the following code example returns 12 (the extent of the Mnth-Sales field is 12):
For more information about passing arrays as parameters see OpenEdge Programming Interfaces, ABL
Reference, Web Services, Java Open Clients, and .NET Open Clients.
• You can pass a determinate array or an indeterminate array with a size to a routine whose corresponding
parameter is a determinate array defined as an INPUT, INPUT-OUTPUT, or OUTPUT parameter with the
same size (extent).
• You can pass an indeterminate array without a size to a routine whose corresponding parameter is another
indeterminate array without a size defined as an INPUT, INPUT-OUTPUT, or OUTPUT parameter.
• You can pass a determinate array or an indeterminate array (with or without a size) to a routine whose
corresponding parameter is an indeterminate array without a size. When passing a determinate or a
indeterminate array with a size to an indeterminate array without a size, defined as either an INPUT or
INPUT-OUTPUT parameter, the indeterminate array parameter inherits the size from the calling routine (but
its definition remains unchanged). When passing an array with a size to an indeterminate array without a
size, defined as an OUTPUT parameter, the sizes must match upon returning to the calling routine. In this
case, the called routine must set the size by either applying the EXTENT statement or inheriting the size
from another called routine.
• You can pass an indeterminate array without a size to a routine whose corresponding parameter is a
determinate array defined as an OUTPUT or INPUT-OUTPUT parameter. In this case, the indeterminate
array inherits the size from the called routine. Likewise, an indeterminate array without a size inherits the
size of an indeterminate array parameter with a size using the EXTENT statement in the called routine. You
cannot pass an indeterminate array without a size to a routine whose corresponding parameter is a
determinate array defined as an INPUT parameter.
• You cannot pass an indeterminate array without a size to a COM object, DLL routine, or UNIX shared library
routine.
The following example passes a determinate array as an input parameter to a routine that defines the parameter
as an indeterminate array without a size:
PROCEDURE foo:
DEFINE INPUT PARAMETER x AS INTEGER EXTENT.
MESSAGE EXTENT(x). /* Returns 3 */
END.
In this case, the indeterminate array parameter inherits the size from the calling routine (but its definition remains
unchanged).
The following example passes an indeterminate array without a size as an output parameter to a routine that
defines the parameter as a determinate array:
PROCEDURE foo:
DEFINE OUTPUT PARAMETER x AS INTEGER EXTENT 4.
END.
In this case, the indeterminate array parameter inherits the size from the called routine.
The following example passes an indeterminate array without a size as an output parameter to a routine that
also defines the parameter as an indeterminate array with no size, but sets the size of the array using the
EXTENT statement:
PROCEDURE foo:
DEFINE OUTPUT PARAMETER x AS INTEGER EXTENT.
EXTENT(x) = 4. /* Sets the extent to 4 */
END.
In this case, the indeterminate array parameter also inherits a size from the called routine.
When deep copying one array to another, the following rules apply:
• If both the array on the left-hand side and the right-hand side of the assignment are determinate arrays, the
EXTENT size must match or the AVM raises an error.
• You cannot assign an indeterminate array without a size to a determinate array. That is, if an array does
not yet have a size, you cannot assign it to one that does have a size.
• You can assign any array to an indeterminate array without a size. The size of the indeterminate array is
set to the size of the other array.
• You cannot assign a scalar value to an indeterminate array without a size.
For more information, see Work with one-dimensional arrays in Basic ABL.