返回首页

gbase数据、南大通用产品文档:GBase8s访存数组

更新日期:2024年09月11日

访存数组使得您能够在您的程序中增加单个 FETCH 语句从访存缓冲区返回至 sqlda
结构的行数。当您访存简单大对象(TEXT 或 BYTE)数据时,访存数组特别有用。

对不带有访存数组的简单大对象的访存,需要与数据库服务器进行下列两项交换:
当 GBase 8s ESQL/C 访存 TEXT 或 BYTE 列时,
数据库服务器为该列返回描述符。

然后,GBase 8s ESQL/C 请求数据库服务器获取该列数据。

当您使用访存数组时,GBase 8s ESQL/C 将一些列简单大对象描述符发送至数据库服
务器,且数据库服务器一次返回所有对应的列数据。
使用访存数组
要使用访存数组:

声明 sqlda 结构来保存您想要访存的列。
您不可在 FETCH 语句中使用主变量或系统描述符区域来为列保存访
存数组。您必须使用 sqlda 结构和 FETCH...USING DESCRIPTOR 语
句。

使用 DESCRIBE...INTO 语句来初始化 sqlda 结构,并获得关于准备好的查询的信息。

DESCRIBE...INTO statement 语句为 sqlda 结构和 sqlvar_struct 结构分配内存。

对于 sqldata 字段,为每一列分配大到足以保存访存数组的缓冲区。
要为 sqldata 字段分配内存,您必须为相关的列将 FetArrSize 全
局变量设置为访存设置的大小。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 489 -


发出 FETCH...USING DESCRIPTOR 语句来将该列值检索至访存设置内。
FETCH 语句将检索到的行放置至 sqlda 中的 sqlvar_struct 结构的 sqldata 字段内。
每一 FETCH 语句将由 FetArrSize 指定的值的数目返回至 sqldata 字段内。

从每一 sqlvar_struct 结构的访存数组获得列值。
在您执行下一 FETCH 语句之前,
您必须从访存数组获得这些值。
您可
检查 sqlca.sqlerrd[2] 字段来确定 FETCH 已返回的有效行的数目。
sqlerrd[2] 中的值等于或小于您在 FetArrSize 中设置的值。

重复步骤 4和 5,直到访存所有行为止。
释放 sqlda 结构使用的内存。
正如 sqlda 结构的其他使用一样,GBase 8s ESQL/C 不为此结构释放资源。当您的应
用程序不再需要分配给 sqlda 结构的内存时,它必须释放它。

重要:
当启用“延迟的 PREPARE” 和 OPTOFC 特性时,
FetArrSize 特性不起作用。
当启用这两个特性时,GBase 8s ESQL/C 不知道行的大小,直到 FETCH 语句完成之后为
止。到此时,对于要以 FetArrSize 值来调整访存缓冲区而言,为时已晚。
样例访存数组程序
下列样例程序展示如何执行 使用访存数组中的步骤。它使用分开的函数来
初始化、打印和释放 sqlda 结构。在下面的部分中描述这些函数。

#include
#include
#include

EXEC SQL include sqlda.h;
EXEC SQL include locator.h;
EXEC SQL include sqltypes.h;


#define BLOBSIZE 32275 /* using a predetermined length for blob */

EXEC SQL begin declare section;
long blobsize; /* finding the maximum blob size at runtime */
EXEC SQL end declare section;


/*******************************************************************

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 490 -

**
* Function: init_sqlda()
* Purpose: With the sqlda pointer that was returned from the DESCRIBE
* statement, function allocates memory for the fetch arrays
* in the sqldata fields of each column. The function uses
* FetArrSize to determine the size to allocate.
* Returns: < 0 for error
* > 0 error with messagesize
********************************************************************
*/
int init_sqlda(struct sqlda *in_da, int print)
{
int i, j,
row_size=0,
msglen=0,
num_to_alloc;
struct sqlvar_struct *col_ptr;
ifx_loc_t *temp_loc;
char *type;


if (print)
printf("columns: %d. \n", in_da->sqld);

/* Step 1: determine row size */
for
(i
=
0,
col_ptr
=
in_da->sqlvar;
i
<
in_da->sqld;
i++,
col_ptr++)
{
/* The msglen variable holds the sum of the column sizes in the
* database; these are the sizes that DESCRIBE returns. This
* sum is the amount of memory that ESQL/C needs to store
* one row from the database. This value is <= row_size. */
msglen += col_ptr->sqllen; /* get database sizes */


/* calculate size for C data: string columns get extra byte added
* to hold null terminator */
col_ptr->sqllen = rtypmsize(col_ptr->sqltype, col_ptr->sqllen);

/* The row_size variable holds the sum of the column sizes in
* the client application; these are the sizes that rtypmsize()
* returns. This sum is amount of memory that the client
* application needs to store one row. */
row_size += col_ptr->sqllen;
if(print)

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 491 -

printf("Column %d size: %d\n", i+1, col_ptr->sqllen);
}

if (print)
{
printf("Total message size = %d\n", msglen);
printf("Total row size = %d\n", row_size);
}

EXEC
SQL
select
max(length(cat_descr))
into
:blobsize
from
catalog;

/* Step 2: set FetArrSize global variable to number of elements
* in fetch array; this function calculates the FetArrSize
* value that can fit into the existing fetch buffer.
* If FetBufSize is not set (equals zero), the code assigns a
* default size of 4096 bytes (4 kilobytes). Alternatively, you
* could set FetArrSize to the number elements you wanted to
* have and let ESQL/C size the fetch buffer. See the text in
* "Allocating Memory for the Fetch Arrays" for more information.*/
if (FetArrSize <= 0) /* if FetArrSize not yet initialized */
{
if (FetBufSize == 0) /* if FetBufSize not set */
FetBufSize = 4096; /* default FetBufSize */
FetArrSize = FetBufSize/msglen;
}
num_to_alloc = (FetArrSize == 0)? 1: FetArrSize;
if (print)
{
printf("Fetch Buffer Size %d\n", FetBufSize);
printf("Fetch Array Size: %d\n", FetArrSize);
}

/* set type in sqlvar_struct structure to corresponding C type */
for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++,
col_ptr++)
{
switch(col_ptr->sqltype)
{
case SQLCHAR:
type = "char ";
col_ptr->sqltype = CCHARTYPE;
break;
case SQLINT:
case SQLSERIAL:

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 492 -

type = "int ";
col_ptr->sqltype = CINTTYPE;
break;
case SQLBYTES:
case SQLTEXT:
if (col_ptr->sqltype == SQLBYTES)
type = "blob ";
else
type = "text ";
col_ptr->sqltype = CLOCATORTYPE;

/* Step 3 (TEXT & BLOB only): allocate memory for sqldata
* that contains ifx_loc_t structures for TEXT or BYTE column
*/
temp_loc = (ifx_loc_t *)malloc(col_ptr->sqllen *
num_to_alloc);
if (!temp_loc)
{
fprintf(stderr, "blob sqldata malloc failed\n");
return(-1);
}
col_ptr->sqldata = (char *)temp_loc;

/* Step 4 (TEXT & BLOB only): initialize ifx_loc_t structures
to
hold blob values in a user-defined buffer in memory */
byfill( (char *)temp_loc, col_ptr->sqllen*num_to_alloc ,0);
for (j = 0; j< num_to_alloc; j++, temp_loc++)
{
/* blob data to go in memory */
temp_loc->loc_loctype = LOCMEMORY;

/* assume none of the blobs are larger than BLOBSIZE */
temp_loc->loc_bufsize = blobsize;
temp_loc->loc_buffer = (char *)malloc(blobsize+1);
if (!temp_loc->loc_buffer)
{
fprintf(stderr, "loc_buffer malloc failed\n");
return(-1);
}
temp_loc->loc_oflags = 0; /* clear flag */
} /* end for */
break;
default: /* all other data types */

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 493 -

fprintf(stderr,
"not
yet
handled(%d)!\n",
col_ptr->sqltype);
return(-1);
} /* switch */

/* Step 5: allocate memory for the indicator variable */
col_ptr->sqlind = (short *)malloc(sizeof(short) * num_to_alloc);
if (!col_ptr->sqlind)
{
printf("indicator malloc failed\n");
return -1;
}

/* Step 6 (other data types): allocate memory for sqldata. This
* function
* casts the pointer to this memory as a (char *). Subsequent
* accesses to the data would need to cast it back to the data
* type that corresponds to the column type. See the print_sqlda()
* function for an example of this casting. */
if (col_ptr->sqltype != CLOCATORTYPE)
{
col_ptr->sqldata = (char *) malloc(col_ptr->sqllen *
num_to_alloc);
if (!col_ptr->sqldata)
{
printf("sqldata malloc failed\n");
return -1;
}
if (print)
printf("column %3d, type = %s(%3d), len=%d\n", i+1, type,
col_ptr->sqltype, col_ptr->sqllen);
}
} /* end for */
return msglen;
}

