All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.firebirdsql.gds.ng.wire.DefaultBlrCalculator Maven / Gradle / Ivy

There is a newer version: 4.0.10.java8
Show newest version
/*
 * $Id$
 *
 * Firebird Open Source JavaEE Connector - JDBC Driver
 *
 * Distributable under LGPL license.
 * You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * LGPL License for more details.
 *
 * This file was created by members of the firebird development team.
 * All individual contributions remain the Copyright (C) of those
 * individuals.  Contributors to this file are either listed here or
 * can be obtained from a source control history command.
 *
 * All rights reserved.
 */
package org.firebirdsql.gds.ng.wire;

import org.firebirdsql.gds.ng.FbExceptionBuilder;
import org.firebirdsql.gds.ng.fields.*;

import java.io.ByteArrayOutputStream;
import java.sql.SQLException;

import static org.firebirdsql.gds.BlrConstants.*;
import static org.firebirdsql.gds.ISCConstants.*;

/**
 * Default BLR calculator for the wire protocol.
 * 

* Most likely this can be used without change for other protocol versions as well, although we may need to investigate * the TODOs specified in {@link #calculateBlr(org.firebirdsql.gds.ng.fields.RowDescriptor)}. *

* * @author Mark Rotteveel * @since 3.0 */ public class DefaultBlrCalculator implements BlrCalculator { /** * Cached instance of {@link DefaultBlrCalculator} for dialect 3 databases. */ public static final DefaultBlrCalculator CALCULATOR_DIALECT_3 = new DefaultBlrCalculator((short) 3); private final short dialect; public DefaultBlrCalculator(short dialect) { this.dialect = dialect; } @Override public byte[] calculateBlr(RowDescriptor rowDescriptor) throws SQLException { final ByteArrayOutputStream bout = getByteArrayOutputStream(rowDescriptor.getCount()); for (FieldDescriptor field : rowDescriptor) { calculateFieldBlr(bout, field, field.getLength()); } bout.write(blr_end); bout.write(blr_eoc); return bout.toByteArray(); } @Override public byte[] calculateBlr(RowDescriptor rowDescriptor, RowValue rowValue) throws SQLException { final ByteArrayOutputStream bout = getByteArrayOutputStream(rowValue.getCount()); for (int idx = 0; idx < rowDescriptor.getCount(); idx++) { final FieldValue fieldValue = rowValue.getFieldValue(idx); final FieldDescriptor field = rowDescriptor.getFieldDescriptor(idx); final int actualDataLength = fieldValue.getFieldData() != null ? fieldValue.getFieldData().length : 0; calculateFieldBlr(bout, field, actualDataLength); } bout.write(blr_end); bout.write(blr_eoc); return bout.toByteArray(); } /** * Creates a byte array stream and writes the header for the specified number of fields. * * @param fieldCount Number of fields. * @return Byte array OutputStream with header already written */ private ByteArrayOutputStream getByteArrayOutputStream(final int fieldCount) { // Approximate size for the blr so we can allocate a ByteArray with a sufficiently large buffer, so no resize is needed // 8 bytes: 6 bytes header + 2 bytes tail // 5 bytes per field: 3 bytes maximum required + 2 bytes for the null indicator and end of parameter final int approximateSize = 8 + 5 * fieldCount; final ByteArrayOutputStream bout = new ByteArrayOutputStream(approximateSize); final int parameterCount = 2 * fieldCount; // 1 actual field, 1 null descriptor (?) bout.write(dialect <= 1 ? blr_version4 : blr_version5); bout.write(blr_begin); bout.write(blr_message); bout.write(0); bout.write(parameterCount); bout.write(parameterCount >> 8); return bout; } /** * Calculates the blr for a single field. * * @param bout Byte array OutputStream * @param field Field descriptor * @param len Length to use for SQL_VARYING and SQL_TEXT * @throws SQLException */ private void calculateFieldBlr(final ByteArrayOutputStream bout, final FieldDescriptor field, final int len) throws SQLException { final int fieldType = field.getType() & ~1; switch (fieldType) { case SQL_VARYING: // TODO Use blr_varying2 instead, blr_varying2 was already in Firebird 1 bout.write(blr_varying); bout.write(len); bout.write(len >> 8); break; case SQL_TEXT: // TODO Use blr_text2 instead, brl_text2 was already in Firebird 1 bout.write(blr_text); bout.write(len); bout.write(len >> 8); break; case SQL_NULL: bout.write(blr_text); bout.write(0); bout.write(0); break; case SQL_DOUBLE: bout.write(blr_double); break; case SQL_FLOAT: bout.write(blr_float); break; case SQL_D_FLOAT: bout.write(blr_d_float); break; case SQL_TYPE_DATE: bout.write(blr_sql_date); break; case SQL_TYPE_TIME: bout.write(blr_sql_time); break; case SQL_TIMESTAMP: bout.write(blr_timestamp); break; case SQL_BLOB: // TODO Use blr_blob2 instead, find out which Firebird version added that bout.write(blr_quad); bout.write(0); // scale? break; case SQL_ARRAY: bout.write(blr_quad); bout.write(0); // scale? break; case SQL_LONG: bout.write(blr_long); bout.write(field.getScale()); break; case SQL_SHORT: bout.write(blr_short); bout.write(field.getScale()); break; case SQL_INT64: bout.write(blr_int64); bout.write(field.getScale()); break; case SQL_QUAD: bout.write(blr_quad); bout.write(field.getScale()); break; case SQL_BOOLEAN: bout.write(blr_bool); break; default: throw new FbExceptionBuilder().exception(isc_dsql_sqlda_value_err).toSQLException(); } bout.write(blr_short); // Null indicator bout.write(0); // End of parameter? } @Override public int calculateIoLength(FieldDescriptor fieldDescriptor) throws SQLException { switch (fieldDescriptor.getType() & ~1) { case SQL_TEXT: return fieldDescriptor.getLength() + 1; case SQL_VARYING: return 0; case SQL_SHORT: case SQL_LONG: case SQL_FLOAT: case SQL_TYPE_TIME: case SQL_TYPE_DATE: return -4; case SQL_DOUBLE: case SQL_TIMESTAMP: case SQL_BLOB: case SQL_ARRAY: case SQL_QUAD: case SQL_INT64: return -8; case SQL_NULL: return 0; case SQL_BOOLEAN: return 1 + 1; default: throw new FbExceptionBuilder().exception(isc_dsql_datatype_err).toSQLException(); } } @Override public int calculateIoLength(FieldDescriptor fieldDescriptor, FieldValue fieldValue) throws SQLException { final int fieldType = fieldDescriptor.getType() & ~1; if (fieldType == SQL_TEXT) { // Use actual data length for SQL_TEXT return (fieldValue.getFieldData() != null ? fieldValue.getFieldData().length : 0) + 1; } return calculateIoLength(fieldDescriptor); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy