Subject Re: [Firebird-Java] Re: Jaybird and replication
Author Nickolay Samofatov
Hello, Roman !

>> But bugs in current isc_database_info cause JBuilder Database Pilot
>> display incorrect database version (depends on length of version
>> string).
>> My changes fix this bug and should not break anything (they are
>> just a few lines).

> Ok, can you post your changes here? BTW, what are the bugs in
> isc_database_info?

1. It was generally broken (unusable in general case)
2. parseTruncatedDatabaseInfo parsed version string for Firebird
incorrectly

> Also I see no problem of giving public access to isc_db_handle, but
> that means that you want to do something that is not implemented in
> driver. Maybe it would be better to add this feature to the driver?
Don't think so. Each new item in isc_database_info would require
support from the driver side than ? There are ~60 types of items now
and they are rarely used. Expert who writes a tool for database can
parse them manually, but for general user they are useless and
built-in parser will only make driver heavier. This is my opinion.

Here are my changes:
Index: src/main/org/firebirdsql/gds/GDS.java
===================================================================
RCS file: /cvsroot/firebird/client-java/src/main/org/firebirdsql/gds/GDS.java,v
retrieving revision 1.7
diff -b -B -u -r1.7 GDS.java
--- src/main/org/firebirdsql/gds/GDS.java 22 Nov 2002 02:30:38 -0000 1.7
+++ src/main/org/firebirdsql/gds/GDS.java 16 Feb 2003 15:39:34 -0000
@@ -51,11 +51,9 @@
isc_db_handle db_handle,
Clumplet c) throws GDSException;

- void isc_database_info(isc_db_handle db_handle,
- int item_length,
+ byte[] isc_database_info(isc_db_handle db_handle,
byte[] items,
- int buffer_length,
- byte[] buffer) throws GDSException;
+ int buffer_length) throws GDSException;

void isc_detach_database(isc_db_handle db_handle) throws GDSException;

Index: src/main/org/firebirdsql/jca/FBManagedConnection.java
===================================================================
RCS file: /cvsroot/firebird/client-java/src/main/org/firebirdsql/jca/FBManagedConnection.java,v
retrieving revision 1.16
diff -b -B -u -r1.16 FBManagedConnection.java
--- src/main/org/firebirdsql/jca/FBManagedConnection.java 17 Dec 2002 16:43:01 -0000 1.16
+++ src/main/org/firebirdsql/jca/FBManagedConnection.java 16 Feb 2003 15:39:34 -0000
@@ -46,6 +46,7 @@
import org.firebirdsql.gds.GDSException;
import org.firebirdsql.gds.XSQLDA;
import org.firebirdsql.gds.XSQLVAR;
+import org.firebirdsql.gds.GDS;
import org.firebirdsql.gds.isc_blob_handle;
import org.firebirdsql.gds.isc_db_handle;
import org.firebirdsql.gds.isc_stmt_handle;
@@ -1019,6 +1020,26 @@
currentDbHandle.clearWarnings();
}

+ /**
+ * Get connection handle for direct Firebird API access
+ *
+ * @return internal handle for connection
+ */
+ public isc_db_handle getIscDBHandle() throws GDSException {
+ if (currentDbHandle == null) {
+ currentDbHandle = mcf.getDbHandle(cri);
+ }
+ return currentDbHandle;
+ }
+
+ /**
+ * Get Firebird API handler (sockets/native/embeded/etc)
+ * @return handler object for internal API calls
+ */
+ public GDS getInternalAPIHandler() {
+ return mcf.gds;
+ }
+
//--------------------------------------------------------------------
//package visibility
//--------------------------------------------------------------------
Index: src/main/org/firebirdsql/jdbc/FBConnection.java
===================================================================
RCS file: /cvsroot/firebird/client-java/src/main/org/firebirdsql/jdbc/FBConnection.java,v
retrieving revision 1.17
diff -b -B -u -r1.17 FBConnection.java
--- src/main/org/firebirdsql/jdbc/FBConnection.java 17 Dec 2002 16:43:02 -0000 1.17
+++ src/main/org/firebirdsql/jdbc/FBConnection.java 16 Feb 2003 15:39:35 -0000
@@ -36,7 +36,9 @@
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.isc_stmt_handle;
import org.firebirdsql.gds.isc_blob_handle;
+import org.firebirdsql.gds.isc_db_handle;
import org.firebirdsql.gds.GDSException;
+import org.firebirdsql.gds.GDS;
import org.firebirdsql.jca.FBLocalTransaction;
import org.firebirdsql.jca.FBManagedConnection;
import java.util.Map;
@@ -152,6 +154,24 @@
}

