mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 20:43:04 +01:00
290 lines
8.3 KiB
Plaintext
290 lines
8.3 KiB
Plaintext
/*
|
|
* 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$PACKAGE_NAME MISSING 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);
|
|
}
|