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);