8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 01:23:03 +01:00
firebird-mirror/src/dsql/array.epp
2002-12-16 16:25:09 +00:00

658 lines
16 KiB
Plaintext

/*
* PROGRAM: Interbase layered support library
* MODULE: array.epp
* DESCRIPTION: Dynamic array 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.18 Claudio Valderrama: get_name() was preventing the API calls
* isc_array_lookup_bounds, isc_lookup_desc & isc_array_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().
*
* 2002-02-24 Sean Leyne - Code Cleanup of old Win 3.1 port (WINDOWS_ONLY)
*
*
*/
#include "firebird.h"
#include <string.h>
#include "../jrd/common.h"
#include <stdarg.h>
#include "../jrd/gds.h"
#include "../dsql/array_proto.h"
#include "../jrd/gds_proto.h"
DATABASE DB = STATIC FILENAME "yachts.lnk";
#define ARRAY_DESC_COLUMN_MAJOR 1 /* Set for FORTRAN */
typedef struct gen {
SCHAR *gen_sdl;
SCHAR **gen_sdl_ptr;
SCHAR *gen_end;
STATUS *gen_status;
SSHORT gen_internal;
} *GEN;
static void adjust_length(ISC_ARRAY_DESC *);
static void copy_exact_name (char *, char*, SSHORT);
static STATUS copy_status(STATUS *, STATUS *);
static STATUS error(STATUS *, SSHORT, ...);
static STATUS gen_sdl(STATUS *, ISC_ARRAY_DESC *, SSHORT *, SCHAR **,
SSHORT *, BOOLEAN);
static STATUS lookup_desc(STATUS *, FRBRD **, FRBRD **, SCHAR *, SCHAR *,
ISC_ARRAY_DESC *, SCHAR *);
static STATUS stuff(GEN, SSHORT, ...);
static STATUS stuff_literal(GEN, SLONG);
static STATUS stuff_string(GEN, SCHAR, SCHAR *);
/* STUFF_SDL used in place of STUFF to avoid confusion with BLR STUFF
macro defined in dsql.h */
#define STUFF_SDL(byte) if (stuff (gen, 1, byte)) return status [1]
#define STUFF_SDL_WORD(word) if (stuff (gen, 2, word, word >> 8)) return status [1]
#define STUFF_SDL_LONG(word) if (stuff (gen, 4, word, word >> 8, word >> 16, word >> 24)) return status [1]
STATUS API_ROUTINE isc_array_gen_sdl(STATUS * status,
ISC_ARRAY_DESC * desc,
SSHORT * sdl_buffer_length,
SCHAR * sdl_buffer, SSHORT * sdl_length)
{
/**************************************
*
* i s c _ a r r a y _ g e n _ s d l
*
**************************************
*
* Functional description
*
**************************************/
return gen_sdl(status, desc, sdl_buffer_length, &sdl_buffer, sdl_length,
FALSE);
}
STATUS API_ROUTINE isc_array_get_slice(STATUS * status,
FRBRD **db_handle,
FRBRD **trans_handle,
GDS_QUAD * array_id,
ISC_ARRAY_DESC * desc,
void *array, SLONG * slice_length)
{
/**************************************
*
* i s c _ a r r a y _ g e t _ s l i c e
*
**************************************
*
* Functional description
*
**************************************/
SCHAR *sdl, sdl_buffer[512];
SSHORT sdl_length;
sdl_length = sizeof(sdl_buffer);
sdl = sdl_buffer;
if (gen_sdl(status, desc, &sdl_length, &sdl, &sdl_length, TRUE))
return status[1];
isc_get_slice(status, db_handle, trans_handle, array_id,
sdl_length, sdl, 0, (ISC_LONG*) NULL_PTR,
*slice_length, array, slice_length);
if (sdl != sdl_buffer)
gds__free((SLONG *) sdl);
return status[1];
}
STATUS API_ROUTINE isc_array_lookup_bounds(STATUS * status,
FRBRD **db_handle,
FRBRD **trans_handle,
SCHAR * relation_name,
SCHAR * field_name,
ISC_ARRAY_DESC * desc)
{
/**************************************
*
* i s c _ a r r a y _ l o o k u p _ b o u n d s
*
**************************************
*
* Functional description
*
**************************************/
ISC_ARRAY_BOUND *tail;
SCHAR global[32];
if (lookup_desc(status, db_handle, trans_handle,
field_name, relation_name, desc, global))
return status[1];
tail = desc->array_desc_bounds;
FOR X IN RDB$FIELD_DIMENSIONS WITH X.RDB$FIELD_NAME EQ global SORTED BY X.RDB$DIMENSION
tail->array_bound_lower = (SSHORT)X.RDB$LOWER_BOUND;
tail->array_bound_upper = (SSHORT)X.RDB$UPPER_BOUND;
++tail;
END_FOR
ON_ERROR
return copy_status(gds_status, status);
END_ERROR;
return status[1];
}
STATUS API_ROUTINE isc_array_lookup_desc(STATUS * status,
FRBRD **db_handle,
FRBRD **trans_handle,
SCHAR * relation_name,
SCHAR * field_name,
ISC_ARRAY_DESC * desc)
{
/**************************************
*
* i s c _ a r r a y _ l o o k u p _ d e s c
*
**************************************
*
* Functional description
*
**************************************/
return lookup_desc(status, db_handle, trans_handle,
field_name, relation_name, desc, (SCHAR*) NULL_PTR);
}
STATUS API_ROUTINE isc_array_put_slice(STATUS * status,
FRBRD **db_handle,
FRBRD **trans_handle,
GDS_QUAD * array_id,
ISC_ARRAY_DESC * desc,
void *array, SLONG * slice_length)
{
/**************************************
*
* i s c _ a r r a y _ p u t _ s l i c e
*
**************************************
*
* Functional description
*
**************************************/
SCHAR *sdl, sdl_buffer[512];
SSHORT sdl_length;
sdl_length = sizeof(sdl_buffer);
sdl = sdl_buffer;
if (gen_sdl(status, desc, &sdl_length, &sdl, &sdl_length, TRUE))
return status[1];
isc_put_slice(status, db_handle, trans_handle, array_id,
sdl_length, sdl, 0, (ISC_LONG*) NULL_PTR, *slice_length, array);
if (sdl != sdl_buffer)
gds__free((SLONG *) sdl);
return status[1];
}
STATUS API_ROUTINE isc_array_set_desc(STATUS * status,
SCHAR * relation_name,
SCHAR * field_name,
SSHORT * sql_dtype,
SSHORT * sql_length,
SSHORT * dimensions,
ISC_ARRAY_DESC * desc)
{
/**************************************
*
* i s c _ a r r a y _ s e t _ d e s c
*
**************************************
*
* Functional description
*
**************************************/
SSHORT dtype;
copy_exact_name (field_name, desc->array_desc_field_name,
sizeof(desc->array_desc_field_name));
copy_exact_name (relation_name, desc->array_desc_relation_name,
sizeof(desc->array_desc_relation_name));
desc->array_desc_flags = 0;
desc->array_desc_dimensions = *dimensions;
desc->array_desc_length = *sql_length;
desc->array_desc_scale = 0;
dtype = *sql_dtype & ~1;
if (dtype == SQL_VARYING)
desc->array_desc_dtype = blr_varying;
else if (dtype == SQL_TEXT)
desc->array_desc_dtype = blr_text;
else if (dtype == SQL_DOUBLE)
desc->array_desc_dtype = blr_double;
else if (dtype == SQL_FLOAT)
desc->array_desc_dtype = blr_float;
else if (dtype == SQL_D_FLOAT)
desc->array_desc_dtype = blr_d_float;
else if (dtype == SQL_TIMESTAMP)
desc->array_desc_dtype = blr_timestamp;
else if (dtype == SQL_TYPE_DATE)
desc->array_desc_dtype = blr_sql_date;
else if (dtype == SQL_TYPE_TIME)
desc->array_desc_dtype = blr_sql_time;
else if (dtype == SQL_LONG)
desc->array_desc_dtype = blr_long;
else if (dtype == SQL_SHORT)
desc->array_desc_dtype = blr_short;
else if (dtype == SQL_INT64)
desc->array_desc_dtype = blr_int64;
else if (dtype == SQL_QUAD)
desc->array_desc_dtype = blr_quad;
else
return error(status, 7, (STATUS) gds_sqlerr,
(STATUS) gds_arg_number, (STATUS) - 804,
(STATUS) gds_arg_gds, (STATUS) gds_random,
(STATUS) gds_arg_string,
(STATUS) "data type not understood");
return error(status, 1, (STATUS) FB_SUCCESS);
}
static void adjust_length( ISC_ARRAY_DESC * desc)
{
/**************************************
*
* a d j u s t _ l e n g t h
*
**************************************
*
* Functional description
* Make architectural adjustment to fixed datatypes.
*
**************************************/
}
static void copy_exact_name (
char *from,
char *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.
*
**************************************/
char *from_end = from + bsize - 1, *to2 = to - 1;
while (*from && from < from_end) {
if (*from != ' ') {
to2 = to;
}
*to++ = *from++;
}
*++to2 = 0;
}
static STATUS copy_status( STATUS * from, STATUS * to)
{
/**************************************
*
* c o p y _ s t a t u s
*
**************************************
*
* Functional description
* Copy a status vector.
*
**************************************/
STATUS status, *end;
status = from[1];
for (end = from + ISC_STATUS_LENGTH; from < end;)
*to++ = *from++;
return status;
}
static STATUS error( STATUS * status, SSHORT count, ...)
{
/**************************************
*
* e r r o r
*
**************************************
*
* Functional description
* Stuff a status vector.
*
**************************************/
STATUS *stat;
va_list ptr;
VA_START(ptr, count);
stat = status;
*stat++ = gds_arg_gds;
for (; count; --count)
*stat++ = (STATUS) va_arg(ptr, STATUS);
*stat = gds_arg_end;
return status[1];
}
static STATUS gen_sdl(STATUS * status,
ISC_ARRAY_DESC * desc,
SSHORT * sdl_buffer_length,
SCHAR ** sdl_buffer,
SSHORT * sdl_length, BOOLEAN internal_flag)
{
/**************************************
*
* g e n _ s d l
*
**************************************
*
* Functional description
*
**************************************/
SSHORT n, from, to, increment, dimensions;
ISC_ARRAY_BOUND *tail;
struct gen *gen, gen_block;
dimensions = desc->array_desc_dimensions;
if (dimensions > 16)
return error(status, 5, (STATUS) gds_invalid_dimension,
(STATUS) gds_arg_number, (STATUS) dimensions,
(STATUS) gds_arg_number, (STATUS) 16);
gen = &gen_block;
gen->gen_sdl = *sdl_buffer;
gen->gen_sdl_ptr = sdl_buffer;
gen->gen_end = *sdl_buffer + *sdl_buffer_length;
gen->gen_status = status;
gen->gen_internal = internal_flag ? 0 : -1;
if (stuff
(gen, 4, gds_sdl_version1, gds_sdl_struct, 1,
desc->array_desc_dtype)) return status[1];
switch (desc->array_desc_dtype) {
case blr_short:
case blr_long:
case blr_int64:
case blr_quad:
STUFF_SDL(desc->array_desc_scale);
break;
case blr_text:
case blr_cstring:
case blr_varying:
STUFF_SDL_WORD(desc->array_desc_length);
break;
default:
break;
}
if (stuff_string(gen, gds_sdl_relation, desc->array_desc_relation_name))
return status[1];
if (stuff_string(gen, gds_sdl_field, desc->array_desc_field_name))
return status[1];
if (desc->array_desc_flags & ARRAY_DESC_COLUMN_MAJOR) {
from = dimensions - 1;
to = -1;
increment = -1;
}
else {
from = 0;
to = dimensions;
increment = 1;
}
for (n = from; n != to; n += increment) {
tail = desc->array_desc_bounds + n;
if (tail->array_bound_lower == 1) {
if (stuff(gen, 2, gds_sdl_do1, n))
return status[1];
}
else {
if (stuff(gen, 2, gds_sdl_do2, n))
return status[1];
if (stuff_literal(gen, (SLONG) tail->array_bound_lower))
return status[1];
}
if (stuff_literal(gen, (SLONG) tail->array_bound_upper))
return status[1];
}
if (stuff(gen, 5, gds_sdl_element, 1, gds_sdl_scalar, 0, dimensions))
return status[1];
for (n = 0; n < dimensions; n++)
if (stuff(gen, 2, gds_sdl_variable, n))
return status[1];
STUFF_SDL(gds_sdl_eoc);
*sdl_length = gen->gen_sdl - *gen->gen_sdl_ptr;
return error(status, 1, (STATUS) FB_SUCCESS);
}
static STATUS lookup_desc(STATUS * status,
FRBRD **db_handle,
FRBRD **trans_handle,
SCHAR * field_name,
SCHAR * relation_name, ISC_ARRAY_DESC * desc, SCHAR * global)
{
/**************************************
*
* l o o k u p _ d e s c
*
**************************************
*
* Functional description
*
**************************************/
SSHORT flag;
if (DB && DB != *db_handle)
RELEASE_REQUESTS;
DB = *db_handle;
gds_trans = *trans_handle;
copy_exact_name (field_name, desc->array_desc_field_name,
sizeof(desc->array_desc_field_name));
copy_exact_name (relation_name, desc->array_desc_relation_name,
sizeof(desc->array_desc_relation_name));
desc->array_desc_flags = 0;
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->array_desc_relation_name AND
X.RDB$FIELD_NAME EQ desc->array_desc_field_name
flag = TRUE;
desc->array_desc_dtype = (UCHAR)Y.RDB$FIELD_TYPE;
desc->array_desc_scale = (SCHAR)Y.RDB$FIELD_SCALE;
desc->array_desc_length = Y.RDB$FIELD_LENGTH;
adjust_length(desc);
desc->array_desc_dimensions = Y.RDB$DIMENSIONS;
if (global) {
copy_exact_name (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, (STATUS) gds_fldnotdef,
(STATUS) gds_arg_string,
(STATUS) desc->array_desc_field_name,
(STATUS) gds_arg_string,
(STATUS) desc->array_desc_relation_name);
return error(status, 1, (STATUS) FB_SUCCESS);
}
static STATUS stuff( GEN gen, SSHORT count, ...)
{
/**************************************
*
* s t u f f
*
**************************************
*
* Functional description
* Stuff a SDL byte.
*
**************************************/
SCHAR c, *new_sdl;
va_list ptr;
SSHORT new_len, current_len;
if (gen->gen_sdl + count >= gen->gen_end) {
if (gen->gen_internal < 0)
return error(gen->gen_status, 3, (STATUS) gds_misc_interpreted,
(STATUS) gds_arg_string,
(STATUS) "SDL buffer overflow");
/* The sdl buffer is too small. Allocate a larger one. */
new_len = gen->gen_end - *gen->gen_sdl_ptr + 512 + count;
new_sdl = (SCHAR *) gds__alloc((SLONG) new_len);
if (!new_sdl)
return error(gen->gen_status, 5, (STATUS) gds_misc_interpreted,
(STATUS) gds_arg_string,
(STATUS) "SDL buffer overflow", (STATUS) gds_arg_gds,
(STATUS) gds_virmemexh);
current_len = gen->gen_sdl - *gen->gen_sdl_ptr;
memcpy(new_sdl, *gen->gen_sdl_ptr, current_len);
if (gen->gen_internal++)
gds__free(*gen->gen_sdl_ptr);
gen->gen_sdl = new_sdl + current_len;
*gen->gen_sdl_ptr = new_sdl;
gen->gen_end = new_sdl + new_len;
}
VA_START(ptr, count);
for (; count; --count) {
c = va_arg(ptr, int);
*(gen->gen_sdl)++ = c;
}
return 0;
}
static STATUS stuff_literal( GEN gen, SLONG literal)
{
/**************************************
*
* s t u f f _ l i t e r a l
*
**************************************
*
* Functional description
* Stuff an SDL literal.
*
**************************************/
STATUS *status;
status = gen->gen_status;
if (literal >= -128 && literal <= 127)
return stuff(gen, 2, gds_sdl_tiny_integer, literal);
if (literal >= -32768 && literal <= 32767)
return stuff(gen, 3, gds_sdl_short_integer, literal, literal >> 8);
STUFF_SDL(gds_sdl_long_integer);
STUFF_SDL_LONG(literal);
return FB_SUCCESS;
}
static STATUS stuff_string( GEN gen, SCHAR sdl, SCHAR * string)
{
/**************************************
*
* s t u f f _ s t r i n g
*
**************************************
*
* Functional description
* Stuff a "thing" then a counted string.
*
**************************************/
STATUS *status;
status = gen->gen_status;
STUFF_SDL(sdl);
STUFF_SDL(strlen(string));
while (*string)
STUFF_SDL(*string++);
return FB_SUCCESS;
}