/* * 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 #include "../jrd/gds.h" #include "../jrd/intl.h" #include "../jrd/constants.h" #include "../dsql/blob_proto.h" DATABASE DB = STATIC "yachts.lnk"; static void copy_exact_name (UCHAR *, UCHAR *, SSHORT); static ISC_STATUS copy_status(ISC_STATUS *, ISC_STATUS *); static ISC_STATUS error(ISC_STATUS *, SSHORT, ...); void API_ROUTINE isc_blob_default_desc( ISC_BLOB_DESC * desc, UCHAR * relation_name, 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 = 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, ISC_BLOB_DESC * to_desc, 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. * **************************************/ UCHAR *p; if (bpb_buffer_length < 17) return error(status, 3, (ISC_STATUS) gds_random, (ISC_STATUS) gds_arg_string, (ISC_STATUS) "BPB buffer too small"); 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, 1, (ISC_STATUS) FB_SUCCESS); } ISC_STATUS API_ROUTINE isc_blob_lookup_desc(ISC_STATUS * status, FRBRD **db_handle, FRBRD **trans_handle, UCHAR * relation_name, 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 name * and column name. it will fill in the information * in the BLOB_DESC. * ***********************************************/ SSHORT flag; if (DB && DB != *db_handle) RELEASE_REQUESTS; DB = *db_handle; gds_trans = *trans_handle; 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)); flag = FALSE; FOR 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 return copy_status(gds_status, status); END_ERROR; if (!flag) return error(status, 5, (ISC_STATUS) gds_fldnotdef, (ISC_STATUS) gds_arg_string, (ISC_STATUS) desc->blob_desc_field_name, (ISC_STATUS) gds_arg_string, (ISC_STATUS) desc->blob_desc_relation_name); return error(status, 1, (ISC_STATUS) FB_SUCCESS); } ISC_STATUS API_ROUTINE isc_blob_set_desc(ISC_STATUS * status, UCHAR * relation_name, 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, 1, (ISC_STATUS) FB_SUCCESS); } static void copy_exact_name ( 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. * **************************************/ UCHAR *from_end = from + bsize - 1, *to2 = to - 1; while (*from && from < from_end) { if (*from != ' ') { to2 = to; } *to++ = *from++; } *++to2 = 0; } static ISC_STATUS copy_status( ISC_STATUS * from, ISC_STATUS * to) { /************************************** * * c o p y _ s t a t u s * ************************************** * * Functional description * Copy a status vector. * **************************************/ ISC_STATUS status, *end; status = from[1]; for (end = from + 20; from < end;) *to++ = *from++; return status; } static ISC_STATUS error( ISC_STATUS * status, SSHORT count, ...) { /************************************** * * e r r o r * ************************************** * * Functional description * Stuff a status vector. * **************************************/ ISC_STATUS *stat; va_list ptr; VA_START(ptr, count); stat = status; *stat++ = gds_arg_gds; for (; count; --count) *stat++ = (ISC_STATUS) va_arg(ptr, ISC_STATUS); *stat = gds_arg_end; return status[1]; }