要使 GBase 8s ESQL/C 在内存中定位 TEXT 或 BYTE 数据,请将定位器结构的字 段 loc_loctype 设置为 LOCMEMORY ,如下所示: GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 140 - EXEC SQL BEGIN DECLARE SECTION; loc_t my_simple_lo; EXEC SQL END DECLARE SECTION; ⋮ my_simole_lo.loc_loctype = LOCMEMORY; 当使用内存作为简单大对象的位置,则定位器结构使用 lc_union 结构的 lc_mem 结 构。下表介绍了 lc_union.lc_mem 字段。 表 3. 用于内存中的简单大对象的 lc_union.lc_mem 结构中字段 字段 数据类型 描述 lc_bufsize 4 字 节整数 lc_buffer 字段指向的缓冲区的大小(以字节为单位) lc_buffer char * 保存简单大对象值缓冲区的地址。 GBase 8s ESQL/C 程序 必须为此缓冲区分配空间并将它的地址存储在 lc_buffer 中。 lc_currdata_p char * 系统缓冲区的地址。这是内部字段并且不能被 GBase 8s ESQL/C 程序修改。 lc_mflags mint 当分配内存时使用的标志。 当您访问 lc_union.lc_mem 中的字段时,locator.h 文件提供以下宏结: #define loc_bufsize lc_union.lc_mem.lc_bufsize #define loc_buffer lc_union.lc_mem.lc_buffer #define loc_currdata_p lc_union.lc_mem.lc_currdata_p #define loc_mflags lc_union.lc_mem.lc_mflags 提示: 建议在访问定位器结构时使用这些快捷方式名称。快捷方式名称提供了代码 的可读性,并减少了编码错误。该引用在引用 lc_union.lc_mem 结构的 lc_bufsize 、 lc_buffer 、lc_currdata_p 和 lc_mflags 字段时使用这些快捷方式名称。 demo 命令包含以下两个示例 GBase 8s ESQL/C 程序, 它们演示了如何处理位于内存 中的简单大对象数据: getcd_me.ec 程序在内存中选择一个简单大对象。 updcd_me.ec 程序从内存中插入一个简单大对象。 GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 141 - 这些程序假设 stores7 数据库作为简单大对象数据的缺省数据库。用户可以指定另一 个数据库(在缺省的数据库服务器上)作为命令行参数。 getcd_me mystores 分配内存缓冲区 当查询将简单大对象选择到内存中,则 GBase 8s ESQL/C 使用内存缓冲区。 在程序获取 TEXT 或 BYTE 数据之前,必须将 loc_bufsize (lc_union.lc_mem.lc_bufsize)字段设置如下,以指示 GBase 8s ESQL/C 如何分配此内存 缓冲区: 如果将 loc_bufsize 设置为 -1, 则 GBase 8s ESQL/C 分配内存缓冲区保存简单大对象 数据。 如果将 loc_bufsize 设置为不是 -1 的值,则 GBase 8s ESQL/C 假定程序处理内存缓 冲区分配和撤销分配。 重要: 当在内存中找到简单大对象时,必须始终将 loc_mflags (lc_union.lc_mem.lc_mflags)和 loc_oflags 设置为 0 。 ESQL/C 库分配的内存缓冲区 当将 loc_bufsize 设置为 -1 时,GBase 8s ESQL/C 对获取和选择分配内存和缓冲区。 GBase 8s ESQL/C使用 malloc() 系统调用内存缓冲区保存简单大对象(如果它不能分配缓 冲区,GBase 8s ESQL/C 将 loc_status 字段设置为 -465 以指示错误)当选择(或第一次 获取)完成时,GBase 8s ESQL/C 将 loc_buffer 设置为缓冲区的地址。将 loc_bufsize 和 loc_size 设置为获取的简单大对象的大小以更改定位器结构。 要获取具有较大或较小数据的连续简单大对象,loc_mflags 设置为 LOC_ALLOC 常 量(locator.h 定义),以请求 GBase 8s ESQL/C 重新分配新的内存缓冲区。将 loc_bufsize 设置为当前已分配缓冲区的大小。 如果在初始提取时未设置 loc_mflags 为 LOC_ALLOC ,则 GBase 8s ESQL/C 不会 释放其为 loc_buffer 缓冲区分配的内存。相反,它为后续的提取分配一个新的缓冲区。这 种情况可能会导致每个提取的程序大小增加,除非明确释放分配给每个 loc_buffer 缓冲区 的内存。如果您的应用程序在 Windows(TM) 操作系统上运行并使用多线程库,则使用 SqlFreeMem()GBase 8s ESQL/C 函数将其释放。否则使用 free() 系统调用。 当将 loc_mflags 设置为 LOC_ALLOC 时,GBase 8s ESQL/C 如下处理内存分配: 如果简单大对象数据大小增加,则 GBase 8s ESQL/C 释放现有的缓冲区并分配重要 的内存。 GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 142 - 如果发生这种重新分配,则 GBase 8s ESQL/C 改变存储简单大对象数据的存储器地 址。 因此, 如果您在程序中引用地址, 则程序逻辑必须考虑地址更改。 GBase 8s ESQL/C 还 将 loc_bufsize 和 loc_size 字段更改为已获取的简单大对象的大小。 如果数据的大小减少,则 GBase 8s ESQL/C 不需要重新分配缓冲区。 获取之后,loc_size 字段指示所获取的简单大对象的大小,而 loc_bufsize 字段仍然 包含已分配的缓冲区的大小。 当 GBase 8s ESQL/C 获取下一个简单大对象值时,它会释放已分配的内存。因此, GBase 8s ESQL/C 不会显式释放所获取的最后一个简单大对象值,直到您的程序从数据库 服务器断开连接。 程序分配的内存缓冲区 如果您想要为简单大对象处理自己的内存分配, 请使用 malloc() 系统调用分配内存然 后在定位器结构中设置一下字段: 在获取或选择 TEXT 或 BYTE 列之前, 将 loc_buffer 字段设置为已分配内存缓冲区 的地址,并将 loc_bufsize 字段设置为内存缓冲区的大小。 在插入 TEXT 或 BYTE 列之前, 为选择和获取设置相同的字段。 此外, 将 loc_size 设 置为要插入到数据库中数据的大小。 如果获取的数据不适合已分配的缓冲区,则 GBase 8s ESQL/C 库将 loc_status(和 SQLCODE)设置为负值(-451)并将数据的实际大小放在 loc_indicator 中。如果已获取 的数据不适合,则 GBase 8s ESQL/C 将 loc_size 设置为已获取数据的大小。 重要:当分配您自己的内存缓冲区时, 也可以在选择或插入简单大对象完成后释放 内存缓冲区。GBase 8s ESQL/C 不会释放此内存,因为它无法确定何时完成内存。由于您 已经使用 malloc() 分配内存,可以使用 free() 系统调用以释放内存。 选择简单大对象到内存中 demo 目录中的 getcd_me 示例程序显示了如何从数据库中的选择一个简单大对象到 内存中。 下图显示了将 catalog 表中的 cat_descr TEXT 列选择到内存中的代码片段, 然后显示 它。 图 2. getcd_me 示例程序代码片段 cat_descr.loc_loctype = LOCMEMORY; /* set loctype for in memory */ GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 143 - cat_descr.loc_bufsize = -1; /* let db get buffer */ cat_descr.loc_oflags = 0; /* clear loc_oflags */ cat_descr.loc_mflags = 0; /* set loc_mflags to 0 */ EXEC SQL select catalog_num, cat_descr /* look up catalog number */ into :cat_num, :cat_descr from catalog where catalog_num = :cat_num; if((ret = exp_chk2("SELECT", WARNNOTIFY)) == 100) /* if not found */ { printf("\nCatalog number %ld not found in catalog table\n", cat_num); if(!more_to_do()) /* More to do? */ break; /* no, terminate loop */ else continue; /* yes */ } if(ret < 0) { printf("\nSelect for catalog number %ld failed\n", cat_num); EXEC SQL disconnect current; printf("GETCD_ME Sample Program over.\n\n"); exit(1); } prdesc(); /* if found, print cat_descr */ 该程序将 cat_descr 定位器结构字段设置如下: loc_loctype 字段设置为 LOCMEMORY , 以便 GBase 8s ESQL/C 返回内存缓冲区中 cat_descr 文本。 loc_bufsize 字段设置为 -1 ,以使 GBase 8s ESQL/C 为此缓冲区分配内存。 loc_oflags 字段设置为 0 ,因为程序不会对简单大对象使用文件。 当您在内存中定位简单大对象时,必须始终将 loc_mflags 字段设置为 0。 SELECT 或 FETCH 语句之后,定位器结构包含下列信息: loc_buffer 字段包含内存缓冲区的地址。 GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 144 - loc_bufsize 字段包含 loc_buffer 缓冲区的大小。它是为简单大对象分配内存的总量。 loc_size 字段包含 loc_buffer 中简单大对象数据的字节数。 如果选择的简单大对象为空,则 loc_indicator 字段包含 -1。 loc_status 字段包含操作的状态:0 表示成功,负数表示发生失败。 如果程序选择了第二个简单大对象,则它需要在第二条 SELECT 语句阻止内存 泄露之前将 loc_mflags 设置为 LOC_ALLOC 常量。 该代码片段显示了用户输出的目录号的 cat_descr 列。下图显示了 stores7 演示数据 库中 cat_descr 列的用户输入和输出。 图 3. getcd_me 示例程序的样本输出 GETCD_ME Sample ESQL Program running. Connected to stores7 This program requires you to enter a catalog number from the catalog table. For example: '10001'. It then displays the content of the cat_descr column for that catalog row. The cat_descr value is stored in memory. Enter a catalog number: 10004 Description for 10004: Jackie Robinson signature glove. Highest professional quality, used by National League. **** More? (y/n) … 从内存插入简单大对象 demo 目录中的 updcd_me 示例程序显示了如何将内存中的简单大对象插入到数据库 中。 程序从包含用户输入的文本的内存缓冲区更改 catalog 表的 cat_descr TEXT 列。 下图 GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 145 - 显示了用户更新 stores7 数据库的 cat_descr 列的示例输出。 图 4. updcd_me 示例程序的示例输出 Enter catalog number: 10004 Description for 10004: Jackie Robinson signature ball. Highest professional quality, used by National League. Update this description? (y/n) …y Enter description (max 255 chars):and press RETURN Jackie Robinson home run ball, signed, 1955. *** Update complete. **** More?(y/n).... n 下图显示了一个代码摘录, 说明了 updcd_me 程序如何使用定位器结构从存储在内存 中的文本更改 cat_descr 列。 图 5. updcd_me 示例程序的代码摘录 /* Update? */ ans[0] = ' '; while((ans[0] = LCASE(ans[0])) != 'y' && ans[0] != 'n') { printf("\nUpdate this description? (y/n) …"); getans(ans, 1); } if(ans[0] == 'y') /* if yes */ { printf("Enter description (max of %d chars) and press RETURN\n", GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 146 - BUFFSZ - 1); /* Enter description */ getans(ans, BUFFSZ - 1); cat_descr.loc_loctype = LOCMEMORY; /* set loctype for in memory */ cat_descr.loc_buffer = ans; /* set buffer addr */ cat_descr.loc_bufsize = BUFFSZ; /* set buffer size */ /* set size of data * cat_descr.loc_size = strlen(ans); /* Update */ EXEC SQL update catalog set cat_descr =:cat_descr where catalog_num = :cat_num; ⋮ } 该程序将 cat_descr 定位器结构设置如下: loc_loctype 字段设置为 LOCMEMORY 以便 GBase 8s ESQL/C 从缓冲区读取 cat_descr 文本。 loc_buffer 字段设置为 ans,保存要插入的简单大对象值的内存缓冲区的地址。 loc_bufsize 字段设置为 BUFFSZ,分配 ans 内存缓冲区的大小。 loc_size 字段设置为 strlen(ans) + 1,当前保存的简单大对象的内存缓冲区中的字节数。 如果插入空简单大对象值,您的程序也需要将 loc_indicator 字段设置为 -1。 下图显示了一段代码摘录,说明了如何在 INSERT 语句中使用定位器结构。 图 6. 来自主内存的 INSERT 操作示例 char photo_buf[BUFFSZ]; EXEC SQL BEGIN DECLARE SECTION; GBase 8s ESQL/C 编程指南 南大通用数据技术股份有限公司 - 147 - char name[20]; loc_t photo; EXEC SQL END DECLARE SECTION; photo.loc_loctype = LOCMEMORY; /* Photo resides in memory */ photo.loc_buffer = photo_buf; /* pointer to where it is */ photo.loc_size = BUFFSZ - 1; /* length of image*/ EXEC SQL insert into employee (name, badge_pic) values (:name, :photo); UPDATE 或 INSERT 语句之后,GBase 8s ESQL/C 从内存缓冲区读取的字节数更 改 loc_size 字段,并将它发送给数据库服务器。它还设置 loc_status 字段 以显示操作的状态:0 表示成功,如果发生错误则为负值。