SQL Dialects - Design Specification
See also: Functional Specification
High-Level Design
The InterVase V6.0 engine depends on SQL Dialects to unambiguously support Delimited Identifiers, SQL Date/Time/Timestamp, and 64 bit numerics. InterBase applications need a way to specify SQL Dialects so that they can make use of these new features. SQL Dialect can be set by either using -s[sldialect] or by the SET SQL DIALECT statement. There is no default Client SQL Dialect except for CREATE DATABASE and the default value is SQL Dialect 2. Otherwise the client SQL Dialect is set to the Database SQL Dialect after the connection to the database is made. The Client SQL Dialect could be reset by the SET SQL DIALECT statement (see the functional spec for detail).
High-Level Algorithm
The SQL dialect is activated/deactivated by '-sqldialect n' command line option or by 'SET SQL DIALECT n' statement where n is:
- 1 - InterBase parser processes as it did in InterBase V5. e.g.: a string constant could be delimited either by single quotes or double quotes
- 2 - transitional flagger. InterBase V6 flags ambiguous SQL constructs and issues an error or warning message. e.g.: InterBase V6 flags any thing that is delimited by double quotes and issues an error message stating that 'a string constant must be delimited by single quotes' accompanied by a SQLCODE -104, SQLSTATE 42501.
- 3 - It processes anything delimited by single quotes as string constants and any thing delimited by double quotes as SQL delimited identifiers.
A new field - RDB$FIELD_PRECISION is added to RDB$FIELDS system table and is to be used by the 64-bit numeric project.
RDB$FIELD_PRECISION is only available in ODS 10 databases. When an application connects to a pre ODS 10 database, RDB$FIELD_PRECISION is removed from internal memory. When backing up and restoring a pre ODS 10 database, RDB$FIELD_PRECISION is added to the ODS 10 database.
One of the requirements of this project is that existing applications should not break. This requires that GBAK must also address this issue.
The following APIs also must be able to speak the old and new dialect:
- isc_dsql_describe
- isc_dsql_describe_bind
- isc_dsql_execute, isc_dsql_execute2
- isc_dsql_execute_immediate
- isc_dsql_execute_immed2
- isc_dsql_fetch
- isc_dsql_fetch2
- isc_dsql_prepare
To support this feature, GPRE needs to to know what dialect the user intends to speak and generates the API that speaks that specified dialect.
New 'SHOW SQL DIALECT' statement is added to InterBase V6 ISQL to show the current Client SQL Dialect setting and Database SQL Dialect value.
New 'isc_dbp_SQL_dialect' parameter is added to the InterBase V6 and to be used with isc_create_database API to create a database.
New 'isc_info_db_SQL_dialect' parameter is added to the InterBase V6 and to be used with isc_database_info API to query the database's dialect.
A new command option -set_db_SQL_dialect is added to InterBase V6 GFIX. This command line option can be used to set a ODS 10 database speaking only SQL dialect 1 or 3.
Data Structures/Class Hierarchy
New #define constructs in ibase.h:
#define SQLDA_VERSION1 1
#define SQLDA_VERSION2 2
#define SQL_DIALECT_V5 1
#define SQL_DIALECT_V6_TRANSITION 2
#define SQL_DIALECT_V6 3
#define SQL_DIALECT_CURRENT SQL_DIALECT_V6
#define isc_dpb_SQL_dialect 63
#define isc_info_db_SQL_dialect 62
error messages:
Error Code Number SQLCODE Message isc_invalid_string_constant 335544763 -104 a string constant is delimited by double quotes
Detailed Design
Internal Data Structures
burp/burp.h:
add att_SQL_dialect and att_field_precision to the att_type enumeration constant
dsql/dsql.h:
add dbb_db_SQL_dialect to the DBB database block definition
isql/isql.h:
add EXTERN USHORT SQL_dialect
jrd/jrd.h:
add the following to bit values for dbb_flags:
#define DBB_DB_SQL_dialect 0X1000L
jrd/names.h:
add NAME ("RDB$FIELD_PRECISION", nam_f_precision)
jrd/ods.h:
- add "#define ODS_VERSION10 10"
- add "#define ODS_CURRENT10 0"
- add "#define ODS_10_0 ENCODE_ODS (ODS_VERSION10, 0)"
- change "#define ODS_VERSION ODS_VERSION9" to "#define ODS_VERSION ODS_VERSION10"
- change "#define ODS_CURRENT ODS_CURRENT9" to "#define ODS_CURRENT ODS_CURRENT10"
- change "#define ODS_CURRENT_VERSION ODS_9_1" to "#define ODS_CURRENT_VERSION ODS_10_0"
- add #define hdr_SQL_dialect 256 as one of the header page flag
dsql/parse_proto.h:
change dsql_yyparse (void) to dsql_yyparse (USHORT, USHORT)
dsql/prepa_proto.h:
add one more parameter USHORT to the proto type definition of PREPARSE_execute function
jrd/relations.h:
add FIELD(f_fld_precision, nam_f_precision, fld_f_position, 1, 0, 0, 0) to RELATION(nam_fields, ...)/RDB$FIELDS
dsql/parse.sed:
- add s/yylex(void)/yylex (USHORT, USHORT)/g
- add s/yylex()/yylex(client_dialect, db_dialect)/g
- add s/dsql_yyparse(void)/dsql_yyparse(client_dialect, db_dialect)/g
- add s/dsql_yyparse()/dsql_yyparse(client_dialect, db_dialect)/g
- add s/YYLEX()/YYLEX(client_dialect, db_dialect)/g
Detailed Algorithm
isql/isql.e:
Replace all hard coded dialect 1 parameter with SQL_dialect (where the SQL_dialect is the client SQL dialect set by user) for the following APIs:
- isc_dsql_describe
- isc_dsql_execute
- isc_dsql_execute2
- isc_dsql_execute_immediate
- isc_dsql_exec_immed2
- isc_dsql_fetch
- isc_dsql_fetch2
- isc_dsql_prepare
ISQL_get_version:
- add isc_info_db_SQL_dialect to db_version_info parameter block.
- Query the database information by executing isc_database_info with the updated db_version_info parameter block
- Process the isc_database_info output buffer to extract the ODS version info and database SQL dialect info.
- Store the database dialect info into dialect_spoken
frontend:
if the input parameters are "SET" "SQL" "DIALECT" { if the dialect < 1 or dialect > 3 issue error message otherwise save the dialect info into SQL_dialect }
create_db:
- if the client dialect was not set, then pass SQL dialect 2 as one of the parameter when invoking isc_dsql_execute_immediate.
- otherwise pass the client SQL dialect as one of the parameter when invoking isc_dsql_execute_immediate.
parse_arg:
- initialize SQL_dialect as SQL_DIALECT_V6_TRANSITION
- process "-sqldialect n"
- issues error messages/USAGE1/USAGE2 when n < 1 or n > 3
- save the command line dialect info into SQL_dialect
isql/show.e/show_dialect:
- display client SQL dialect setting
- getting database SQL dialect info by passing isc_info_db_SQL_dialect parameter to isc_database_info function
- display database SQL dialect
dsql/dsql.c
add isc_info_db_SQL_dialect to db_version_info parameter block
init:
- get the database SQL dialect info by invoking isc_database_info function
- get the database SQL dialect info by extract database SQL dialect in out off the isc_database_info output buffer
- save the database SQL dialect info into dbb_db_SQL_dialect
prepare:
- verify the client dialect that was passed in is dialect 0 - 3
- invoke dsql_yyparse by passing client_dialect and dbb_db_SQL_dialect
dsql/parse.y/yylex:
- change "yylex PROTO ((void))" to "yylex PROTO ((USHORT, USHORT))"
- change "yylex (void)" to "yylex (USHORT client_dialect, USHORT db_dialect)"
jrd/why.c
GDS_DSQL_EXEC_IMM2_m:
pass one more parameter --- dialect when invoking PREPARE_execute
get_sqlda_buffer:
change "else if (dialect & 1)" to "else if (dialect > DIALECT_xsqlda)"
dsql/preparse.c:
PREPARSE_execute:
- add one more parameter --- dialect
- when NO_MORE_TOKEN then adds isc_dpb_SQL_dialect/dialect to DPB stream
- invoke isc_create_database (dialect is part of the dpb stream)
dsql/utld.c:
UTLD_parse_sql_info:
change "if ((dialect & 1)==DIALECT_xsqlda)" to "if (dialect >=DIALECT_xsqlda)"
UTLD_parse_sqlda:
change "if ((dialect & 1)==DIALECT_xsqlda)" to "if (dialect >=DIALECT_xsqlda)"
jrd/ini.e:
INI_init2:
when field_name is RDB$FIELD_PRECISION and the database is ODS 10 or greater, then increment field counter n
jrd/jrd.c:
add dpb_SQL_dialect to DPB (Option block for database parameter block)
GDS_CREATE_DATABASE:
if (options.dpb_SQL_dialect !=SQL_DIALECT_V5) set dbb->dbb_flags ||=DBB_DB_SQL_dialect
get_options:
- extracting SQL dialect info out off the DPB
- assign it to options->dpb_SQL_dialect
jrd/pag.c:
PAG_format_header:
if (dbb->dbb_flags & DBB_DB_SQL_dialect) set header->hdr_flags |=hdr_SQL_dialect
PAG_header:
if the header ODS version is not ODS_VERSION8 or ODS_VERSION9 or ODS_VERSION10 then issue gds__wrong_ods message if (header->hdr_flags & hdr_SQL_dialect) set dbb->dbb_flags |=DBB_DB_SQL_dialect.
jrd/inf.c:
INF_database_info:
loop of processing DPB ... case isc_info_SQL_dialect if db >=ODS_10_0 then if (dbb->dbb_flags & DBB_DB_SQL_dialect) then passes back SQL_DIALECT_V6 as database SQL dialect else passes back SQL_DIALECT_V5 as database SQL dialect else passes back SQL_DIALECT_V5 as database SQL dialect end-loop
burp/backup.e:
add "#define BCK_ods10 8912
add '"RDB$FIELDS", "RDB$FIELD_PRECISION", BCK_ods10, 0, 0, 0' to rfr_table structure
add isc_info_db_SQL_dialect to db_info_items parameter block
write_database:
- invoke gds__database_info
- extract database SQL dialect info from the gds__database_info output buffer
- write out the database SQL dialect into to logical database record
write_global_fields:
add "(tdgbl->BCK_capabilities & BCK_ods10)" as part of the tdgbl->BCK_capabilities test
if tdgbl->BCK_capabilities is BCK_ods8 and BCK_ods10 backup the data of RDB$FIELD_PRECISION else if (tdgbl->BCK_capabilities & BCK_ods10) backup the data of RDB$FIELD_PRECISION
burp/restore.e:
create_database:
- read database record
- extract database SQL dialect info out off the logical database record
- build the DPB stream with addition database SQL dialect info
- invokes isc_create_database with DPB stream
get_global_field:
- set RDB$FIELD_PRECISION.NULL=TRUE
- when attribute is att_field_precision:
- set RDB$FIELD_PRECISION.NULL=FALSE
- RDB$FIELD_PRECISION=get_numeric ()
New/Affected Modules
dsql:
- dsql.h
- parse_proto.h
- prepa_proto.h
- parse.y
- parse.sed
- dsql.c
- preparse.c
- utld.c
isql:
- isql.h
- isql.e
- show.e
jrd:
- jrd.h
- ods.h
- ibase.h
- relations.h
- names.h
- jrd.c
- ini.e
- why.c
- pag.c
- inf.c
burp:
- burp.h
- backup.e
- restore.e
Testing Considerations
CREATE/ALTER TABLE Statement:
- column with domain as default value
- column with default value
- column with constraint (column/table level check constraints)
- column with computed by clause
- default value was in the domain
CREATE VIEW Statements
CREATE/ALTER TRIGGER/PROCEDURE Statements
Connecting to pre ODS 10 database with -sqldialect 3 command line option
Connecting to ODS 10 database
- backed up and restored ODS 10 database from pre ODS 10 database with -sqldialect n (where n=1, 2, or 3) command line option
- ODS 10 database (created with IB V6.0) with -sqldialect n (where n=1, 2, or 3) command line option
- backed up and restored ODS 10 database from ODS 10 database with -sqldialect n (where n=1, 2, or 3) command line option
change dialect value with SET DIALECT statements after connecting to a database
GBAK
- backs up and restores pre ODS 10 database
- backs up and restores ODS 10 database (the database was backed up and restored from pre ODS 10 database)
- backs up and restores ODS 10 database (the database was created with IB V6.0)
API applications
- existing API apps against ODS 10 database that was backed up and restored from pre ODS 10 database
- API apps mixed with old/new dialect against ODS 10 database that was backed up and restored from pre ODS 10 database
GPRE applications
- existing GPRE apps against ODS 10 database that was backed up and restored from pre ODS 10 database
- API apps mixed with old/new dialect against ODS 10 database that was backed up and restored from pre ODS 10 database