/*******************************************************************
***
* Function: print_sqlda
* Purpose: Prints contents of fetch arrays for each column that the
* sqlda structure contains. Current version only implements
* data types found in the blobtab table. Other data types
* would need to me implemented to make this function complete.
********************************************************************
**/

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 494 -

void print_sqlda(struct sqlda *sqlda, int count)
{
void *data;
int i, j;
ifx_loc_t *temp_loc;
struct sqlvar_struct *col_ptr;
char *type;
char buffer[512];
int ind;
char i1, i2;

/*
print
number
of
columns
(sqld)
and
number
of
fetch-array
elements
*/
printf("\nsqld: %d, fetch-array elements: %d.\n", sqlda->sqld,
count);

/* Outer loop: loop through each element of a fetch array */
for (j = 0; j < count; j ++)
{
if (count > 1)
{
printf("record[%4d]:\n", j);
printf("col | type | id | len | ind | rin | data ");
printf("| value\n");
printf("--------------------------------------------");
printf("------------------\n");
}

/* Inner loop: loop through each of the sqlvar_struct structures */
for (i = 0, col_ptr = sqlda->sqlvar; i < sqlda->sqld; i++, col_ptr++)
{
data = col_ptr->sqldata + (j*col_ptr->sqllen);
switch (col_ptr->sqltype)
{
case CFIXCHARTYPE:
case CCHARTYPE:
type = "char";
if (col_ptr->sqllen > 40)
sprintf(buffer, " %39.39s<..", data);
else
sprintf(buffer, "%*.*s", col_ptr->sqllen,
col_ptr->sqllen, data);
break;
case CINTTYPE:

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 495 -

type = "int";
sprintf(buffer, " %d", *(int *) data);
break;
case CLOCATORTYPE:
type = "byte";
temp_loc = (ifx_loc_t *)(col_ptr->sqldata +
(j * sizeof(ifx_loc_t)));
sprintf(buffer, " buf ptr: %p, buf sz: %d, blob sz: %d",
temp_loc->loc_buffer,
temp_loc->loc_bufsize, temp_loc->loc_size);
break;
default:
type = "??????";
sprintf(buffer, " type not implemented: ",
"can't print %d", col_ptr->sqltype);
break;
} /* end switch */

i1 = (col_ptr->sqlind==NULL) ? 'X' :
(((col_ptr->sqlind)[j] != 0) ? 'T' : 'F');
i2 = (risnull(col_ptr->sqltype, data)) ? 'T' : 'F';

printf("%3d | %-6.6s | %3d | %3d | %c | %c | ",
i, type, col_ptr->sqltype, col_ptr->sqllen, i1, i2);
printf("%8p |%s\n", data, buffer);
} /* end for (i=0...) */
} /* end for (j=0...) */
}

/*******************************************************************
***
* Function: free_sqlda
* Purpose: Frees memory used by sqlda. This memory includes:
* o loc_buffer memory (used by TEXT & BYTE)
* o sqldata memory
* o sqlda structure
********************************************************************
**/
void free_sqlda(struct sqlda *sqlda)
{
int i,j, num_to_dealloc;
struct sqlvar_struct *col_ptr;
ifx_loc_t *temp_loc;


GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 496 -

for (i = 0, col_ptr = sqlda->sqlvar; i < sqlda->sqld; i++,
col_ptr++)
{
if ( col_ptr->sqltype == CLOCATORTYPE )
{
/* Free memory for blob buffer of each element in fetch array */
num_to_dealloc = (FetArrSize == 0)? 1: FetArrSize;
temp_loc = (ifx_loc_t *) col_ptr->sqldata;
for (j = 0; j< num_to_dealloc; j++, temp_loc++)
{
free(temp_loc->loc_buffer);
}
}
/* Free memory for sqldata (contains fetch array) */
free(col_ptr->sqldata);
}

/* Free memory for sqlda structure */
free(sqlda);
}

