Hello:
We are going to need to implement the version 11 of the Firebird
Protocol and review the buffer handling code to make better checks on
buffer lengths and server resposnses.
Now the Firebird server supports batching of messages ( not available
for all of them ), so we can send several messages in the same request
and retrieve all the answers at the same time.
An example will be the statement preparation, in the actual GDS
implementation we make two calls to the server:
1. To prepare the statement
2. To get the statement type
Now we can send them in the same request to the server, something like this:
public override void Prepare(string commandText)
{
// Clear data
this.Clear();
this.parameters = null;
this.fields = null;
lock (this.db)
{
if (this.state == StatementState.Deallocated)
{
// Allocate statement
this.Allocate();
}
try
{
// Prepare the statement
this.db.Send.Write(IscCodes.op_prepare_statement);
this.db.Send.Write(this.transaction.Handle);
this.db.Send.Write(this.handle);
this.db.Send.Write((int)this.db.Dialect);
this.db.Send.Write(commandText);
this.db.Send.WriteBuffer(DescribeInfoItems,
DescribeInfoItems.Length);
this.db.Send.Write(IscCodes.MAX_BUFFER_SIZE);
// Grab statement type
this.db.Send.Write(IscCodes.op_info_sql);
this.db.Send.Write(this.handle);
this.db.Send.Write(0);
this.db.Send.WriteBuffer(StatementTypeInfoItems,
StatementTypeInfoItems.Length);
this.db.Send.Write(IscCodes.STATEMENT_TYPE_BUFFER_SIZE);
// Flush data
this.db.Send.Flush();
// Prepare statement info processing
GdsGenericResponse response =
(GdsGenericResponse)this.db.ReadResponse();
this.fields = this.ParseSqlInfo(response.Data,
DescribeInfoItems);
// Statement type information processing
GdsGenericResponse stmtmTypeResponse =
(GdsGenericResponse)this.db.ReadResponse();
this.statementType =
this.ParseStatementTypeInfo(stmtmTypeResponse.Data);
this.state = StatementState.Prepared;
}
catch (IOException)
{
this.state = StatementState.Error;
throw new IscException(IscCodes.isc_net_read_err);
}
}
}
Another example, could be the statement execution method that makes two
calls ( wehn execution insert, updates, deletes )
1. To execute the statement
2. To retrieve the number of rows affected by the statement execution
Now we can send them in the same request to the server, something like this:
public override void Execute()
{
if (this.state == StatementState.Deallocated)
{
throw new InvalidOperationException("Statment is not
correctly created.");
}
// Clear data
this.Clear();
lock (this.db)
{
try
{
byte[] descriptor = null;
if (this.parameters != null)
{
XdrStream xdr = new XdrStream(this.db.Charset);
xdr.Write(this.parameters);
descriptor = xdr.ToArray();
xdr.Close();
}
if (this.statementType ==
DbStatementType.StoredProcedure)
{
this.db.Send.Write(IscCodes.op_execute2);
}
else
{
this.db.Send.Write(IscCodes.op_execute);
}
this.db.Send.Write(this.handle);
this.db.Send.Write(this.transaction.Handle);
if (this.parameters != null)
{
this.db.Send.WriteBuffer(this.parameters.ToBlrArray());
this.db.Send.Write(0); // Message number
this.db.Send.Write(1); // Number of messages
this.db.Send.Write(descriptor, 0,
descriptor.Length);
}
else
{
this.db.Send.WriteBuffer(null);
this.db.Send.Write(0);
this.db.Send.Write(0);
}
if (this.statementType ==
DbStatementType.StoredProcedure)
{
this.db.Send.WriteBuffer((this.fields == null) ?
null : this.fields.ToBlrArray());
this.db.Send.Write(0); // Output message number
}
// Obtain records affected by query execution
if (this.ReturnRecordsAffected &&
(this.StatementType == DbStatementType.Insert ||
this.StatementType == DbStatementType.Delete ||
this.StatementType == DbStatementType.Update ||
this.StatementType ==
DbStatementType.StoredProcedure ||
this.StatementType == DbStatementType.Select))
{
// Grab statement type
this.db.Send.Write(IscCodes.op_info_sql);
this.db.Send.Write(this.handle);
this.db.Send.Write(0);
this.db.Send.WriteBuffer(RecordsAffectedInfoItems,
RecordsAffectedInfoItems.Length);
this.db.Send.Write(IscCodes.ROWS_AFFECTED_BUFFER_SIZE);
this.recordsAffected = 0;
}
else
{
this.recordsAffected = -1;
}
this.db.Send.Flush();
if (this.db.NextOperation() == IscCodes.op_sql_response)
{
// This would be an Execute procedure
this.outputParams.Enqueue(this.ReadStoredProcedureOutput());
}
this.db.ReadResponse();
if (this.recordsAffected == 0)
{
GdsGenericResponse response =
(GdsGenericResponse)this.db.ReadResponse();
this.ProcessRecordsAffectedBuffer(response.Data);
}
this.state = StatementState.Executed;
}
catch (IOException)
{
this.state = StatementState.Error;
throw new IscException(IscCodes.isc_net_read_err);
}
}
}
For the new GDS implementation, my first thought is that we can make all
the public methods on the current GDS implementation virtual, and
override ( and rewrite ) them in the new GDS implementation ( i will try
to check if that approach will be possible or not ... i think it's but
.. better to be sure XD )
--
Carlos Guzmán Álvarez
Vigo-Spain
http://carlosga.wordpress.com
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Firebird-net-provider mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/firebird-net-provider