/* * PROGRAM: InterBase layered support library * MODULE: blob.epp * DESCRIPTION: Dynamic blob support * * The contents of this file are subject to the Interbase Public * License Version 1.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy * of the License at http://www.Inprise.com/IPL.html * * Software distributed under the License is distributed on an * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express * or implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code was created by Inprise Corporation * and its predecessors. Portions created by Inprise Corporation are * Copyright (C) Inprise Corporation. * * All Rights Reserved. * Contributor(s): ______________________________________. * * 2001.09.10 Claudio Valderrama: get_name() was preventing the API calls * isc_blob_default_desc, isc_blob_lookup_desc & isc_blob_set_desc * from working properly with dialect 3 names. Therefore, incorrect names * could be returned or a lookup for a blob field could fail. In addition, * a possible buffer overrun due to unchecked bounds was closed. The fc * get_name() as been renamed copy_exact_name(). * */ #include "firebird.h" #include "../jrd/common.h" #include "../jrd/ibase.h" #include "../jrd/intl.h" #include "../dsql/blob_proto.h" #include "../dsql/utld_proto.h" #include "../common/StatusArg.h" using namespace Firebird; DATABASE DB = STATIC "yachts.lnk"; static void copy_exact_name (const UCHAR*, UCHAR*, SSHORT); static ISC_STATUS error(ISC_STATUS* status, const Arg::StatusVector& v); void API_ROUTINE isc_blob_default_desc( ISC_BLOB_DESC* desc, const UCHAR* relation_name, const UCHAR* field_name) { /************************************** * * i s c _ b l o b _ d e f a u l t _ d e s c * ************************************** * * Functional description * * This function will set the default * values in the blob_descriptor. * **************************************/ desc->blob_desc_subtype = isc_blob_text; desc->blob_desc_charset = CS_dynamic; desc->blob_desc_segment_size = 80; copy_exact_name (field_name, desc->blob_desc_field_name, sizeof(desc->blob_desc_field_name)); copy_exact_name (relation_name, desc->blob_desc_relation_name, sizeof(desc->blob_desc_relation_name)); } ISC_STATUS API_ROUTINE isc_blob_gen_bpb( ISC_STATUS* status, const ISC_BLOB_DESC* to_desc, const ISC_BLOB_DESC* from_desc, USHORT bpb_buffer_length, UCHAR* bpb_buffer, USHORT* bpb_length) { /************************************** * * i s c _ b l o b _ g e n _ b p b * ************************************** * * Functional description * * This function will generate a bpb * given a to_desc and a from_desc * which contain the subtype and * character set information. * **************************************/ if (bpb_buffer_length < 17) return error(status, Arg::Gds(isc_random) << Arg::Str("BPB buffer too small")); UCHAR* p = bpb_buffer; *p++ = isc_bpb_version1; *p++ = isc_bpb_target_type; *p++ = 2; *p++ = (UCHAR)to_desc->blob_desc_subtype; *p++ = (UCHAR)(to_desc->blob_desc_subtype >> 8); *p++ = isc_bpb_source_type; *p++ = 2; *p++ = (UCHAR)from_desc->blob_desc_subtype; *p++ = (UCHAR)(from_desc->blob_desc_subtype >> 8); *p++ = isc_bpb_target_interp; *p++ = 2; *p++ = (UCHAR)to_desc->blob_desc_charset; *p++ = (UCHAR)(to_desc->blob_desc_charset >> 8); *p++ = isc_bpb_source_interp; *p++ = 2; *p++ = (UCHAR)from_desc->blob_desc_charset; *p++ = (UCHAR)(from_desc->blob_desc_charset >> 8); *bpb_length = p - bpb_buffer; return error(status, Arg::Gds(FB_SUCCESS)); } ISC_STATUS API_ROUTINE isc_blob_lookup_desc(ISC_STATUS* status, FB_API_HANDLE* db_handle, FB_API_HANDLE* trans_handle, const UCHAR* relation_name, const UCHAR* field_name, ISC_BLOB_DESC* desc, UCHAR* global) { /*********************************************** * * i s c _ b l o b _ l o o k u p _ d e s c * *********************************************** * * Functional description * * This routine will lookup the subtype, * character set and segment size information * from the metadata, given a relation/procedure name * and column/parameter name. it will fill in the information * in the BLOB_DESC. * ***********************************************/ ISC_STATUS_ARRAY isc_status = {0}; isc_db_handle DB = *db_handle; isc_req_handle handle = 0; copy_exact_name (field_name, desc->blob_desc_field_name, sizeof(desc->blob_desc_field_name)); copy_exact_name (relation_name, desc->blob_desc_relation_name, sizeof(desc->blob_desc_relation_name)); bool flag = false; FOR (REQUEST_HANDLE handle TRANSACTION_HANDLE *trans_handle) X IN RDB$RELATION_FIELDS CROSS Y IN RDB$FIELDS WITH X.RDB$FIELD_SOURCE EQ Y.RDB$FIELD_NAME AND X.RDB$RELATION_NAME EQ desc->blob_desc_relation_name AND X.RDB$FIELD_NAME EQ desc->blob_desc_field_name flag = true; desc->blob_desc_subtype = Y.RDB$FIELD_SUB_TYPE; desc->blob_desc_charset = Y.RDB$CHARACTER_SET_ID; desc->blob_desc_segment_size = Y.RDB$SEGMENT_LENGTH; if (global) { copy_exact_name ((UCHAR*) Y.RDB$FIELD_NAME, global, sizeof(Y.RDB$FIELD_NAME)); } END_FOR ON_ERROR ISC_STATUS_ARRAY temp_status; isc_release_request(temp_status, &handle); return UTLD_copy_status(isc_status, status); END_ERROR; isc_release_request(isc_status, &handle); if (!flag) { handle = 0; FOR (REQUEST_HANDLE handle TRANSACTION_HANDLE *trans_handle) X IN RDB$PROCEDURE_PARAMETERS CROSS Y IN RDB$FIELDS WITH X.RDB$FIELD_SOURCE EQ Y.RDB$FIELD_NAME AND X.RDB$PROCEDURE_NAME EQ desc->blob_desc_relation_name AND X.RDB$PARAMETER_NAME EQ desc->blob_desc_field_name flag = true; desc->blob_desc_subtype = Y.RDB$FIELD_SUB_TYPE; desc->blob_desc_charset = Y.RDB$CHARACTER_SET_ID; desc->blob_desc_segment_size = Y.RDB$SEGMENT_LENGTH; if (global) { copy_exact_name ((UCHAR*) Y.RDB$FIELD_NAME, global, sizeof(Y.RDB$FIELD_NAME)); } END_FOR ON_ERROR ISC_STATUS_ARRAY temp_status; isc_release_request(temp_status, &handle); return UTLD_copy_status(isc_status, status); END_ERROR; isc_release_request(isc_status, &handle); } if (!flag) return error(status, Arg::Gds(isc_fldnotdef) << Arg::Str((const char *)(desc->blob_desc_field_name)) << Arg::Str((const char *)(desc->blob_desc_relation_name))); return error(status, Arg::Gds(FB_SUCCESS)); } ISC_STATUS API_ROUTINE isc_blob_set_desc(ISC_STATUS* status, const UCHAR* relation_name, const UCHAR* field_name, SSHORT subtype, SSHORT charset, SSHORT segment_size, ISC_BLOB_DESC* desc) { /************************************** * * i s c _ b l o b _ s e t _ d e s c * ************************************** * * Functional description * * This routine will set the subtype * and character set information in the * BLOB_DESC based on the information * specifically passed in by the user. * **************************************/ copy_exact_name (field_name, desc->blob_desc_field_name, sizeof(desc->blob_desc_field_name)); copy_exact_name (relation_name, desc->blob_desc_relation_name, sizeof(desc->blob_desc_relation_name)); desc->blob_desc_subtype = subtype; desc->blob_desc_charset = charset; desc->blob_desc_segment_size = segment_size; return error(status, Arg::Gds(FB_SUCCESS)); } static void copy_exact_name ( const UCHAR* from, UCHAR* to, SSHORT bsize) { /************************************** * * c o p y _ e x a c t _ n a m e * ************************************** * * Functional description * Copy null terminated name ot stops at bsize - 1. * CVC: This is just another fc like DYN_terminate. * **************************************/ const UCHAR* const from_end = from + bsize - 1; UCHAR *to2 = to - 1; while (*from && from < from_end) { if (*from != ' ') { to2 = to; } *to++ = *from++; } *++to2 = 0; } static ISC_STATUS error(ISC_STATUS* status, const Arg::StatusVector& v) { /************************************** * * e r r o r * ************************************** * * Functional description * Stuff a status vector. * **************************************/ return v.copyTo(status); }