 |
Functional Spec For Boolean Datatype |
| Revision |
Description |
Date |
Author |
| 2.0 |
I abandoned the first attempt to implement a BOOLEAN
datatype. This spec describes a second effort. |
May 9, 2007 |
Rick Hillegas |
This spec describes the introduction of the ANSI BOOLEAN
datatype. Derby 10.3 already partially supports this datatype:
- System tables - Some of the system tables have
BOOLEAN columns, which users can SELECT.
- Qualification - The WHERE clause evaluates to a BOOLEAN value.
- Casts - BOOLEAN values can be cast explicitly to other
datatypes.
- ResultSet
-
getXXX()
methods can be called on BOOLEAN columns in JDBC
ResultSets.
In Target Release, Derby behavior changes as follows:
- CREATE TABLE/FUNCTION/PROCEDURE - Users can create
tables with BOOLEAN columns. Users can create functions
with BOOLEAN parameters and/or return values. Users can
create procedures with BOOLEAN arguments.
- Casts - In Target Release, BOOLEANs obey the
ANSI casting rules.
- ResultSet
- The behavior of some getXXX() methods changes.
For the remainder of this spec, we use the following terms:
- Target Release - The release which carries these
changes. This would be 10.4 or later.
The following changes create incompatibilities with
previous Derby releases. The community needs to decide
whether these incompatibilities warrant bumping the release
identifier's major number.
We introduce new SQL syntax:
- CREATE TABLE - Users can create
tables with BOOLEAN columns.
- CREATE INDEX - Users can include BOOLEAN columns in indexes.
- CREATE FUNCTION - Users can create functions
with BOOLEAN parameters and return values.
- CREATE PROCEDURE - Users can create procedures
with BOOLEAN arguments.
- New Literals - SQL statements can contain 3 new
BOOLEAN literals:
- true
- false
- unknown - This evaluates to a BOOLEAN null.
- Sorts - Users can include BOOLEAN typed values in
GROUP BY and ORDER BY clauses. Null sorts before
false, which sorts before true.
So, for instance, the following script is supported:
CREATE TABLE sample( boolCol BOOLEAN );
CREATE INDEX boolIndex on sample( boolCol );
INSERT INTO SAMPLE( boolCol ) VALUES
( true ),
( false ),
( null ),
( unknown );
select * from sample order by boolCol;
In Target Release, Derby implements ANSI casting behavior with
respect to BOOLEANs. This is a change from Derby's
behavior in release 10.3.
The ANSI casting behavior is
described in the SQL Standard, part 2, section 6.12 (<cast specification>).
For details on the discrepancy between Derby 10.3 and the ANSI spec,
see Appendix A.
Derby 10.3 lets you cast BOOLEAN to most other
datatypes. However, ANSI only allows you to cast
BOOLEANs to the string types CHAR, VARCHAR, LONG
VARCHAR, and CLOB.
According to the SQL Standard, the result of casting a BOOLEAN
to a string type is an uppercase string value "TRUE" or "FALSE". For
fixed-length string types, this value is then padded with
trailing spaces. A truncation error is raised if the
fixed-length string type is too small. Derby 10.3 correctly
pads and raises truncation errors. However, Derby 10.3 casts
BOOLEAN to lowercase "true" and "false".
In Target Release, Derby behavior changes to conform to the SQL
Standard:
- BOOLEAN values may only be cast to BOOLEAN and to the string types CHAR,
VARCHAR, LONG VARCHAR, and CLOB. All other casts raise
syntax errors.
- The result of casting a BOOLEAN value to a string type is
uppercase 'TRUE" and "FALSE" rather than lowercase "true"
and "false".
In addition, in Target Release, only the string types and BOOLEAN itself
may be cast to BOOLEAN. The reverse casts are also
allowed and those are the only legal casts from BOOLEAN.
Derby 10.3 allows comparisons between BOOLEAN values and
numbers. In these comparisons, the number is implicitly cast
to a BOOLEAN: 0 becomes false and all other values
become true. The SQL Standard does not allow these comparisons
because the underlying cast is illegal.
In Target Release, Derby behavior changes to conform to the SQL
Standard:
- Derby raises a syntax error when asked to compare a number to a BOOLEAN.
In Derby 10.3, the ODBC metadata queries depend on the ability to perform
a non-ANSI cast from a BOOLEAN to an INT. These queries
are rewritten in Target Release to use a CASE clause
instead. E.g.:
select
case
when boolcol then 1
when not boolcol then 0
else null
end
...
;
Several
DatabaseMetaData
methods return datatype information:
All of these
ResultSets
have a column, DATA_TYPE, which contains the type ID
of the described column/parameter/result.
Another field in this row, TYPE_NAME, contains the server's
name for the datatype of the described column/parameter/result.
In Target Release, these columns contain the following values
for BOOLEAN columns/parameters/results:
Appendix B
describes the old behavior of these
DatabaseMetaData
methods.
Two
ResultSetMetaData
methods describe type information for the columns returned by queries:
These methods return the following values for BOOLEAN columns
when either the client and server are at Derby
Target Release or higher:
Appendix C describes legacy behavior. Note that jdk 1.3 is not a
supported platform for Target Release.
JDK 1.4 introduced the
ParameterMetaData
interface with the following
methods which describe type information for ? query parameters:
These methods return the following values for BOOLEAN parameters:
See
Appendix D
for a description of how the
ParameterMetaData
methods behave in earlier Derby releases.
Appendix E
describes the old behavior of getXXX() methods on
BOOLEAN columns in
ResultSets.
Note that embedded and client/server behavior differ for two methods:
getString()
and
getObject().
The getXXX() methods of
ResultSet
and
CallableStatement
continue to behave as described in Appendix E
UNLESS both the client and server are at Target Release or
higher. In that case, the old embedded behavior prevails and
getString()
and
getObject()
behave as follows:
getXXX() on BOOLEANs
|
When both client and server are at Target Release or higher |
| getString() |
| null |
null |
| false |
"false" |
| true |
"true" |
|
| getObject() |
|
Appendix F
describes the old behavior of setXXX() methods on
BOOLEAN columns in
PreparedStatements.
If both the client and server are at Target Release, then
setXXX() methods on
PreparedStatements
and
CallableStatements
conform to the embedded behavior described in
Appendix F.
Otherwise, these methods behave according to the Derby client and
DB2JCC behavior described in
Appendix F.
After a soft-upgrade to Target Release, you see the following
changes introduced by this spec:
| Scenario |
Old behavior |
New behavior |
Customer needs to make these changes... |
| JDBC Behavior |
Datatype identification and getter/setter methods behaved as
described in
Appendix B,
Appendix C,
Appendix D
Appendix E
and
Appendix F.
|
Datatype identification and getter/setter methods behave
differently if both the client and
server are at Target Release.
|
The customer's application may need to be recoded to expect
the Target Release type identification and JDBC
getter/setter behavior. |
| Casts from BOOLEAN |
BOOLEAN could be cast to various datatypes, contrary
to the ANSI rules. In addition BOOLEANs were
implicitly cast to numerics in comparisons with
numbers. In addition casting a BOOLEAN to a string
type resulted in a lowercase "true" or "false". |
ANSI casting rules enforced:
BOOLEANs can only be cast to string types. BOOLEANs cannot be compared to
numbers. The result of casting a BOOLEAN to a
string type is an uppercase "TRUE" or "FALSE". |
The customer may need to rewrite her queries to eliminate
non-ANSI casts and illegal comparisons of BOOLEANs
to numbers. |
| ODBC Metadata Queries |
Relied on non-ANSI casting of BOOLEAN to INT. |
Uses CASE clauses to convert BOOLEAN to
INT. The upgrade behavior of metadata queries is
described on the
Metadata and Upgrade wiki page.
|
No action needed. |
After a hard-upgrade to Target Release, you also see the following behavior:
| Scenario |
Old behavior |
New behavior |
Customer needs to make these changes... |
| BOOLEAN columns/arguments/returnValues |
Not recognized in old releases. The user could not create
tables/functions/procedures with BOOLEAN
columns/arguments/returnValues.
|
Now you can create tables/functions/procedures with
BOOLEAN columns/arguments/returnValues. |
No action needed. |
| Casts to BOOLEAN |
Explicit casts to BOOLEAN were not allowed. |
ANSI casting rules enforced: String types can be cast
explicitly to
BOOLEAN. |
No action needed. |
This new behavior will require changes to the user guides:
- Reference Guide
- Data types - This section needs a sub-section on the
BOOLEAN datatype.
- Data type assignments and comparison, sorting, and
ordering - We need to add
BOOLEAN to the tables in this section, listing the
legal casts.
We need a release note for this feature. The release note should describe:
- Casts - Changes to casting behavior.
- JDBC - Changes to JDBC behavior.
The following script demonstrates the BOOLEAN casting behavior
in Derby 10.3:
--
-- supported
--
select
cast (systemalias as SMALLINT),
cast (systemalias as INTEGER),
cast (systemalias as BIGINT),
cast (systemalias as DECIMAL),
cast (systemalias as NUMERIC),
cast (systemalias as REAL),
cast (systemalias as DOUBLE),
cast (systemalias as FLOAT),
cast (systemalias as CHAR(1)),
cast (systemalias as VARCHAR(1)),
cast (systemalias as LONG VARCHAR),
cast (systemalias as CLOB),
cast (systemalias as char(1) for bit data),
cast (systemalias as varchar(1) for bit data),
cast (systemalias as long varchar for bit data),
xmlserialize( cast (systemalias as xml) as clob),
cast (systemalias as BLOB)
from sys.sysaliases
where 0=1;
--
-- NOT supported
--
select
cast (systemalias as date)
from sys.sysaliases
where 0=1;
select
cast (systemalias as time)
from sys.sysaliases
where 0=1;
select
cast (systemalias as timestamp)
from sys.sysaliases
where 0=1;
--
-- Result of casting booleans to character types
-- is a lowercase value although ANSI specifies uppercase.
-- Fixed length character types are correctly padded with
-- trailing spaces.
--
select
cast (systemalias as CHAR(8)) || 'foo',
cast (systemalias as VARCHAR(8)) || 'foo',
cast (systemalias as LONG VARCHAR),
cast (systemalias as CLOB)
from sys.sysaliases
where alias='SYSCS_IMPORT_TABLE';
--
-- Correctly raises truncation exceptions.
--
select
cast (systemalias as CHAR(3))
from sys.sysaliases
where alias='SYSCS_IMPORT_TABLE';
select
cast (systemalias as VARCHAR(3))
from sys.sysaliases
where alias='SYSCS_IMPORT_TABLE';
--
-- Comparing booleans to numbers. Should raise
-- a syntax error but Derby tolerates this syntax.
-- The number is implicitly cast to a boolean: 0 becomes
-- false and all other values become true.
--
select systemalias
from sys.sysaliases
where systemalias = 1;
select systemalias
from sys.sysaliases
where systemalias < -1;
The following table describes casts from BOOLEAN to target
datatypes. Note the discrepancy between the ANSI casting
behavior and the casting behavior observed in Derby 10.3.
Explicit Casts: X marks allowed casts
| Target Datatype |
Derby 10.3 |
ANSI |
| from BOOLEAN to BIGINT |
X |
- |
| from BOOLEAN to BLOB |
X |
- |
| from BOOLEAN to CHAR |
X |
X |
| from BOOLEAN to CHAR FOR BIT DATA |
X |
- |
| from BOOLEAN to CLOB |
X |
X |
| from BOOLEAN to DATE |
- |
- |
| from BOOLEAN to DECIMAL |
X |
- |
| from BOOLEAN to DOUBLE |
X |
- |
| from BOOLEAN to DOUBLE PRECISION |
X |
- |
| from BOOLEAN to FLOAT |
X |
- |
| from BOOLEAN to INTEGER |
X |
- |
| from BOOLEAN to LONG VARCHAR |
X |
X |
| from BOOLEAN to LONG VARCHAR FOR BIT DATA |
X |
- |
| from BOOLEAN to NUMERIC |
X |
- |
| from BOOLEAN to REAL |
X |
- |
| from BOOLEAN to SMALLINT |
X |
- |
| from BOOLEAN to TIME |
- |
- |
| from BOOLEAN to TIMESTAMP |
- |
- |
| from BOOLEAN to VARCHAR |
X |
X |
| from BOOLEAN to VARCHAR FOR BIT DATA |
X |
- |
| from BOOLEAN to XML |
X |
- |
The following table describes casts from source datatypes to BOOLEAN.
Note the discrepancy between the ANSI casting
behavior and the casting behavior observed in Derby 10.3.
Explicit Casts: X marks allowed casts
| Target Datatype |
Derby 10.3 |
ANSI |
| from BIGINT to BOOLEAN |
- |
- |
| from BLOB to BOOLEAN |
- |
- |
| from CHAR to BOOLEAN |
- |
X |
| from CHAR FOR BIT DATA to BOOLEAN |
- |
- |
| from CLOB to BOOLEAN |
- |
X |
| from DATE to BOOLEAN |
- |
- |
| from DECIMAL to BOOLEAN |
- |
- |
| from DOUBLE to BOOLEAN |
- |
- |
| from DOUBLE PRECISION to BOOLEAN |
- |
- |
| from FLOAT to BOOLEAN |
- |
- |
| from INTEGER to BOOLEAN |
- |
- |
| from LONG VARCHAR to BOOLEAN |
- |
X |
| from LONG VARCHAR FOR BIT DATA to BOOLEAN |
- |
- |
| from NUMERIC to BOOLEAN |
- |
- |
| from REAL to BOOLEAN |
- |
- |
| from SMALLINT to BOOLEAN |
- |
- |
| from TIME to BOOLEAN |
- |
- |
| from TIMESTAMP to BOOLEAN |
- |
- |
| from VARCHAR to BOOLEAN |
- |
X |
| from VARCHAR FOR BIT DATA to BOOLEAN |
- |
- |
| from XML to BOOLEAN |
- |
- |
The following table describes the values of the DATA_TYPE and
TYPE_NAME fields returned by
DatabaseMetaData.getColumns()
for SYS.SYSALIASES.SYSTEMALIAS
in various combinations of Derby clients, servers, and VMs. These are
the results for Derby 10.2 and earlier.
DatabaseMetaData.getColumns()
|
Server / 1.3 |
Server / 1.4 |
| Embedded |
|
|
| DerbyClient / 1.3 |
|
|
| DerbyClient / 1.4 |
|
|
| DB2JCC / 1.3 |
|
|
| DB2JCC / 1.4 |
|
|
The following table describes the values of the
getColumnType()
and
getColumnTypeName()
methods of the
ResultSetMetaData
returned for the query "select systemalias from sys.sysaliases"
in various combinations of Derby clients, servers, and VMs. These are
the results for Derby 10.2 and earlier.
ResultSetMetaData methods
|
Server / 1.3 |
Server / 1.4 |
| Embedded |
|
|
| DerbyClient / 1.3 |
|
|
| DerbyClient / 1.4 |
|
|
| DB2JCC / 1.3 |
|
|
| DB2JCC / 1.4 |
|
|
I do not know of any legal way for an old version of Derby to compile a SQL
statement with a parameter which has type
BOOLEAN. However, as of the writing of this spec, bug
DERBY-2605
allows you to create user tables with BOOLEAN columns in the mainline.
The following table describes the values of the
getParameterType()
and
getParameterTypeName()
methods of the
ParameterMetaData
returned for the statement "insert into foo( boolcol ) values ( ? )"
thanks to this bug:
ParameterMetaData methods
|
Method results |
| Embedded |
|
| Derby client |
|
| DB2JCC client |
|
Here is how
ResultSet
getXXX() methods behave on BOOLEAN columns in Derby 10.3
and earlier. Note that the embedded and client/server behavior
is identical except for
getString()
and
getObject().
I do not know of any legal way for an old version of Derby to compile a SQL
statement which inserts into a
BOOLEAN column. However, as of the writing of this spec, bug
DERBY-2605
allows you to create user tables with BOOLEAN columns in the mainline.
The following table describes the behavior of various
PreparedStatement
setXXX() methods
for the statement "insert into foo( boolcol ) values ( ? )",
thanks to this bug. Derby embedded and client behavior
mostly agree. DB2JCC behavior, however, diverges. Differences
from the embedded behavior are marked in gold.
ResultSet.setXXX() behavior for BOOLEANs
|
Embedded |
Derby client |
DB2JCC client |
| setBigDecimal() |
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| setByte() |
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| setDouble() |
| Value set by client |
Value actually inserted |
| 0.0 |
false |
| 1.0 |
true |
| 2.0 |
true |
|
| Value set by client |
Value actually inserted |
| 0.0 |
false |
| 1.0 |
true |
| 2.0 |
true |
|
| Value set by client |
Value actually inserted |
| 0.0 |
false |
| 1.0 |
true |
| 2.0 |
false |
|
| setFloat() |
| Value set by client |
Value actually inserted |
| 0.0 |
false |
| 1.0 |
true |
| 2.0 |
true |
|
| Value set by client |
Value actually inserted |
| 0.0 |
false |
| 1.0 |
true |
| 2.0 |
true |
|
| Value set by client |
Value actually inserted |
| 0.0 |
false |
| 1.0 |
true |
| 2.0 |
false |
|
| setInt() |
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| setLong() |
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| setObject() |
| Value set by client |
Value actually inserted |
| new Integer( 0 ) |
false |
| new Integer( 1 ) |
true |
| new Integer( 2 ) |
true |
| "FALSE" |
false |
| "TRUE" |
true |
| "false" |
false |
| "true" |
true |
| new Boolean( false ) |
false |
| new Boolean( true ) |
true |
|
| Value set by client |
Value actually inserted |
| new Integer( 0 ) |
false |
| new Integer( 1 ) |
true |
| new Integer( 2 ) |
true |
| "FALSE" |
false |
| "TRUE" |
true |
| "false" |
false |
| "true" |
true |
| new Boolean( false ) |
false |
| new Boolean( true ) |
true |
|
| Value set by client |
Value actually inserted |
| new Integer( 0 ) |
false |
| new Integer( 1 ) |
true |
| new Integer( 2 ) |
false |
| "FALSE" |
ERROR |
| "TRUE" |
ERROR |
| "false" |
ERROR |
| "true" |
ERROR |
| new Boolean( false ) |
false |
| new Boolean( true ) |
true |
|
| setShort() |
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
true |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| Value set by client |
Value actually inserted |
| 0 |
false |
| 1 |
true |
| 2 |
false |
|
| setString() |
| Value set by client |
Value actually inserted |
| "FALSE" |
false |
| "TRUE" |
true |
| "false" |
false |
| "true" |
true |
| "baffle" |
ERROR |
|
| Value set by client |
Value actually inserted |
| "FALSE" |
false |
| "TRUE" |
true |
| "false" |
false |
| "true" |
true |
| "baffle" |
ERROR |
|
| Value set by client |
Value actually inserted |
| "FALSE" |
ERROR |
| "TRUE" |
ERROR |
| "false" |
ERROR |
| "true" |
ERROR |
| "baffle" |
ERROR |
|
| setNull() |
|
|
|