8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 00:03:02 +01:00

Improve gbak performance over network using batch interface

This commit is contained in:
AlexPeshkoff 2017-12-27 16:18:20 +03:00 committed by Adriano dos Santos Fernandes
parent 0a1b23004e
commit 520a28fc19
21 changed files with 792 additions and 140 deletions

View File

@ -1089,7 +1089,7 @@ void put_array( burp_fld* field, burp_rel* relation, ISC_QUAD* blob_id)
lstring xdr_slice;
xdr_slice.lstr_allocated = xdr_slice.lstr_length = return_length;
xdr_slice.lstr_address = slice;
return_length = CAN_slice(&xdr_buffer, &xdr_slice, TRUE, /*blr_length,*/ blr_buffer);
return_length = CAN_slice(&xdr_buffer, &xdr_slice, true, blr_buffer);
put(tdgbl, att_xdr_array);
put(tdgbl, (UCHAR) (return_length));
put(tdgbl, (UCHAR) (return_length >> 8));
@ -1684,7 +1684,7 @@ void put_data(burp_rel* relation)
const UCHAR* p;
if (tdgbl->gbl_sw_transportable)
{
record_length = CAN_encode_decode(relation, &xdr_buffer, buffer, TRUE);
record_length = CAN_encode_decode(relation, &xdr_buffer, buffer, true);
put_int32(att_xdr_length, record_length);
p = xdr_buffer.lstr_address;
}

View File