void main()
{
int i = 0;
int row_count, row_size;


EXEC SQL begin declare section;
char *db = "stores7";
char *uid = "odbc";
char *pwd = "odbc";
EXEC SQL end declare section;


/*******************************************************************
*
* Step 1: declare an sqlda structure to hold the retrieved column
* values

********************************************************************
/
struct sqlda *da_ptr;

EXEC SQL connect to :db user :uid using :pwd;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 497 -

if ( SQLCODE < 0 )
{
printf("CONNECT failed: %d\n", SQLCODE);
exit(0);
}

/* Prepare the SELECT */
EXEC SQL prepare selct_id from 'select catalog_num, cat_descr from
catalog';
if ( SQLCODE < 0 )
{
printf("prepare failed: %d\n", SQLCODE);
exit(0);
}


/*******************************************************************
*
*
Step
2:
describe
the
prepared
SELECT
statement
to
allocate
memory
* for the sqlda structure and the sqlda.sqlvar structures
* (DESCRIBE can allocate sqlda.sqlvar structures because
* prepared statement is a SELECT)

********************************************************************
/
EXEC SQL describe selct_id into da_ptr;
if ( SQLCODE < 0 )
{
printf("describe failed: %d\n", SQLCODE);
exit(0);
}


/*******************************************************************
*
* Step 3: initialize the sqlda structure to hold fetch arrays for
* columns

********************************************************************
/
row_size = init_sqlda(da_ptr, 1);

/* declare and open a cursor for the prepared SELECT */
EXEC SQL declare curs cursor for selct_id;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 498 -

if ( SQLCODE < 0 )
{
printf("declare failed: %d\n", SQLCODE);
exit(0);
}
EXEC SQL open curs;
if ( SQLCODE < 0 )
{
printf("open failed: %d\n", SQLCODE);
exit(0);
}
while (1)
{

/*******************************************************************
*
* Step 4: perform fetch to get "FetArrSize" array of rows from
* the database server into the sqlda structure

********************************************************************
/
EXEC SQL fetch curs using descriptor da_ptr;

/* Reached last set of matching rows? */
if ( SQLCODE == SQLNOTFOUND )
break;


/*******************************************************************
*
* Step 5: obtain the values from the fetch arrays of the sqlda
* structure; use sqlca.sqlerrd[2] to determine number
* of array elements actually retrieved.

********************************************************************
/
printf("\n===============\n");
printf("FETCH %d\n", i++);
printf("===============");
print_sqlda(da_ptr, ((FetArrSize == 0) ? 1 : sqlca.sqlerrd[2]));


/*******************************************************************
*

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 499 -

* Step 6: repeat the FETCH until all rows have been fetched (SQLCODE
* is SQLNOTFOUND

********************************************************************
/
}


/*******************************************************************
*
* Step 7: Free resources:
* o statement id, selct_id
* o select cursor, curs
* o sqlda structure (with free_sqlda() function)
* o delete sample table and its rows from database

********************************************************************
/

EXEC SQL free selct_id;
EXEC SQL close curs;
EXEC SQL free curs;
free_sqlda(da_ptr);
}
为访存数组分配内存
DESCRIBE...INTO 语句为 sqlda 结构及其 sqlvar_struct 结构分配内存。
然而,
它不
为 sqlvar_struct 结构的 sqldata 字段分配内存。sqldata 字段为检索了的列保存访存数组。
因此,您必须将足够的内存分配给每一 sqldata 字段来保存该访存数组的元素。

新的全局变量 FetArrSize 指示由 FETCH 语句返回的行数。定义此变量为 C 语言
short integer 数据类型。它的缺省值为零,其禁用访存数组特性。您可将 FetArrSize 设置
为在下列范围内的任何整数值:
0 <= FetArrSize <= MAXSMINT

MAXSMINT 值是 GBase 8s ESQL/C 可检索的数据类型的最大数量。
它的值为 32767
字节(32 KB)。如果该访存数组的大小大于 MAXSMINT,则 GBase 8s ESQL/C 自动地
将它的大小减为 32 KB。

您可使用下列计算来确定该访存数组的适当的大小:
(fetch-array size) = (fetch-buffer size) / (row size)

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 500 -


前面的等式使用下列信息:
fetch-array size
访存数组的大小,由 FetArrSize 全局变量来指示
fetch-buffer size
访存缓冲区的大小,
由 FetBufSize 和 BigFetBufSize 全局变量来指
示。
row size
要访存的行的大小。要确定要访存的行的大小,对于该行的每一列,
请调用 rtypmsize() 函数。此函数返回需要存储该数据类型的字节数。

然而,如果您设置 FetArrSize 以便于下列关系为真,
(FetArrSize * row size) > FetBufSize

则 GBase 8s ESQL/C 自动地调整该访存缓冲区的大小(FetBufSize)如下,来保存该
访存数组的大小:
FetBufSize = FetArrSize * row size

如果该值大于 32 KB
(MAXSMINT)

则 GBase 8s ESQL/C 将 FetBufSize 设置为 32
KB 和 FetArrSize 如下:
FetArrSize = MAXSMINT / (row size)

重要: FetArrSize 全局变量可用在线程安全 GBase 8s ESQL/C 应用程序中。
为访存数组分配内存
要为访存数组分配内存:

确定您正从数据库检索的行的大小。
确定该访存数组的大小,并将 FetArrSize 全局变量设置为此值。
对于每一简单大对象列(TEXT 或 BYTE),分配一个 ifx_loc_t 结构的访存数组。
对于每一简单大对象列(TEXT 或 BYTE),初始化 ifx_loc_t 数据结构如下。
将 loc_loctype 字段设置为 LOCMEMORY。
a) 将 loc_buffer 字段设置为您在步骤 3中分配的缓冲区的
地址。
将 loc_bufsize 字段设置为您分配了的缓冲区的大小。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 501 -

或者,您可将 loc_bufsize 设置为 -1,来让 GBase 8s ESQL/C 自动地为简单
大对象列分配内存。

为指示符变量分配内存。
对于所有其他列,分配保存那列的数据类型的访存数组。

对于下列准备好的查询,下列示例代码说明您会如何为访存数组分配内存:
SELECT * from blobtab;

该函数称为 init_sqlda():
/**********************************************************************
* Function: init_sqlda()
* Purpose: With the sqlda pointer that was returned from the DESCRIBE
* statement, function allocates memory for the fetch arrays
* in the sqldata fields of each column. The function uses
* FetArrSize to determine the size to allocate.
* Returns: < 0 for error
* > 0 error with messagesize

**********************************************************************/
int init_sqlda(struct sqlda *in_da, int print)
{
int i, j,
row_size=0,
msglen=0,
num_to_alloc;
struct sqlvar_struct *col_ptr;
ifx_loc_t *temp_loc;
char *type;


if (print)
printf("columns: %d. \n", in_da->sqld);


GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 502 -

/* Step 1: determine row size */
for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++,
col_ptr++)
{
/* The msglen variable holds the sum of the column sizes in the
* database; these are the sizes that DESCRIBE returns. This
* sum is the amount of memory that ESQL/C needs to store
* one row from the database. This value is <= row_size. */
msglen += col_ptr->sqllen; /* get database sizes */


/* calculate size for C data: string columns get extra byte added
* to hold null terminator */
col_ptr->sqllen = rtypmsize(col_ptr->sqltype, col_ptr->sqllen);

/* The row_size variable holds the sum of the column sizes in
* the client application; these are the sizes that rtypmsize()
* returns. This sum is amount of memory that the client
* application needs to store one row. */
row_size += col_ptr->sqllen;
if(print)
printf("Column %d size: %d\n", i+1, col_ptr->sqllen);
}

if (print)
{
printf("Total message size = %d\n", msglen);
printf("Total row size = %d\n", row_size);
}

EXEC SQL select max(length(cat_descr)) into :blobsize from catalog;

/* Step 2: set FetArrSize global variable to number of elements

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 503 -

* in fetch array; this function calculates the FetArrSize
* value that can fit into the existing fetch buffer.
* If FetBufSize is not set (equals zero), the code assigns a
* default size of 4096 bytes (4 kilobytes). Alternatively, you
* could set FetArrSize to the number elements you wanted to
* have and let ESQL/C size the fetch buffer. See the text in
* "Allocating Memory for the Fetch Arrays" for more information.*/
if (FetArrSize <= 0) /* if FetArrSize not yet initialized */
{
if (FetBufSize == 0) /* if FetBufSize not set */
FetBufSize = 4096; /* default FetBufSize */
FetArrSize = FetBufSize/msglen;
}
num_to_alloc = (FetArrSize == 0)? 1: FetArrSize;
if (print)
{
printf("Fetch Buffer Size %d\n", FetBufSize);
printf("Fetch Array Size: %d\n", FetArrSize);
}

/* set type in sqlvar_struct structure to corresponding C type */
for (i = 0, col_ptr = in_da->sqlvar; i < in_da->sqld; i++,
col_ptr++)
{
switch(col_ptr->sqltype)
{
case SQLCHAR:
type = "char ";
col_ptr->sqltype = CCHARTYPE;
break;
case SQLINT:
case SQLSERIAL:
type = "int ";

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 504 -

col_ptr->sqltype = CINTTYPE;
break;
case SQLBYTES:
case SQLTEXT:
if (col_ptr->sqltype == SQLBYTES)
type = "blob ";
else
type = "text ";
col_ptr->sqltype = CLOCATORTYPE;

/* Step 3 (TEXT & BLOB only): allocate memory for sqldata
* that contains ifx_loc_t structures for TEXT or BYTE column */
temp_loc = (ifx_loc_t *)malloc(col_ptr->sqllen * num_to_alloc);
if (!temp_loc)
{
fprintf(stderr, "blob sqldata malloc failed\n");
return(-1);
}
col_ptr->sqldata = (char *)temp_loc;

/* Step 4 (TEXT & BLOB only): initialize ifx_loc_t structures to
hold blob values in a user-defined buffer in memory */
byfill( (char *)temp_loc, col_ptr->sqllen*num_to_alloc ,0);
for (j = 0; j< num_to_alloc; j++, temp_loc++)
{
/* blob data to go in memory */
temp_loc->loc_loctype = LOCMEMORY;

/* assume none of the blobs are larger than BLOBSIZE */
temp_loc->loc_bufsize = blobsize;
temp_loc->loc_buffer = (char *)malloc(blobsize+1);
if (!temp_loc->loc_buffer)
{

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 505 -

fprintf(stderr, "loc_buffer malloc failed\n");
return(-1);
}
temp_loc->loc_oflags = 0; /* clear flag */
} /* end for */
break;
default: /* all other data types */
fprintf(stderr, "not yet handled(%d)!\n", col_ptr->sqltype);
return(-1);
} /* switch */

/* Step 5: allocate memory for the indicator variable */
col_ptr->sqlind = (short *)malloc(sizeof(short) * num_to_alloc);
if (!col_ptr->sqlind)
{
printf("indicator malloc failed\n");
return -1;
}

/* Step 6 (other data types): allocate memory for sqldata. This function
* casts the pointer to this memory as a (char *). Subsequent
* accesses to the data would need to cast it back to the data
* type that corresponds to the column type. See the print_sqlda()
* function for an example of this casting. */
if (col_ptr->sqltype != CLOCATORTYPE)
{
col_ptr->sqldata = (char *) malloc(col_ptr->sqllen *
num_to_alloc);
if (!col_ptr->sqldata)
{
printf("sqldata malloc failed\n");
return -1;
}

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 506 -

if (print)
printf("column %3d, type = %s(%3d), len=%d\n", i+1, type,
col_ptr->sqltype, col_ptr->sqllen);
}
} /* end for */
return msglen;
}
从访存数组获得值
每一 FETCH 尝试将值的 FetArrSize 数目返回至 sqlda 结构的 sqlvar_struct 结构
的 sqldata 字段内。
您可检查 sqlca.sqlerrd[2] 值来确定 FETCH 确实返回了的实际行数。


对于该查询的一列,每一访存数组保存该值。要获得值的行,您必须访问每一访存数
组的同一索引处的元素。例如,要获得值的第一行,请访问每一访存数组的第一个元素。

样例程序调用 print_sqlda() 函数来为下列准备好的查询从访存数组获得值:
SELECT * from blobtab


/**********************************************************************
* Function: print_sqlda
* Purpose: Prints contents of fetch arrays for each column that the
* sqlda structure contains. Current version only implements
* data types found in the blobtab table. Other data types
* would need to me implemented to make this function complete.

**********************************************************************/
void print_sqlda(struct sqlda *sqlda, int count)
{
void *data;
int i, j;
ifx_loc_t *temp_loc;
struct sqlvar_struct *col_ptr;
char *type;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 507 -

char buffer[512];
int ind;
char i1, i2;

/* print number of columns (sqld) and number of fetch-array elements
*/
printf("\nsqld: %d, fetch-array elements: %d.\n", sqlda->sqld,
count);

/* Outer loop: loop through each element of a fetch array */
for (j = 0; j < count; j ++)
{
if (count > 1)
{
printf("record[%4d]:\n", j);
printf("col | type | id | len | ind | rin | data ");
printf("| value\n");
printf("--------------------------------------------");
printf("------------------\n");
}

/* Inner loop: loop through each of the sqlvar_struct structures */
for (i = 0, col_ptr = sqlda->sqlvar; i < sqlda->sqld; i++, col_ptr++)
{
data = col_ptr->sqldata + (j*col_ptr->sqllen);
switch (col_ptr->sqltype)
{
case CFIXCHARTYPE:
case CCHARTYPE:
type = "char";
if (col_ptr->sqllen > 40)
sprintf(buffer, " %39.39s<..", data);
else

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 508 -

sprintf(buffer, "%*.*s", col_ptr->sqllen,
col_ptr->sqllen, data);
break;
case CINTTYPE:
type = "int";
sprintf(buffer, " %d", *(int *) data);
break;
case CLOCATORTYPE:
type = "byte";
temp_loc = (ifx_loc_t *)(col_ptr->sqldata +
(j * sizeof(ifx_loc_t)));
sprintf(buffer, " buf ptr: %p, buf sz: %d, blob sz: %d",
temp_loc->loc_buffer,
temp_loc->loc_bufsize, temp_loc->loc_size);
break;
default:
type = "??????";
sprintf(buffer, " type not implemented: ",
"can't print %d", col_ptr->sqltype);
break;
} /* end switch */

i1 = (col_ptr->sqlind==NULL) ? 'X' :
(((col_ptr->sqlind)[j] != 0) ? 'T' : 'F');
i2 = (risnull(col_ptr->sqltype, data)) ? 'T' : 'F';

printf("%3d | %-6.6s | %3d | %3d | %c | %c | ",
i, type, col_ptr->sqltype, col_ptr->sqllen, i1, i2);
printf("%8p |%s\n", data, buffer);
} /* end for (i=0...) */
} /* end for (j=0...) */
}
为访存数组释放内存

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 509 -

GBase 8s ESQL/C 不为 sqlda 结构释放资源。当您的应用程序不再需要 sqlda 结构
时,它必须释放它使用的所有内存。

该样例程序调用 free_sqlda() 函数来释放 sqlda 结构使用的内存。
/**********************************************************************
* Function: free_sqlda
* Purpose: Frees memory used by sqlda. This memory includes:
* o loc_buffer memory (used by TEXT & BYTE)
* o sqldata memory
* o sqlda structure

**********************************************************************/
void free_sqlda(struct sqlda *sqlda)
{
int i,j, num_to_dealloc;
struct sqlvar_struct *col_ptr;
ifx_loc_t *temp_loc;

for (i = 0, col_ptr = sqlda->sqlvar; i < sqlda->sqld; i++,
col_ptr++)
{
if ( col_ptr->sqltype == CLOCATORTYPE )
{
/* Free memory for blob buffer of each element in fetch array */
num_to_dealloc = (FetArrSize == 0)? 1: FetArrSize;
temp_loc = (ifx_loc_t *) col_ptr->sqldata;
for (j = 0; j< num_to_dealloc; j++, temp_loc++)
{
free(temp_loc->loc_buffer);
}
}
/* Free memory for sqldata (contains fetch array) */
free(col_ptr->sqldata);

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 510 -

}

/* Free memory for sqlda structure */
free(sqlda);
}

要理解并发的危险性,您必须从多个程序的方面考虑,每一程序以它自己的速度执行。 假
设您的程序通过下列游标正在访存行:
EXEC SQL DECLARE sto_curse CURSOR FOR
SELECT * FROM stock
WHERE manu_code = 'ANZ';
将每一行从数据库服务器传送到程序都花费时间。在传送期间和传送之间,其他程序可执
行其他数据块操作。大约在您的程序访存由那个查询产生的行的同一时刻,另一用户的程
序可能执行下列更新:
EXEC SQL UPDATE stock
SET unit_price = 1.15 * unit_price
WHERE manu_code = 'ANZ';
换句话说,两个程序都在通读同一个表,一个正在访存某些行,而另一个正在更改相同的
行。可能出现下列情况:
1. 在您的程序访存它的第一行之前,其他程序完成了它的更新。
您的程序仅向您显示更新了的行。
2. 在其他程序有机会更新它之前,您的程序访存了每行。
您的程序仅向您显示原始的行。
3. 在您的程序访存某些原始的行之后,其他程序赶上并继续更新您的程序还要读取的
一些行;然后,它执行 COMMIT WORK 语句。
您的程序可能返回的既有原始的行,也有更新了的行。
4. 与第 3 种情况一样,除了在更新表之后,另一程序发出 ROLLBACK WORK 语句
之外。
您的程序可向您显示的既有原始的行,也有在数据库中不再存在的更新了的行。
前两种可能性是无害的。在第 1 种可能的情况中,在您的查询开始之前完成了更新。更新
是在一毫秒之前结束的,还是一周前结束的,并无差异。
在第 2 种可能的情况中,实际上,您的查询在更新开始之前完成。其他程序可能紧跟在您
的程序之后只处理了一行,或它可能直到明晚才开始;这没有关系。

GBase 8s SQL 指南:教程
南大通用数据技术股份有限公司 - 238 -

然而,后两种可能的情况对于某些应用程序的设计可至关重要。在第 3 种可能的情况下,
查询返回的既有更新了的数据,也有原始数据。在某些应用程序中,那种结果可能是有害
的。在其他程序中,诸如计算所有价格的平均值,根本无关紧要。
由于取消了它们的事务,如果程序返回一些在表中不可再找到的数据行,则第 4 种可能的
情况是灾难性的。
当您的程序使用游标来更新或删除最后访存的数据时,需要引起另外的关注。下列的事件
序列产生错误的结果:

您的程序访存该行。

另一程序更新或删除该行。

您的程序更新或删除 WHERE CURRENT OF cursor_name。
要控制诸如此类的事件,请使用数据库服务器的锁定和隔离级别特性。

如果更改存储管理器供应商,那么在有证据表明新存储管理器对备份与恢复操作均适用之
前,请不要除去旧存储管理器。您可以使用旧存储管理器作为备份存储管理器,以在新存
储管理器无法满足您的需要时进行使用。
ON-Bar 支持同时使用多个存储管理器。要设置为测试一个存储管理器并将另一个作为备
份存储管理器,请在 BAR_BSALIB_PATH 配置参数中以及
$GBS_HOME/etc/sm_versions 文件中指定这两个存储管理器的信息。
如果无法同时使用新旧存储管理器,请使用 ON-Bar 和 GBase 8s 主存储管理器Storage
Manager 或 ontape 作为在检查备份和恢复操作是否能正确用于新存储管理器时的备份的
备用方法。仅当您确认新存储管理器能够正确工作后,才将所有备份作为整个系统的 0
级备份来执行 (onbar -b-L 0 -w)。
如果更改物理连接(例如,将存储设备从本地连接移动到网络服务器),请确保新存储管
理器可以在网络中移动数据。另请确保新存储管理器可以向存储设备发送多个数据流。它
也可以使用不同版本的 XBSA。