BFSQL
BFSQL
BFSQL
Table of Contents
Preface 1
Overview 3
System Architecture 7
Establishing Connections 23
SQL Reference 75
Troubleshooting 137
Index a
iii
1 Blackfish SQL
1 Preface
This Preface describes the manual, lists technical resources, and provides CodeGear contact information.
Intended Audience
This document is for:
• Java programming
• DataExpress
• JDBC
• SQL
Document Conventions
This document uses the following typographic conventions:
1
Blackfish SQL 1
To discuss issues with other Blackfish SQL users, visit the Blackfish newsgroups at:
http://support.codegear.com/forums/directory/Blackfish.
CodeGear Support
CodeGear offers a variety of support options for Blackfish SQL. For pre-sales support, installation support, and a variety of
technical support options, visit: http://support.codegear.com.
When you are ready to deploy Blackfish SQL, you may need additional deployment licenses. To purchase licenses and
upgrades, visit the CodeGear Online Shop at: http://shop.codegear.com.
Additional Resources
Useful technical resources include:
JDBC
• A Guide to The SQL Standard, by C. J. Date and Hugh Darwen; published by Addison Wesley
DataExpress JavaBeans
• DataExpress Component Library Reference in the Blackfish SQL for Java Help
See Also
Overview ( see page 3)
Using Stored Procedures and User Defined Functions ( see page 41)
2
2 Blackfish SQL
2 Overview
This chapter describes Blackfish SQL features.
• Blackfish SQL
• Blackfish SQL DataStore
• Compatibility Between Windows and Java
• Blackfish SQL for Java Connectivity
• Blackfish SQL API for Windows
• Administration and Utility Functions Available from SQL
Blackfish SQL
Blackfish™ SQL is a high-performance, small-footprint, transactional database. Blackfish SQL was originally implemented as an
all-Java database called JDataStore. This is now called Blackfish SQL for Java. Blackfish SQL was then ported from Java to C#.
The C# implementation is called Blackfish SQL for Windows.
The design and implementation of Blackfish SQL emphasizes database performance, scalability, ease of use, and a strong
adherence to industry standards. Blackfish SQL capabilities include the following:
3
Blackfish SQL 2
For additional information about Blackfish SQL compatibility, see System Architecture.
• DBXClient: This 100% Object Pascal dbExpress 4 database driver enables C++ and Win32 Delphi applications to connect to
a remote Blackfish SQL for Windows or Blackfish SQL for Java server.
• Local ADO.NET 2.0 Provider: This 100% managed code driver enables .NET applications to connect to a local Blackfish
SQL for Windows server. The local ADO.NET driver executes in the same process as the BlackFish SQL database kernel, for
better performance.
• Remote ADO.NET 2.0 Provider: This 100% managed code driver enables .NET applications to acquire a remote connection
to either a Blackfish SQL for Windows or Blackfish SQL for Java server.
For instructions on using these drivers, see Establishing Connections.
The administrative capabilities listed below are not yet supported in DataExplorer for Blackfish SQL for Windows. Use SQL
commands or Blackfish SQL built-in DB_ADMIN stored procedures to complete these tasks.
4
2 Blackfish SQL
DB_ADMIN Class
DB_ADMIN is a group of stored procedures for performing a variety of database administration tasks. Some of the capabilities
include:
DB_UTIL Class
DB_UTIL is a set of SQL stored procedures for performing numeric, string and date/time operations on data stored in database
tables. These procedures include such functions as:
ADO.NET
Blackfish SQL includes an ADO.NET implementation. This is similar to the AdoDbx Client, which is also an ADO.NET
implementation.
5
Blackfish SQL 2
Using Stored Procedures and User Defined Functions ( see page 41)
6
3 Blackfish SQL
3 System Architecture
This chapter provides an overview of Blackfish SQL system architecture.
• Compatibility
• Windows Connectivity
• Java Connectivity
• Differences Between Local and Remote Drivers
• Database Files
• Database File System
• Transaction Management
• High Availability
• Heterogeneous Replication Using DataExpress
Blackfish SQL Compatibility
Blackfish SQL for Windows and Blackfish SQL for Java are compatible in these ways:
• The Object type uses platform-specific serialization; therefore the data cannot be shared between two different clients:
• An ADO driver cannot read a Java serialized object.
• A Java driver cannot read a .NET serialized object.
• A DbxClient driver cannot read Java or .NET serialized objects.
• The maximum scale for a decimal is different in Java and .NET.
• For Blackfish SQL for Java, the Timestamp type has two more digits in the fractional portion.
The following Blackfish SQL for Java features are not yet supported in the Windows version:
7
Blackfish SQL 3
• DBXClient DBXClient is a 100% Object Pascal dbExpress 4 database driver that enables Win32 Delphi and C++
applications to connect to a Blackfish SQL for Windows or Blackfish SQL for Java server.
• ADO.NET ADO.NET is the Microsoft standard for database connectivity on the .NET platform. Blackfish SQL for Windows has
the following ADO.NET providers:
• Local ADO.NET 2.0 Provider: This 100% managed code driver enables .NET applications to connect to a local Blackfish
SQL server. The local ADO.NET driver executes in the same process as the BlackFish SQL database kernel, for better
performance.
• Remote ADO.NET 2.0 Provider: This 100% managed code driver enables .NET applications to acquire a remote
connection to either a Blackfish SQL for Windows or Blackfish SQL for Java server.
See Establishing Connections for instructions and code examples for using these drivers.
• JDBC Type 4 Drivers JDBC is the industry standard SQL call-level interface for Java applications. Blackfish SQL for Java
provides the following JDBC drivers:
• Local JDBC driver: This 100% managed code driver enables Java applications to connect to a local Blackfish SQL server.
The local JDBC driver executes in the same process as the BlackFish SQL database kernel, for better performance.
• Remote JDBC driver: This 100% managed code driver enables Java applications to acquire a remote connection to either
a Blackfish SQL for Windows or Blackfish SQL for Java server.
• ODBC to JDBC Gateway Provided by EasySoft Limited, this gateway is an industry standard SQL call-level interface. The
EasySoft ODBC to JDBC Gateway enables native applications to access Blackfish SQL databases.
• DataExpress JavaBeans DataExpress JavaBeans provides additional functionality not addressed by the JDBC standard.
See DataExpress JavaBeans for details.
See Establishing Connections for instructions and code examples for using these drivers.
DataExpress JavaBeans
NOTE: This feature is available only with Blackfish SQL for Java.
DataExpress is a set of JavaBean runtime components that provide functionality not addressed by the JDBC standard.
JavaBean is an industry-standard component architecture for Java. The JavaBean standard specifies many important aspects of
components needed for RAD development environments. JavaBean components can be designed in a visual designer and can
be customized with the properties, methods, and events that they expose.
DataExpress is included in the component palette of CodeGear JBuilder Visual Designer. For information on using DataExpress
from within JBuilder, see the JBuilder Help.
Because DataExpress is a set of runtime components, you need not use JBuilder to develop and deploy applications that use
DataExpress.
The majority of DataExpress JavaBean components are those required to build both server-side and client-side database
8
3 Blackfish SQL
applications. Client-side applications require high quality data binding to visual components such as grid controls, as well as
support for reading and writing data to a database.
Server-side applications require data access components to help with reading and writing data to a database, but presentation is
typically handled by a web page generation system such as Java Server Pages (JSPs). Even though DataExpress has extensive
support for client-side data binding to visual component libraries such as dbSwing and JBCL, the DataExpress design still
separates the presentation from the data access layer. This allows DataExpress components to be used as a data access layer
for other presentation paradigms such as the JSP/servlet approach employed by JBuilder InternetBeans Express technology.
The DataExpress architecture allows for a pluggable storage interface to cache the data that is read from a data source.
Currently, there are only two implementations of this interface, MemoryStore (the default), and DataStore. By setting just two 3
properties on a StorageDataSet JavaBean component, a Blackfish SQL table can be directly navigated and edited with a
StorageDataSet JavaBean. By setting the DataSet property of a dbSwing grid control, the entire contents of large tables can
be directly browsed, searched, and edited at high speed. This effectively provides an ISAM-level data access layer for Blackfish
SQL tables.
Task Component
Custom server start and shutdown com.borland.datastore.jdbc.DataStoreServer
Database backup, restore, and pack com.borland.datastore.DataStoreConnection.copyStreams()
Security administration com.borland.datastore.DataStoreConnection
Transaction management com.borland.datastore.TxManager com.borland.datastore.DataStore
• Local driver: The Blackfish SQL database engine executes in the same process as the application.
• Remote driver: The Blackfish SQL database engine executes in either the same process or in a different process as the
application.
• High-speed interface to the database Driver calls are made directly into the database kernel on the same call stack. There
are no remote procedure calls to a database server running in another process.
• Easy to embed in an application The database server does not need to be configured or started. The executable code for
the database kernel, database driver and application execute in the same process.
9
Blackfish SQL 3
• Multi process access to a database If multiple processes on one or more computers need to access a single Blackfish SQL
database, a Blackfish SQL server must be started and the remote drivers must be used by the application.
• Improved performance using multiple computers If your application or web server is consuming a large portion of the
3 memory or CPU resources, it is often possible to achieve better performance by running the Blackfish SQL server on a
separate computer.
• Improved fault tolerance Applications that use a remote connection typically run in a separate process. Errant applications
can be terminated without having to shutdown the database server.
Since the local driver causes the database file to be open in the same process, it prevents connections from the remote driver.
However, if the process that uses the local driver also starts a Blackfish SQL server in the same process, then other processes
using the remote driver can access the same database as the local driver.
The Blackfish SQL server can be started inside an application by using a single line of Java code that instantiates a
DataStoreServer component and executes its start method. The DataStoreServer runs on a separate thread and
services connection requests from processes that use the remote driver to access a Blackfish SQL database on the computer
that on which the DataStoreServer was started.
In addition, the local driver can be used by the application that launched the DataStoreServer for faster in-process driver calls
into the Blackfish SQL database engine.
A non-transactional (read only) database only needs the .jds database file.
Specification Value
Minimum block size: 1 KB
Maximum block size: 32 KB
Default block size 4 KB
10
3 Blackfish SQL
Maximum Blackfish SQL database file size 2 billion blocks. For the default block size, that yields a maximum of
8,796,093,022,208 bytes (8TB).
Maximum number of rows per table stream 281,474,976,710,656
Maximum row length 1/3 of the block size. Long Strings, objects, and input streams that are
stored as Blobs instead of occupying space in the row.
Maximum Blob size 2GB each
Maximum file stream size 2GB each
3
Blackfish SQL Database File System
A Blackfish SQL database file can contain these types of data streams:
• Table streams: These are database tables typically created using SQL. A table stream can have secondary indexes and
Blob storage associated with it.
• File streams: There are two types of file streams:
• Arbitrary files created with DataStoreConnection.createFileStream()
• Serialized Java objects stored as file streams
A single Blackfish SQL database can contain all stream types.
Streams are organized in a file system directory. The ability to store both tables and arbitrary files in the same file system allows
all of the data for an application to be contained in a single portable, transactional file system. A Blackfish SQL database can
also be encrypted and password protected.
Specification Value
Directory separator /
character for streams
Maximum stream name 192 bytes
length
• Best case (all single-byte character sets): 192 characters
• Worst case (all double-byte character sets): 95 characters (one byte lost to indicate DBCS)
Reserved names Stream names that begin with SYS are reserved. Blackfish SQL has the following system tables:
• SYS/Connections
• SYS/Queries
• SYS/Users
If the resolvable property for the table is set, all insert, update, and delete operations made against the table are recorded.
This edit tracking feature enables DataExpress components to synchronize changes from a replicated table to the database from
which the table was replicated.
File streams are random-access files. File streams can be further broken down into two different categories:
• Arbitrary files created with DataStoreConnection.createFileStream(): You can write to, seek in, and read from these
11
Blackfish SQL 3
streams.
• Serialized Java objects stored as file streams: You can write to, seek in, and read from these streams.
Each stream is identified by a case-sensitive name referred to as a storeName in the API. The name can be up to 192 bytes
long. The name is stored along with other information about the stream in the internal directory of the Blackfish SQL database.
The forward slash (/) is used as a directory separator in the name to provide a hierarchical directory organization. JdsExplorer
uses this structure to display the contents of the directory in a tree.
The JdsExplorer tree provides a hierarchical view of the the Blackfish SQL directory. The Blackfish SQL directory can also be
opened programmatically with a DataExpress StorageDataSet component. This provides a tabular view of all streams stored
in the Blackfish SQL file system. The directory table has the following structure:
You can reference the columns by name or by number. There are constants defined as DataStore class variables for each of
the column names. The best way to reference these columns is to use these constants. The constants provide compile-time
checking to ensure that you are referencing a valid column. Constants with names ending with the suffix _STATE exist for the
different values for the State column. There are also constants for the different values and bit masks for the Type column, with
12
3 Blackfish SQL
names ending with the suffix _STREAM. See the online help for the DataStore class for a listing of these constants.
Stream Details
Time columns in the Blackfish SQL directory are Coordinated Universal Time (UTC).
As with many file systems, when you delete a stream in Blackfish SQL, the space it occupied is marked as available, but the
contents and the directory entry that points to it are not immediately reused for new allocations. This means you can sometimes
restore a deleted stream if it has not been overwritten.
For more information on deleting and restoring streams, see Deleting Streams, How Blackfish SQL Reuses Blocks, and
Restoring Streams. 3
The Type column indicates whether a stream is a file or table stream, but there are also many internal table stream subtypes (for
example, for indices and aggregates). These internal streams are marked with the HIDDEN_STREAM bit to indicate that they
should not be displayed. Of course, when you are reading the directory, you can decide whether these streams should be hidden
or visible.
These internal streams have the same StoreName as the table stream with which they are associated. This means that the
StoreName alone does not always uniquely identify a stream. Some internal stream types can have multiple instances. The ID
for each stream is always unique; however, the StoreName is sufficiently unique for the storeName parameter used at the API
level. For example, when you delete a table stream, all the streams with that StoreName are deleted.
A database file has a block size property that defaults to 4096 bytes. The database block size property is the unit size used for
new allocations in the database. This size also determines the maximum storage size of a Blackfish SQL database. The formula
for computing the maximum database file size is:
<bytes-per-block> * 2^31
A Blackfish SQL database file does not automatically shrink as data is deleted or removed from it. However, new allocations
reuse the space from deleted allocations. Deleted space in the file system is made available to new allocations in two ways:
• Deleted blocks In this case, an entire block is reallocated from the list of deleted blocks.
• Blocks that are partially full In this case, free space can be reused only on a per-stream basis. Specifically, the free space
in a block in Table A can be reused only by a new allocation for a row in Table A. From an allocation perspective, tables,
secondary indices, Blobs, and files are all separate streams.
On average, partially allocated blocks are kept at least 50 percent full. The file system goes to great lengths to ensure this is true
for all stream types in the Blackfish SQL file system. The one exception to this rule occurs when a stream has a small number of
blocks allocated.
A Blackfish SQL database file can be compacted to remove all deleted space and to defragment the file system so that blocks
for each stream are located in contiguous regions. To compact a database using JdsExplorer, choose Tools > Pack. You can
accomplish this programmatically by using the DB_ADMIN.COPY_USERS and DB_ADMIN.COPY_STREAMS methods.
13
Blackfish SQL 3
Deleting Streams
Deleting a stream does not actually overwrite or clear the stream contents. As in most file systems, the space used by the
stream is marked as available, and the directory entry that points to that space is marked as deleted. The time at which the
stream was deleted is recorded in the directory. Over time, new stream allocations overwrite the space that was formerly
occupied by the deleted stream, making the content of the deleted streams unrecoverable.
You can use JdsExplorer to delete streams, or you can delete streams programmatically using the
DataStoreConnection.deleteStream() method, which takes as an argument the name of the stream to delete.
3
How Blackfish SQL Reuses Blocks
Blocks in the Blackfish SQL database file that were formerly occupied by deleted streams are reclaimed according to the
following rules:
• Blackfish SQL always reclaims deleted space before allocating new disk space for its blocks.
• If the database is transactional, the transaction that deleted the stream must commit before the used space can be reclaimed.
• The oldest deleted streams (those with the earliest delete times) are reclaimed first.
• For table streams, the support streams (those for indices and aggregates) are reclaimed first.
• Space is reclaimed from the beginning of the stream to the end of the stream. This means you are more likely to recover the
end of a file or table than the beginning.
• Because of the way table data is stored in blocks, you never lose or recover a partial row in a table stream, only complete
rows.
• When all the space for a stream has been reclaimed, the directory entry for the stream is automatically erased, since there is
nothing left to restore.
Restoring Streams
Blackfish SQL allows deleted streams to be restored if their space has not be consumed by new allocations as described in
above. You can restore a stream either by using JdsExplorer to restore it, or by calling the
DataStoreConnection.undeleteStream() method.
Because table streams have multiple streams with the same name, the stream name alone is not sufficient for attempting to
restore a stream programmatically. You must use a row from the Blackfish SQL directory. The row contains enough information
to uniquely identify a particular stream.
The DataStoreConnection.undeleteStream() method takes such a row as a parameter. You can pass the directory
dataset itself. The current row in the directory dataset is used as the row to restore.
If you create a new stream with the name of a deleted stream, you cannot restore that stream while the same name is being
used by an active stream.
Transaction Management
The lifecycle of a transaction begins with any read or write operation through a connection. Blackfish SQL uses stream locks to
control access to resources. To read a stream or modify any part of a stream (e.g., a byte in a file, a row in a table), a connection
must acquire a lock on that stream. Once a connection acquires a lock on a stream, it holds the lock until the transaction is
committed or rolled back.
In single-connection applications, transactions primarily provide crash recovery and allows an application to undo changes. Or,
you may decide to make a Blackfish SQL database transactional so that it can be accessed through JDBC. If you want to access
that Blackfish SQL database using DataExpress, you must deal with transactions.
14
3 Blackfish SQL
The serializable isolation level provides complete transaction isolation. An application can employ a weaker isolation level to
improve performance or to avoid lock manager deadlocks. Weaker isolation levels are susceptible to one or more of the following
isolation violations:
• Dirty reads One connection is allowed to read uncommitted data written by another connection.
• Nonrepeatable reads A connection reads a committed row, another connection changes and commits that row, and the first 3
connection rereads that row, getting a different value the second time.
• Phantom reads A connection reads all of the rows that satisfy a WHERE condition, a second connection adds another row that
also satisfies that condition, and the first connection sees the new row that was not there before, when it reads a second time.
SQL-92 defines four levels of isolation in terms of the behavior that a transaction running at a particular isolation level is
permitted to experience, which are:
Isolation Description
level
Read This isolation level is suitable for single-user applications for reports that allow transactionally inconsistent views
Uncommitted of the data. It is especially useful when browsing Blackfish SQL tables with dbSwing and DataExpress DataSet
components. This isolation level incurs minimal locking overhead.
Read This isolation level is commonly used for high-performance applications. It is ideal for data access models that
Committed use Optimistic Concurrency Control. In these data access models, read operations are generally performed first.
In some cases, read operations are actually performed in a separate transaction than write operations.
Repeatable This isolation level provides more protection for transactionally consistent data access without the reduced
Read concurrency of TRANSACTION_SERIALIZABLE. However, this isolation level results in increased locking
overhead because row locks must be acquired and held for the duration of the transaction.
Serializable This isolation level provides complete serializability of transactions at the risk of reduced concurrency and
increased potential for deadlocks. Although row locks can still be used for common operations with this isolation
level, some operations cause the Blackfish SQL lock manager to escalate to using table locks.
15
Blackfish SQL 3
Lock Description
Critical These are internal locks used to protect internal data structures. Critical section locks are usually held for a short
section period of time. They are acquired and released independent of when the transaction is committed.
locks
Row Row locks are used to lock a row in a table. These locks support shared and exclusive lock modes. Row locks are
locks released when the transaction commits.
Table Table locks are used to lock an entire table. These locks support shared and exclusive lock modes. Table locks are
locks released when the transaction commits.
3 DDL DDL table locks are locks acquired when database metadata is created, altered, or dropped. These support shared
table and exclusive lock modes:
locks
• Shared DDL locks are held by transactions that have tables opened. Shared DDL locks are held until the
transaction commits and the connection closes the table and all statements that refer to the table.
• Exclusive DDL locks are used when a table must be dropped or structurally modified and are released when a
transaction commits.
Property Behavior
tableLockTables Specifies the tables for which row locking is to be disabled. This can be a list of tables, defined as a string of
semicolon-separated, case-sensitive table names. Set this property to “*”.
maxRowLocks Specifies the maximum number of row locks per table that a transaction should acquire before escalating to
a table lock. The default value is 50.
lockWaitTime Specifies the maximum number of milliseconds to wait for a lock to be released by another transaction.
When this timeout period expires, an appropriate exception is thrown.
readOnlyTxDelay Specifies the maximum number of milliseconds to wait before starting a new read-only view of the database.
For details, see the discussion on read only transaction, in Tuning Blackfish SQL Concurrency Control
Performance
All isolation levels acquire at least an exclusive row lock for row update, delete, and insert operations. In some lock escalation
scenarios, an exclusive table lock occurs instead.
The row locking behavior of the Blackfish SQL connection isolation levels are:
16
3 Blackfish SQL
Note that although lock escalation from row locks to table locks occurs in some situations for Serializable as described
above, it also occurs for all isolation levels if the maxRowLocks property is exceeded.
Blackfish SQL for Java Connection Pooling and Distributed Transaction Support
Blackfish SQL provides several components for dealing with JDBC DataSources, connection pooling, and distributed
transaction (XA) support. These features require J2EE. If you are running with a JRE version less than 1.4, download the
J2EE.jar file from java.sun.com, and add it to the classpath.
17
Blackfish SQL 3
• javax.sql.XAConnection
• javax.sql.XADataSource
• javax.transaction.xa.XAResource
3
To acquire a distributed connection to a Blackfish SQL database from a JdbcConnectionPool, call
JdbcConnectionPool.getXAConnection(). The connection returned by this method works only with the Blackfish SQL
JDBC driver. XA support is useful only when combined with a distributed transaction manager, such as the one provided by
Borland Enterprise Server.
Under normal operation, all global transactions should be committed or rolled back before the associated XAConnection is
closed. If a connection is participating in a global transaction that is not yet in a prepared state but is in a successful started or
suspended state, the transaction will be rolled back during any crash recovery that may occur.
• commit causes the transaction to be heuristically committed when Blackfish SQL reopens the database. This is the default.
• rollback causes the transaction to be heuristically rolled back when Blackfish SQL reopens the database.
• none causes Blackfish SQL to keep the transaction state when reopening a database. When this option is used, the locks that
were held when the transaction was prepared are reacquired and held until the transaction is committed or rolled back by a
JTA/JTS-compliant transaction manager.
The heuristic commit and rollback options allow for more efficient execution, because the locks can be released sooner and
less information is written to the transaction log file.
One of the most important areas of concern for any database application is eliminating single points of failure. The Blackfish SQL
server provides a broad range of capabilities for making a database application fail-safe by avoiding application down time and
loss of critical data. The High Availability server uses database mirroring technologies to ensure data availability in the event of
software or hardware failure, and to provide a method of routine incremental backup. While a more general database replication
scheme could provide similar protection, a mirroring approach provides advantages in terms of simplicity, ease of use, and
performance.
A more general data replication solution could be employed to solve many of the same problems that the Blackfish SQL High
Availability server addresses. Even though a more general solution would solve a broader variety of synchronization needs, it
would do so at a much higher set of costs, including greater complexity and slower performance.
The Blackfish SQL database engine uses its transactional log files to maintain read-only mirror images of a database. The same
TCP/IP database connections used for general database access are also used to synchronize mirrored databases.
Mirror Types
These mirror types can be used by an application:
18
3 Blackfish SQL
• Primary
• Read-only
• Directory
Directory Mirrors
Directory mirror databases mirror only the mirror configuration table and the tables needed for security definition. They do not
mirror the actual application tables in the primary mirror.
There can be any number of directory mirrors. Connections to these databases can perform read operations, only. The storage
requirements for a directory mirror database are very small, since they contain only the mirror table and security tables. Directory
mirrors redirect read-only connection requests to read-only mirrors. Writable connection requests are redirected to the primary
mirror.
Automatic failover
When a primary mirror that is configured with two or more automatic failover mirrors fails, one of the read-only mirrors that is
configured for automatic failover is promoted to be the primary mirror. The application can be affected in one of two ways:
• If an application has already connected to the primary before it failed, all operations attempted against the failed primary will
encounter SQLException or IOException errors. The application can cause itself to be hot swapped over to the new primary
by rolling back the transaction. This is identical to how database deadlock is handled in high-concurrency OLTP applications.
• If an application has never connected to the primary before it failed, its connection attempt fails. Directory mirrors can be used
to automatically redirect new connection requests to the new primary mirror.
19
Blackfish SQL 3
Manual failover
Unlike automatic failover, manual failover is performed only on request. Any read-only mirror can become the primary mirror.
This is useful when the computer the primary server is executing on needs to be taken off line for system maintenance.
The replication support provided by DataExpress for Blackfish SQL easier to use and deploy than most replication solutions. This
replication solution is also heterogeneous because it uses JDBC for database access.
The replication topology provided is best described as a simple client-server relationship. Blackfish SQL does not require the
server-side software or database triggers required for more complex publish-subscribe solutions. Complex multi-level hierarchies
and network topologies are not directly supported.
There are three distinct phases in the replication cycle when using DataExpress JavaBean components with Blackfish SQL for a
disconnected or mobile computing model:
• Provide Phase: Provides the client database with a snapshot of the server tables being replicated.
20
3 Blackfish SQL
• Edit Phase: The client application, which need not be connected to the database, reads/edits the client database.
• Resolve Phase: The client database edits are saved back to the server database.
The provide operation for a collection of database tables can be performed in a single transaction, so that a transactionally
consistent view of a collection of tables can be replicated.
There are also higher-level DataStorePump and DataStoreSync components that you can use to perform provide and
resolve operations for a collection of tables. For details, see Administering Blackfish SQL.
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
21
Blackfish SQL 3
22
4 Blackfish SQL
4 Establishing Connections
This chapter explains the basics for establishing a connection to a Blackfish SQL database, using dbExpress, ADO.NET, or
JDBC.
• Types of Connections
• Using dbExpress to Connect to the Server
• Using ADO.NET to Connect to the Server
• Using JDBC to Connect to the Server
• Specifying Connection Properties
• Using Blackfish SQL with JBuilder and Borland Enterprise Server
• DataDirectory Macro Support
Types of Connections
Connections can be local, remote, or a combination of both:
• Local connections Local connections access the Blackfish SQL database engine in-process. This provides improved
performance over a remote driver, but requires that the Blackfish SQL engine be present and running in the same process as
the application. Several simultaneous local connections created in the same process can connect to a database. However,
only one process can have a database file open at a time. Consequently, while a process has a database file open, it
becomes the only process that can connect to that database over a local connection.
• Remote connections To use a remote connection, first launch the Blackfish SQL server. (For instructions, see Administering
Blackfish SQL.) The remote driver communicates with the server over TCP/IP. Remote connections can be slower for
database interactions that involve multiple round trips between the client and the database for small packets of data. Remote
connections allow more than one process running on one or more computers to access the same database. If several
processes require simultaneous access, it is best to use remote connections.
• Combination of local and remote connections A third option is to use a combination of the local and remote connections. If
there is one process that performs the majority of database interactions, this process can launch the Blackfish SQL Server
inside its own process. In this way, the demanding database process can use the local driver while still allowing other
processes to access the same database via the remote driver.
Using dbExpress to Connect to the Server
Native applications can use dbExpress to establish remote connections with a Blackfish SQL server. Local connections are
currently not supported for dbExpress. You must start the Blackfish SQL server before you can use the remote dbExpress driver
to connect. (For instructions, see Administering Blackfish SQL.)
23
Blackfish SQL 4
Example
uses DBXCommon;
uses DBXClient;
Connection :=
TDBXConnectionFactory.GetConnectionFactory.GetConnection('BLACKFISHSQLCONNECTION');
The dbExpress dbxdriver.ini file contains default driver properties appropriate for most applications. The dbExpress
dbxconnections.ini file has a BLACKFISHSQLCONNECTION section that contains the default connection settings. New
4 connections can copy most of these properties. This list of properties are typically customized for new connections:
• [BLACKFISHCUSTOMCONNECTION]
• HostName=localhost
• port=2508
• Database=c:/tmp/test
Using ADO.NET to Connect to the Server
The Blackfish SQL assembly Borland.Data.BlackfishSQL.LocalClient.dll contains an ADO.NET 2.0 driver. You can
build an application without directly referencing this assembly by using the DbProviderFactory class. For this approach to
work, the file machine.config must contain references to the Blackfish SQL assemblies in the DbProviderFactory section,
and the Blackfish SQL assemblies must be installed in the Global Assembly Cache (GAC). For easier deployment, use a direct
reference to the Blackfish SQL assembly.
You can use a local ADO connection, a remote ADO connection, or a combination of both to connect with the Blackfish SQL
server.
This example illustrates how to acquire a local ADO connection using DbProviderFactory:
[References: System.Data.dll]
uses System.Data.Common;
var Factory: DbProviderFactory;
var Connection: DbConnection;
Factory := DbProviderFactories.GetFactory('Borland.Data.BlackfishSQL.LocalClient');
Connection := Factory.CreateConnection();
Connection.ConnectionString := 'database=<filename>;user=<username>;password=<password>';
Connection.Open;
24
4 Blackfish SQL
This example illustrates how to acquire a local ADO connection by using a direct class reference:
[References: System.Data.dll]
[References: Borland.Data.BlackfishSQL.LocalClient.dll]
uses System.Data.Common;
uses Borland.Data.DataStore;
var Connection: DbConnection;
Connection := DataStoreConnection.Create;
Connection.ConnectionString := 'database=<filename>;user=<username>;password=<password>';
Connection.Open;
4
Connection := Factory.CreateConnection();
Connection.ConnectionString :=
'database=<filename>;user=<username>;password=<password>;host=<servername>;protocol=TCP';
Connection.Open;
uses System.Data.Common;
uses Borland.Data.DataStore;
var Connection: DbConnection;
Connection := DataStoreConnection.Create;
Connection.ConnectionString :=
'database=<filename>;user=<username>;password=<password>;host=<servername>;protocol=TCP';
Connection.Open;
25
Blackfish SQL 4
You can establish a local JDBC connection in either of the following ways:
You can establish a remote JDBC connection in either of the following ways:
This example shows how to acquire a remote JDBC connection using the DriverManager:
[jdsremote.jar must be in classpath]
java.sql.DriverManager.registerDriver(new com.borland.datastore.jdbc.DataStoreDriver());
connection =
java.sql.DriverManager.getConnection("jdbc:borland:dsremote://<servername>/<filename>",
"<username>", "<password>");
26
4 Blackfish SQL
dataSource.setNetworkProtocol("tcp");
datasource.setServerName("<servername>");
• dbExpress 4
• ADO
• JDBC
For more information, see the RAD Studio help for Borland.Data.DataStore.ConnectionProperties.
Example
This example shows a sample Blackfish SQL connection properties section in the dbxconnections.ini file:
[BLACKFISHSQLCONNECTION]
DriverName=BlackfishSQL
HostName=localhost
port=2508
Database=/tmp/test
create=true
User_Name=sysdba
Password=masterkey
BlobSize=-1
TransIsolation=ReadCommitted
The HostName, port, and create properties are documented in ConnectionProperties. The DriverName, User_Name,
BlobSize, and TransIsolation properties are documented in TDBXPropertyNames of the DBXCommon unit.
You can use DataExplorer to set and modify values for ConnectionProperties. For instructions, see the RAD Studio help for
the DataExplorer Connection dialog box.
• a JDBC URL
• java.util.Properties
27
Blackfish SQL 4
This example shows how to specify JDBC connection properties using a java.util.Properties object:
java.util.Properties props = new java.util.Properties();
props.setProperty("create","true");
props.setProperty("user","SYSDBA");
4 props.setProperty("password","masterkey");
connection = DriverManager.getConnection("jdbc:borland:dslocal:c:/mydb.jds", props);
Using Blackfish SQL with JBuilder and Borland Enterprise Server
To make the latest version of Blackfish SQL available to JBuilder and the Borland Enterprise Server (BES), copy these files from
the Blackfish SQL lib directory to the lib directory of the target product:
• beandt.jar
• dbtools.jar
• dx.jar
• jds.jar
• jdsremote.jar
• jdsserver.jar
1. For JBuilder or BES, find the listed files in the lib directory of the install tree and copy them to a backup directory.
2. Find the files in the lib directory of the Blackfish SQL installation and copy them to the lib directory of JBuilder or BES.
DataDirectory Macro Support
You can use the DataDirectory macro to specify relative path names for database files. The DataDirectory macro is
supported for both the Blackfish SQL ADO.NET and DBXClient drivers. If a database file name is prepended with the following
string:
|DataDirectory|
for example:
|DataDirectory|employee.jds
the string |DataDirectory| will be replaced with the appropriate string, as follows:
• For ASP.NET web based applications, this will be the App_Data folder name.
• For non-web applications, this defaults to the directory of the application executable. You can override the default by setting
the DataDirectory property for AppDomain:
AppDomain.CurrentDomain.SetData("DataDirectory", "CustomAppPath")
If the System property blackfishsql.datadirectory is set, the setting for this property will be used as the replacement
string. Otherwise the setting for the user.home property will be used.
28
4 Blackfish SQL
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
29
5 Blackfish SQL
You can use RAD Studio DataExplorer to perform many administrative tasks. DataExplorer has been enhanced with a
connection string editor for Blackfish SQL for Windows, and the ability to create or alter Blackfish SQL databases. DataExplorer
enables you to browse and view stored procedures. Some DataExplorer tasks are not yet supported for Blackfish SQL for
Windows. See the DataExplorer help for more information.
• JdsExplorer
• ServerConsole
Documentation for both JdsExplorer and ServerConsole are provided with JBuilder.
31
Blackfish SQL 5
Using BSQLServer.exe
• To start the server: BSQLServer.exe
• To stop the server: BsqlServer.exe -shutdown or Type Ctrl-C in the Console window
• To install the server as a Windows service: BsqlServer.exe -install
• To remove the Windows server: BsqlServer.exe -remove
• To explore other options for server configuration: BsqlServer.exe -?
Using JdsServer.exe
• To start the server: JdsServer.exe
• To stop the server: JdsServer.exe -shutdown or Type Ctrl-C in the Console window
• To install the server as a Windows service: JdsServer.exe -install JDataStore
32
5 Blackfish SQL
Using Stored Procedures and User Defined Functions ( see page 41) 5
Using Triggers in Blackfish SQL Tables ( see page 55)
33
6 Blackfish SQL
• User authentication
• User authorization
• Database encryption
User Authentication
User authentication restricts access to a Blackfish SQL database to authorized users only. Users must log into the database
using an authorized user account and password. Permissions can be granted to or revoked from an account to fine tune access.
In general, full access is reserved for the Administrator account(s), and a more restricted account or accounts are provided for
general users.
The following section describes how to create and modify user accounts.
Adding a User
CREATE <userid> PASSWORD <password>
Where:
<userid> is the account to be added
35
Blackfish SQL 6
Removing a User
DROP <userid> [ CASCADE|RESTRICT ]
Where:
<userid> is the account to be removed.
CASCADE deletes the user and all objects that the user owns.
RESTRICT causes the statement to fail if the user owns any objects, such as tables, views, or methods.
(no option) causes the statement to fail if the user owns any objects, such as tables, views, or methods.
Where:
<userid> is the account for which the password should be changed.
User Authorization
There are several database access privileges which you can grant to or revoke from an account The following section describes
6 the set of access privileges, and how to grant and revoke privileges for an account.
To grant or revoke a privilege for an account, use the following SQL commands:
GRANT <role>|<privilege> TO <userid>
Revokes the specified privilege or role from the specified user account.
Where:
<userid> is the account to be modified.
<role> is the user role to be granted or revoked, such as ADMIN. This can be a single role, or a comma-separated list of roles.
<privilege> is the privilege to be granted or revoked. This can be a single privilege or a comma-separated list of privileges,
and can be one or more of the following:
• STARTUP confers the ability to open a database that is shut down. The user's password is required to add STARTUP rights to
a user account. You can also specify STARTUP rights at the time the user account is created.
• ADMINISTRATOR confers the ability to add, remove, and change rights of users, and the ability to encrypt the database. Also
includes the four stream rights: WRITE, CREATE, DROP, RENAME. By default, STARTUP rights are granted to an Administrator
account when the account is created, but you can remove STARTUP rights from the account. You cannot remove WRITE,
CREATE, DROP, or RENAME privileges from an Administrator account; attempts to remove these rights are ignored.
• WRITE confers the ability to write to file or table streams in the Blackfish SQL database.
• CREATE confers the ability to create new file or table streams in the Blackfish SQL database.
• DROP confers the ability to remove file or table streams from the Blackfish SQL database.
36
6 Blackfish SQL
• RENAME confers the ability to rename file or table streams in the Blackfish SQL database.
Database Encryption
Only a user with Administrator privileges can encrypt a database. When a database is encrypted, the STARTUP privilege is
automatically revoked for all users (including Administrators) other than the Administrator issuing the encryption command.
Consequently, after encrypting you must use the same Administrator account to restart the database. You can reassign
STARTUP privileges to other users after the database has been encrypted and restarted.
To encrypt a new database, log in from an Administrator account, and issue the following SQL command:
CALL DB_ADMIN.ENCRYPT(<AdminPassword>,<EncryptionSeed>)
Where:
DB_ADMIN.ENCRYPT() is the built-in stored procedure for encrypting a database.
<AdminPassword> is the password for the user issuing the encryption command.
To encrypt a Blackfish SQL for Java database that has existing tables, use the JBuilder utility, JdsExplorer. For instructions, see
the JBuilder online help for JdsExplorer.
1. Use RAD Studio DataExplorer to create a new database. For instructions, see the online help for DataExplorer.
2. Copy the existing users to the new database. DB_ADMIN.COPY_USERS(<OtherFilename>, <AdminUser>,
<AdminPass>,<DoCopyEncryption>, <ReplaceExistingUsers>) Where: <OtherFilename> is the filename of the
destination database. <AdminUser> is a user with ADMIN privileges in destination database. <AdminPass> is a password of
the specified adminUser in destination database. If <DoCopyEncryption> is TRUE and the current database is encrypted,
then encrypt the target database with the same key. If <ReplaceExistingUsers> is TRUE, then the existing users in the
target database is replaced with the users in the source database.
3. Encrypt the new database. DB_ADMIN.ENCRYPT(<password>,<EncryptionSeed>)
4. Copy the contents of the old database into the newly encrypted database.
DB_ADMIN.COPY_STREAMS(<OtherFilename>, <AdminUser>, <AdminPass>, <DoOverwrite>,
<DoIgnoreErrors>) Where: <OtherFilename> is the filename of the destination database. <AdminUser> is a user
with ADMIN privileges in destination database. <AdminPass> is a password of the specified adminUser in destination
database. If <DoOverwrite> is TRUE, it allows tables to be overwritten. If FALSE, this would be an error. If
<IgnoreErrors> is TRUE, then this method can be used to repair a corrupted database.
For additional information, see the Stored Procedures Reference.
The authentication and authorization support is secure for server-side applications where opponents do not have access to the
physical Blackfish SQL database files. The SYS.USERS table stores passwords, user IDs, and rights in encrypted form. The
table also stores the user ID and rights in an unencrypted column, but this is for display purposes only. The encrypted values for
user ID and rights are used for security enforcement.
37
Blackfish SQL 6
The stored passwords are encrypted using a strong TwoFish block cipher. A pseudo-random number generator is used to salt
the encryption of the password. This makes traditional password dictionary attacks much more difficult. In a dictionary attack, the
opponent makes guesses until the password is guessed. This process is easier if the the opponent has personal information
about the user, and the user has chosen an obvious password. There is no substitution for a well chosen (obscure) password as
a defense against password dictionary attacks. When an incorrect password is entered, the current thread sleeps for 500
milliseconds.
If a Blackfish SQL database is unencrypted, it is important to restrict physical access to the file, for the following reasons:
• If a Blackfish SQL database file is not password protected, and it is possible for an opponent to write to it with a separate file
editing utility or program, the authentication and authorization support can be disabled.
• If it is possible for an opponent to read a Blackfish SQL database file that is not encrypted with a separate file-editing program,
the opponent might be able to reverse-engineer the file format and view its contents.
For environments where a dangerous opponent may gain access to physical copies of a Blackfish SQL database, the database
and log files should be encrypted, in addition to being password protected. WARNING: The cryptographic techniques that
Blackfish SQL uses to encrypt data blocks are state-of-the-art. The TwoFish block cipher used by Blackfish SQL has never been
defeated. This means that if you forget your password for an encrypted Blackfish SQL database, you will not be able to access
the database. The best chance of recovering the data would be to have someone guess the password.
There are measures that can be used to guard against forgetting a password for an encrypted database. It is important to note
that there is a master password used internally to encrypt data blocks. Any user that has STARTUP rights has the master
password encrypted using their password in the SYS.USERS table. This allows one or more users to open a database that has
6 been shut down, because their password can be used to decrypt a copy of the master password. This feature can be used to
create a new database that has one secret user who has Administrator privileges (which includes STARTUP rights). If you use
this virgin database whenever a new empty database is needed, you will always have one secret user who can unlock the
encryption.
Encrypting a database has some effect on performance. Data blocks are encrypted when they are written from the Blackfish
SQL cache to the Blackfish SQL database and are decrypted when they are read from the Blackfish SQL database into the
Blackfish SQL cache. So the cost of encryption is only incurred when file I/O is performed.
Blackfish SQL encrypts all but the first 16 bytes of .jds file data blocks. There is no user data in the first 16 bytes of a data
block. Some blocks are not encrypted. This includes allocation bitmap blocks, the header block, log anchor blocks and the
SYS.USERS table blocks. Note that the sensitive fields in the SYS.USERS table are encrypted using the user's password. Log
file blocks are completely encrypted. Log anchor and status log files are not encrypted. The temporary database used by the
query engine is encrypted. Sort files used by large merge sorts are not encrypted, but they are deleted after the sort completes.
NOTE: The remote client for Blackfish SQL currently uses sockets to communicate with a Blackfish SQL Server. This
communication is not secure. Since the local client for Blackfish SQL is in-process, it is secure.
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
38
6 Blackfish SQL
39
7 Blackfish SQL
Stored procedures can also increase the performance of an application, since they are executed in the same Virtual Machine as
7
the Blackfish SQL database engine itself. This results in execution with minimal overhead. While a stored procedure is executing
SQL statements, no network traffic is generated. The stored procedure uses an in-process ADO.NET connection. This provides
the same performance advantage as using the in-process Blackfish SQL ADO.NET driver rather than the remote driver.
• Business logic, such as integrity constraints, is isolated in the database engine, where the logic is available and reinforced for
all clients.
• Data is retrieved locally, which is faster than sending that data to and from the client.
• Blackfish SQL language can be extended with C#, Delphi, or Visual Basic functions.
• There is no performance penalty, since the stored procedures are executing in the same virtual machine as the database
itself.
• You can debug .NET stored procedures in the same manner as debugging the client application.
This chapter covers:
41
Blackfish SQL 7
stored procedure executes several SQL queries against the tables of the database to yield the desired result. In Blackfish SQL,
these SQL queries are written in the language of choice, that is available on the .NET or Java platforms. The desired effect may
be to update a set of tables, or to calculate an accumulated value from one or more tables, or to add specialized integrity
constraints. A stored procedure may have several parameters, which can be either input only, output only, or both.
Example
Consider an ADD_ORDER procedure that takes a customerId, an itemId, and a quantity value as input, and adds a record
to the ORDERS table. However, suppose that you also want to verify that this customer has paid for previous orders. To
achieve this, you can cause the procedure to throw an exception if this is not the case.
The stored procedure is executed with an IDbCommand object by setting the properties CommandType and CommandText, and
then adding the appropriate parameters.
Notice the difference in the interpretation of the parameters, depending on the combination of CommandType and the style of the
parameter markers that are used. If the CommandType is StoredProcedure, the parameter names are taken from the
implementation of the stored procedure, in which case it is possible to omit optional parameters.
Example
Consider a MAX_VALUE function that takes two values, <value1> and <value2>, and returns the greater of the two. The UDF
can be executed in an SQL statement:
'SELECT * FROM PEOPLE WHERE MAX_VALUE(HEIGHT,5*WIDTH) < ?'
Or, in an SQL CALL statement:
'?=CALL MAX_VALUE(?,?)'
Creating Stored Procedures for the .NET Platform
This section provides detailed information on how to create Blackfish SQL stored procedures and UDFs for the .NET platform.
1. Write the code for the stored procedure as a static public member of a class.
2. Build an assembly with the stored procedures. Blackfish SQL must be able to locate the assembly. When developing in
Delphi, Blackfish SQL is able to find the assembly in BDSCOMMONDIR. That is, it is not necessary to move the assembly to any
special location. For deployment, it is recommended that you copy the assembly to the subdirectory where the executable for
the Blackfish SQL server (BSQLServer.exe) resides, or install it in the Global Assembly Cache (GAC).
3. Create the binding of a SQL identifier to the assembly member.
Example
This example uses the sample ADD_ORDER from the previous example in About Stored Procedures, with this schema:
42
7 Blackfish SQL
CUSTOMER TABLE
ORDERS TABLE
ITEMS TABLE
Owed := 0
else
Owed := Decimal(P1.Value);
Command.Parameters.Clear;
43
Blackfish SQL 7
P2.Value := CustId;
Command.ExecuteNonQuery;
Credit := Decimal(P1.Value);
Command.Parameters.Clear;
Command.Parameters.Clear;
P1.Value := CustId;
P2.Value := ItemId;
P3.Value := Quantity;
P4.Value := Amount;
Command.ExecuteNonQuery;
Command.Free;
7 end;
end.
Step 2: Build the assembly and make it available to the Blackfish SQL server process.
After completing the code for the stored procedure:
1. Build an assembly DLL (for example, Procs.dll) which contains the class MyClass shown in Step 1.
2. When deploying, copy the assembly to the subdirectory where the executable for the Blackfish SQL server
(BSQLServer.exe) resides.
interface
implementation
uses
44
7 Blackfish SQL
System.Data;
type
TSomething = class
public
procedure AddOrder(
Connection: DbConnection;
CustId: Integer;
ItemId: Integer;
Quantity: Integer);
end;
{ Assume:
Connection: is a valid Blackfish SQL connection.
CustId: is a customer in the CUSTOMER table.
ItemId: is an item from the ITEMS table.
Quantity: is the quantity of this item ordered.
}
procedure TSomething.AddOrder(
Connection: DbConnection;
CustId: Integer;
ItemId: Integer;
Quantity: Integer);
var
Command: DbCommand;
P1, P2, P3: DbParameter;
begin
Command := con.CreateCommand;
Command.CommandText := 'ADD_ORDER';
Command.CommandType := CommandType.StoredProcedure;
P1 := Command.Parameters.Add('custId', DbType.Int32);
P2 := Command.Parameters.Add('itemId', DbType.Int32);
P3 := Command.Parameters.Add('quantity', DbType.Int32); 7
P1.Value := CustId;
P2.Value := ItemId;
P3.Value := Quantity;
Command.ExecuteNonQuery;
Command.Free;
end;
end.
When TSomeThing.AddOrder is called in the client application, this in turn calls the stored procedure ADD_ORDER, which
causes TMyClass.AddOrder to be executed in the Blackfish SQL server process. By making TMyClass.AddOrder into a
stored procedure, only one statement has to be executed over a remote connection. The five statements executed by
TMyClass.AddOrder are executed in-process of the Blackfish SQL server, using a local connection.
Note that the application is not passing a connection instance to the call of the ADD_ORDER stored procedure. Only the actual
logical parameters are passed.
Blackfish SQL generates an implicit connection object, when it finds a stored procedure or UDF where the first argument is
expected to be a System.Data.IDbConnection instance.
Database NULL values require special handling. The System.String can be handled by the NULL value. However, for all
other types, the formal parameter type must be changed to TObject, since NULL is not a valid value for a .NET ValueType. If
the formal parameter is a TObject type, then the value of System.DBNull is used for a database NULL value. Blackfish SQL
will also accept nullable types in stored procedures written in C# (for example, int).
45
Blackfish SQL 7
Examples:
Example of a stored procedure with an INOUT parameter; NULL values are ignored:
class procedure TMyClass.AddFive(ref Param: Integer);
begin
Param := Param + 5;
end;
Example of a stored procedure with an INOUT parameter; NULL values are kept as NULL values:
class procedure TMyClass.AddFour(ref Param: TObject);
begin
if Param <> nil then
Param := TObject(Integer(Param) + 4);
end;
Use:
procedure TryAdding(Connection: DbConnection);
var
Command: DbCommand;
begin
Command := Connection.CreateCommand;
Command.CommandText := 'ADD_FIVE';
Command.CommandType := CommandType.StoredProcedure;
P1 := Command.Parameters.Add('param', DbType.Int32);
P1.Direction := ParameterDirection.InputOutput;
P1.Value = 17;
Command.ExecuteNonQuery;
if 22 <> Integer(P1.Value) then
raise Exception.Create('Wrong result');
7
Command.Parameters.Clear;
Command.CommandText := 'ADD_FOUR';
Command.CommandType := CommandType.StoredProcedure;
P1 := Command.Parameters.Add('param', DbType.Int32);
P1.Direction := ParameterDirection.InputOutput;
P1.Value = 17;
Command.ExecuteNonQuery;
if 21 <> Integer(P1.Value) then
raise Exception.Create('Wrong result');
P1.Value = DBNull.Value;
Command.ExecuteNonQuery;
if DbNull.Value <> P1.Value then
raise Exception.Create('Wrong result');
Command.Free;
end;
The above implementation of AddFour uses a TObject wrapper class for integers. This allows the developer of addFour to
recognize NULL values passed by Blackfish SQL, and to set an output parameter to NULL to be recognized by Blackfish SQL.
In contrast, in the implementation for AddFive, it is impossible to know if a parameter was NULL, and it is impossible to set the
result of the output parameter to NULL.
46
7 Blackfish SQL
Consider the UDF example given earlier, involving the MAX_VALUE UDF:
'SELECT * FROM PEOPLE WHERE MAX_VALUE(HEIGHT,5*WIDTH) < ?'
That query is equivalent to this query:
'SELECT * FROM PEOPLE WHERE HEIGHT < ? AND 5*WIDTH < ?'
where the same value is given for both parameter markers. This SQL statement yields the same result, because the
implementation of MAX_VALUE is known. However, Blackfish SQL will be able to use only indices available for the HEIGHT and
WIDTH column for the second query. If there were no such indices, the performance of the two queries would be about the same.
The advantage of writing a UDF occurs when functionality does not already exist in Blackfish SQL (for example: a bit wise AND
operator).
1. Create a project to use for debugging. Using your favorite IDE, create a project that includes the client code of the application,
the stored procedures, and a reference to the Borland.Data.BlackfishSQL.LocalClient.dll library.
2. Add breakpoints to the stored procedure(s). The debugger will handle the stored procedures in the same way as with the
client code.
7
1. Create a project to use for debugging. Set up the project to debug the server directly.
2. Create an executable that calls Borland.Data.DataStore.DataStoreServer.StartDefaultServer.
3. Add a breakpoint to the stored procedure.
4. Run the separate client process.
Using a Stored Procedure to Produce an ADO.NET IDataReader
A stored procedure can produce an ADO.NET DbDataReader simply by returning a DbDataReader.
Example 6
class function GetRiskyCustomers(
47
Blackfish SQL 7
Connection: DbConnection;
Credit: Decimal credit): DbDataReader;
var
Command: DbCommand;
P1: DbParameter;
begin
Command := Connection.CreateCommand;
Command.CommandText := 'SELECT NAME FROM CUSTOMER WHERE CREDIT > ? ';
P1 := Command.Parameters.Add('param', DbType.Decimal);
P1.Value := Credit;
Result := Command.ExecuteReader;
end;
Note that the command object is not freed at the end of the method. If the command was freed, it would implicitly close the
DbDataReader, which results in no data being returned from the stored procedure. Instead, Blackfish SQL closes the command
implicitly after the stored procedure has been called.
You can update the classpath for the Blackfish SQL tools by adding the classes to the <jds_home>/lib/storedproc
directory.
• If the stored procedure consists of a .jar file, then place the jar file in <jds_home>/storedproc/lib/jars.
• If the stored procedure consists of one or more class files, place the class files in <jds_home>/storedproc/classes. For
example, if your stored procedure file is com.acme.MyProc, then you would place it as:
c:<jds_home>/lib/storedproc/classes/com/acme/MyProc.class
48
7 Blackfish SQL
A UDF Example
This example defines a method that locates the first space character after a certain index in a string. The the first SQL snippet
defines the UDF and and the second shows an example of how to use it.
Assume that TABLE1 has two VARCHAR columns: FIRST_NAME and LAST_NAME. The CHAR_LENGTH function is a built-in SQL
function.
package com.mycompany.util;
public class MyClass {
public static int findNextSpace(String str, int start) {
return str.indexOf(' ',start);
}
}
Input Parameters
A final type-checking of parameters is performed when the Java method is called. Numeric types are cast to a higher type if
necessary in order to match the parameter types of a Java method. The numeric type order for Java types is:
1. double or Double
2. float or Float
3. java.math.BigDecimal
4. long or Long
5. int or Integer
6. short or Short
7. byte or Byte
The other recognized Java types are:
• boolean or Boolean
• String
• java.sql.Date
• java.sql.Time
• java.sql.Timestamp
• byte[]
• java.io.InputStream
49
Blackfish SQL 7
Note that if you pass NULL values to the Java method, you cannot use the primitive types such as short and double. Use the
equivalent encapsulation classes instead (Short, Double). A SQL NULL value is passed as a Java null value.
If a Java method has a parameter or an array of a type that is not listed in the tables above, it is handled as SQL OBJECT type.
Output Parameters
If a Java method parameter is an array of one of the recognized input types (other than byte[]), the parameter is expected to
be an output parameter. Blackfish SQL passes an array of length 1 (one) into the method call, and the method is expected to
populate the first element in the array with the output value. The recognized Java types for output parameters are:
• double[] or Double[]
• float[] or Float[]
• java.math.BigDecimal[]
• long[] or Long[]
• int[] or Integer[]
• short[] or Short[]
• Byte[] (but not byte[] since that is a recognized input parameter by itself)
• boolean[] or Boolean[]
• String[]
• java.sql.Date[]
• java.sql.Time[]
• java.sql.Timestamp[]
7 • byte[][]
• java.io.InputStream[]
Output parameters can be bound only to variable markers in SQL. All output parameters are essentially INOUT parameters,
since any value set before the statement is executed is passed to the Java method. If no value is set, the initial value is arbitrary.
If any of the parameters can output a SQL NULL (or have a valid NULL input), use the encapsulated classes instead of the
primitive types.
Example 8
package com.mycompany.util;
public class MyClass {
public static void max(int i1, int i2, int i3, int result[]) {
result[0] = Math.max(i1, Math.max(i2,i3));
}
}
CALL MAX(1,2,3,?);
The CALL statement must be prepared with a CallableStatement in order to get the output value. See the JDBC
documentation for how to use java.sql.CallableStatement. Note the assignment of result[0] in the Java method. The
array passed into the method has exactly one element.
50
7 Blackfish SQL
Do not pass anything for this parameter. Let Blackfish SQL do it.
Example 9
package com.mycompany.util;
public class MyClass {
public static void increaseSalary(java.sql.Connection con,
java.math.BigDecimal amount) {
java.sql.PreparedStatement stmt
= con.prepareStatement("UPDATE EMPLOYEE SET SALARY=SALARY+?");
stmt.setBigDecimal(1,amount);
stmt.executeUpdate();
stmt.close();
}
}
CALL INCREASE_SALARY(20000.00);
Note:
• INCREASE_SALARY requires only one parameter: the amount by which to increase the salaries. The corresponding Java
method has two parameters.
• Do not call commit(), rollback, setAutoCommit(), or close() on the connection object passed to stored procedures.
For performance reasons, it is not recommended to use this feature for a UDF, even though it is possible.
Example
Example
51
Blackfish SQL 7
Example
Example 10
package com.mycompany.util;
public class MyClass {
public static int abs(int p) {
return Math.abs(p);
}
52
7 Blackfish SQL
See Also
Preface ( see page 1)
53
8 Blackfish SQL
• About Triggers
• Viewing Triggers
• Creating Triggers in Blackfish SQL for Windows Databases
• Creating Triggers in Blackfish SQL for Java Databases
About Triggers
You can create row level triggers for a Blackfish SQL table. In Blackfish SQL for Java, you can implement them in Java. In
Blackfish SQL for Windows, you can implement them in Delphi, C#, or VB.NET.
All trigger methods must be declared static and have only one parameter of type TriggerContext. The TriggerContext 8
class is symantically identical in Blackfish SQL for Java and Blackfish SQL for Windows. However, there are differences in
syntax for the two different platforms. On the Windows platform, the class TriggerContext is in the
Borland.Data.DataStore namespace. On the Java platform, the TriggerContext class is in the
com.borland.datastore package.
• A connection object
• The new row for insert, and update triggers
• The old row for update and delete triggers
These rules apply:
• New row values are modified in a BEFORE UPDATE or BEFORE INSERT trigger.
• Old row values cannot be modified.
• Foreign key and primary key constraints are applied after BEFORE triggers.
• AFTER triggers are called after the operation has completed, including successful completion of foreign key and primary key
constraints.
• The trigger implementation should avoid DML operations against the same table. This has the potential for infinite recursion.
• If there are multiple triggers of the same type for the same table, the calling order of the triggers is the order in which they
were created.
55
Blackfish SQL 8
• Commit and rollback operations are ignored inside the execution of the trigger If an exception is thrown from inside a trigger.
The affects of the statment that caused the trigger to be executed will be rolled back.
The requirements for deploying applications with trigger implementations are the same for both stored procedures and triggers.
Viewing Triggers
To view the triggers created for a table, call the DB_ADMIN.GET_TRIGGERS stored procedure. For a complete description see
the Stored Procedures Reference.
Example
{ TCustomer }
class procedure TCustomer.AfterDeleteTrigger(Context: TriggerContext);
begin
HandleBeforeInsert(Context.GetNewRow());
end;
class procedure TCustomer.AfterInsertTrigger(Context: TriggerContext);
begin
HandleBeforeUpdate(Context.GetOldRow(), Context.GetNewRow());
end;
class procedure TCustomer.AfterUpdateTrigger(Context: TriggerContext);
begin
HandleBeforeDelete(Context.GetOldRow(), Context.GetNewRow());
end;
class procedure TCustomer.BeforeDeleteTrigger(Context: TriggerContext);
begin
HandleAfterInsert(Context.getNewRow());
end;
class procedure TCustomer.BeforeInsertTrigger(Context: TriggerContext);
begin
HandleAfterUpdate(Context.getNewRow());
end;
class procedure TCustomer.BeforeUpdateTrigger(Context: TriggerContext);
begin
56
8 Blackfish SQL
HandleAfterDelete(Context.getNewRow());
end;
This shows the C# implementation of the Customer class triggers:
public class Customer {
public static void BeforeInsertTrigger(TriggerContext Context)
{
HandleBeforeInsert(Context.GetNewRow());
}
public static void BeforeUpdateTrigger(TriggerContext Context)
{
HandleBeforeUpdate(Context.GetOldRow(), Context.GetNewRow());
}
public static void beforeDeleteTrigger(TriggerContext Context)
{
HandleBeforeDelete(Context.getNewRow());
}
public static void afterInsertTrigger(TriggerContext Context)
{
HandleAfterInsert(Context.getNewRow());
}
public static void afterUpdateTrigger(TriggerContext Context)
{
HandleAfterUpdate(Context.getNewRow());
}
public static void afterDeleteTrigger(TriggerContext Context)
{
HandleAfterDelete(Context.getNewRow());
}
}
Creating Triggers in Blackfish SQL for Java Databases
Use the CREATE TRIGGER statement to create a trigger in a Blackfish SQL for Java database. See the SQL Reference for
syntax and examples of the CREATE TRIGGER statement.
Examples:
57
Blackfish SQL 8
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
58
9 Blackfish SQL
• Viewing metadata
• Altering automatic failover and incremental backup
• Altering database properties
• Verifying tables
• Database copy for backup purposes
• Database encryption 9
• Change database password
• Displaying database staus, such as the following:
• locks
• status log IDs
These methods can be called from SQL using the CALL statement. They can be called without creating a METHOD alias because
the Blackfish SQL recognizes the methods in DB_ADMIN as built-in methods.
DB_ADMIN Methods
The following sections provide the syntax and a brief description of each DB_ADMIN method.
ALTER_DATABASE
ALTER_DATABASE(string properties)
Alters specified database properties. properties is a comma-separated list of settings for the columns from the
DatabaseColumns class. Each property is specified as follows: <COLUMN_NAME>=<VALUE>. See the online help for
information on the DatabaseColumns class.
59
Blackfish SQL 9
ALTER_MIRROR
ALTER_MIRROR(string mirrorName, string properties)
Alters an existing mirror configuration. mirrorName is a value from the SysMirrors.NAME column. properties is a
comma-separated list of settings for the columns from the SysMirrors class. Each property is specified as follows:
<COLUMN_NAME>=<VALUE>. See the online help for information on the SysMirrors class.
ALTER_MIRROR_SCHEDULE
ALTER_MIRROR_SCHEDULE(INT32 mirrorId, string properties)
Alters an existing mirror schedule item. mirrorName is value from the SysMirrorSchedule.NAME column. properties A
comma separated list of settings for the columns from the SysMirrorSchedule class. Each property is specified as follows:
<COLUMN_NAME>=<VALUE>. See the online help for information on the SysMirrorSchedule class.
CHANGE_PASSWORD
CHANGE_PASSWORD(string oldpassword, string newPassword)
CLOSE_CONNECTION
CLOSE_CONNECTION(INT32 connectionId, INT64 birthTimeMilliseconds)
Closes an open connection. Can be used to close unwanted connections. connectionId From the ID column returned by
GET_CONNECTIONS. birthTimeMilliseconds from the BIRTH column returned by GET_CONNECTIONS. Returns true if
successful See GET_CONNECTIONS to obtain a table of connections to close.
CLOSE_OTHER_CONNECTIONS
CLOSE_OTHER_CONNECTIONS()
Closes all other open connections. Administrator rights are required to execute this method.
COPY_STREAMS
COPY_STREAMS(string otherFilename, string adminUser, string adminPass, boolean doOverwrite,
boolean doIgnoreErrors)
9
Copies all tables and indexes from the current database to another database. COPY_USERS method should be called first if users
have been added to the database. otherFilename is the file name of the destination database. adminUser is the user with
ADMIN privileges in the destination database. adminPass is the password of the ADMIN user in the destination database.
overwrite allows the tables to be overwritten. If false this will cause an error. ignoreErrors causes errors to be ignored
when recovering a corrupt database.
COPY_USERS
COPY_USERS(string otherFilename, string adminUser, string adminPass, boolean doCopyEncryption,
boolean replaceExistingUsers)
Copies all users from the current database to another specified database. otherFilename is the file name of the destination
database. adminUser user with ADMIN privileges in the destination database. adminPass password of the ADMIN user in the
destination database. copyEncryption if the current database is encrypted then encrypt the target database with the same
key. replaceExistingUsers if true replace the existing users in the target database.
CREATE_MIRROR
CREATE_MIRROR(string properties)
60
9 Blackfish SQL
Creates a new mirror with the configuration properties provided. properties A comma-separated list of settings for the
columns from the SysMirrors class. Each property is specified as follows: <COLUMN_NAME>=<VALUE>. Returns a unique ID
for new new mirror. See the online help for information on the SysMirrors class.
CREATE_MIRROR_SCHEDULE
CREATE_MIRROR_SCHEDULE(string mirrorName, string properties)
Creates a new mirror synchronization schedule. mirrorName the name of the mirror to add the mirror schedule item for.
properties a comma-separated list of settings for the columns in the SysMirrorSchedule table. Each property is defined by
specified as follows: <COLUMN_NAME>=<VALUE>. Returns a unique INT64 identifier for the new schedule item. See the online
help for information on the SysMirrorSchedule class.
DROP_MIRROR
DROP_MIRROR(string mirrorName)
Drops an existing mirror configuration. mirrorName is a value from the SysMirrors.NAME column. See the online help for
information on the SysMirrors class.
DROP_MIRROR_SCHEDULE
DROP_MIRROR_SCHEDULE(INT32 mirrorID)
Drops an existing mirror schedule item. mirrorID is a value from the SysMirrorSchedule.ID column See the online help for
information on the SysMirrorSchedule class.
ENCRYPT
ENCRYPT(string adminPassword, string masterKeySeed)
Encrypts an empty database. adminPass password of the user performing this command. masterKeySeed a random
sequence of 16 characters that is used internally as the master password. Once provided, it does not needed to be provided for
access to the database. This should be very random sequence of characters.
GET_ALL_LICENCES
GET_ALL_LICENCES( )
Returns a result table with zero or more rows of all licenses that could be found. The columns for this result table are defined in
LicenseColumns class. See the online help for information on the LicenseColumns class.
9
GET_COLUMN_PRIVILEGES
GET_COLUMN_PRIVILEGES(string catalogPattern, string schemaPattern, string tablePattern, string
columnPattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. columnPattern specifies the LIKE column search patttern. null means means that the column name should not
be used to narrow the search. Returns a result table with column privileges for the specified table(s). The columns for this result
table are defined in the ColumnPrivilegeColumns class. See the online help for information on the
ColumnPrivilegeColumns class.
GET_COLUMNS
GET_COLUMNS(string catalogPattern, string schemaPattern, string tablePattern, string
columnPattern)
61
Blackfish SQL 9
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. columnPattern specifies the LIKE column search patttern. null means means that the column name should not
be used to narrow the search. Returns a result table with metadata for the columns of the specified table(s). The columns for this
result table are defined in the ColumnsColumns class. See the online help for information on the ColumnsColumns class.
GET_CONNECTIONS
GET_CONNECTIONS()
Returns a result table of the open connections for the current server connection. The columns for this result table are defined in
the ConColumns class. See the online help for information on the ConColumns class.
GET_DATABASE_PRIVILEGES
GET_DATABASE_PRIVILEGES(boolean forRoles)
Returns a result table with database access rights for each user or role using the following columns:
GET_DATABASE_PRODUCT_NAME
GET_DATABASE_PRODUCT_NAME()
GET_DATABASE_PRODUCT_VERSION
GET_DATABASE_PRODUCT_VERSION()
9
Returns the product version of the server as a string
GET_DATABASE_PROPS
GET_DATABASE_PROPS()
Returns a result table with the properties for the current database. The columns for this result table are defined in the
DatabaseColumns class. See the online help for information on the DatabaseColumns class.
GET_DATABASE_STATUS
GET_DATABASE_STATUS()
Returns a result table with one row of status information about the current database. The columns for this result table are defined
in the DatabaseStatusTable class. See the online help for information on the DatabaseStatusTable class.
GET_DATABASE_STATUS_LOG_FILTER
GET_DATABASE_STATUS_LOG_FILTER()
Returns an INT32 filter that controls what kind of logging information is logged to the status log file for all current database
62
9 Blackfish SQL
connections. The meaning of the bit masks is found in LogFilterCodes class. See the online help for information on the
LogFilterCodes class.
GET_DATATYPES
GET_DATATYPES()
Returns a result table with a row for each supported data type in the database server. The columns for this result table are
defined in the DataTypesColumns class. See the online help for information on the DataTypesColumns class.
GET_FOREIGN_KEYS
GET_FOREIGN_KEYS(catalogPattern, schemaPattern, tablePattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. Returns a result table with a row for each foreign key in the specified table(s). The columns for this result table are
defined in the ForeignKeyColumnsColumns class. See the online help for information on the ForeignKeyColumnsColumns
class.
GET_FOREIGN_KEY_COLUMNS
GET_FOREIGN_KEY_COLUMNS(string catalogPattern, string schemaPattern, string tablePattern,
string foreignKeyPattern, string primaryCatalogPattern, string primarySchemaPattern, string
primaryTablePattern, string primaryIndexPattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. foreignKeyPattern specifies the LIKE foreign key search patttern. null means means that the table name
should not be used to narrow the search. primaryCatalogPattern specifies the LIKE primary catalog search pattern. Not
used. Reserved for future use. primarySchemaPattern specifies the LIKE primary schema search patttern. null means
means that the primary schema name should not be used to narrow the search. primaryTablePattern specifies the LIKE
primary table search patttern. null means means that the table name should not be used to narrow the search.
primaryIndexPattern specifies the LIKE primary table index search patttern. null means means that the table name
should not be used to narrow the search. Returns a result table with a row for each foreign key column pairs in the specified
table(s). The columns for this result table are defined in the ForeignKeyColumns class. See the online help for information on 9
the ForeignKeyColumns class.
GET_INDEXES
GET_INDEXES(string catalogPattern, string schemaPattern, string tablePattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. Returns a result table with the indexes of the specified table(s). The columns for this result table are defined in the
IndexesColumns class. See the online help for information on the IndexesColumns class.
GET_INDEX_COLUMNS
GET_INDEX_COLUMNS(string catalogPattern, string schemaPattern, string tablePattern, string
indexPattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
63
Blackfish SQL 9
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. indexPattern specifies the LIKE index search patttern. null means means that the table name should not be used
to narrow the search. Returns a result table with the column information of the specified table index(es). The columns for this
result table are defined in the IndexColumnsColumns class. See the online help for information on the
IndexColumnsColumns class.
GET_KEYWORDS
GET_KEYWORDS()
GET_LICENSE
GET_LICENSE()
Returns a result table with one row of license information for the best deployment license found. The columns for this result table
are defined in the LicenseColumns class. See the online help for information on the LicenseColumns class.
GET_LICENSE_SEARCH_DIRS
GET_LICENSE_SEARCH_DIRS()
Returns a result table with a row for each directory that is searched for license files.
GET_LOCKS
GET_LOCKS()
Returns a result table of all the currently held table and row locks for all connections to the current database. The columns for
this result table are defined in the LockColumns class. See the online help for information on the LockColumns class.
GET_MIRROR_ID
GET_MIRROR_ID()
GET_MIRRORS
9 GET_MIRRORS(mirrorName, checkStatus)
name is the name of the mirror or null to get all mirrors. checkStatus is set to TRUE to provide additional columns on the
status of the mirror. Status checking requires more work to be performed, but provides additional information on a mirror.
Returns a result table with a row for each mirror. The columns for this result table are defined in the MirrorStatusColumns
class. See the online help for information on the MirrorStatusColumns class.
GET_NEWEST_STATUS_LOG_ID
GET_NEWEST_STATUS_LOG_ID()
Returns the INT32 ID of the newest log file that can be retrieved using the GET_STATUS_LOG() method.
GET_OLDEST_STATUS_LOG_ID
GET_OLDEST_STATUS_LOG_ID()
Returns the INT32 ID of the oldest log file that can be retrieved using the GET_STATUS_LOG() method.
64
9 Blackfish SQL
GET_PROCEDURES
GET_PROCEDURES(string catalogPattern, string schemaPattern, string procedurePattern, string
type)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
procedurePattern specifies the LIKE procedure search patttern. null means means that the procedure name should not be
used to narrow the search. procedureType a procedure type; must be either PROCEDURE or FUNCTION or null for any
procedure type. Returns a result table with metadata for the known stored procedures. The columns for this result table are
defined in the ProcedureColumns class. See the online help for information on the ProcedureColumns class.
GET_PROCEDURE_COLUMNS
GET_PROCEDURE_COLUMNS(string catalogPattern, string schemaPattern, string procedurePattern,
string parameterPattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means that the schema name should not be used to narrow the search.
procedureNamePattern specifies the LIKE procedure search patttern. null means that the procedure name should not be
used to narrow the search. columnNamePattern specifies the LIKE column search patttern. null means that the column
name should not be used to narrow the search. Returns a result table with the parameters of the specified procedure(s). The
columns for this result table are defined in the ProcedureParametersColumns class. See the online help for information on
the ProcedureParametersColumns class.
GET_PROCEDURE_PRIVILEGES
GET_PROCEDURE_PRIVILEGES() Returns a result table with descriptions of the access rights for each procedure. The result
table has the following columns:
GET_ROLES
GET_ROLES()
Returns a result table with the roles in the database. The columns for this result table are defined in the RolesColumns class.
See the online help for information on the RolesColumns class.
GET_ROLE_GRANTS
GET_ROLE_GRANTS(boolean forRoles)
65
Blackfish SQL 9
GET_SCHEMAS
GET_SCHEMAS(string catalogPattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. Returns a result table with the
schemas in the database.
GET_STATUS_LOG_FILTER
GET_STATUS_LOG_FILTER()
Returns the INT32 filter that controls the type of logging information to be logged to the status log for this connection. The
meaning of the bit masks is found in LogFilterCodes class. See the online help for information on the LogFilterCodes
class.
GET_STATUS_LOG
GET_STATUS_LOG(INT32 log_id, INT64 offset)
id is the ID of the log file being retrieved. offset is the offset into the log file from the start of the file. Returns the status log for
the current databas as a stream.
GET_STATUS_LOGS
GET_STATUS_LOGS()
Returns a result table with id of the existing logs for this database. The columns for this result table are defined in the
StatusLogColumns class. See the online help for information on the StatusLogColumns class.
GET_TABLE_PRIVILEGES
GET_TABLE_PRIVILEGES(string catalogPattern, string schemaPattern, string tablePattern)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
9 LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. Returns a result table privilege descriptions for the selected table(s). The columns for this result table are defined in
the TablePrivilegeColumns class. See the online help for information on the TablePrivilegeColumns class.
GET_TABLES
GET_TABLES(string catalogPattern, string schemaPattern, string tablePattern, string type)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. types comma separated list of TABLE, VIEW, SYSTEM_TABLE or null. Returns a result table with metadata for the
specified table(s). The columns for this result table are defined in the TableColumns class. See the online help for information
on the TableColumns class.
GET_THIS_MIRROR
GET_THIS_MIRROR(boolean checkStatus) checkStatus TRUE to provide additional columns on the status of the mirror.
66
9 Blackfish SQL
Like GET_MIRRORS except that it returns information for only the mirror this procedure is executed against. Returns a result table
with a row for this mirror. The columns for this result table are defined in the MirrorStatusColumns class. See the online help
for information on the MirrorStatusColumns class.
GET_TRIGGERS
GET_TRIGGERS(string catalogPattern, string schemaPattern, string tablePattern, string trigger)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
tablePattern specifies the LIKE table search patttern. null means means that the table name should not be used to narrow
the search. triggerPattern specifies the LIKE trigger search patttern. null means means that the trigger name should not
be used to narrow the search. Returns a result table of the triggers of the specified table(s).
GET_USERS
GET_USERS()
GET_VIEWS
GET_VIEWS(string catalogPattern, string schemaPattern, string view)
catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved for future use. schemaPattern specifies the
LIKE schema search patttern. null means means that the schema name should not be used to narrow the search.
viewNamePattern specifies the LIKE view search patttern. null means that the view name should not be used to narrow the
search. Returns a result table with the definitions of the specified view(s). The columns for this result table are defined in the
ViewsColumns class. See the online help for information on the ViewsColumns class.
9
SET_DATABASE_STATUS_LOG_FILTER
SET_DATABASE_STATUS_LOG_FILTER(INT32 filter)
Sets the filter that controls the type of logging information to be entered in the status log file for all current database connections.
SET_PRIMARY_MIRROR
SET_PRIMARY_MIRROR(INT64 txTerminationTimeout, boolean forceTransactionAbort, boolean
forceSwitch)
Sets the current mirror to the primary mirror. txTerminationTimeout is milliseconds to wait for existing transactions to
terminate. forceTxTermination causes existing transactions to abort after txTerminationTimeout milliseconds have
elapsed. forceSwitch causes this mirror to become the primary mirror even if other mirrors could not be synchronized with this
change.
SET_STATUS_LOG_FILTER
SET_STATUS_LOG_FILTER(INT32 filter)
67
Blackfish SQL 9
Sets the filter that controls the type of logging information to be logged to the status log file for the current connection.
SYNCH_MIRROR
SYNCH_MIRROR(string mirrorName)
Updates the mirror specified for mirrorName with the most recent log files of its update mirror if necessary.
VALIDATE_PRIMARY_MIRROR
VALIDATE_PRIMARY_MIRROR()
Validates a primary mirror so that write transactions can be performed against it.
VERIFY
VERIFY(string catalogPattern, string schemaPattern, string tablePattern, INT32 displayOptions,
INT32 errorCount, out INT32 errorsEncountered, out String output)
Verifies one or more tables in the database. catalogPattern specifies the LIKE catalog search pattern. Not used. Reserved
for future use. schemaPattern specifies the LIKE schema search patttern. null means means that the schema name should
not be used to narrow the search. tablePattern specifies the LIKE table search patttern. null means means that the table
name should not be used to narrow the search. displayOptions one or more of the StreamVerifierDisplay bit settings
ORed together that instruct the verifier to display progress messages as the stream is verified. errorCount specifies the
number of errors that can be ignored before an exception is thrown. errorsEncountered is an output parameter that returns
the number of errors that were encountered. output is an output parameter that can be used to return a string with diagnostic
output from the verifier.
VERIFY
VERIFY(string tablePattern, INT32 displayOptions, INT32 errorCount, out INT32
errorsEncountered, out String output)
Verifies one or more tables in the database. tablePattern specifies the LIKE table search patttern. null means means that
the table name should not be used to narrow the search. displayOptions one or more of the StreamVerifierDisplay bit
settings ORed together that instruct the verifier to display progress messages as the stream is verified. errorCount specifies
the number of errors that can be ignored before an exception is thrown. errorsEncountered is an output parameter that
returns the number of errors that were encountered. output is an output parameter that can be used to return a string with
9 diagnostic output from the verifier.
Examples
The following statement computes the square root of the column COL1:
SELECT DB_UTIL.SQRT(COL1) FROM TABLE1;
The following statement computes some timestamps that are equal to the timestamp COL2 plus five hours.
SELECT DB_UTIL.TIMESTAMPADD('SQL_TSI_HOUR',5,COL2) FROM TABLE1;
Numeric Functions
68
9 Blackfish SQL
ACOS
ACOS(expression)
ASIN
ASIN(expression)
ATAN
ATAN(expression)
ATAN2
ATAN2(y, x)
Returns the arctangent of the quotient of its two arguments. The angle returned is a numeric value in radians between PI and -PI
and represents the counterclockwise angle between the positive X axis and the point (x, y). Note that the y value is passed in
first.
CEILING
CEILING(expression)
Returns the smallest integer that is greater than or equal to the argument. The return is of the same data type as the input.
COS
COS(expression)
COT
COT(expression)
9
Returns the cotangent of an angle.
DEGREES
DEGREES(expression)
EXP
EXP(expression)
FLOOR
FLOOR(expression)
Returns the largest integer that is equal to or less than expression. The return is of the same data type as the input.
69
Blackfish SQL 9
LOG
LOG(expression)
LOG10
LOG10(expression)
MOD
MOD(expression1, expression2)
Returns the remainder for expression divided by expression, where both expressions evaluate to integers of type SHORT, INTs
or LONGs. The return is of the same data type as the input.
PI
PI()
POWER
POWER(expression1, expression2)
RADIANS
RADIANS(expression)
RAND
RAND()
RAND
RAND(expression)
ROUND
ROUND(expression1, expression2)
SIGN
SIGN(expression)
Returns –l if the value of expression is negative, zero if expression is zero, and 1 if expression is positive. The return is of
the same data type as the input.
70
9 Blackfish SQL
SIN
SIN(expression)
SQRT
SQRT(expression)
TAN
TAN(expression)
TRUNCATE
TRUNCATE(expression1, expression2)
String Functions
ASCII
ASCII(string)
Returns an integer representing the ASCII code value of the leftmost character in string.
TO_CHAR
TO_CHAR(ascii_code)
DIFFERENCE
9
DIFFERENCE(string1, string2)
Returns an integer in the range 0 through 4 indicating how many of the four digits returned by the function SOUNDEX for string1
are the same as those returned for string2. A return value of 4 indicates that the SOUNDEX codes are identical.
INSERT_STRING
INSERT_STRING(string1, start, length, string2)
Returns a character string formed by deleting length characters from string1 beginning at start and then inserting string2 into
string1 at start.
LEFT_STRING
LEFT_STRING(string, count)
REPEAT
REPEAT(string, count)
71
Blackfish SQL 9
REPLACE
REPLACE (string1, string2, string3)
Returns a character string formed by replacing all occurrences of string2 in string1 with string3.
RIGHT
RIGHT_STRING(string, count)
Returns a string formed by taking the right-hand count characters from string.
SOUNDEX
SOUNDEX (string)
Returns a string that represents the sound of the words in string; the return is data source-dependent and could be a four-digit
SOUNDEX code, a phonetic representation of each word, or some other form.
SPACE
SPACE(count)
DAYNAME
DAYNAME(date)
Returns the day of the week as a string from the given date.
DAYOFWEEK
DAYOFWEEK(date)
MONTHNAME
MONTHNAME(date)
QUARTER
QUARTER(date)
Returns the quarter as a number from the given date: 1=January through March, 2=April through June.
TIMESTAMPADD
TIMESTAMPADD(interval, count, timestamp)
72
9 Blackfish SQL
interval can be any one of the following and must be enclosed in single quotes: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND,
SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER, or
SQL_TSI_YEAR.
timestamp can be any of the following SQL data types: DATE, TIME, TIMESTAMP.
TIMESTAMPDIFF
TIMESTAMPDIFF(interval, timestamp1, timestamp2)
Returns a number representing the number of intervals by which timestamp2 is greater than timestamp1.
interval can be any one of the following and must be enclosed in single quotes: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND,
SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH, SQL_TSI_QUARTER, or
SQL_TSI_YEAR.
timestamp1 and timestamp2 can be any of the following SQL data types: DATE, TIME, TIMESTAMP.
WEEK
WEEK(date)
Returns an integer from 1 to 53 representing the week of the year in date. 1=the first week of the year.
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
73
10 Blackfish SQL
10 SQL Reference
The SQL Reference includes the following topics:
Data Types
Literals Keywords
Identifiers List Syntax
Expressions Predicates
Functions Table Expressions
Statements Data Definition Statements
Transaction Control Statements Data Manipulation Statements
Security Statements Escape Sequences
Escape Functions ISQL
Data Types
In SQL, you can specify data types by using Blackfish SQL names or by using synonyms, which are more portable to other SQL
dialects. The following table lists the Blackfish SQL SQL data types and their Java equivalents. See Administering Blackfish SQL
for a description of each data type.
Strings are stored in UNICODE character format. However, if a string contains no high-bit characters. the high bytes are not 10
saved and the number of bytes is equal to the number of characters. In double-byte languages such as Japanese, the number of
bytes is double the number of characters.
NOTE: The word “inline” refers to the portion of the field data that is stored in the table row. When the maximum inline value is
surpassed, the remaining data is stored in a separate stream as a Blob.
75
Blackfish SQL 10
1 In the SQL Equivalents column, bold indicates the more portable forms.
Examples
VARCHAR(30,10) A string with a maximum size of 30 characters; the first 10 bytes are stored inline, the
remainder in a Blob (a separate stream for large objects)
VARCHAR(30) A string with a maximum size of 30 characters, all stored inline because the precision is less
than default inline value of 64
VARCHAR A string with no length limit; the first 64 bytes are stored inline, any additional bytes are stored
in a Blob (a separate stream for large objects)
DECIMAL(5,2) A BigDecimal with a precision of at least 5 and exactly 2 decimal places
DECIMAL(4) A BigDecimal with a precision of at least 4 and exactly 0 decimal places
DECIMAL A BigDecimal with space for at least 72 significant digits and exactly 0 decimal places
OBJECT A serializable Java object
OBJECT('java.math.BigInteger') A serializable Java object that must consist of java.math.BigInteger objects
Literals
The following table lists the types of scalar literal values supported:
REAL DOUBLE 8E0 4E3 0.3E2 6.2E-72 An approximate numeric: a number followed by the letter E, followed by an
FLOAT(p) optionally signed integer
VARCHAR(p,m) 'Hello' 'don''t do that' A string: must be enclosed in single quotes. The single quote character is
represented by two consecutive single quotes
VARBINARY(p,m) B'1011001' X'F08A' A binary or hexadecimal sequence enclosed in single quotes and preceded by
X'f777' the letter B for binary or X for hexadecimal
BOOLEAN TRUE FALSE
76
10 Blackfish SQL
DATE DATE '2002-06-17' Displays local time of origin; format is DATE 'yyyy-mm-dd'
TIME TIME '15:46:55' Displays local time of origin; format is TIME 'hh:mm:ss' in 24-hour format
TIMESTAMP TIMESTAMP Displays local time of display; format is TIMESTAMP 'yyyy-mm-dd hh:mm:ss'
'2001-12-31 13:15:45'
Keywords
The two lists below show all the current keywords for Blackfish SQL. The words in the first list are reserved and can be used as
SQL identifiers only when enclosed in double quotation marks. The keywords in the second list are not reserved and can be
used either with or without quotation marks.
Note that not all SQL-92 keywords are treated as a keyword by the Blackfish SQL SQL engine. For maximum portability,
don’t use identifiers that are treated as keywords in any SQL dialect.
ABSOLUTE ACTION ADD CURRENT_ROLE INTO IS ISOLATION JOIN RESTRICT REVOKE RIGHT
ADMIN ADMINISTRATOR ALL CURRENT_TIME KEY LEADING LEFT LEVEL SCHEMA SELECT SET
ALTER AND ANY AS ASC CURRENT_TIMESTAMP LIKE LOWER MAX MIN SMALLINT SOME SQRT
AUTHORIZATION CURRENT_USER DATE NATURAL NO NONE NOT STARTUP SUBSTRING
AUTOINCREMENT AVG DECIMAL DEFAULT DELETE NULL NULLIF NUMERIC SUM TABLE THEN TIME
BETWEEN BIT BIT_LENGTH DESC DISTINCT DOUBLE OCTET_LENGTH ON ONLY TIMESTAMP TO TRAILING
BOTH BY CALL CASCADE DROP ELSE END ESCAPE OPTION OR ORDER TRANSACTION TRIM
CASE CAST CHAR EXCEPT EXECUTE EXISTS OUTER POSITION TRUE UNION UNIQUE
CHAR_LENGTH CHARACTER EXTRACT FALSE FLOAT PRECISION PRIMARY UNKNOWN UPDATE
CHARACTER_LENGTH FOR FOREIGN FROM FULL PRIVILEGES PUBLIC REAL UPPER USER USING
CHECK COALESCE COLUMN GRANT GROUP HAVING IN REFERENCES RENAME VALUES VARCHAR
CONSTRAINT COUNT INDEX INNER INSERT INT RESOLVABLE VARYING VIEW WHEN
CREATE CROSS INTEGER INTERSECT WHERE WITH
CURRENT_DATE
Identifiers
Unquoted SQL identifiers are case insensitive and are treated as uppercase. An identifier can be enclosed in double quotes, and
is then treated as case sensitive. An unquoted identifier must follow these rules:
77
Blackfish SQL 10
Valid identifiers:
Identifier Description
customer Treated as CUSTOMER
Help_me Treated as HELP_ME
"Hansen" Treated as Hansen
"" Treated as a single space
Invalid identifiers:
Identifier Problem
_order Must start with a character
date date is a reserved keyword
borland.com Dots are not allowed
The forms in the following list are all the same identifier and are all treated as LAST_NAME:
• last_name
• Last_Name
• lAsT_nAmE
• "LAST_NAME"
List Syntax
The following section contains element names ending with the words “list” or “commalist” that are not further defined. For
example:
<select item commalist>
<column constraint list>
These definitions are to be read as a lists with at least one element, comma separated in the case of a commalist:
<select item commalist> ::=
<select item> [ , <select item> ] *
10
<column constraint list> ::=
<column constraint> [ <column constraint> ] *
Expressions
Expressions are used throughout the SQL language. They contain several infix operators and a few prefix operators. This is the
operator precedence from strongest to weakest:
• prefix + -
• infix * /
• infix + - ||
• infix = <> < > <= >=
• prefix NOT
• infix AND
78
10 Blackfish SQL
• infix OR
Syntax
<expression> ::=
<scalar expression>
| <conditional expression>
<scalar expression> ::=
<scalar expression> {+ | - | * | / | <concat> }
<scalar expression>
| {+ | -} <scalar expression>
| ( <expression> )
| ( <table expression> )
| <column reference>
| <user defined function reference>
| <literal>
| <aggregator function>
| <function>
| <parameter marker>
For a list of functions supported in Blackfish SQL, see Functions.
<conditional expression> ::=
<conditional expression> OR <conditional expression>
| <conditional expression> AND <conditional expression>
| NOT <conditional expression>
| <scalar expression> <compare operator> <scalar expression>
| <scalar expression> <compare operator> { ANY | SOME | ALL }
(<table expression>)
| <scalar expression> [NOT] BETWEEN <scalar expression>
| <scalar expression> [NOT] LIKE <scalar expression>
[ ESCAPE <scalar expression> ]
| <scalar expression> [NOT] IS { NULL | TRUE | FALSE | UNKNOWN }
| <scalar expression> IN ( <scalar expression commalist> )
| <scalar expression> IN ( <table expression> )
| EXISTS ( <table expression> )
<compare operator> ::=
= | <> | < | > | <= | >=
<concat> ::= ||
<table expression> ::=
<table expression> UNION [ ALL ] <table expression>
| <table expression> EXCEPT [ ALL ] <table expression>
| <table expression> INTERSECT [ ALL ] <table expression>
| <join expression>
| <select expression>
| ( <table expression> )
<aggregator function> ::=
<aggregator name> ( <expression> )
| COUNT ( * )
79
Blackfish SQL 10
The following statement selects the calculated value of Amount times Price from the Orders table for a to-be-provided
customer for orders in January:
SELECT Amount * Price FROM Orders
WHERE CustId = ? AND EXTRACT(MONTH FROM Ordered) = 1;
The following statement gets data using a scalar subquery:
SELECT Name, (SELECT JobName FROM Job WHERE Id=Person.JobId)
FROM Person;
Note that it is an error if the subquery returns more than one row.
Predicates
The following predicates, used in condition expressions, are supported.
BETWEEN
The BETWEEN predicate defines an inclusive range of values. The result of:
expr BETWEEN leftExpr AND rightExpr
is equivalent to the expression:
leftExpr <= expr AND expr <= rightExpr
Syntax
<between expression> ::=
<scalar expression> [NOT] BETWEEN <scalar expression>
AND <scalar expression>
Example
The following statement selects all the orders where a customer orders between 3 and 7 items of the same kind:
SELECT * from Orders WHERE Amount BETWEEN 3 AND 7;
EXISTS
An EXISTS expression evaluates to either TRUE or FALSE depending on whether there are any elements in a result table.
Syntax
<exists predicate> ::= EXISTS ( <table expression> )
Example
The following statement finds all diving equipment where the beginning of the name is the same as the beginning of a name of a
10 different piece of equipment.
SELECT * FROM zodiac z
WHERE EXISTS
( SELECT * FROM zodiac z2 WHERE POSITION(z.name IN z2.name) = 1
AND z.name < > z2.name );
IN
The IN clause indicates a list of values to be matched. Any one of the values in the list is considered a match for the SELECT
statement containing the IN clause.
Syntax
<in expression> ::=
80
10 Blackfish SQL
The following statement returns all records where the name column matches either "leo" or "aquarius":
SELECT * FROM zodiac WHERE name IN ('leo', 'aquarius');
The IN clause also has a variant where a subquery is used instead of an expression list.
Syntax
<in expression> ::= <scalar expression>
IN ( <table expression> )
Example 8
SELECT * FROM zodiac WHERE name IN (SELECT name FROM people);
IS
The IS predicate tests expressions. Any expression can evaluate to the value NULL, but conditional expressions can evaluate to
one of the three values: TRUE, FALSE, or UNKNOWN. UNKNOWN is equivalent to NULL for conditional expressions. Note that for a
SELECT query with a WHERE clause, only rows that evaluate to TRUE are included. If the expression evaluates to FALSE or
UNKNOWN, the row isn't included. The output of the IS predicate can have two results: TRUE or FALSE.
Syntax
<is expression> ::=
<scalar expression> IS [NOT] { NULL | TRUE | FALSE | UNKNOWN }
Examples
TRUE IS TRUE evaluates to TRUE.
LIKE
The LIKE predicate provides SQL with simple string pattern matching. The search item, pattern, and escape character (if given)
must all evaluate to strings. The pattern can include the special wildcard characters _ and % where:
1. The following expression evaluates to TRUE if Item contains the string "shoe" anywhere inside it:
Item LIKE '%shoe%'
2. The following expression evaluates to TRUE if Item is exactly three characters long and starts with the letter "S":
Item LIKE 'S__'
81
Blackfish SQL 10
3. The following expression evaluates to TRUE if Item ends with the percent character. The * is defined to escape the two
special characters. If it precedes a special character, it is treated as a normal character in the pattern:
Item Like '%*%' ESCAPE '*'
Quantified Comparisons
An expression can be compared to some or all elements of a result table.
Syntax
<quantified comparison> ::=
<scalar expression> <compare operator>
{ ANY | SOME | ALL } ( <table expression> )
Example 9
SELECT * FROM zodiac
WHERE quantify <= ALL ( SELECT quantify FROM zodiac );
Functions
Functions that act on strings work for strings of any length. Large strings are stored as Blobs, so you might want to define large
text fields as VARCHAR to enable searches.
ABSOLUTE
The ABSOLUTE function works on numeric expressions only, and yields the absolute value of the number passed.
Syntax
<absolute function> ::= ABSOLUTE( <expression> )
Example 11
SELECT * FROM Scapes WHERE ABSOLUTE( Height - Width ) < 50;
BIT_LENGTH
The BIT_LENGTH function gives the length in bits of a STRING, INPUTSTREAM, or OBJECT value.
Syntax
<bit length function> ::=
BIT_LENGTH( <expression> )
Example 12
10 SELECT * FROM TABLE1 WHERE BIT_LENGTH( binary_column ) > 8192;
CASE
The CASE function returns a conditional value.
Syntax
<case function> ::=
CASE [ <expression> ]
<when clause commalist>
ELSE <expression>
END
82
10 Blackfish SQL
Examples
CASE
WHEN COL1 > 50 THEN 'Heavy Item'
WHEN COL1 > 25 THEN 'Middle weight Item'
WHEN COL1 > 0 THEN 'Light Item'
ELSE 'No weight specified'
END
CASE COL2
WHEN 4 THEN 'A'
WHEN 3 THEN 'B'
WHEN 2 THEN 'C'
WHEN 1 THEN 'D'
ELSE 'Invalid Grade'
END
CAST
The CAST function casts one data type to another data type.
Syntax
<cast function> ::=
CAST ( <column name> AS <data type> )
Example
The following example yields a row where a string column ID equals '001234'
SELECT * FROM employee WHERE CAST ( id AS long ) = 1234;
Syntax
<char length function> ::=
CHAR_LENGTH ( <scalar expression> )
CHARACTER_LENGTH ( <scalar expression> )
COALESCE
The COALESCE function returns the first non-NULL value from the expression list. 10
Syntax
<coalesce function> ::=
COALESCE( expression commalist )
Example
The following statement yields a list of names. The name is the last_name if this column is not NULL, otherwise it is the
first_name.
SELECT COALESCE(last_name, first_name) AS name FROM table1;
83
Blackfish SQL 10
Example 13
SELECT * from Returns where ReturnDate <= CURRENT_DATE;
CURRENT_ROLE
The CURRENT_ROLE function returns the current role, or NULL if no role has been set using the SET ROLE statement.
Syntax
<current_role_function> ::= CURRENT_ROLE
Example
The following statement returns all notes from the CUSTOMERS table that were placed there by anyone using the MANAGER role.
The SOURCE column has a data type of VARCHAR.
SET ROLE MANAGER;
CURRENT_USER
The CURRENT_USER function returns the name of the current user.
Syntax
<current_user function> ::= CURRENT_USER
Example
The following statement returns returns all notes from the INVOICES table that were placed there by the current user. The
SOURCE column has a data type of VARCHAR.
SELECT * FROM INVOICES
WHERE SOURCE = CURRENT_USER;
10 EXTRACT
The SQL EXTRACT function extracts parts of date and time values. The expression can be a DATE, TIME, or TIMESTAMP value.
Syntax
<extract function> ::=
EXTRACT ( <extract field> FROM <scalar expression> )
84
10 Blackfish SQL
Syntax
<lower function> ::=
LOWER ( <scalar expression> )
NULLIF
The NULLIF function compares two expressions. It returns NULL if the expressions are equal. Otherwise, it returns the first
expression. It is logically equivalent to the following CASE expression: CASE WHEN expr1 = expr2 THEN NULL ELSE
expr1 END.
Syntax
<NULLIF> ::=
( <scalar expression>, <scalar expression> )
Example
The following statement returns a row with the last_name value for each row in TABLE1 where the first name is not the same
as the last name. If the first_name value is the same as the last_name value, it returns NULL.
SELECT NULLIF(last_name,first_name) FROM TABLE1;
OCTET_LENGTH
The OCTET_LENGTH function gives the length in bytes of a STRING, INPUTSTREAM, or OBJECT value.
Syntax
<octet_length> ::= OCTET_LENGTH(<expression>)
Example 14
10
SELECT * FROM TABLE1 WHERE OCTET_LENGTH(binary_column)>1024;
POSITION
The SQL POSITION function returns the position of a string within another string. If any of the arguments evaluate to NULL, the
result is NULL.
Syntax
<position function> ::=
POSITION ( <string> IN <another> )
Examples
POSITION('BCD' IN 'ABCDEFG') yields 2.
85
Blackfish SQL 10
SQRT
The SQRT function works on numeric expressions only, and yields the square root of the number passed.
Syntax
<sqrt function> ::= SQRT( <expression> )
Example 15
SELECT * FROM Scapes WHERE SQRT(HEIGHT*WIDTH - ?) > ?;
SUBSTRING
The SQL SUBSTRING function extracts a substring from a given string. If any of the operands are NULL, the result is NULL. The
start position indicates the first character position of the substring, where 1 indicates the first character. If FOR is used, it
indicates the length of the resulting string.
Syntax
<substring function> ::=
SUBSTRING ( <string expression>
FROM <start pos> [ FOR <length> ] )
Examples
SUBSTRING('ABCDEFG' FROM 2 FOR 3)
yields 'BCD'.
SUBSTRING('ABCDEFG' FROM 4)
yields 'DEFG'.
SUBSTRING('ABCDEFG' FROM 10)
yields ''.
SUBSTRING('ABCDEFG' FROM -6 FOR 3)
yields 'ABC'.
SUBSTRING('ABCEDFG' FROM 2 FOR -1)
raises an exception.
10
TRIM
The SQL TRIM function removes leading and/or trailing padding characters from a given string. The <padding> must be a
string of length 1, which is the character that is removed from the string.
86
10 Blackfish SQL
LEADING
| TRAILING
| BOTH
<padding> ::=
<scalar expression>
Examples
TRIM(' Hello world ')
yields 'Hello world'.
TRIM(LEADING '0' FROM '00000789.75')
yields '789.75'.
USER
The USER function returns the name of the current user; this function is the same as CURRENT_USER.
Syntax
<user function> ::= USER
Example
The following statement returns all notes from the INVOICES table that were placed there by the current user.
SELECT * FROM INVOICES
WHERE SOURCE = USER;
Table Expressions
This section describes a number of conventions that are used in the following statements reference. Specifically:
• Select expressions
• Unions, intersections, and differences
• Join expressions
<table expression> ::= <table expression> UNION
[ALL] <table expression> |
<table expression> EXCEPT [ALL] <table expression> |
Select Expressions
10
A select expression is the table expression most often used in a SELECT statement.
87
Blackfish SQL 10
Syntax
<select expression> ::=
SELECT [ ALL | DISTINCT ] <select item commalist>
FROM <table reference commalist>
[ WHERE <conditional expression> ]
[ GROUP BY <column reference commalist> ]
[ HAVING <conditional expression> ]
<select item> ::=
<scalar expression> [ [AS] <output column name> ]
| [ <range variable> . ] *
<table reference> ::=
<join expression>
| <table name> [ <output table rename> ]
| ( <table expression> ) [ <output table rename> ]
The following statement yields a single row with the total value of all orders.
SELECT SUM(Amount * Price) FROM Orders;
Example 2
88
10 Blackfish SQL
The following statement returns a single row with the number of orders where Amount is non-null for the customer 123.
SELECT COUNT(Amount) FROM Orders WHERE CustId = 123;
Example 3
The following statement returns a set of rows where the total value of all orders grouped by customers for the customers with an
ID number less than 200.
SELECT CustId, SUM(Amount * Price), COUNT(Amount)
WHERE CustId < 200 GROUP BY CustId;
Example 4
The following example yields a set of big customers with the value of all their orders.
SELECT CustId, SUM(Amount * Price), COUNT(Amount)
GROUP BY CustId HAVING SUM(Amount * Price) > 500000;
Example 5
The following statement is illegal because the CustId column is referenced in the select item list, but it is not present in the
GROUP BY reference list.
SELECT CustId, SUM(Amount* Price) GROUP BY Amount;
For the syntax of table expressions see "Table expressions".
UNION ALL Creates the union of two tables including all duplicates.
UNION Creates the union of two tables. If a row occurs multiple times in both tables, the result has this row exactly
twice. Other rows in the result have no duplicates.
INTERSECTION Creates the intersection of two tables including all duplicates.
ALL
INTERSECTION Creates the intersection of two tables. If a row has duplicates in both tables, the result has this row exactly
twice. Other rows in the result has no duplicates.
EXCEPT ALL Creates a table that has all rows that occur only in the first table. If a row occurs m times in the first table and 10
n times in the second, the result holds that row the larger of zero and m-n times.
EXCEPT Creates a table that has all rows that occur only in the first table. If a row occurs m times in the first table and
n times in the second, the result holds the row exactly twice if m > 1 and n = 0. Other rows in the result has
no duplicates.
Example 1
SELECT * FROM T1 UNION SELECT * FROM T2 UNION SELECT * FROM T3;
is executed as:
(SELECT * FROM T1 UNION SELECT * FROM T2) UNION SELECT * FROM T3;
Example 2
SELECT * FROM T1 UNION SELECT * FROM T2 INTERSECT SELECT * FROM T3;
89
Blackfish SQL 10
is executed as:
SELECT * FROM T1 UNION (SELECT * FROM T2 INTERSECT SELECT * FROM T3);
Join Expressions
In Blackfish SQL, join expressions give access to a wide variety of join mechanisms. The two most commonly used, inner joins
and cross joins, can be expressed with a SELECT expression alone, but any kind of outer join must be expressed with a JOIN
expression.
CROSS A CROSS JOIN B produces the same result set as SELECT A.*, B.* FROM A,B
JOIN
INNER A INNER JOIN B ON A.X=B.X produces the same result as SELECT A.*, B.* FROM A,B WHERE A.X=B.X
JOIN
LEFT A LEFT OUTER JOIN B ON A.X=B.X produces the rows from the corresponding inner join plus the rows from A
OUTER that didn't contribute, filling in the spaces corresponding to columns in B with NULLs.
RIGHT A RIGHT OUTER JOIN B ON A.X=B.X produces the rows from the corresponding inner join plus the rows from B
OUTER that didn't contribute, filling in the spaces corresponding to columns in A with NULLs.
FULL A FULL OUTER JOIN B ON A.X=B.X produces the rows from the corresponding inner join plus the rows from A
OUTER and B that didn't contribute, filling in the spaces corresponding to columns in B and A with NULLs.
UNION A UNION JOIN B produces a result similar to the following: A LEFT OUTER JOIN B ON FALSE UNION ALL A
RIGHT OUTER JOIN B ON FALSE a table with columns for all columns in A and B, with all the rows from A having
NULL values for columns from B appended with all the rows from B having NULL values for columns from A.
The
following
are
mutually
exclusive:
ON ON is an expression that needs to be fulfilled for a JOIN expression.
USING USING( C1, C2, C3) is equivalent to the ON expression above A.C1=B.C1 AND A.C2=B.C2 AND A.C3=B.C3,
except that the resulting table has columns C1, C2, and C3 occurring once each as the first three columns.
NATURAL NATURAL is the same as a USING clause with all the column names that appear in both tables A and B.
Syntax
<join expression> ::=
<table reference> CROSS JOIN <table reference>
| <table reference> [NATURAL] [INNER] JOIN <table reference>
10 [ <join kind> ]
| <table reference> [NATURAL] LEFT [OUTER] JOIN <table reference>
[ <join kind> ]
| <table reference> [NATURAL] RIGHT [OUTER] JOIN <table reference>
[ <join kind> ]
| <table reference> [NATURAL] FULL [OUTER] JOIN <table reference>
[ <join kind> ]
| <table reference> UNION JOIN <table reference>
90
10 Blackfish SQL
[ <join kind> ]
| <table reference> [NATURAL] FULL [OUTER] JOIN <table reference>
[ <join kind> ]
| <table reference> UNION JOIN <table reference>
• Data definition language for managing tables and indexes, schemas, views, and security elements.
• Data manipulation and selection with INSERT, UPDATE, DELETE, and SELECT; but no cursors.
• Support for general table expressions including JOIN, UNION, and INTERSECT.
For Blackfish SQL for Java, cursor operations are supported through the JDBC version 3.0 ResultSet API.
Syntax
<SQL statement> ::=
<data definition statement>
| <transaction control statement>
| <data manipulation statement>
<data definition statement> ::=
<create schema statement> 10
| <drop schema statement>
| <create table statement>
| <alter table statement>
| <drop table statement>
| <create view statement>
| <alter view statement>
| <drop view statement>
| <create index statement>
| <drop index statement>
| <create method statement>
| <drop method statement>
| <create class statement>
| <drop class statement>
| <create user statement>
| <alter user statement>
| <drop user statement>
| <create role statement>
91
Blackfish SQL 10
CREATE SCHEMA
The CREATE SCHEMA statement creates a name space for tables, views, and methods. You can use it to create multiple objects
in one SQL statement.
• You can create a table, view, or method in an existing schema in two ways:
• You can create it as part of a CREATE SCHEMA statement.
• You can specify a schema name as part of the object name when you issue a standalone CREATE TABLE, CREATE VIEW,
or CREATE METHOD statement. If you use the latter method (using CREATE TABLE, for example), you must specify a
schema name that already exists.
• To create an object in a new schema, specify a new schema name in the CREATE SCHEMA statement and then create the
table, view, or method as part of the CREATE SCHEMA statement.
• The AUTHORIZATION clause names the owner of the schema. If you do not specify an owner, the owner is the user of the
SQL session. Only an administrator can specify a user name other than their own user name in the AUTHORIZATION clause.
• If you issue a standalone CREATE TABLE, CREATE VIEW, or CREATE METHOD statement (meaning that it s not embedded in
a CREATE SCHEMA statement) and you do not specify a schema name as part of the CREATE statement, Blackfish SQL uses
the following algorithm to assign the new object to a schema:
• If you have explicitly created a schema that has the same name as your current user name, then you have created a
personal default schema. The table, view, or method belongs to your default schema.
• If you have not created a personal default schema, the table, view, or method belongs to the DEFAULT_SCHEMA schema.
10 • You can create schemas with names other than your user name, but you cannot create schemas that have other users'
names unless you have administrative privileges.
• All objects created in early versions of Blackfish SQL that did not support schemas belong to the DEFAULT_SCHEMA schema
when migrated to version 7 or later.
• A semicolon marks the end of the CREATE SCHEMA statement. There cannot be any semicolons between the schema
elements.
• All the statements in the schema element list are executed as one statement in the same transaction.
Default Schemas
Initially your default schema is DEFAULT_SCHEMA. When you create a schema with the same name as your current user name,
that schema becomes your default schema. You can create objects without specifying a schema name and those objects
92
10 Blackfish SQL
automatically belongs to your default schema. Assume, for example, that user PETER created a schema PETER. At a later time,
PETER creates a table without specifying a schema. The table belongs to the PETER schema.
In the following example, the created table would actually be named PETER.FOO.
[USER: PETER]
CREATE TABLE FOO (COL1 INT, COL2 VARCHAR);
You are permitted to create schemas with names other than your user name, but they can never be your default schema. You
cannot create a schema that has another user's name unless you are an administrator.
Syntax
<create schema statement> ::=
CREATE SCHEMA [ <schema name> ]
[ AUTHORIZATION <user name> ]
<schema element list>
Example
The following statement creates the schema BORIS with a table T1 and a view V1. In this schema, the user BJORN is granted
SELECT privileges on view V1. After this statement executes, BORIS is the default schema for user BORIS.
[USER: BORIS]
CREATE SCHEMA BORIS
CREATE TABLE T1 (C1 INT, C2 VARCHAR)
CREATE VIEW V1 AS SELECT C2 FROM T1
GRANT SELECT ON V1 TO BJORN;
DROP SCHEMA
The DROP SCHEMA statement deletes the specified schema. If the command is used without options, it is the same as specifying
the RESTRICT option: the schema to be dropped must be empty. The command fails if the schema contains any objects.
• The RESTRICT option causes the statement to fail if there are any objects in the schema. RESTRICT is the default option.
• Used with the CASCADE option, DROP SCHEMA deletes the named schema including all of its tables, views, foreign key 10
dependencies, and methods.
WARNING: The DROP SCHEMA command used with the CASCADE option is extremely powerful and should be used with caution.
When this command is issued, it drops the schema and all of its objects and dependencies without any chance to change your
mind. There is no undo.
TIP: If you want to drop a schema but wish to preserve some of its tables, use the ALTER TABLE command to assign the tables
to another schema. For example:
ALTER TABLE OLDSCHEMA.JOBS
RENAME TO NEWSCHEMA.JOBS;
Syntax
<drop schema statement> ::=
DROP SCHEMA <schema name> [ CASCADE | RESTRICT ]
93
Blackfish SQL 10
Examples
1. The following two statements are the same: they drop the schema BORIS; they both fail if the schema contains any objects.
DROP SCHEMA BORIS;
CREATE TABLE
The CREATE TABLE statement creates a Blackfish SQL table. Each column definition must include at least a column name and
data type. Optionally, you can specify a default value for each column, along with uniqueness constraints.
You can also optionally specify a foreign key and primary key. Blackfish SQL supports the use of one or more columns as a
primary key or foreign key.
Specifying Schemas
To create a table in a particular schema, specify the schema name as part of the table name:
CREATE TABLE SOMESCHEMA.MYTABLE(. . .);
If you do not specify a schema name, the table is created in your default schema. See CREATE SCHEMA for more information
about schemas.
If you specify RESOLVABLE as part of the table definition, Blackfish SQL keeps track of changes made to the data. The recorded
changes are available to the DataExpress application, but not to SQL. The default is NOT RESOLVABLE.
94
10 Blackfish SQL
<action> ::=
NO ACTION
| CASCADE 10
| SET DEFAULT
| SET NULL
The following statement creates a table with four columns. The CustId column is the primary key and the OrderDate column
has the current time as the default value.
CREATE TABLE Orders ( CustId INTEGER PRIMARY KEY, Item VARCHAR(30),
Amount INT, OrderDate DATE DEFAULT CURRENT_DATE);
Example 2
The following statement creates a table that uses two columns for the primary key constraint:
95
Blackfish SQL 10
CREATE TABLE T1 (C1 INT, C2 STRING, C3 STRING, PRIMARY KEY (C1, C2));
Example 3
ALTER TABLE
The ALTER TABLE statement performs the following operations:
96
10 Blackfish SQL
<action> ::=
NO ACTION
| CASCADE
| SET DEFAULT
| SET NULL
Example
The following example adds a column named ShipDate to the Orders table and drops the Amount column from the table.
ALTER TABLE Orders
ADD ShipDate DATE,
DROP Amount;
The following example moves the Jobs table from the OldSchema schema to the NewSchema schema.
ALTER TABLE OldSchema.Jobs
RENAME TO NewSchema.Jobs;
DROP TABLE
10
The DROP TABLE statement deletes a table and its indexes from a Blackfish SQL database.
• The RESTRICT option guarantees that the statement will fail if there are foreign key or view dependencies on the table.
• The CASCADE option causes all dependent views and foreign keys to be dropped when the table is dropped.
• Specifying neither RESTRICT nor CASCADE drops the table and any foreign keys that reference it. The statement fails if there
are dependent views.
Syntax
<drop table statement> ::=
DROP TABLE [ <schema name> . ]<table name> [ CASCADE|RESTRICT ]
97
Blackfish SQL 10
1. The following statement drops the Orders table only if there are no dependent views. If there are dependent foreign keys, the
statement succeeds and the foreign keys are dropped.
DROP TABLE Orders;
2. The following statement drops the Orders table only if there are no dependent views or foreign keys.
DROP TABLE Orders RESTRICT;
3. The following statement drops the Orders table. All dependent views and dependent foreign keys are also dropped.
DROP TABLE Orders CASCADE;
CREATE VIEW
The CREATE VIEW statement creates a derived table by selecting specified columns from existing tables. Views provide a way
of accessing a consistent subcollection of the data stored in one or more tables. When the data in the underlying tables changes,
the view reflects this change.
Views look just like ordinary database tables, but they are not physically stored in the database. The database stores only the
view definition, and uses this definition to filter the data when a query referencing the view occurs.
When you create a view, you can specify names for the columns in the view using the optional <column name commalist>
portion of the syntax. If you do not specify column names, the names of the table columns from which the view columns are
derived are used. If you do specify column names, you must specify exactly the number of columns that will be returned from the
SELECT query.
The WITH CHECK OPTION clause causes a runtime check to be performed to ensure that an inserted or updated row will not be
filtered out by the WHERE clause of the view definition.
Views are updatable only under limited conditions. If you want to execute INSERT, UPDATE, or DELETE on a view, it must meet
all of the following conditions:
The following statement creates a view V1 from table T1. The columns in the view are named C1 and C2.
CREATE VIEW V1(C1,C2)
AS SELECT C8+C9, C6 FROM T1 WHERE C8 < C9;
98
10 Blackfish SQL
ALTER VIEW
The ALTER VIEW statement modifies a view without losing dependent views and existing GRANTs. This statement can be used
to change the name of a view, the columns that comprise the view, and whether the view has the WITH CHECK OPTION
constraint.
Note that after ALTER VIEW executes, it is possible that there are dependent views that are no longer valid.
Syntax
<alter view statement> ::=
ALTER VIEW <view name> [ ( <column name commalist> ) ]
The following statements show how the ALTER VIEW statement can be used to validate an invalid view. The first two statements
create a table and then create a view based on that table. The third statement, SELECT, succeeds.
CREATE TABLE T1 (C1 INT, C2 VARCHAR);
CREATE VIEW V1 AS SELECT C1, C2 FROM T1;
SELECT * FROM V1;
The following statement changes a column name in the table.
ALTER TABLE T1 ALTER COLUMN C1 RENAME TO ID;
The next SELECT statement therefore fails because there is no longer a C1 column in the table T1, which is accessed by view
V1.
SELECT * FROM V1;
The following ALTER VIEW statement changes the definition of the view, so that the next SELECT statement succeeds.
ALTER VIEW V1 (C1, C2) AS SELECT ID, C2 FROM T1;
SELECT * FROM V1;
DROP VIEW
The DROP VIEW statement drops the named view. It fails if there are dependencies on the view.
• The RESTRICT option is the same as specifying no options: the statement fails if there are dependencies on the view.
• The CASCADE option drops the view and any dependent views.
Syntax 10
<drop view statement> ::=
DROP VIEW <view name> [ CASCADE | RESTRICT ]
Example
99
Blackfish SQL 10
CREATE INDEX
The CREATE INDEX statement creates an index for a Blackfish SQL table. Each column can be ordered in ascending or
descending order. The default value is ascending order.
Syntax
<create index statement> ::=
The following statement generates a non-unique, case-sensitive, ascending index on the Item column of the Orders table:
CREATE INDEX OrderIndex ON Orders (Item ASC);
DROP INDEX
The DROP INDEX statement deletes an index from a Blackfish SQL table.
Syntax
<drop index statement> ::=
DROP INDEX <index name> ON <table name>
Example
The following statement deletes the OrderIndex index from the Orders table:
DROP INDEX OrderIndex ON Orders;
CREATE METHOD
The CREATE METHOD statement makes a stored procedure or a UDF implemented in Java or a .NET language (e.g., Delphi, C#,
10 or VB.NET) available for use in Blackfish SQL. The class files for the code must be added to the classpath of the Blackfish SQL
server process before use. See Stored Procedures and UDFs for details about how to implement stored procedures and UDFs
for Blackfish SQL.
To create a method in a particular schema, specify the schema name as part of the table name:
CREATE METHOD SOMESCHEMA.MYMETHOD AS . . .
If you do not specify a schema name, the method is assigned to a schema as follows:
• If you have created a personal default schema (a schema that has the same name as your user name), the method is created
in that schema.
• If you have have not created a personal default schema, the method is created in the DEFAULT_SCHEMA schema.
See CREATE SCHEMA for more information about schemas. The AUTHORIZATION clause causes the called stored procedure
to be run as if the username in the AUTHORIZATION clause were the actual user. If this clause is omitted, the current_user is
100
10 Blackfish SQL
used as the actual user during method calls. This feature allows the current user controlled access to tables and views that
would not otherwise be accessible. Syntax
<create method statement> ::=
CREATE METHOD <method name> [AUTHORIZATION <username>]
AS <method definition>
DROP METHOD
The DROP METHOD statement drops a stored procedure or a UDF, making it unavailable for use in Blackfish SQL SQL.
Syntax
<drop method statement> ::=
DROP METHOD <method_name>
Example 20
DROP METHOD ABS;
CREATE CLASS
The CREATE CLASS statement makes all public static methods of a class available to Blackfish SQL SQL as stored procedures
or UDFs. You must ensure that the class files for the code are on the classpath of the Blackfish SQL server process before use.
See the Stored Procedures and UDFs chapter for details.
The AUTHORIZATION clause causes the called stored procedure to be run as if the username in the AUTHORIZATION clause
were the actual user. If this clause is omitted, the current_user is used as the actual user during method calls. This feature allows
the current user controlled access to tables and views that would not otherwise be accessible.
Syntax
<create class statement> ::=
CREATE CLASS <class name> [AUTHORIZATION <username>]
AS <class definition> 10
<class name> ::=
[ <schema name> . ] <SQL identifier>
Usage
101
Blackfish SQL 10
DROP CLASS
The DROP CLASS statement drops a stored class, making it unavailable for use in Blackfish SQL.
Syntax
<drop class statement> ::=
DROP CLASS <method_name>
Example 21
DROP CLASS MATH;
CREATE TRIGGER
The CREATE TRIGGER statement creates a row level trigger for a table. You must ensure that the classes can be loaded by the
Blackfish SQL server process. See Triggers for Blackfish SQL for details on implementing trigger methods and ensuring that the
method classes can be loaded.
Syntax
create trigger statement> ::= CREATE TRIGGER <trigger name>
10 Examples
OrderEntryAssembly::OrderEntry.Customers.ValidateCustomer
Blackfish SQL for Java:
CREATE TRIGGER VALIDATE_CUSTOMER BEFORE INSERT ON CUSTOMER AS
OrderEntry.Customers.validateCustomer
102
10 Blackfish SQL
DROP TRIGGER
The DROP TRIGGER statement drops a trigger, making it unavailable for use in Blackfish SQL.
Syntax
<drop trigger statement> ::= DROP TRIGGER
<trigger
name>
ON <table name>
COMMIT
The COMMIT statement commits the current transaction. It has an effect only if AUTOCOMMIT is turned off.
Syntax
<commit statement> ::=
COMMIT [WORK]
ROLLBACK
The ROLLBACK statement rolls back the current transaction. This statement does not have any effect when AUTOCOMMIT is
turned on.
Syntax
<rollback statement> ::=
ROLLBACK [WORK]
10
SET AUTOCOMMIT
The SET AUTOCOMMIT statement changes the autocommit mode. Autocommit is initially ON when a JDBC connection is created.
The autocommit mode is also controllable using the JDBC Connection instance.
Syntax
<set autocommit statement> ::=
SET AUTOCOMMIT { ON | OFF };
SET TRANSACTION
The SET TRANSACTION statement sets the properties for the following transaction. You can use it to specify the isolation level
and whether the transaction is read-write or read-only. See System Architecture for a discussion of Blackfish SQL transaction
103
Blackfish SQL 10
management.
This command must be issued when there is no open transaction. It affects only the next transaction and does not itself start a
transaction.
• A dirty read occurs when a row changed by one transaction is read by another transaction before any changes in that row
have been committed.
• A non-repeatable read occurs when one transaction reads a row, a second transaction alters the row, and the first
transaction rereads the row, getting different values the second time.
• A phantom read occurs when one transaction reads all rows that satisfy a WHERE condition, a second transaction inserts a
row that satisfies that WHERE condition, and the first transaction rereads for the same condition, retrieving the additional
"phantom" row in the second read.
Blackfish SQL offers the following transaction isolation levels: TRANSACTION_READ_UNCOMMITTED permits dirty reads,
non-repeatable reads, and phantom reads. If any of the changes are rolled back, the row retrieved by the second transaction is
invalid. This isolation level does not acquire row locks for read operations. It also ignores exclusive row locks held by other
connections that have inserted or updated a row.
TRANSACTION_READ_COMMITTED prevents dirty reads; non-repeatable reads and phantom reads are permitted. This level
only prohibits a transaction from reading a row with uncommitted changes in it. This level does not acquire row locks for read
operations, but blocks when reading a row that has an exclusive lock held by another transaction.
TRANSACTION_REPEATABLE_READ prevents dirty reads and non-repeatable reads but prevents phantom reads. It acquires
shared row locks for read operations. This level provides protection for transactionally consistent data access without the
reduced concurrency of TRANSACTION_SERIALIZABLE, but results in increased locking overhead.
TRANSACTION_SERIALIZABLE provides complete serializability of transactions at the risk of reduced concurrency and
increased potential for deadlocks.
Syntax
<set transaction statement> ::=
SET TRANSACTION <transaction option commalist>
In the following example the select from T1 will be a dirty read, meaning that the data cannot yet be committed by another user.
After the second COMMIT, the isolation level returns to whatever was specified for the session.
COMMIT;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM T1;
COMMIT;
Data Manipulation Statements
104
10 Blackfish SQL
SELECT
A SELECT statement retrieves data from one or more tables. The optional keyword DISTINCT eliminates duplicate rows from the
result set. The keyword ALL, which is the default, returns all rows including duplicates. The data can optionally be sorted using
ORDER BY. The retrieved rows can optionally be locked for an upcoming UPDATE by specifying FOR UPDATE.
Syntax
<select statement> ::=
<table expression> [ ORDER BY <order item list> ]
[ FOR UPDATE|FOR READ ONLY ]
The following statement orders the output by the first column in descending order.
SELECT Item FROM Orders ORDER BY 1 DESC;
The next statement orders by the calculated column CALC:
SELECT CustId, Amount*Price+500.00
AS CALC FROM Orders
ORDER BY CALC;
The next statement orders the output by the given expression, Amount*Price:
SELECT CustId, Amount
FROM Orders
ORDER BY Amount*Price;
10
SELECT INTO
A SELECT INTO statement is a SELECT statement that evaluates into exactly one row, whose values are retrieved in output
parameters. It is an error if the SELECT evaluates into more than one row or to the empty set.
Syntax
<single row select statement> ::=
SELECT [ ALL|DISTINCT ] <select item commalist>
INTO <parameter commalist>
FROM <table reference commalist>
[ WHERE <conditional expression> ]
[ GROUP BY <column reference commalist> ]
[ HAVING <conditional expression> ]
105
Blackfish SQL 10
Example
In the following statement, the first two parameter markers indicate output parameters from which the result of the query can be
retrieved:
SELECT CustId, Amount
INTO ?, ?
FROM Orders
WHERE CustId=? ;
INSERT
The INSERT statement inserts rows into a table in a Blackfish SQL database. The INSERT statement lists columns and their
associated values. Columns that aren't listed in the statement are set to their default values.
Syntax
<insert statement> ::=
[ SELECT AUTOINCREMENT FROM ]
INSERT INTO <table name> [ ( <column name commalist> ) ]
[ <insert table expression>|DEFAULT VALUES ]
The following statement inserts one row each time it is executed. It inserts one row each time it is executed. The columns not
mentioned are set to their default values. If a column doesn't have a default value, it is set to NULL.
INSERT INTO Orders (CustId, Item) VALUES (?,?);
Example 2
The following statement finds all the orders from the customer with CustId of 123 and inserts the Item of these orders into the
ResTable table.
INSERT INTO ResTable
SELECT Item FROM Orders
WHERE CustId = 123;
Example 3
The following statement inserts one row each time it is executed. In this case, the CustId column of the Orders table is not
10 specified. It is assumed that the CustId is an AUTOINCREMENT column, for which the SQL engine automatically generates an
incremented value. In this example, SELECT AUTOINCREMENT FROM is specified, causing the generated value to be returned
as a result set. If the Orders table does not have an AUTOINCREMENT column, and the result set will be the INTERNALROW
values for the inserted rows.
SELECT AUTOINCREMENT FROM INSERT INTO Orders (Item) VALUES (?)
UPDATE
The UPDATE statement is used to modify existing data. The columns to be changed are listed explicitly. All the rows for which the
WHERE clause evaluates to TRUE are changed. If no WHERE clause is specified, all rows in the table are changed.
Syntax
<update statement> ::=
106
10 Blackfish SQL
The following statement changes all orders from customer 123 to orders from customer 500:
UPDATE Orders SET CustId = 500 WHERE CustId = 123;
Example 2
The following statement increases the amount of all orders in the table by 1:
UPDATE Orders SET Amount = Amount + 1;
Example 3
DELETE
A DELETE statement deletes rows from a table in a Blackfish SQL database. If no WHERE clause is specified, all the rows are
deleted. Otherwise only the rows that match the WHERE expression are deleted.
Syntax
<delete statement> ::=
DELETE FROM <table name>
[ WHERE <conditional expression> ]
<table name> ::=
[ <schema name> . ] <SQL
identifier>
Example
10
The following statement deletes all orders for shorts from the Orders table.
DELETE FROM Orders WHERE Item = 'Shorts';
CALL
A CALL statement calls a stored procedure.
Syntax
<call statement> ::=
[ ? = ] CALL <method name> ( <expression commalist> )
Example 1
107
Blackfish SQL 10
The parameter marker indicates an output parameter position from which the result of the stored procedure can be retrieved.
?=CALL ABS(-765);
Example 2
The method implementing IncreaseSalaries updates the salaries table with an increase of some percentage for all
employees. A connection object will be passed implicitly to the method. An updateCount of all the rows affected by
IncreaseSalaries will be returned from Statement.executeUpdate.
CALL IncreaseSalaries(10);
LOCK TABLE
The LOCK TABLE statement explicitly locks a table. The lock ceases to exist when the transaction is committed or rolled back.
Syntax
<lock statement> ::=
`LOCK <table name commalist>
<table name> ::=
[ <schema name> . ] <SQL identifier>
Example
CREATE USER
The CREATE USER statement adds the named user and associated password to the database. Only an administrator can create
users.
Note: The password that you enter is always case sensitive. The user name is not case-sensitive.
A newly created user has all database privileges except ADMINISTRATOR by default. That is, they have STARTUP, WRITE,
CREATE, DROP, CREATE ROLE, and CREATE SCHEMA privileges. If you wish to remove certain privileges from a user, use
REVOKE to remove them.
Syntax
<create user statement> ::=
10 CREATE USER <user name> PASSWORD <SQL identifier>
Example 26
CREATE USER jmatthews PASSWORD "@nyG00dPas2d";
ALTER USER
The ALTER USER statement sets a new password for an existing user. Only an administrator or the named user can change a
password.
Note: The password that you enter is stored in all caps unless you enclose the password string in double quotation marks. It is
recommended that you always use the double quotes when specifying the password.
Syntax
108
10 Blackfish SQL
DROP USER
The DROP USER statement drops a user and all objects that the user owns.
• Used with RESTRICT or with no option, the statement fails if the user owns any objects, such as tables, views, or methods.
• Used with CASCADE, it deletes the user and all objects that the user owns.
Syntax
<drop user statement> ::=
DROP USER <user name> [ CASCADE|RESTRICT ]
Example
The following statement drops the user gsmith and all tables, views, and methods that he owns.
DROP USER gsmith CASCADE;
CREATE ROLE
The CREATE ROLE statement creates a named role.
SET ROLE
The SET ROLE statement makes the named role active. The current user acquires all privileges assigned to that role. Use SET
ROLE NONE to deactivate the current role without setting another role.
Note: This command must be issued when there is no active transaction. The role remains active until the end of the session or
until another SET ROLE command is issued.
Syntax
<set role statement> ::=
SET ROLE <role specification>
109
Blackfish SQL 10
NONE
| <role name>
Example
DROP ROLE
The DROP ROLE statement drops the specified role.
• When DROP ROLE is used with CASCADE, all privileges that were granted through this role are revoked.
• When DROP ROLE is used with RESTRICT, the statement fails if the role is currently granted to any users or roles.
• Issuing DROP ROLE with neither option is the same as DROP ROLE with RESTRICT.
Syntax
<drop role statement> ::=
DROP ROLE <role name> [ CASCADE|RESTRICT ]
Example
The following statement drops the Sales role. All privileges that were granted to users or other roles through the Sales role are
revoked.
DROP ROLE Sales CASCADE;
GRANT
The GRANT statement performs the following three actions:
• It grants object privileges, such as INSERT or SELECT, on tables or methods to PUBLIC, users, or roles.
• It grants database privileges (for example, STARTUP or RENAME) to users or roles.
• It grants roles to users or roles.
GRANT options:
• When object privileges are granted with the GRANT option, the grantee has the power to pass on the granted object privileges
10 to other users.
• When database privileges or roles are granted with the ADMINISTRATOR option, the grantee has the power to pass on the
granted database privileges or roles to other users.
• The ADMINISTRATOR database privilege grants STARTUP, WRITE, CREATE, DROP, RENAME, CREATE ROLE, and CREATE
SCHEMA privileges. When these privileges are acquired through the ADMINISTRATOR privilege, they can be revoked only by
revoking the ADMINISTRATOR privilege. In other words, if you grant ADMINISTRATOR to a user and then revoke CREATE, that
user still has CREATE privileges.
Note that when specifying the privilege object, you can use the optional TABLE keyword to grant privileges on either tables or
views. You do not use the VIEW keyword in this context. You can also revoke privileges on a method, using the required METHOD
keyword. It is possible to grant the following database privileges:
Privilege Description
ADMINISTRATOR Grants startup, write, create, drop, rename, create role, and create schema privileges
110
10 Blackfish SQL
CREATE ROLE and CREATE SCHEMA are granted by default when a user is created.
Syntax
<grant statement> ::=
<grant database privileges statement>
| <grant object privileges statement>
| <grant role statement>
<privilege>::=
SELECT
| INSERT [ ( <column name commalist> ) ]
| UPDATE [ ( <column name commalist> ) ]
| REFERENCES [ ( <column name commalist> ) ]
| DELETE
| EXECUTE
111
Blackfish SQL 10
In the following example, USER_1 receives SELECT and INSERT privileges on table T1. USER_2 receives SELECT privileges on
table T1 because the SELECT privilege was granted to ROLE_B and ROLE_B was granted to USER_2. However, USER_2 can use
this SELECT privilege only after enabling ROLE_B with a SET ROLE statement.
GRANT SELECT ON TABLE T1 TO USER_1, ROLE_B;
GRANT INSERT ON T1 TO USER_1;
REVOKE
The REVOKE statement can perform the following operations:
• It revokes object privileges, such as INSERT or SELECT, on tables or methods from PUBLIC, users, or roles.
• If the user or role has granted the now-revoked privilege to others, CASCADE revokes the privileges from those others as
well. If any views depend on the revoked privileges, they are dropped.
• When the REVOKE statement includes RESTRICT, the statement fails if the grantee has granted the acquired privileges to
others.
• It revokes database privileges—such as STARTUP or RENAME—from users or roles.
• It revokes roles from users or roles.
• It revokes the ADMIN option from a role without revoking the role itself.
• REVOKE GRANT OPTION FOR privilege revokes the power to grant the privilege to others without revoking the privilege
itself. REVOKE ADMIN OPTION FOR role similarly revokes the power to grant the named role without revoking the role
itself.
Note that when specifying the privilege object, you can use the optional TABLE keyword to revoke privileges on either tables or
views. You do not use the VIEW keyword in this context. You can also revoke privileges on a method, using the required METHOD
keyword. Syntax
<revoke statement> ::=
<revoke database privileges statement>
| <revoke object privileges statement>
| <revoke role statement>
10
<revoke database privileges statement> ::=
REVOKE <database privilege commalist>
FROM <grantee commalist>
112
10 Blackfish SQL
<grantee> ::=
PUBLIC
| <user name>
| <role name>
<privilege>::=
SELECT
| INSERT [ ( <column name commalist> ) ]
| UPDATE [ ( <column name commalist> ) ]
| REFERENCES [ ( <column name commalist> ) ]
| DELETE
| EXECUTE
In all of the following examples, the name before the colon is the nameof the user executing the statement.
The following GRANT statements are issued by users U1, U2, and U3 and are the context for the examples that follow:
Statement 1:
U1: GRANT SELECT ON TABLE T1 TO U2 WITH GRANT OPTION;
Statement 2:
U2: GRANT SELECT ON TABLE T1 TO U3 WITH GRANT OPTION;
Statement 3:
U3: GRANT SELECT ON TABLE T1 TO U4 WITH GRANT OPTION;
Example 1a: 10
The RESTRICT option causes the following REVOKE statement to fail because in Statement 2, user U2 exercised the privilege he
acquired in Statement 1.
U1: REVOKE SELECT ON TABLE T1 FROM U2 RESTRICT;
Example 1b:
The RESTRICT option causes the following statement to fail because in Statement 2, user U2 exercised the GRANT OPTION
privilege he acquired in Statement 1.
113
Blackfish SQL 10
The following statement succeeds and negates Statements 2 and 3. U2 retains SELECT privilege on T1, but cannot grant this
privilege to others.
U1: REVOKE GRANT OPTION FOR SELECT ON TABLE T1 FROM U2 CASCADE;
Example 2
The following GRANT and CREATE statements are issued by users U1, U2, and U3 and are the context for the examples that
follow. The name before the colon is the name of the user who issued the statement.
Statement 1:
U1: GRANT SELECT ON TABLE T1 TO U2 WITH GRANT OPTION;
Statement 2:
U2: GRANT SELECT ON TABLE T1 TO U3 WITH GRANT OPTION;
Statement 3:
U3: GRANT SELECT ON TABLE T1 TO U4 WITH GRANT OPTION;
Statement 4:
U2: CREATE VIEW V2 AS SELECT A, B FROM T1;
Statement 5:
U3: CREATE VIEW V3 AS SELECT A, B FROM T1;
Example 2a:
The following statement succeeds and negates Statements 1, 2, and 3. In addition, views V2 and V3 are dropped because U2
and U3 no longer have the SELECT privileges on T1 that are required by the views.
U1: REVOKE SELECT ON TABLE T1 FROM U2 CASCADE
Example 2b:
The following statement succeeds and negates Statements 2 and 3. User U2 retains the SELECT privilege on T1, but cannot
grant this privilege to others. In addition, the view V3 is dropped because U3 no longer has the SELECT privilege on T1. View V2
is not dropped because U2 still holds SELECT privileges on T1.
U1: REVOKE GRANT OPTION FOR SELECT ON TABLE T1 FROM U2 CASCADE
Example 3
The following GRANT and CREATE statements are issued by users U1, U2, and U3 and are the context for the examples that
10 follow. The name before the colon is the name of the user who issued the statement.
Statement 1:
U1: CREATE ROLE R1;
Statement 2:
U1: GRANT SELECT ON TABLE T1 TO R1;
Statement 3:
U1: GRANT R1 TO U2 WITH ADMIN OPTION;
Statement 4:
U2: GRANT R1 TO U3 WITH ADMIN OPTION;
Statement 5:
114
10 Blackfish SQL
The following statement fails because user U2 has exercised the privileges acquired as a result of being granted role R1.
U1: REVOKE R1 FROM U2 RESTRICT;
Example 3b:
The following statement fails because in Statement 3, user U2 exercised the ADMIN OPTION.
U1: REVOKE ADMIN OPTION FOR R1 FROM U2 RESTRICT;
Example 3d:
The following statement succeeds. Statements 4 and 5 are negated. U2 retains the privileges granted by role R1, but cannot
grant this role to others.
U1: REVOKE ADMIN OPTION FOR R1 FROM U2 CASCADE;
Escape Syntax
Blackfish SQL supports escape sequences for the following:
{T 'hh:mm:ss'} Specifies a time, which must be entered in the sequence: hours, followed by minutes, followed by seconds.
{D 'yyyy-mm-dd} Specifies a date, which must be entered in the sequence; year, followed by month, followed by day.
{TS 'yyyy-mm-dd Specifies a timestamp, which must be entered in the format indicated; year, month, day, hour, minute,
hh:mm:ss'} second.
Examples 10
INSERT INTO tablename VALUES({D '2004-2-3'}, {T '2:55:11'});
SELECT {T '10:24'} FROM tablename;
SELECT {D '2000-02-01'} FROM tablename;
SELECT {TS '2000-02-01 10:24:32'} FROM tablename;
Outer Joins
115
Blackfish SQL 10
Example 30
SELECT * FROM {OJ a LEFT JOIN b USING(id)};
{ESCAPE <char>} The specified character becomes the escape character in the preceding LIKE clause.
Example 31
SELECT * FROM a WHERE name LIKE '%*%' {ESCAPE '*'}
The method implementing IncreaseSalaries updates the salaries table with an increase of some percentage for all employees. A
connection object is passed implicitly to the method. An updateCount of all the rows affected by IncreaseSalaries is
returned from Statement.executeUpdate.
{CALL IncreaseSalaries(10)};
Example 2
The parameter marker indicates an output parameter position from which the result of the stored procedure can be retrieved.
{?=CALL ABS(-765)};
Escape Functions
Functions are written in the following format, where FN indicates that the function following it should be performed:
{fn <function_name>(<argument_list>) }
Numeric functions
10
Function name Function returns
ABS(number) Absolute value of number
ACOS(float) Arccosine, in radians, of float
ASIN(float) Arcsine, in radians, of float
ATAN(float) Arctangent, in radians, of float
ATAN2(float1, float2) Arctangent, in radians, of float2 divided by float1
CEILING(number) Smallest integer >= number
COS(float) Cosine of float radians
COT(float) Cotangent of float radians
116
10 Blackfish SQL
String Functions
117
Blackfish SQL 10
Examples
SELECT {FN LCASE('Hello')} FROM tablename;
118
10 Blackfish SQL
TIMESTAMPDIFF(interval, An integer representing the number of intervals by which timestamp2 is greater than timestamp1;
timestamp1, timestamp2) interval can be any one of the following: SQL_TSI_FRAC_SECOND, SQL_TSI_SECOND,
SQL_TSI_MINUTE, SQL_TSI_HOUR, SQL_TSI_DAY, SQL_TSI_WEEK, SQL_TSI_MONTH,
SQL_TSI_QUARTER, or SQL_TSI_YEAR
WEEK(date) An integer from 1 to 53 representing the week of the year in date
YEAR(date) An integer representing the year component of date
Examples
SELECT {FN NOW()} FROM tablename;
System Functions
Conversion Functions
10
Function name Function returns
CONVERT(value, value converted to SQLtype where SQLtype can be one of the following SQL types: BIGINT, BINARY, BIT,
SQLtype) CHAR, DATE, DECIMAL, DOUBLE, FLOAT, INTEGER, LONGVARBINARY, LONGVARCHAR, REAL,
SMALLINT, TIME, TIMESTAMP, TINYINT, VARBINARY, or VARCHAR
Example 33
SELECT {FN CONVERT('34.5',DECIMAL(4,2))} FROM tablename;
ISQL
ISQL is a SQL command interpreter that can be used to execute SQL statements interactively. This feature is currently available
for Blackfish SQL for Java only.
119
Blackfish SQL 10
Getting Help
To see a help display for Blackfish SQL ISQL, issue one of the following help commands: From the system prompt:
• HELP CREATE displays help on creating datasources.HELP SHOW displays a list of SHOW commands with briefdescriptions.
• HELP SET displays a list of SET commands with brief descriptions of each.
Starting ISQL
To start Blackfish SQL ISQL, either ensure that <BlackfishSQL_install_dir>\bin is in your system path, or go to that
directory to issue the ISQL command. These options are available:
120
10 Blackfish SQL
Command Description
CREATE Associates a datasource with the dataSourceName. You pass this dataSourceName to CONNECT
DATASOURCE in order to connect to a database. See "Creating datasources with ISQL" below, for information on
dataSourceName creating datasources in ISQL.
[dataSourceClassName]
properties
CONNECT Connects to the datasource specified by dataSourceName. Before you can use CONNECT, you
dataSourceName must use CREATE DATASOURCE to associate a database with the dataSourceName that you pass
[userpassword] to CONNECT. You do not need to specify user name or password if it was specified as part of the
CREATE DATASOURCE statement.
INPUT filename Takes the contents of the named SQL file as input.
OUTPUT filename Writes the output to the specified file.
OUTPUT Writes the output to stdout.
EXPORT Exports the data definition statements and data of the current database to SQL.
EXPORT Exports the data definition statements and data of the current database to the specified datasource.
[userpassword] To export to a file, use EXPORT in conjunction with OUTPUT: OUTPUT sqlfile.txt; EXPORT;
IMPORT [userpassword] Imports the data definition statements and data from the specified datasource.
VERSION Shows the version of ISQL and the version of any connected database.
EXIT Commits changes and exits.
QUIT Rolls back changes and exits.
dataSourceClassName is the class that specifies the properties needed to connect to a JDBC database. It must be an
implementation of the standard JDBC javax.sql.DataSource interface. If this argument is not provided,
com.borland.javax.sql.JdbcDataSource is used. To access InterBase databases, you can use
interbase.interclient.DataSource.
10
properties can include any properties in the class supplied as the dataSourceClassName. Properties are separated by commas
and commonly include the following:
• user='username' If you do not supply a user name here, you can supply it as part of the CONNECT statement.
• password='password' If you do not supply a password here, you can supply it as part of the CONNECT statement.
• databaseName='database_name_to_connect_to'
Example
You can supply values for any properties in the datasource class. For example, to create a new database, add the following:
CREATE=true: CREATE DATASOURCE
databaseName='c:/databases/test.jds',CREATE=true';
121
Blackfish SQL 10
Examples
These examples both use the Blackfish SQL default class com.borland.javax.sql.JdbcDataSource, since no
className is specified.
Command Description
SHOW DATASOURCE [name] Displays all datasources or the specified datasource.
SHOW DATABASE Displays settings for the current database.
SHOW VERSION Displays the ISQL version and the version of any connected database.
SHOW DDL Displays the data definition statements for the current database.
SHOW SYSTEM Displays the system tables.
SHOW TABLE [[schema.]table] Displays all tables or the specified table.
SHOW VIEW [[schema.]view] Displays all views or the specified view.
SHOW PROCEDURE Displays all procedures or the specified pprocedures
[[schema.]name]
SHOW FUNCTION [[schema.]name] Displays all functions or the specified function.
SHOW INDEX [index [ON Displays all indexes or the specified index.
10 [schema.]table]]
SHOW ROLES Lists all roles defined in the database.
SHOW USERS Lists all users defined in the database.
SHOW GRANT TABLE Lists all privileges on tables that have been granted WITH GRANT OPTION.
[[schema.]table]
SHOW GRANT VIEW Lists all privileges on views that have been granted WITH GRANT OPTION.
[[schema.]view]
SHOW GRANT PROCEDURE Lists all privileges on procedures that have been granted WITH GRANT OPTION.
[[schema.]name]
SHOW GRANT FUNCTION Lists all privileges on functions that have been granted WITH GRANT OPTION.
[[schema.]name]
SHOW GRANT ROLE [role] Lists all users who have been granted the specified role.
122
10 Blackfish SQL
SHOW GRANT DATABASE Lists all database privileges that have been granted to the specified user or role.
[user|role]
Command Description
SET Displays the current value of ECHO, STACKTRACE, and PAGELENGTH.
SET ECHO {ON|OFF} Toggles echoing of all commands to standard out.
SET STACKTRACE Toggles display of error traces.
{ON|OFF}
SET PAGELENGTH Sets the page length in lines; default is 0, meaning that the column headings print out only once.
number
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
10
123
11 Blackfish SQL
• Use prepared statements or commands whenever possible. If the number of parameters changes from one insert to the next,
clear the parameters before setting the new parameters.
• Create the table without primary keys, foreign keys, or secondary indexes. Load the table and then create any needed primary
keys, foreign keys, or secondary indexes.
125
Blackfish SQL 11
General Recommendations
This section provides some general guidelines for improving performance for Blackfish SQL applications.
Another benefit to closing connections is that when they are all closed, the memory allocated to the Blackfish SQL cache is
released.
Currently, non-transactional databases can be accessed from SQL only if the database read-only property is true. However,
DataExpress JavaBeans can perform write operations on a non-transactional database.
Closing a non-transactional Blackfish SQL database ensures that all modifications are saved to disk. There is a daemon thread
for all open DataStoreConnection instances that is constantly saving modified cache data. (By default modified data is saved
every 500 milliseconds.) If you directly exit the Java Virtual Machine without closing the database, the daemon thread might not
have the opportunity to save the last set of changes. There is a small chance that a non-transactional Blackfish SQL could
become corrupted.
A transactional Blackfish SQL database is guaranteed not to lose data, but the transaction manager rolls back any uncommitted
changes.
You can use the DataStore.shutdown() method to make sure all database connections are closed before an application
terminates.
NOTE: Do not arbitrarily change the database cache size. Be sure first to verify that doing so will improve the performance of
your application.
Keep in mind the following considerations when changing the Blackfish SQL cache size:
11 • Modern OS caches are typically high performance. In many cases, increasing the Blackfish SQL cache size does not
significantly improve performance, and simply uses more memory.
• There is only one Blackfish SQL disk cache for all Blackfish SQL databases open in the same process. When all Blackfish
SQL databases are shut down, the memory for this global disk cache is released.
• For handheld devices with small amounts of memory, set the DataStore.MinCacheSize property to a smaller number,
such as 96.
126
11 Blackfish SQL
• The Blackfish SQL database file itself (filename extension is .jds) as specified by the DataStore.FileName property
• Blackfish SQL transactional log files (filename extension is LOGAnnnnnnnnnn, where n is a numeric digit) as specified by the
TxManager.ALogDir property
• Temporary files used for large sort operations as specified by the DataStore.TempDirName property
• Temporary .jds files used for SQL query results as specified by the DataStore.TempDirName property
You can potentially improve performance by instructing Blackfish SQL to place the files mentioned above on different disk drives.
File Storage
The following are some guidelines for file storage handling that can improve performance of your applications:
• It is especially important to place the log files on a separate disk drive. Note that log files are generally appended in sequential
order, and their contents must be forced to disk in order to complete commit operations. Consequently, it is advantageous to
have a disk drive that can complete write operations quickly.
• On Win32 platforms, performance can be improved by placing Blackfish SQL log files in a separate directory. Storing
numerous files other than the log files in the log file directory can slow down the performance of commit operations. This
performance tip may also apply to platforms other than Windows NT/2000/XP.
• Remember to defragment your disk drive file systems on a regular basis. This practice is especially important for the disk
drive that stores the log files, because Blackfish SQL performs many sequential read/write operations to this file.
• For Win32 platforms, consider using a FAT32 file system with a large cluster size such as 64KB for the disk drive to which
your log files are written.
Use the saveMode property of the DataStore component to control how often cache blocks are written to disk. This property
applies only to non-transactional Blackfish SQL databases. The following are valid values for the method:
0 Let the daemon thread handle all cache writes. This setting gives the highest performance but the greatest risk of corruption.
1 Save immediately when blocks are added or deleted; let the daemon thread handle all other changes. This is the default
mode. Performance is almost as good as with saveMode(0).
2 Save all changes immediately. Use this setting whenever you debug an application that uses a DataStore component.
Unlike other properties of DataStore, saveMode can be changed when the connection is open. For example, if you are using a
DataStoreConnection, you can access the value through the dataStore property:
DataStoreConnection store = new DataStoreConnection();
...
store.getDataStore().setSaveMode(2); 11
Note that this changes the behavior for all DataStoreConnection objects that access that particular Blackfish SQL database
file.
Tuning Memory
You can tune the use of memory in a number of ways. Be aware that asking for too much memory can be as bad as having too
little.
• Try increasing the ConnectionProperties.MinCacheBlocks property, which controls the minimum number of blocks
that are cached.
127
Blackfish SQL 11
• The ConnectionProperties.MaxSortBuffer property controls the maximum size of the buffer used for in-memory sorts.
Sorts that exceed this buffer size use a slower disk-based sort.
• Setting the ConnectionProperties.TempDirName property, used by the query engine, to a directory on another (fast)
disk drive can often help.
• Try changing the check point frequency for the Transaction Manager. A higher value can improve performance, but might
result in slower crash recovery. This can be updated from SQL by using the DB_ADMIN.ALTER_DATABASE built-in stored
procedure. In Blackfish SQL for Java, you can use JdsExplorer to set this property by choosing TxManager > Modify.
Optimizing Transactional Applications
The increased reliability and flexibility you gain from using transactional Blackfish SQL databases comes at the price of some
performance. You can reduce this cost in several ways, as described in the following sections.
Read-only transactions work by simulating a snapshot of the Blackfish SQL database. This snapshot sees only data from
transactions that were committed at the point the read-only transaction starts. This snapshot is created when the
DataStoreConnection opens, and it refreshes every time a commit method is called.
Another benefit of read-only transactions is that they are not blocked by writers or other readers. Both reading and writing usually
require a lock. But because a read-only transaction uses a snapshot, it does not require any locks.
You can further optimize the application by specifying a value for the property readOnlyTxDelay. The readOnlyTxDelay
property specifies the maximum age (in milliseconds) for an existing snapshot that the connection can share. When the property
is non-zero, existing snapshots are searched from most recent to oldest. If there is one that is under readOnlyTxDelay in age,
it is used and no new snapshot is taken. By default, this property is set to 5000 milliseconds.
128
11 Blackfish SQL
• Choose the weakest isolation level with which your application can function properly. Lower isolations tend to acquire fewer
and weaker locks.
• Batch multiple statements into a single transaction. Connections default to autocommit mode commit after every statement
execution.
• Commit transactions as soon as possible. Most locks are not released until a transaction is committed or rolled back.
• Reuse statement or command objects whenever possible, or better yet, use prepared statements or commands when
possible.
• Close all statements or commands, all result sets or readers, and all connection objects when they are no longer needed.
Single-directional result set or reader objects automatically close when the last row is read.
• Use read-only transactions for long-running reports or online backup operations. Use the DB_ADMIN.COPYDATABASE method
for online backups. Read-only transactions provide a transactionally consistent (serializable), read-only view of the tables they
access. They do not acquire locks, so lock timeouts and deadlocks are not possible. See the section Using Read-only
Transactions.
• There is some overhead for maintaining a read-only view. Consequently, multiple transactions can share the same read-only
view. The ConnectionProperties.ReadOnlyTxDelay property specifies how old the read-only view can be when a
read-only transaction is started. Committing the transaction for a read-only connection refreshes the view of the database.
Note that a read-only transaction uses the transactional log files to maintain views. Therefore, read-only connections should
be closed as soon as they are no longer needed.
• If Blackfish SQL is used without the JDBC driver, exclude the following classes:
• com.borland.datastore.Sql*.class
• com.borland.datastore.jdbc.*
• com.borland.datastore.q2.*
• If you are using DataExpress, and the StorageDataSet.store property is always set to an instance of DataStore or
DataStoreConnection, exclude the following classes:
• com.borland.dx.memorystore.*
• If StorageDataSet is used, but not QueryDataSet, QueryProvider, StoredProcedureDataSet or
StoredProcedureProvider, exclude the following classes:
• com.borland.dx.sql.* 11
• If DataExpress isn't using any visual components from the JBCL or dbSwing libraries, exclude the following classes:
• com.borland.dx.text.*
• If com.borland.dx.dataset.TextDataFile is not used, exclude the following classes:
• com.borland.jb.io.*
• com.borland.dx.dataset.TextDataFile.class
• com.borland.dx.dataset.SchemaFile.class
129
Blackfish SQL 11
AutoIncrement Columns
You can specify columns of type int and long as having AutoIncrement values.
An AutoIncrement column is the internal row identifier for a row, and so provides the fastest random access path to a
particular row in a Blackfish SQL table.
Each table can have only one AutoIncrement column. Using an AutoIncrement column saves the space of one integer
column and one secondary index in your table if you use it as a replacement for your primary key. The Blackfish SQL Query
Optimizer optimizes queries that reference an AutoIncrement column in a WHERE clause. For instructions on using
AutoIncrement columns with SQL, see “Using AutoIncrement Columns with SQL” in the SQL Reference.
• DBDisposeMonitor automatically disposes of data-aware component resources when a container is closed. It has a
closeDataStores property. When true (the default), it automatically closes any Blackfish SQL databases that are
attached to components it cleans. For example, if you drop a DBDisposeMonitor into a JFrame that contains dbSwing
components attached to a Blackfish SQL database, when you close the JFrame, DBDisposeMonitor automatically closes
the Blackfish SQL database for you. This component is particularly handy when building simple applications to experiment
using Blackfish SQL.
• DBExceptionHandler has an Exit button. You can hide it with a property setting, but it is visible by default. Clicking this
button automatically closes any open Blackfish SQL database files it can find. DBExceptionHandler is the default dialog
box displayed by dbSwing components when an exception occurs.
Using Data Modules for Blackfish SQL for Java DataExpress JavaBean Components
When using a Blackfish SQL table with a StorageDataSet, you should consider grouping them all inside data modules. Make
any references to these StorageDataSets through DataModule accessor methods, such as
businessModule.getCustomer. You should do this because much of the functionality surfaced through StorageDataSets
is driven by property and event settings.
Although most of the important structural StorageDataSet properties are persisted in the Blackfish SQL table itself, the
classes that implement the event listener interfaces are not. Instantiating the StorageDataSet with all event listener settings,
11 constraints, calculated fields, and filters implemented with events, ensures that they are properly maintained at both run time and
design time.
See Also
Preface ( see page 1)
130
11 Blackfish SQL
Using Stored Procedures and User Defined Functions ( see page 41)
11
131
12 Blackfish SQL
133
Blackfish SQL 12
134
12 Blackfish SQL
-DblackfishSQL.licenseDirectory=/mylicenseDir
Alternatively, you can set this property in the JdsServer.config file by adding a vmparam -D statement:
vmparam -DblackfishSQL.licenseDirectory=/mylicenseDir
• The Java user.home system property
• All directories specified in the Java classpath setting
See Also
Preface ( see page 1)
Using Stored Procedures and User Defined Functions ( see page 41)
12
135
13 Blackfish SQL
13 Troubleshooting
This chapter presents some guidelines for troubleshooting and resolving possible error conditions and other issues that may
arise when creating, maintaining, and accessing Blackfish SQL databases.
You can enable Blackfish SQL system logging in the following ways.
Set the blackfishsql.logFile system property to the name of the file to which the log output should be written. If you set
this to con, the log output is displayed to the console. You can specify the types of operations to include in the log file by setting
the blackfishsql.logFilters property.
137
Blackfish SQL 13
should be written. If you set this to con, the log output is displayed to the console. You can specify the types of operations to
include in the log file by setting the blackfishsql.logFilters property.
If your application uses the Blackfish SQL server, set system properties in the BSQLServer.exe.config file. If your
application does not use the Blackfish SQL server, set system properties by calling the
System.AppDomain.CurrentDomain.SetData method.
If your application uses the Blackfish SQL server, set system properties in the BSQLServer.config file by prefixing the
property setting with vmparam -D. If your application does not use the Blackfish SQL server, set system properties by calling
the System.setProperty method.
• If you are using a javax.sql.DataSource implementation, call the setLogWriter method of the DataSource
implementation. See com.borland.javax.sql.JdbcDataSource and
com.borland.javax.sql.JdbcConnectionPool.
• Call the java.sql.DriverManager.setLogStream method.
• Call the java.sql.DriverManager.setLogWriter method.
Enabling Blackfish SQL Database Logging
Database logging output is performed on a per-database basis and is sent to the status log files for that database. The lifetime of
status log files is managed in the same fashion as the transactional log files for the database. When a transactional log file is
dropped, the corresponding status log file is dropped also. When you create a database, status logging is disabled by default.
You can enable database status logging by calling the DB_ADMIN.ALTER_DATABASE built-in stored procedure. You can set the
log filtering options for all connections to a database by calling the DB_ADMIN.SET_DATABASE_STATUS_LOG_FILTER built-in
stored procedure. You can set the log filtering options for a single connection by setting the logFilter connection property or
by calling the DB_ADMIN.SET_STATUS_LOG_FILTER built-in stored procedure.
Blackfish SQL has automatic, high speed deadlock detection that should detect all deadlocks. An appropriate exception is
thrown that identifies which connection encountered the deadlock, and the connection with which it is deadlocked. Unlike lock
timeout exceptions, deadlock exceptions encountered by a java.sql.Connection cause that connection to automatically roll
back its transaction. This behavior allows other connections to continue their work.
• Read the exception message from the timeout or deadlock. The message has information on what tables and what
connections are involved.
• Enable system or database logging. To restrict log output to lock-related issues, set the log filter options to LOCK_ERRORS.
• Use the DB_ADMIN.GET_LOCKS built-in stored procedure to report locks held by all connections.
13
138
13 Blackfish SQL
Setting the readOnlyTx connection property to true causes a connection to use read only connections. Note that there is also a
readOnly connection property, which is very different from the readOnlyTx connection property. The readOnly connection
property causes the database file to be open in read only mode, preventing any other connections from writing to the database.
For Blackfish SQL for Java JDBC connections you can also enable read-only transactions by setting the readOnly property of
the java.sql.Connection object or the com.borland.dx.sql.dataset.Database.getJdbcConnection methods to
true. When using Blackfish SQL for Java DataStoreConnection objects, set the readOnlyTx property to true before
opening the connection.
Read-only transactions work by simulating a snapshot of the Blackfish SQL database. The snapshot sees only data from
transactions that are committed at the point the read-only transaction starts; otherwise, the connection would have to check if
there were pending changes and roll them back whenever it accessed the data. A snapshot begins when the connection opens.
The snapshot is refreshed each time the commit method is called.
Note that transactional Blackfish SQL databases have automatic crash recovery when they are opened. Under normal
circumstances, Blackfish SQL databases do not require verification.
If your application uses the local JDBC driver, there is nothing special to set up, since the database engine is executing in the
same process as your application.
If your application uses the remote JDBC driver, you can use either of the following procedures.
139
Blackfish SQL 13
start method.
1. Add the following lines to your <jds_home>/bin/JdsServer.config file: vmparam -Xdebug vmparam -Xnoagent
vmparam -Djava.compiler=NONE vmparam
-Xrunjdwp:transport=dt_socket,server=y,address=5000,suspend=y
2. Execute the JdsServer. The server will not come up until a remote debugger (such as the JBuilder debugger) is launched to
attach to the JdsServer process on port 5000.
When you use DataExpress components to create a table, the table and column names are case sensitive. If you specify these
identifiers in lowercase or mixed case, SQL is not able to access them unless the identifiers are quoted.
When you use DataExpress to access a table, the StorageDataSet storeName property is case sensitive. However, the
column identifiers can be referenced in a case-insensitive fashion. Consequently, for DataExpress, you can access an address
column by using ADDRESS or address.
The simplest way to avoid problems with identifiers for both SQL and DataExpress components is to always use uppercase
identifiers when your application creates or accesses tables.
• Locate and query operations might not find records that they should find.
• A table viewed in secondary index order (by setting the StorageDataSet.sort property) might not be ordered properly.
Currently, the only way to correct this is to drop the secondary indices and rebuild them with the current JDK. The
StorageDataSet.restructure() method also drops all the secondary indexes.
See Also
Preface ( see page 1)
140
13 Blackfish SQL
Using Stored Procedures and User Defined Functions ( see page 41)
13
141
14 Blackfish SQL
Index
A
Administering Blackfish SQL 31
D
DB_ADMIN 59
DB_UTIL 59
Deploying Blackfish SQL Database Applications 133
E
Establishing Connections 23
O
Optimizing Blackfish SQL Applications 125
Overview 3
P
Preface 1
S
SQL Reference 75
Stored Procedures Reference 59
System Architecture 7
T
Troubleshooting 137
U
Using Blackfish SQL Security 35
Using Stored Procedures and User Defined Functions 41
Using Triggers in Blackfish SQL Tables 55