ACCI环境中的SQL语句类型¶
在ACCI环境中有三种类型的SQL语句:
- 标准语句:使用具有指定值的SQL命令
- 参数化语句:有参数或绑定变量
- 可调用语句:调用PL / SQL存储过程和函数
Statement类的方法被细分为适用于所有statement、参数化statement和可调用statement的方法。
标准statement¶
必须显示定义标准statement的值,示例3-12演示了如何使用标准statement创建数据库表并向表中插入数据
示例2-12 如何使用标准statement创建数据库表并向表中插入数据
stmt->executeUpdate("CREATE TABLE shopping_basket(item_number VARCHAR2(30), quantity NUMBER(3))");
stmt->executeUpdate("INSERT INTO shopping_basket VALUES('MANGO', 3)");
参数化statement¶
通过为statement的输入变量设置占位符,可以使用不同的参数执行相同的statement。这些statement被称为参数化statement,因为它们可以接受来自用户或程序的参数输入。
如果您想要执行带有不同参数的INSERT语句,您必须首先通过Statement对象的setSQL()方法指定该语句,如示例2-13所示。
例2-13 参数化statement实例
stmt->setSQL("INSERT INTO shopping_basket VALUES(:1,:2)");
然后调用setxxx()方法来指定参数,其中xxx代表参数的类型。在示例2-13中,statement对象的值是"INSERT INTO shopping_basket VALUES(:1,:2)",可以使用示例2-13中的代码调用setString()方法和setInt()方法来将这些类型的值输入到第一个和第二个参数中,调用executeUpdate()方法来将新行插入到表中。也可以通过重新设置参数并再次调用executeUpdate()方法来重用statement对象。如果应用程序重复执行相同的语句,则应该避免更改输入参数类型,因为这会启动重新绑定操作,并影响应用程序性能。
示例2-13 如何使用setxxx()方法设置各个列的值
stmt->setString(1, "Banana"); // 第一个参数值
stmt->setInt(2, 5); // 第二个参数值
stmt->executeUpdate(); // 执行语句
...
stmt->setString(1, "Apple"); // 第一个参数值
stmt->setInt(2, 9); // 第二个参数值
stmt->executeUpdate(); // 执行语句
可调用statement¶
PL/SQL存储过程,顾名思义,是存储在数据库服务器上供应用程序重用的过程。在ACCI中,可调用语句是对包含其他SQL语句的过程的调用。
如果您想调用countGrocery()过程,它返回指定种类水果的数量,那么必须首先通过Statement类的setXXX()方法指定PL/SQL存储过程的输入参数,如示例2-14所示。
示例2-14 如何指定PL/SQL存储过程的IN参数
stmt->setSQL("BEGIN countGroceries(:1, :2); END;");
int quantity;
stmt->setString(1, "Apple"); // 指定过程的第一个(IN)参数
但是,在调用存储过程之前,必须通过调用registerOutParam()方法来指定OUT参数的类型和大小,如示例2-15所示。对于IN/OUT参数,使用setXXX()方法传入参数,使用getXXX()方法检索结果。
示例2-15 如何指定PL/SQL存储过程的OUT参数
stmt->registerOutParam(2, Type::ACCIINT, sizeof(quantity));
// 指定第二个(OUT)参数的类型和大小
流式读写¶
ACCI支持流式接口,通过将数据分解成一系列小块来插入和检索非常大的列。这种方法最小化了客户端内存需求。这个流接口可以与参数化statement(如SELECT和各种DML命令)以及PL/SQL块中的可调用statement一起使用。流支持的数据类型是BLOB、CLOB、LONG、LONG RAW、RAW和VARCHAR2。
流式数据有三种:
- 可写流对应于SELECT/DML语句中的绑定变量或可调用语句中的in参数。
- 可读流对应于SELECT语句中提取的列值或可调用statement中的OUT参数。
- 双向流对应于一个IN/OUT绑定变量。
Stream类的方法支持流接口。
Statement类的getStream()方法返回一个支持读写DML和可调用statement的流对象:
- 写入时,它将数据传递给绑定变量或IN或IN/OUT参数
- 读取时,它从一个OUT或IN/OUT参数中获取数据
ResultSet类的getStream()方法返回一个可用于读取数据的流对象。
这些类的status()方法确定流操作的状态。
本小节包括以下主题:
- 流模式下的数据绑定;SELECT/DML 和 PL/SQL
- 以流模式获取数据:PL/SQL
流模式下的数据绑定;SELECT/DML 和 PL/SQL¶
要以流模式绑定数据,请遵循以下步骤并查看示例2-16:
1.使用适当的绑定占位符创建SELECT/DML或PL/SQL语句。
2.为流模式中使用的每个绑定位置调用语句类的setBinaryStreamMode()或setCharacterStreamMode()方法。
3.执行该语句;语句类的status()方法返回NEEDS_STREAM_DATA。
4.通过语句类的getStream()方法获取流对象。
5.使用流类的writeBuffer()和writeLastBuffer()方法来写数据。
6.使用语句类的closeStream()方法关闭流。
7.在关闭所有流之后,Statement类的status()方法会更改为一个合适的值,比如UPDATE_COUNT_AVAILABLE。
示例2-16如何在流模式下绑定参数
Statement *stmt = conn->createStatement("Insert Into testtab(longcol) values (:1)"); //longcol 列是LONG类型
stmt->setCharacterStreamMode(1, 100000);
stmt->executeUpdate();
Stream *instream = stmt->getStream(1);
char buffer[1000];
instream->writeBuffer(buffer, len); //写入数据
instream->writeLastBuffer(buffer, len); //重复
stmt->closeStream(instream); //stmt->status() 是UPDATE_COUNT_AVAILABLE
以流模式获取数据:PL/SQL¶
要从流模式中获取数据,请按照以下步骤操作,并查看示例3-25:
1.创建具有适当的绑定占位符的SELECT / DML语句。
2.为每个绑定位置调用声明类的setBinaryStreamMode()或setCharacterStreamMode()方法,该绑定位置是从流模式中检索到的数据。
3.通过Statement类的getStream()方法获取流对象。
4.使用Stream类的readBuffer()和readLastBuffer()方法读取数据。
5.使用Statement类的closeStream()方法关闭流。
示例2-17如何使用PL / SQL以流模式获取数据
string csql = "create table blob_test(a int, col1 blob)";
string dsql = "drop table blob_test";
string isql = " insert into blob_test values(1, :col1)";
string exec_sql ="select * from blob_test";
Statement *stmt = GetStmt();
ResultSet *rs;
FILE *fp = NULL;
int filelen = 0;
char write_stream_buf[BLOB_STREAM_UNIT] = {0};
char read_stream_buf[BLOB_STREAM_UNIT] = {0};
int readcount = 0;
int readcountsum = 0;
Stream *instream;
stmt->execute(dsql);
/*先写入数据*/
stmt->execute(csql);
stmt->setSQL(isql);
stmt->setBinaryStreamMode(1, BLOB_MAX_SIZE);
stmt->executeUpdate();
instream = stmt->getStream(1);
fp = fopen("./src/aaa1.jpg", "rb");
ASSERT_TRUE(fp);
fseek(fp, 0, SEEK_END);
filelen = ftell(fp);
fseek(fp, 0 , SEEK_SET);
while (readcountsum < filelen)
{
readcount = fread(write_stream_buf, 1, BLOB_STREAM_UNIT, fp);
readcountsum += readcount;
if(readcountsum >= filelen)
{
instream->writeLastBuffer(write_stream_buf, readcount);
}
else
{
instream->writeBuffer(write_stream_buf, readcount);
}
}
stmt->closeStream(instream);
fclose(fp);
/*在取出数据*/
rs = stmt->executeQuery(exec_sql);
rs->next();
Blob blob = rs->getBlob(2);
Stream *stream1 = blob.getStream();
blob.open();
fp = fopen("./src/bbb1.jpg", "wb+");
ASSERT_TRUE(fp);
while (-1 != (readcount = stream1->readBuffer(read_stream_buf, BLOB_STREAM_UNIT)))
{
fwrite(read_stream_buf, 1, readcount, fp);
}
blob.closeStream(stream1);
fclose(fp);