/**
+ * Get connection handle for direct Firebird API access
+ *
+ * @return internal handle for connection
+ * @exception GDSException if handle needed to be created and creation failed
+ */
+ public isc_db_handle getIscDBHandle() throws GDSException {
+ return mc.getIscDBHandle();
+ }
+
+ /**
+ * Get Firebird API handler (sockets/native/embeded/etc)
+ * @return handler object for internal API calls
+ */
+ public GDS getInternalAPIHandler() {
+ return mc.getInternalAPIHandler();
+ }
+
+ /**
* Creates a <code>Statement</code> object for sending
* SQL statements to the database.
* SQL statements without parameters are normally
Index: src/main/org/firebirdsql/jgds/GDS_Impl.java
===================================================================
RCS file: /cvsroot/firebird/client-java/src/main/org/firebirdsql/jgds/GDS_Impl.java,v
retrieving revision 1.27
diff -b -B -u -r1.27 GDS_Impl.java
--- src/main/org/firebirdsql/jgds/GDS_Impl.java 1 Feb 2003 01:55:18 -0000 1.27
+++ src/main/org/firebirdsql/jgds/GDS_Impl.java 16 Feb 2003 15:39:35 -0000
@@ -243,6 +243,13 @@



+ final static byte[] describe_database_info = new byte[] { ISCConstants.isc_info_db_sql_dialect,
+ ISCConstants.isc_info_isc_version,
+ ISCConstants.isc_info_ods_version,
+ ISCConstants.isc_info_ods_minor_version,
+ ISCConstants.isc_info_end
+ };
+
public void isc_attach_database(DbAttachInfo dbai,
isc_db_handle db_handle,
Clumplet dpb) throws GDSException {
@@ -274,25 +281,16 @@
throw ge;
}
// read database information
- isc_database_info(db,0,null,0,null);
+ parseAttachDatabaseInfo(isc_database_info(db,describe_database_info,1024),db);
} catch (IOException ex) {
throw new GDSException(ISCConstants.isc_net_write_err);
}
}
}

- final static byte[] describe_database_info = new byte[] { ISCConstants.isc_info_db_sql_dialect,
- ISCConstants.isc_info_isc_version,
- ISCConstants.isc_info_ods_version,
- ISCConstants.isc_info_ods_minor_version,
- ISCConstants.isc_info_end
- };
-
- public void isc_database_info(isc_db_handle handle,
- int item_length,
+ public byte[] isc_database_info(isc_db_handle handle,
byte[] items,
- int buffer_length,
- byte[] buffer) throws GDSException {
+ int buffer_length) throws GDSException {
boolean debug = log != null && log.isDebugEnabled();
isc_db_handle_impl db = (isc_db_handle_impl) handle;
synchronized (db){
@@ -301,47 +299,28 @@
db.out.writeInt(op_info_database);
db.out.writeInt(db.getRdb_id());
db.out.writeInt(0);
- db.out.writeBuffer(describe_database_info);
- db.out.writeInt(1024);
+ db.out.writeBuffer(items);
+ db.out.writeInt(buffer_length);
db.out.flush();
if (debug) log.debug("sent");
receiveResponse(db,-1);
- parseDatabaseInfo(db,db.getResp_data(),describe_database_info);
if (debug) log.debug("parseSqlInfo: first 2 bytes are " + isc_vax_integer(db.getResp_data(), 0, 2) + " or: " + db.getResp_data()[0] + ", " + db.getResp_data()[1]);
+ return db.getResp_data();
} catch (IOException ex) {
throw new GDSException(ISCConstants.isc_network_error);
}
}
}

- private void parseDatabaseInfo(isc_db_handle db,
- byte[] info,
- byte[] items) throws GDSException {
-
- boolean debug = log != null && log.isDebugEnabled();
- if (debug) log.debug("parseDatabaseInfo started");
-
- int lastindex = 0;
- parseTruncDatabaseInfo(info, lastindex, db);
- while ((lastindex = parseTruncDatabaseInfo(info, lastindex, db)) > 0) {
- lastindex--; // Is this OK ?
- byte[] new_items = new byte[4 + items.length];
- new_items[0] = ISCConstants.isc_info_sql_sqlda_start;
- new_items[1] = 2;
- new_items[2] = (byte) (lastindex & 255);
- new_items[3] = (byte) (lastindex >> 8);
- System.arraycopy(items, 0, new_items, 4, items.length);
-// info = isc_database_info(db, 0,
-// new_items, info.length, null);
- }
- if (debug) log.debug("parseDatabaseInfo ended");
- }
-
- private int parseTruncDatabaseInfo(byte[] info,
- int lastindex, isc_db_handle handle) throws GDSException {
+/**
+ * Parse database info returned after attach. This method assumes that
+ * it is not truncated.
+ * @param info information returned by isc_database_info call
+ * @param handle isc_db_handle to set connection parameters
+ * @throws GDSException if something went wrong :))
+ */
+ private void parseAttachDatabaseInfo(byte[] info, isc_db_handle handle) throws GDSException {
boolean debug = log != null && log.isDebugEnabled();
- byte item;
- int index = 0;
if (debug) log.debug("parseDatabaseInfo: first 2 bytes are " + isc_vax_integer(info, 0, 2) + " or: " + info[0] + ", " + info[1]);
int value=0;
int len=0;
@@ -361,9 +340,9 @@
len = isc_vax_integer(info, i, 2);
i += 2;
if (debug) log.debug("isc_info_version len:"+len);
- //
- byte[] vers = new byte[len];
- System.arraycopy(info, i, vers, 0, len);
+ // This +/-2 offset is to skip count and version string length
+ byte[] vers = new byte[len-2];
+ System.arraycopy(info, i+2, vers, 0, len-2);
String versS = new String(vers);
i += len;
db.setVersion(versS);
@@ -387,13 +366,11 @@
break;
case ISCConstants.isc_info_truncated:
if (debug) log.debug("isc_info_truncated ");
- return lastindex;
+ return;
default:
throw new GDSException(ISCConstants.isc_dsql_sqlda_err);
}
- lastindex = index;
}
- return 0;
}

public void isc_detach_database(isc_db_handle db_handle) throws GDSException {


> Thanks,
> Roman


Nickolay Samofatov