@ -664,12 +664,14 @@ struct burp_fld
SSHORT fld_type;
SSHORT fld_sub_type;
FLD_LENGTH fld_length;
FLD_LENGTH fld_total_len; // including additional 2 bytes for VARYING CHAR
SSHORT fld_scale;
SSHORT fld_position;
SSHORT fld_parameter;
SSHORT fld_missing_parameter;
SSHORT fld_id;
RCRD_OFFSET fld_offset;
RCRD_OFFSET fld_missing_offset;
RCRD_OFFSET fld_old_offset;
SSHORT fld_number;
SSHORT fld_system_flag;
@ -698,6 +700,8 @@ struct burp_fld
ISC_QUAD fld_default_source;
SSHORT fld_character_set_id;
SSHORT fld_collation_id;
RCRD_OFFSET fld_sql;
RCRD_OFFSET fld_null;
};
enum fld_flags_vals {
@ -958,6 +962,7 @@ public:
bool gbl_sw_deactivate_indexes;
bool gbl_sw_kill;
USHORT gbl_sw_blk_factor;
USHORT gbl_dialect;
const SCHAR* gbl_sw_fix_fss_data;
USHORT gbl_sw_fix_fss_data_id;
const SCHAR* gbl_sw_fix_fss_metadata;
@ -976,6 +981,7 @@ public:
burp_fil* gbl_sw_files;
burp_fil* gbl_sw_backup_files;
gfld* gbl_global_fields;
unsigned gbl_network_protocol;
burp_act* action;
ULONG io_buffer_size;
redirect_vals sw_redirect;

View File

@ -24,8 +24,8 @@
#ifndef BURP_CANON_PROTO_H
#define BURP_CANON_PROTO_H
ULONG CAN_encode_decode (burp_rel*, lstring*, UCHAR*, int);
ULONG CAN_slice (lstring*, lstring*, int, /*USHORT,*/ UCHAR*);
ULONG CAN_encode_decode (burp_rel* relation, lstring* buffer, UCHAR* data, bool direction, bool useMissingOffset = false);
ULONG CAN_slice (lstring* buffer, lstring* slice, bool direction, UCHAR* sdl);
#endif // BURP_CANON_PROTO_H

View File

@ -63,7 +63,7 @@ static xdr_t::xdr_ops burp_ops =
const int increment = 1024;
ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool_t direction)
ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool direction, bool useMissingOffset)
{
/**************************************
*
@ -203,17 +203,21 @@ ULONG CAN_encode_decode(burp_rel* relation, lstring* buffer, UCHAR* data, bool_t
{
if (field->fld_flags & FLD_computed)
continue;
UCHAR* p = data + field->fld_missing_offset;
if (!useMissingOffset)
{
offset = FB_ALIGN(offset, sizeof(SSHORT));
UCHAR* p = data + offset;
p = data + offset;
offset += sizeof(SSHORT);
}
if (!xdr_short(xdrs, (SSHORT*) p))
return FALSE;
offset += sizeof(SSHORT);
}
return (xdrs->x_private - xdrs->x_base);
}
ULONG CAN_slice(lstring* buffer, lstring* slice, bool_t direction, /*USHORT sdl_length,*/ UCHAR* sdl)
ULONG CAN_slice(lstring* buffer, lstring* slice, bool direction, UCHAR* sdl)
{
/**************************************
*

View File

@ -30,6 +30,10 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#include "../burp/burp.h"
#include "../jrd/align.h"
#include "../jrd/flags.h"
@ -55,6 +59,7 @@
#include "memory_routines.h"
#include "../burp/OdsDetection.h"
#include "../auth/trusted/AuthSspi.h"
#include "../common/dsc_proto.h"
using MsgFormat::SafeArg;
using Firebird::FbLocalStatus;
@ -111,12 +116,14 @@ void fix_security_class_name(BurpGlobals* tdgbl, TEXT* sec_class, bool is_field)
// returned value is not checked by the caller!
bool get_acl(BurpGlobals* tdgbl, const TEXT*, ISC_QUAD*, ISC_QUAD*);
void get_array(BurpGlobals* tdgbl, burp_rel*, UCHAR*);
void get_blob(BurpGlobals* tdgbl, const burp_fld*, UCHAR*);
void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld*, UCHAR*);
void get_blob_old(BurpGlobals* tdgbl, const burp_fld*, UCHAR*);
void get_blr_blob(BurpGlobals* tdgbl, ISC_QUAD&, bool);
bool get_character_set(BurpGlobals* tdgbl);
bool get_chk_constraint(BurpGlobals* tdgbl);
bool get_collation(BurpGlobals* tdgbl);
rec_type get_data(BurpGlobals* tdgbl, burp_rel*, bool);
rec_type get_data_old(BurpGlobals* tdgbl, burp_rel*);
bool get_exception(BurpGlobals* tdgbl);
burp_fld* get_field(BurpGlobals* tdgbl, burp_rel*);
bool get_field_dimensions(BurpGlobals* tdgbl);
@ -930,7 +937,8 @@ void create_database(BurpGlobals* tdgbl, const TEXT* file_name)
// When we restore backup files that came from prior
// to V6, we force the SQL database dialect to 1
dpb.insertByte(isc_dpb_sql_dialect, SQL_dialect_flag ? SQL_dialect : SQL_DIALECT_V5);
tdgbl->gbl_dialect = SQL_dialect_flag ? SQL_dialect : SQL_DIALECT_V5;
dpb.insertByte(isc_dpb_sql_dialect, tdgbl->gbl_dialect);
// start database up shut down,
// use single-user mode to avoid conflicts during restore process
@ -956,6 +964,14 @@ void create_database(BurpGlobals* tdgbl, const TEXT* file_name)
// msg 33 failed to create database %s
}
tdgbl->gbl_network_protocol = DB->getRemoteProtocolVersion(&status_vector);
// treat errors as old provider missing new calls
if (status_vector->hasData())
{
status_vector->init();
tdgbl->gbl_network_protocol = 1;
}
if (tdgbl->gbl_sw_version && !tdgbl->uSvc->isService())
{
BURP_print(false, 139, file_name);
@ -1759,7 +1775,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
get_block(tdgbl, p, lcount);
if (tdgbl->gbl_sw_transportable)
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, /*blr_length,*/ blr_buffer);
CAN_slice (&xdr_buffer, &xdr_slice, false, blr_buffer);
}
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
@ -1885,7 +1901,7 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
get_block(tdgbl, p, lcount);
if (tdgbl->gbl_sw_transportable)
CAN_slice (&xdr_buffer, &xdr_slice, FALSE, /*blr_length,*/ blr_buffer);
CAN_slice (&xdr_buffer, &xdr_slice, false, blr_buffer);
DB->putSlice(&status_vector, gds_trans, blob_id, blr_length, blr_buffer,
@ -1908,7 +1924,108 @@ void get_array(BurpGlobals* tdgbl, burp_rel* relation, UCHAR* record_buffer)
BURP_free (xdr_buffer.lstr_address);
}
void get_blob(BurpGlobals* tdgbl, const burp_fld* fields, UCHAR* record_buffer)
void get_blob(BurpGlobals* tdgbl, Firebird::IBatch* batch, const burp_fld* fields, UCHAR* record_buffer)
{
/**************************************
*
* g e t _ b l o b
*
**************************************
*
* Functional description
* Read blob attributes and copy data from input file to nice,
* shiny, new blob.
*
**************************************/
// Pick up attributes
ULONG segments = 0;
USHORT field_number = MAX_USHORT;
USHORT max_segment = 0;
UCHAR blob_type = 0;
att_type attribute;
scan_attr_t scan_next_attr;
skip_init(&scan_next_attr);
while (skip_scan(&scan_next_attr), get_attribute(&attribute, tdgbl) != att_blob_data)
{
switch (attribute)
{
case att_blob_field_number:
field_number = (USHORT) get_int32(tdgbl);
break;
case att_blob_max_segment:
max_segment = (USHORT) get_int32(tdgbl);
break;
case att_blob_number_segments:
segments = get_int32(tdgbl);
break;
case att_blob_type:
blob_type = (UCHAR) get_int32(tdgbl);
break;
default:
bad_attribute(scan_next_attr, attribute, 64);
// msg 64 blob
break;
}
}
// Find the field associated with the blob
const burp_fld* field;
for (field = fields; field; field = field->fld_next)
{
if (field->fld_number == field_number)
break;
}
if (!field)
{
BURP_error_redirect(NULL, 36);
// msg 36 Can't find field for blob
}
// Create new blob
ISC_QUAD* blob_id = (ISC_QUAD*) ((UCHAR*) record_buffer + field->fld_offset);
const UCHAR blob_desc[] = {isc_bpb_version1, isc_bpb_type, 1, blob_type};
BlobBuffer local_buffer;
UCHAR* const buffer = local_buffer.getBuffer(max_segment);
FbLocalStatus status_vector;
bool first = true;
// Eat up blob segments
for (; segments > 0; --segments )
{
USHORT length = get(tdgbl);
length |= get(tdgbl) << 8;
if (length)
{
get_block(tdgbl, buffer, length);
}
if (first)
batch->addBlob(&status_vector, length, buffer, blob_id, sizeof(blob_desc), blob_desc);
else
batch->appendBlobData(&status_vector, length, buffer);
if (status_vector->hasData())
{
BURP_error_redirect(&status_vector, 38); // !!!!!!!!! new message
// msg 38 isc_put_segment failed
}
first = false;
}
}
void get_blob_old(BurpGlobals* tdgbl, const burp_fld* fields, UCHAR* record_buffer)
{
/**************************************
*
@ -2710,14 +2827,507 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
* Write data records for a relation.
*
**************************************/
Firebird::IRequest* req_handle = 0;
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
ULONG records = 0;
rec_type record;
burp_fld* field;
// If we're only doing meta-data, ignore data records
if (tdgbl->gbl_sw_meta || skip_relation)
return ignore_data(tdgbl, relation);
// For old versions and embedded connections switch to old style method
// Avoid if possible switch to old style when system domains are used in a table
if (tdgbl->gbl_network_protocol == 0)
{
bool sysDomFlag = false;
for (field = relation->rel_fields; field && (!sysDomFlag); field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
const char* dom = field->fld_source;
if (strncmp(dom, "RDB$", 4) != 0)
continue;
for (dom += 4; *dom; ++dom)
{
#ifdef HAVE_CTYPE_H
if (!isdigit(*dom))
#else
if (*dom < '0' || *dom > '9')
#endif
{
sysDomFlag = true;
break;
}
}
}
if (!sysDomFlag)
return get_data_old(tdgbl, relation);
}
else if (tdgbl->gbl_network_protocol < 16)
return get_data_old(tdgbl, relation);
// Number of fields in a message
unsigned count = 0;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (!(field->fld_flags & FLD_computed))
++count;
}
// Time to generate SQL and message metadata to store data. Whoppee.
try
{
Firebird::string sqlStatement;
sqlStatement.printf("insert into %s(", relation->rel_name);
Firebird::RefPtr<Firebird::IMetadataBuilder> builder(Firebird::REF_NO_INCR,
Firebird::MasterInterfacePtr()->getMetadataBuilder(fbStatus, count));
if (fbStatus->hasData())
general_on_error();
RCRD_OFFSET offset = 0;
count = 0;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
USHORT dtype = field->fld_type;
// arrays are of various fld_types but are really blobs
if (field->fld_flags & FLD_array)
dtype = blr_blob;
DSC desc;
if (!DSC_make_descriptor(&desc, dtype, field->fld_scale, field->fld_length,
field->fld_sub_type, field->fld_character_set_id, field->fld_collation_id))
{
BURP_error(26, true, SafeArg() << dtype);
// msg 26 datatype %ld not understood
}
SSHORT alignment = type_alignments[desc.dsc_dtype];
if (alignment)
offset = FB_ALIGN(offset, alignment);
field->fld_offset = offset;
offset += field->fld_total_len = desc.dsc_length;
SLONG sqlLength, sqlSubType, sqlScale, sqlType;
desc.getSqlInfo(&sqlLength, &sqlSubType, &sqlScale, &sqlType);
SLONG characterSetId = field->fld_character_set_id;
if (tdgbl->gbl_sw_fix_fss_data && field->fld_character_set_id == CS_UNICODE_FSS &&
((sqlType == SQL_BLOB && field->fld_sub_type == isc_blob_text && !(field->fld_flags & FLD_array)) ||
sqlType == SQL_TEXT || sqlType == SQL_VARYING))
{
characterSetId = tdgbl->gbl_sw_fix_fss_data_id;
}
else if (field->fld_flags & FLD_array)
{
sqlType = SQL_QUAD;
sqlScale = 0;
}
builder->setType(&tdgbl->throwStatus, count, sqlType);
builder->setSubType(&tdgbl->throwStatus, count, sqlSubType);
builder->setLength(&tdgbl->throwStatus, count, sqlLength);
builder->setScale(&tdgbl->throwStatus, count, sqlScale);
builder->setCharSet(&tdgbl->throwStatus, count, characterSetId);
sqlStatement += field->fld_name;
sqlStatement += ", ";
field->fld_parameter = count++;
}
fb_assert(sqlStatement.end()[-2] == ',');
sqlStatement.end()[-2] = ')';
Firebird::RefPtr<Firebird::IMessageMetadata> meta(Firebird::REF_NO_INCR,
builder->getMetadata(&tdgbl->throwStatus));
builder = nullptr;
sqlStatement += "values (";
count = 0;
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
offset = FB_ALIGN(offset, sizeof(SSHORT));
field->fld_missing_parameter = count;
field->fld_missing_offset = offset;
offset += sizeof(SSHORT);
field->fld_sql = meta->getOffset(&tdgbl->throwStatus, count);
field->fld_null = meta->getNullOffset(&tdgbl->throwStatus, count);
if (tdgbl->gbl_sw_transportable)
{
field->fld_offset = field->fld_sql;
field->fld_missing_offset = field->fld_null;
}
sqlStatement += "?, ";
++count;
}
fb_assert(sqlStatement.end()[-2] == ',');
sqlStatement.end()[-2] = ')';
RCRD_LENGTH length = offset;
// Create batch
const int GBAK_BATCH_STEP = 1000;
Firebird::AutoDispose<Firebird::IXpbBuilder> pb(Firebird::UtilInterfacePtr()->
getXpbBuilder(&tdgbl->throwStatus, Firebird::IXpbBuilder::BATCH, NULL, 0));
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_MULTIERROR, 1);
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BLOB_POLICY, Firebird::IBatch::BLOB_ID_ENGINE);
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_DETAILED_ERRORS, GBAK_BATCH_STEP);
pb->insertInt(&tdgbl->throwStatus, Firebird::IBatch::TAG_BUFFER_BYTES_SIZE, 0);
Firebird::RefPtr<Firebird::IBatch> batch(DB->
createBatch(fbStatus, gds_trans, sqlStatement.length(), sqlStatement.c_str(), tdgbl->gbl_dialect,
meta, pb->getBufferLength(&tdgbl->throwStatus), pb->getBuffer(&tdgbl->throwStatus)));
if (fbStatus->hasData())
{
// Possible reason of fail - use of keywords as fields in old backup
// Try to roll back to use of old version (fieldnames independent)
BURP_print(false, 27/*, sqlStatement.c_str()*/); // msg 27 isc_compile_request failed !!!!!!!! new WARNING
BURP_print_warning(fbStatus);
return get_data_old(tdgbl, relation);
}
UCHAR* buffer = NULL;
Firebird::Array<UCHAR> requestBuffer;
BURP_verbose (124, relation->rel_name); // msg 124 restoring data for relation %s
lstring data;
data.lstr_allocated = 0;
data.lstr_address = NULL;
Firebird::Array<UCHAR> dataBuffer;
RCRD_LENGTH old_length = 0;
Firebird::Array<UCHAR> sqlBuffer;
UCHAR* sql = sqlBuffer.getBuffer(meta->getMessageLength(&tdgbl->throwStatus));
while (true)
{
if (get(tdgbl) != att_data_length)
BURP_error_redirect(NULL, 39); // msg 39 expected record length
RCRD_LENGTH len = get_int32(tdgbl);
if (!tdgbl->gbl_sw_transportable && len != length)
{
#ifdef sparc
if (!old_length)
old_length = recompute_length(tdgbl, relation);
#endif
if (len != old_length)
{
BURP_error(40, true, SafeArg() << length << len);
// msg 40 wrong length record, expected %ld encountered %ld
}
}
if (!buffer)
buffer = requestBuffer.getBuffer(MAX (length, len));
UCHAR* p;
if (tdgbl->gbl_sw_transportable)
{
if (get(tdgbl) != att_xdr_length)
{
BURP_error_redirect(NULL, 55);
// msg 55 Expected XDR record length
}
else
{
data.lstr_length = len = get_int32(tdgbl);
if (len > data.lstr_allocated)
{
data.lstr_allocated = len;
data.lstr_address = dataBuffer.getBuffer(data.lstr_allocated);
}
p = data.lstr_address;
}
}
else
p = buffer;
if (get(tdgbl) != att_data_data)
BURP_error_redirect(NULL, 41); // msg 41 expected data attribute
if (tdgbl->gbl_sw_compress)
decompress (tdgbl, p, len);
else
{
get_block(tdgbl, p, len);
}
if (old_length)
realign (tdgbl, buffer, relation);
if (tdgbl->gbl_sw_transportable)
{
buffer = sql;
CAN_encode_decode (relation, &data, buffer, false, true);
}
if ((++records % tdgbl->verboseInterval) == 0)
BURP_verbose(107, SafeArg() << records);
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (!(field->fld_flags & FLD_computed))
{
if (field->fld_type == blr_blob || (field->fld_flags & FLD_array))
{
ISC_QUAD* blob_id = (ISC_QUAD*) &buffer[field->fld_offset];
blob_id->gds_quad_high = 0;
blob_id->gds_quad_low = 0;
}
}
}
get_record(&record, tdgbl);
while (record == rec_blob || record == rec_array)
{
if (record == rec_blob)
get_blob (tdgbl, batch, relation->rel_fields, buffer);
else if (record == rec_array)
get_array (tdgbl, relation, buffer);
get_record(&record, tdgbl);
}
if (!tdgbl->gbl_sw_transportable)
{
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
continue;
// convert record to SQL format
memcpy(&sql[field->fld_sql], &buffer[field->fld_offset], field->fld_total_len);
memcpy(&sql[field->fld_null], &buffer[field->fld_missing_offset], sizeof(SSHORT));
}
}
batch->add(&tdgbl->throwStatus, 1, sql);
if ((records % 1000 != 0) && (record == rec_data))
continue;
Firebird::AutoDispose<Firebird::IBatchCompletionState> cs(batch->execute(&tdgbl->throwStatus, gds_trans));
if (tdgbl->throwStatus->getState() && Firebird::IStatus::STATE_WARNINGS)
BURP_print_warning(&tdgbl->throwStatus);
for (unsigned pos = 0; pos = cs->findError(&tdgbl->throwStatus, pos),
pos != Firebird::IBatchCompletionState::NO_MORE_ERRORS; ++pos)
{
Firebird::LocalStatus status_vector;
cs->getStatus(&tdgbl->throwStatus, &status_vector, pos);
ISC_STATUS code = status_vector.getErrors()[1];
if (code == isc_not_valid)
{
if (tdgbl->gbl_sw_incremental)
{
BURP_print (false, 138, relation->rel_name);
// msg 138 validation error on field in relation %s
BURP_print_status (false, &status_vector);
}
else
BURP_error_redirect(&status_vector, 47);
// msg 47 warning -- record could not be restored
}
else if (code == isc_malformed_string)
{
if (tdgbl->gbl_sw_incremental)
{
// msg 114 restore failed for record in relation %s
BURP_print(false, 114, relation->rel_name);
BURP_print_status(false, &status_vector);
BURP_print(false, 342); // isc_gbak_invalid_data
}
else
BURP_error_redirect(&status_vector, 342); // isc_gbak_invalid_data
}
else
{
if (tdgbl->gbl_sw_incremental)
{
BURP_print (false, 114, relation->rel_name);
// msg 114 restore failed for record in relation %s
BURP_print_status (false, &status_vector);
}
else
BURP_error_redirect(&status_vector, 48);
// msg 48 isc_send failed
}
records--;
}
if (record != rec_data)
break;
} // while (true)
}
catch(const Firebird::FbException& ex)
{
BURP_print_status (true, ex.getStatus());
BURP_abort();
}
if (tdgbl->gbl_sw_incremental)
{
BURP_verbose (72, relation->rel_name);
// msg 72 committing data for relation %s
COMMIT
// existing ON_ERROR continues past error, beck
ON_ERROR
// Fix for bug_no 8055:
// don't throw away the database just because an index
// could not be made
// don't bring the database on-line
tdgbl->flag_on_line = false;
ISC_STATUS error_code;
while (error_code = tdgbl->status_vector[1])
{
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
Firebird::IRequest* req_handle = 0;
switch (error_code)
{
case isc_sort_mem_err:
case isc_no_dup:
strcpy(index_name, (TEXT *)tdgbl->status_vector[3]);
BURP_print_status(false, &tdgbl->status_vector);
FOR (REQUEST_HANDLE req_handle)
IDX IN RDB$INDICES WITH IDX.RDB$INDEX_NAME EQ index_name
MODIFY IDX USING
IDX.RDB$INDEX_INACTIVE = TRUE;
BURP_print(false, 240, index_name);
// msg 240 Index \"%s\" failed to activate because:
if ( error_code == isc_no_dup )
{
BURP_print(false, 241);
// msg 241 The unique index has duplicate values or NULLs
BURP_print(false, 242);
// msg 242 Delete or Update duplicate values or NULLs, and activate index with
}
else
{
BURP_print(false, 244);
// msg 244 Not enough disk space to create the sort file for an index
BURP_print(false, 245);
// msg 245 Set the TMP environment variable to a directory on a filesystem that does have enough space, and activate index with
}
BURP_print(false, 243, index_name);
// msg 243 ALTER INDEX \"%s\" ACTIVE
END_MODIFY;
END_FOR;
// commit one more time
COMMIT
ON_ERROR
continue;
END_ERROR
break;
default:
BURP_print (false, 69, relation->rel_name);
// msg 69 commit failed on relation %s
BURP_print_status (false, &tdgbl->status_vector);
ROLLBACK;
ON_ERROR
general_on_error ();
END_ERROR;
break;
} // end of switch
} // end of while
END_ERROR;
EXEC SQL SET TRANSACTION NO_AUTO_UNDO;
if (gds_status->hasData())
EXEC SQL SET TRANSACTION;
}
BURP_verbose (107, SafeArg() << records);
// msg 107 %ld records restored
return record;
}
// We have a corrupt backup, save the restore process from becoming useless.
void fix_exception(BurpGlobals* tdgbl, const char* exc_name, scan_attr_t& scan_next_attr,
const att_type attribute, att_type& failed_attrib, UCHAR*& msg_ptr, ULONG& l2, bool& msg_seen)
{
if (msg_seen && (tdgbl->RESTORE_format == 7 || tdgbl->RESTORE_format == 8))
{
if (!failed_attrib)
{
failed_attrib = attribute;
BURP_print(false, 313, SafeArg() << failed_attrib << exc_name);
}
// Notice we use 1021 instead of 1023 because this is the maximum length
// for this field in v2.0 and v2.1 and they produce the corrupt backups.
const unsigned int FIELD_LIMIT = 1021;
if (FIELD_LIMIT < l2 + 1) // not enough space
{
bad_attribute(scan_next_attr, failed_attrib, 287);
return;
}
const unsigned int remaining = FIELD_LIMIT - l2;
*msg_ptr++ = char(attribute); // (1)
UCHAR* rc_ptr = get_block(tdgbl, msg_ptr, MIN(remaining - 1, 255));
if (remaining > 1 && rc_ptr == msg_ptr) // we couldn't read anything
{
bad_attribute(scan_next_attr, failed_attrib, 287);
return;
}
l2 += rc_ptr - msg_ptr + 1; // + 1 because (1)
msg_ptr = rc_ptr;
*msg_ptr = 0;
if (l2 == FIELD_LIMIT)
msg_seen = false;
}
else
bad_attribute(scan_next_attr, attribute, 287); // msg 287 exception
}
rec_type get_data_old(BurpGlobals* tdgbl, burp_rel* relation)
{
/**************************************
*
* g e t _ d a t a
*
**************************************
*
* Functional description
* Write data records for a relation.
*
**************************************/
Firebird::IRequest* req_handle = 0;
BASED_ON RDB$INDICES.RDB$INDEX_NAME index_name;
// Start by counting the interesting fields
RCRD_OFFSET offset = 0;
@ -2734,7 +3344,6 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
}
}
if (tdgbl->RESTORE_format >= 2)
count += count;
// Time to generate blr to store data. Whoppee.
@ -2846,9 +3455,6 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
offset += length;
}
// If this is format version 2, build fields for null flags
if (tdgbl->RESTORE_format >= 2)
for (field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
@ -2878,19 +3484,12 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
if (field->fld_flags & FLD_computed)
continue;
add_byte(blr, blr_assignment);
if (tdgbl->RESTORE_format >= 2)
{
add_byte(blr, blr_parameter2);
add_byte(blr, 0);
add_word(blr, field->fld_parameter);
add_word(blr, field->fld_missing_parameter);
}
else
{
add_byte(blr, blr_parameter);
add_byte(blr, 0);
add_word(blr, field->fld_parameter);
}
add_byte(blr, blr_field);
add_byte(blr, 0);
add_string(blr, field->fld_name);
@ -2995,7 +3594,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
realign (tdgbl, (UCHAR*) buffer, relation);
if (tdgbl->gbl_sw_transportable)
CAN_encode_decode (relation, &data, (UCHAR *)buffer, FALSE);
CAN_encode_decode (relation, &data, (UCHAR *)buffer, false);
records++;
@ -3019,7 +3618,7 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
while (record == rec_blob || record == rec_array)
{
if (record == rec_blob)
get_blob (tdgbl, relation->rel_fields, (UCHAR *) buffer);
get_blob_old (tdgbl, relation->rel_fields, (UCHAR *) buffer);
else if (record == rec_array)
get_array (tdgbl, relation, (UCHAR *) buffer);
get_record(&record, tdgbl);
@ -3164,49 +3763,6 @@ rec_type get_data(BurpGlobals* tdgbl, burp_rel* relation, bool skip_relation)
return record;
}
// We have a corrupt backup, save the restore process from becoming useless.
void fix_exception(BurpGlobals* tdgbl, const char* exc_name, scan_attr_t& scan_next_attr,
const att_type attribute, att_type& failed_attrib, UCHAR*& msg_ptr, ULONG& l2, bool& msg_seen)
{
if (msg_seen && (tdgbl->RESTORE_format == 7 || tdgbl->RESTORE_format == 8))
{
if (!failed_attrib)
{
failed_attrib = attribute;
BURP_print(false, 313, SafeArg() << failed_attrib << exc_name);
}
// Notice we use 1021 instead of 1023 because this is the maximum length
// for this field in v2.0 and v2.1 and they produce the corrupt backups.
const unsigned int FIELD_LIMIT = 1021;
if (FIELD_LIMIT < l2 + 1) // not enough space
{
bad_attribute(scan_next_attr, failed_attrib, 287);
return;
}
const unsigned int remaining = FIELD_LIMIT - l2;
*msg_ptr++ = char(attribute); // (1)
UCHAR* rc_ptr = get_block(tdgbl, msg_ptr, MIN(remaining - 1, 255));
if (remaining > 1 && rc_ptr == msg_ptr) // we couldn't read anything
{
bad_attribute(scan_next_attr, failed_attrib, 287);
return;
}
l2 += rc_ptr - msg_ptr + 1; // + 1 because (1)
msg_ptr = rc_ptr;
*msg_ptr = 0;
if (l2 == FIELD_LIMIT)
msg_seen = false;
}
else
bad_attribute(scan_next_attr, attribute, 287); // msg 287 exception
}
bool get_exception(BurpGlobals* tdgbl)
{
/**************************************
@ -3597,6 +4153,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation)
case att_field_source:
GET_TEXT(X.RDB$FIELD_SOURCE);
strcpy(field->fld_source, X.RDB$FIELD_SOURCE);
break;
case att_field_security_class:
@ -3799,6 +4356,7 @@ burp_fld* get_field(BurpGlobals* tdgbl, burp_rel* relation)
case att_field_source:
GET_TEXT(X.RDB$FIELD_SOURCE);
strcpy(field->fld_source, X.RDB$FIELD_SOURCE);
break;
case att_field_security_class:
@ -9671,10 +10229,6 @@ void realign(BurpGlobals* tdgbl, UCHAR* buffer, const burp_rel* relation)
}
}
// If this is format version 2 or greater, build fields for null flags
if (tdgbl->RESTORE_format >= 2)
{
for (const burp_fld* field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
@ -9685,7 +10239,6 @@ void realign(BurpGlobals* tdgbl, UCHAR* buffer, const burp_rel* relation)
*p++ = *q++;
}
}
}
#ifdef sparc
USHORT recompute_length(BurpGlobals* tdgbl, burp_rel* relation)
@ -9733,10 +10286,6 @@ USHORT recompute_length(BurpGlobals* tdgbl, burp_rel* relation)
offset += length;
}
// If this is format version 2, build fields for null flags
if (tdgbl->RESTORE_format >= 2)
{
for (const burp_fld* field = relation->rel_fields; field; field = field->fld_next)
{
if (field->fld_flags & FLD_computed)
@ -9744,7 +10293,6 @@ USHORT recompute_length(BurpGlobals* tdgbl, burp_rel* relation)
offset = FB_ALIGN(offset, sizeof(SSHORT));
offset += sizeof(SSHORT);
}
}
return offset;
}
@ -9777,9 +10325,9 @@ bool restore(BurpGlobals* tdgbl, const TEXT* file_name, const TEXT* database_nam
// restore only from those backup files created by current or previous GBAK
if (tdgbl->RESTORE_format < 1 || tdgbl->RESTORE_format > ATT_BACKUP_FORMAT)
if (tdgbl->RESTORE_format < 2 || tdgbl->RESTORE_format > ATT_BACKUP_FORMAT)
{
BURP_error(344, true, SafeArg() << tdgbl->RESTORE_format << 1 << ATT_BACKUP_FORMAT);
BURP_error(344, true, SafeArg() << tdgbl->RESTORE_format << 2 << ATT_BACKUP_FORMAT);
// msg 44 Expected backup version @2..@3. Found @1
}

View File

@ -89,7 +89,7 @@ bool BlobWrapper::getSegment(FB_SIZE_T len, void* buffer, FB_SIZE_T& real_len)
if (!m_blob || m_direction != dir_read)
return false;
if (!len || !buffer)
if (len && !buffer)
return false;
unsigned ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast<unsigned>(len);

View File

@ -168,6 +168,16 @@ private:
};
template <typename ID>
class AutoDispose : public AutoPtr<ID, SimpleDispose<ID> >
{
public:
AutoDispose(ID* v = nullptr)
: AutoPtr<ID, SimpleDispose<ID> >(v)
{ }
};
template <typename T>
class AutoSetRestore
{

View File

@ -140,7 +140,6 @@ DsqlBatch::DsqlBatch(dsql_req* req, const dsql_msg* /*message*/, IMessageMetadat
switch (t)
{
case SQL_BLOB:
case SQL_ARRAY:
{
BlobMeta bm;
bm.offset = m_meta->getOffset(&st, i);
@ -264,6 +263,7 @@ void DsqlBatch::add(thread_db* tdbb, ULONG count, const void* inBuffer)
return;
m_messages.align(m_alignment);
m_messages.put(inBuffer, (count - 1) * m_alignedMessage + m_messageSize);
DEB_BATCH(fprintf(stderr, "Put to batch %d messages\n", count));
}
void DsqlBatch::blobCheckMeta()
@ -413,6 +413,7 @@ void DsqlBatch::addBlobStream(thread_db* tdbb, unsigned length, const void* inBu
m_lastBlob = MAX_ULONG;
// store stream for further processing
DEB_BATCH(fprintf(stderr, "Store stream %d\n", length));
fb_assert(m_blobs.getSize() % BLOB_STREAM_ALIGN == 0);
m_blobs.put(inBuffer, length);
}
@ -533,13 +534,13 @@ private:
// parse blob header
fb_assert(intptr_t(flow.data) % BLOB_STREAM_ALIGN == 0);
ISC_QUAD* batchBlobId = reinterpret_cast<ISC_QUAD*>(flow.data);
ISC_QUAD batchBlobId = *reinterpret_cast<ISC_QUAD*>(flow.data);
ULONG* blobSize = reinterpret_cast<ULONG*>(flow.data + sizeof(ISC_QUAD));
ULONG* bpbSize = reinterpret_cast<ULONG*>(flow.data + sizeof(ISC_QUAD) + sizeof(ULONG));
flow.newHdr(*blobSize);
ULONG currentBpbSize = *bpbSize;
if (batchBlobId->gds_quad_high == 0 && batchBlobId->gds_quad_low == 0)
if (batchBlobId.gds_quad_high == 0 && batchBlobId.gds_quad_low == 0)
{
// Sanity check
if (*bpbSize)
@ -585,7 +586,8 @@ private:
bid engineBlobId;
blob = blb::create2(tdbb, transaction, &engineBlobId, bpb->getCount(),
bpb->begin(), true);
registerBlob(reinterpret_cast<ISC_QUAD*>(&engineBlobId), batchBlobId);
//DEB_BATCH(fprintf(stderr, "B-ID: (%x,%x)\n", batchBlobId.gds_quad_high, batchBlobId.gds_quad_low));
registerBlob(reinterpret_cast<ISC_QUAD*>(&engineBlobId), &batchBlobId);
}
}
@ -696,6 +698,9 @@ private:
continue;
ISC_QUAD* id = reinterpret_cast<ISC_QUAD*>(&data[m_blobMeta[i].offset]);
if (id->gds_quad_high == 0 && id->gds_quad_low == 0)
continue;
ISC_QUAD newId;
if (!m_blobMap.get(*id, newId))
{
@ -713,9 +718,9 @@ private:
remains -= m_messageSize;
UCHAR* msgBuffer = m_request->req_msg_buffers[message->msg_buffer_number];
DEB_BATCH(fprintf(stderr, "\n\n+++ Send\n\n"));
try
{
// runsend data to request and collect stats
ULONG before = req->req_records_inserted + req->req_records_updated +
req->req_records_deleted;
EXE_send(tdbb, req, message->msg_number, message->msg_length, msgBuffer);
@ -747,6 +752,15 @@ private:
m_messages.remained(remains, alignedData - data);
}
DEB_BATCH(fprintf(stderr, "Sent %d messages\n", completionState->getSize(tdbb->tdbb_status_vector)));
// make sure all blobs were used in messages
if (m_blobMap.count())
{
DEB_BATCH(fprintf(stderr, "BLOBs %d were not used in messages\n", m_blobMap.count()));
ERR_post_warning(Arg::Warning(isc_random) << "m_blobMap.count() BLOBs were not used in messages"); // !!!!!!! new warning
}
// reset to initial state
cancel(tdbb);
@ -756,15 +770,12 @@ private:
void DsqlBatch::cancel(thread_db* tdbb)
{
m_messages.clear();
if (m_blobMeta.hasData())
{
m_blobs.clear();
m_setBlobSize = false;
m_lastBlob = MAX_ULONG;
memset(&m_genId, 0, sizeof(m_genId));
m_blobMap.clear();
}
}
void DsqlBatch::genBlobId(ISC_QUAD* blobId)
{
@ -805,7 +816,7 @@ void DsqlBatch::DataCache::put3(const void* data, ULONG dataSize, ULONG offset)
void DsqlBatch::DataCache::put(const void* d, ULONG dataSize)
{
if (m_used + m_cache.getCount() + dataSize > m_limit)
if (m_limit && (m_used + m_cache.getCount() + dataSize > m_limit))
{
ERRD_post(Arg::Gds(isc_sqlerr) << Arg::Num(-104) <<
Arg::Gds(isc_batch_too_big));

View File

@ -107,7 +107,7 @@ private:
{
public:
DataCache(MemoryPool& p)
: PermanentStorage(p),
: PermanentStorage(p), m_cache(getPool()),
m_used(0), m_got(0), m_limit(0), m_shift(0), m_cacheCapacity(0)
{ }

View File

@ -599,6 +599,8 @@ version: // 3.0 => 4.0
// Batch API
Batch createBatch(Status status, Transaction transaction, uint stmtLength, const string sqlStmt,
uint dialect, MessageMetadata inMetadata, uint parLength, const uchar* par);
uint getRemoteProtocolVersion(Status status);
/*
Pipe createPipe(Status status, uint stmtLength, const string sqlStmt, uint dialect,
Transaction transaction, MessageMetadata inMetadata, void* inBuffer,

View File

@ -2122,6 +2122,7 @@ namespace Firebird
unsigned (CLOOP_CARG *getStatementTimeout)(IAttachment* self, IStatus* status) throw();
void (CLOOP_CARG *setStatementTimeout)(IAttachment* self, IStatus* status, unsigned timeOut) throw();
IBatch* (CLOOP_CARG *createBatch)(IAttachment* self, IStatus* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) throw();
unsigned (CLOOP_CARG *getRemoteProtocolVersion)(IAttachment* self, IStatus* status) throw();
};
protected:
@ -2340,6 +2341,20 @@ namespace Firebird
StatusType::checkException(status);
return ret;
}
template <typename StatusType> unsigned getRemoteProtocolVersion(StatusType* status)
{
if (cloopVTable->version < 4)
{
StatusType::setVersionError(status, "IAttachment", cloopVTable->version, 4);
StatusType::checkException(status);
return 0;
}
StatusType::clearException(status);
unsigned ret = static_cast<VTable*>(this->cloopVTable)->getRemoteProtocolVersion(this, status);
StatusType::checkException(status);
return ret;
}
};
class IService : public IReferenceCounted
@ -9800,6 +9815,7 @@ namespace Firebird
this->getStatementTimeout = &Name::cloopgetStatementTimeoutDispatcher;
this->setStatementTimeout = &Name::cloopsetStatementTimeoutDispatcher;
this->createBatch = &Name::cloopcreateBatchDispatcher;
this->getRemoteProtocolVersion = &Name::cloopgetRemoteProtocolVersionDispatcher;
}
} vTable;
@ -10141,6 +10157,21 @@ namespace Firebird
}
}
static unsigned CLOOP_CARG cloopgetRemoteProtocolVersionDispatcher(IAttachment* self, IStatus* status) throw()
{
StatusType status2(status);
try
{
return static_cast<Name*>(self)->Name::getRemoteProtocolVersion(&status2);
}
catch (...)
{
StatusType::catchException(&status2);
return static_cast<unsigned>(0);
}
}
static void CLOOP_CARG cloopaddRefDispatcher(IReferenceCounted* self) throw()
{
try
@ -10203,6 +10234,7 @@ namespace Firebird
virtual unsigned getStatementTimeout(StatusType* status) = 0;
virtual void setStatementTimeout(StatusType* status, unsigned timeOut) = 0;
virtual IBatch* createBatch(StatusType* status, ITransaction* transaction, unsigned stmtLength, const char* sqlStmt, unsigned dialect, IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par) = 0;
virtual unsigned getRemoteProtocolVersion(StatusType* status) = 0;
};
template <typename Name, typename StatusType, typename Base>

View File

@ -396,6 +396,7 @@ public:
Firebird::IBatch* createBatch(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction,
unsigned stmtLength, const char* sqlStmt, unsigned dialect,
Firebird::IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par);
unsigned int getRemoteProtocolVersion(Firebird::CheckStatusWrapper* status);
public:
explicit JAttachment(StableAttachmentPart* js);

View File

@ -2250,7 +2250,7 @@ bool BTR_types_comparable(const dsc& target, const dsc& source)
return (source.dsc_dtype <= dtype_long || source.dsc_dtype == dtype_int64);
if (DTYPE_IS_NUMERIC(target.dsc_dtype))
return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64); //!!!!!!!!
return (source.dsc_dtype <= dtype_double || source.dsc_dtype == dtype_int64);
if (target.dsc_dtype == dtype_sql_date)
return (source.dsc_dtype <= dtype_sql_date || source.dsc_dtype == dtype_timestamp);

View File

@ -148,6 +148,7 @@ enum db_info_types
fb_info_ses_idle_timeout_run = 131,
fb_info_conn_flags = 132,
fb_info_protocol_version = 133,
fb_info_crypt_key = 133,
fb_info_crypt_state = 134,

View File

@ -4827,6 +4827,12 @@ IBatch* JAttachment::createBatch(CheckStatusWrapper* status, ITransaction* trans
}
unsigned int JAttachment::getRemoteProtocolVersion(Firebird::CheckStatusWrapper* status)
{
return 0; // protocol == 0, i.e. no network, i.e. embedded connection
}
int JResultSet::fetchNext(CheckStatusWrapper* user_status, void* buffer)
{
try

View File

@ -371,6 +371,7 @@ private:
// working with blob stream buffer
void newBlob()
{
setBlobAlignment();
alignBlobBuffer(blobAlign);
fb_assert(blobStream - blobStreamBuffer <= blobBufferSize);
@ -384,6 +385,8 @@ private:
void alignBlobBuffer(unsigned alignment, ULONG* bs = NULL)
{
fb_assert(alignment);
FB_UINT64 zeroFill = 0;
UCHAR* newPointer = FB_ALIGN(blobStream, alignment);
ULONG align = FB_ALIGN(blobStream, alignment) - blobStream;
@ -464,6 +467,7 @@ private:
void flashBatch()
{
setBlobAlignment();
alignBlobBuffer(blobAlign);
ULONG size = blobStream - blobStreamBuffer;
if (size)
@ -472,6 +476,12 @@ private:
blobStream = blobStreamBuffer;
}
if (messageStream)
{
sendMessagePacket(messageStream, messageStreamBuffer);
messageStream = 0;
}
batchActive = false;
}
@ -760,6 +770,11 @@ public:
unsigned stmtLength, const char* sqlStmt, unsigned dialect,
IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par);
unsigned getRemoteProtocolVersion(CheckStatusWrapper* status)
{
return rdb->rdb_port->port_protocol & FB_PROTOCOL_MASK;
}
public:
Attachment(Rdb* handle, const PathName& path)
: rdb(handle), dbPath(getPool(), path)

View File

@ -48,7 +48,6 @@ USHORT MERGE_database_info(const UCHAR* in,
USHORT base_level,
const UCHAR* version,
const UCHAR* id)
//ULONG mask Was always zero
{
/**************************************
*

View File

@ -893,7 +893,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
while (count--)
{
DEB_BATCH(fprintf(stderr, "BatRem: xdr packed msg\n"));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr packed msg\n"));
if (!xdr_packed_message(xdrs, message, statement->rsr_format))
return P_FALSE(xdrs, p);
message->msg_address += statement->rsr_batch_size;
@ -912,7 +912,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
MAP(xdr_short, reinterpret_cast<SSHORT&>(b->p_batch_transaction));
if (xdrs->x_op != XDR_FREE)
DEB_BATCH(fprintf(stderr, "BatRem: xdr execute\n"));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr execute\n"));
return P_TRUE(xdrs, p);
}
@ -931,7 +931,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
rem_port* port = (rem_port*) xdrs->x_public;
SSHORT statement_id = b->p_batch_statement;
DEB_BATCH(fprintf(stderr, "BatRem: xdr CS %d\n", statement_id));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr CS %d\n", statement_id));
Rsr* statement;
if (statement_id >= 0)
@ -961,12 +961,12 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
if ((xdrs->x_op == XDR_DECODE) && (!b->p_batch_updates))
{
DEB_BATCH(fprintf(stderr, "BatRem: xdr reccount=%d\n", b->p_batch_reccount));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr reccount=%d\n", b->p_batch_reccount));
statement->rsr_batch_cs->regSize(b->p_batch_reccount);
}
// Process update counters
DEB_BATCH(fprintf(stderr, "BatRem: xdr up %d\n", b->p_batch_updates));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr up %d\n", b->p_batch_updates));
for (unsigned i = 0; i < b->p_batch_updates; ++i)
{
SLONG v;
@ -988,7 +988,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
// Process status vectors
ULONG pos = 0u;
LocalStatus to;
DEB_BATCH(fprintf(stderr, "BatRem: xdr sv %d\n", b->p_batch_vectors));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr sv %d\n", b->p_batch_vectors));
for (unsigned i = 0; i < b->p_batch_vectors; ++i, ++pos)
{
@ -1026,7 +1026,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
// Process status-less errors
pos = 0u;
DEB_BATCH(fprintf(stderr, "BatRem: xdr err %d\n", b->p_batch_errors));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr err %d\n", b->p_batch_errors));
for (unsigned i = 0; i < b->p_batch_errors; ++i, ++pos)
{
@ -1059,7 +1059,7 @@ bool_t xdr_protocol(XDR* xdrs, PACKET* p)
MAP(xdr_short, reinterpret_cast<SSHORT&>(b->p_batch_statement));
if (xdrs->x_op != XDR_FREE)
DEB_BATCH(fprintf(stderr, "BatRem: xdr release\n"));
DEB_RBATCH(fprintf(stderr, "BatRem: xdr release\n"));
return P_TRUE(xdrs, p);
}

View File

@ -64,7 +64,7 @@
//#define COMPRESS_DEBUG 1
#endif // WIRE_COMPRESS_SUPPORT
#define DEB_BATCH(x)
#define DEB_RBATCH(x)
#define REM_SEND_OFFSET(bs) (0)
#define REM_RECV_OFFSET(bs) (bs)

View File

@ -510,6 +510,7 @@ public:
YBatch* createBatch(Firebird::CheckStatusWrapper* status, Firebird::ITransaction* transaction,
unsigned stmtLength, const char* sqlStmt, unsigned dialect,
Firebird::IMessageMetadata* inMetadata, unsigned parLength, const unsigned char* par);
unsigned int getRemoteProtocolVersion(Firebird::CheckStatusWrapper* status);
public:
Firebird::IProvider* provider;

View File

@ -5931,6 +5931,22 @@ YBatch* YAttachment::createBatch(CheckStatusWrapper* status, ITransaction* trans
return NULL;
}
unsigned int YAttachment::getRemoteProtocolVersion(CheckStatusWrapper* status)
{
try
{
YEntry<YAttachment> entry(status, this);
return entry.next()->getRemoteProtocolVersion(status);
}
catch (const Exception& e)
{
e.stuffException(status);
}
return 0;
}
//-------------------------------------