• warning: DOMXPath::query(): Invalid expression in /var/www/ictedge/sites/all/modules/print/lib/dompdf-0.5.1/include/stylesheet.cls.php on line 573.
  • warning: DOMXPath::query(): Invalid expression in /var/www/ictedge/sites/all/modules/print/lib/dompdf-0.5.1/include/stylesheet.cls.php on line 573.
  • warning: Invalid argument supplied for foreach() in /var/www/ictedge/sites/all/modules/print/lib/dompdf-0.5.1/include/stylesheet.cls.php on line 575.

Derby database tips

Making a database connection in ij

ij is the sql client that comes with Derby. Here are a few sample connection strings:

connect 'jdbc:derby:admin' user 'APP' password '';
connect 'jdbc:derby:C:\zephyr\databases\zeprs' user 'APP' password '';
connect 'jdbc:derby://localhost/C:\zephyr\databases\zeprs'' user 'APP' password '';
connect 'jdbc:derby://localhost//var/www/zeprs_standalone/databases/zeprs' user 'APP' password ' ';

Backups

This dumps the db filesystem - not the DDL.

set connection zeprs;
CALL SYSCS_UTIL.SYSCS_BACKUP_DATABASE('C:/zephyr/backup/');

Export data from a single table:

CALL SYSCS_UTIL.SYSCS_EXPORT_TABLE (null,'SITE','C:/zephyr/site.txt',null,null,null);

Exporting Admin schema

BackupDAO.backupAdminSchema() saves all of the dynasite-related tables in the Admin schema to .csv files according to the following format:

  • Columns: comma-delimited
  • Characters: double quotation mark (")

It uses the CALL SYSCS_UTIL.SYSCS_EXPORT_TABLE system procedure.

Links to exporting both the Admin schema and certain administrative tables in the App schema (site* and user*) are available in the Data Centre section of Administration.

Import data from a single file into the ADMIN schema:

CALL SYSCS_UTIL.SYSCS_IMPORT_TABLE ('ADMIN','SITE','C:/zephyr/site.txt',null,null,null,0);

Generate Schema

To generate schema, use the Derby command "dblook". Must close all connection to the db - it does an embedded connection to the db. There is a script in the databases/scripts folder  - dblook.bat - that will backup the schema to zeprs.ddl. Example:

dblook -d 'jdbc:derby:C:\zcore\databases\zeprs' -o zeprs.ddl

Run a sql script

ijz C:\zephyr\databases\admin.ddl

Reset an identity column (autogenerated id)

First get the max id for the field:

select MAX(id)+1 from ADMIN.DISTRICT;

Then reset the id using the value returned:

ALTER TABLE ADMIN.DISTRICT ALTER COLUMN id RESTART WITH 6

Substitutions for MySQL commands

LIMIT

A substitute for the LIMIT keyword is setMaxRows. Example: DatabaseUtils.getList(Connection conn, Class clazz, String sql, ArrayList values, Integer maxRows) calls ZEPRSQueryRunner.query(Connection conn, String sql, Object[] params, ResultSetHandler rsh, Integer maxRows).

public Object query(Connection conn, String sql, Object[] params,
            ResultSetHandler rsh, Integer maxRows) throws SQLException {

        PreparedStatement stmt = null;
        ResultSet rs = null;
        Object result = null;

        try {
            stmt = this.prepareStatement(conn, sql);
            stmt.setMaxRows(maxRows);
            this.fillStatement(stmt, params);
            rs = this.wrap(stmt.executeQuery());
            result = rsh.handle(rs);

        } catch (SQLException e) {
            this.rethrow(e, sql, params);

        } finally {
            try {
                close(rs);
            } finally {
                close(stmt);
            }
        }

        return result;
    }

 

After the list is returned, select the first element:

List items = DatabaseUtils.getList(conn, EncounterData.class, sql, values, 1);
        if (items.size() > 0) {
            item = (EncounterData) items.get(0);
        }

Also check out the ROW_NUMBER function in the Derby documentation: db-derby-10.4.1.3-bin/docs/html/ref/rreffuncrownumber.html

PAGING

In the 10.5 release, paging capabilities have been greatly enhanced by the new result offset and fetch first clauses.

        String sql = (String) queries.get(genSqlName) + " ORDER BY id desc OFFSET " + offset + " ROWS FETCH NEXT " 
+ maxRows + " ROWS ONLY";

Paging could be accomplished in earlier releases using the following caveats:

Derby does not currently support ORDER BY in subqueries, so there is currently no way to guarantee the order of rows in the SELECT subquery. An optimizer override can be used to force the optimizer to use an index ordered on the desired column(s) if ordering is a firm requirement.

So, you'd need to make sure that the column you need to have ordered by is indexed with ASC or DESC.

SELECT * FROM (
   SELECT 
     ROW_NUMBER() OVER () AS R, 
     p.id AS patientId, o.id AS referralId, o.encounter_id AS encounterId
   FROM outcome o
   INNER JOIN (patient p) ON o.patient_id = p.id
) AS TR 
   WHERE R <= 100
   ORDER BY patientId desc; 

View the following JIRA's for more information as these capabilities progress:

Query Optimization

As noted in the Paging section, one may use an optimizer override to force the optimizer to use an index ordered on the desired column(s). In a sql statement, the syntax is

 -- DERBY-PROPERTIES index = indexname 

Example:

String sql = "SELECT * FROM (SELECT ROW_NUMBER() OVER () AS R," +
                                    "id, date_of_record AS field2241, item_id AS field2236, type_of_change AS field2250, " +
                                    "change_value AS field2251, expiry_date AS field2244, notes AS field2237, " +
                                    "balance AS field2248, last_patient_item_id AS field2249 " +
                                    "FROM stock_control -- DERBY-PROPERTIES index = FKSTOCK_CONTROLID \r" +
                                    ") AS TR WHERE (R > " + offset + " AND R <= " + (maxRows + offset) + ")";

See Overriding the default optimizer behavior for more information about optimizer over-riding.

Also note the user of the "\r" character (carriage return) in the statement/ There must be a carriage return between the properties statement and the order by or else the system will throw an error. See http://www.mail-archive.com/derby-user@db.apache.org/msg06296.html.

Concatenation

u2.lastName || ', ' || u2.firstName AS lastModifiedByName

Date fields

ALTER TABLE site add column created TIMESTAMP DEFAULT CURRENT_TIMESTAMP;

UUID/GUID's

There is not a function for creating a UUID in Derby - the app must provide the UUID.

Or you can create a jar with a uuid generating method. Here is the class:

package org.cidrz.webapp.dynasite.utils;

public class ZcoreDerbyUuid {
/**
* Used to generate uuid's. Create a jar and pop it into Derby.
* @return
*/
public static String generateUuid() {
return java.util.UUID.randomUUID().toString();
}
}

To install the jar:

CALL SQLJ.install_jar('C:\tcc\databases\zcoreUuid.jar', 'zcoreUuid', 0);

Set the derby classpath to recognise the new class:

CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath','APP.zcoreUuid');

Create a function to generate the uuid:

CREATE FUNCTION GENERATE_UUID()
RETURNS VARCHAR(255)
PARAMETER STYLE JAVA
NO SQL LANGUAGE JAVA
EXTERNAL NAME 'org.cidrz.webapp.dynasite.utils.ZcoreDerbyUuid.generateUuid';

To query in ij:

values GENERATE_UUID();

Here's the ALTER TABLE statement for adding a uuid field.

ALTER TABLE admin.form_type add column GLOBAL_IDENTIFIER_NAME CHAR(36);

Using the new function in a sql statement

UPDATE admin.form_field AS t SET uuid = (SELECT GENERATE_UUID() AS newuuid FROM admin.form_field WHERE t.id = admin.form_field.id );

Escape Syntax

Within a character string, to represent a single quotation mark or apostrophe, use two single quotation marks. (In other words, a single quotation mark is the escape character for a single quotation mark.)

VALUES 'Joe''s umbrella'

-- in ij, you don't need to escape the double quotation marks

VALUES 'He said, "hello!"'

see db-derby-10.4.1.3-bin/docs/html/ref/rrefsqlj28468.html

To get the last autogenerated id:

in MySQL - LAST_INSERT_ID()
in Derby - VALUES IDENTITY_VAL_LOCAL()

Strange error message

java.sql.SQLException: A network protocol error was encountered and the connection has been terminated: 
the requested command encountered an unarchitected and implementation-specific condition for which there was no architected message 

Sometimes the Derby log (databases/derby.log) has a useful message. Unfortunately it is still cryptic:

java.lang.NullPointerException
	at org.apache.derby.impl.sql.execute.IndexChanger.insertAndCheckDups(Unknown Source)
...

But it does shed a little light - IndexChanger.insertAndCheckDups hints that the error has something to do w/ indexes and checking for duplicate values. A column in this table is a Char 36 named uuid - that has a unique index. I did a select on the table to see if there was already an index with this value - et voila - there was.