dbi_plugin
TSL语言的跨平台实现的数据库接口插件。
安装
(已集成到mytsl
发行版中)
动态库文件:Windows: dbi_plugin.dll 或者 Linux: libdbi_plugin.so,把动态库文件拷贝TSL目录的plugin目录。
辅助动态库:Windows: pk_sql.dll 或者 Linux: libpk_sql.so,把动态库文件拷贝TSL目录。
(如果需要下载兼容正式版的Windows版本的动态库文件请访问这里)。
- Linux系统需要预先安装unixODBC,各大发行版都有相应的系统包:
- apt install unixodbc
- yum install unixODBC
除了可以直接用URL方式连接数据库以外,还可以通过dbi.ini设置别名:
设置以后,就可以用dbi_session(name)或者db_pool_session(name)来创建数据库会话。 如果设置了pool_max,将支持连接池。 请将dbi.ini放在当前项目的工作目录里,这样方便为每个项目设置不同的数据库权限。安全增强(SE)版:
动态库文件:Windows: dbi_se_plugin.dll 下载 或者 Linux: libdbi_se_plugin.so,把动态库文件拷贝TSL目录的plugin目录。
安全增强版只支持dbi.ini别名的方式,用dbi.ini来进行安全检查,可以部署到服务器上。
使用指南
提供的TSL函数:
dbi_session
dbi_session(uri)
: 创建数据库会话。
-
参数列表
参数 描述 uri 数据库配置,字符串格式 数据库配置格式定义:
数据库 格式 sqlite "sqlite://数据库文件位置",可以用:memory:来表示在内存中。 mysql "mysql://host=;port=;user=;password=;db=;"。 postgresql "postgresql://host= user= password= dbname= port="。 ODBC "odbc://DRIVER=;UID=;PWD=;DATABASE=;SERVER=;"。例如sql server:"odbc://DRIVER=ODBC Driver 17 for SQL Server;UID=sa;PWD=password;DATABASE=mydb;SERVER=tcp:127.0.0.1,1433;"。oracle: "odbc://DRIVER=Oracle 19 ODBC driver;UID=user;PWD=password;SERVER=127.0.0.1:1521/ORCLCDB;"。 gaussdb "gaussdb://host= user= password= dbname= port="。 uri参数也可以是dbi.ini中设置的别名。
还支持设置SQL方言,格式是“方言+数据库配置URL”,例如oracle+odbc://.....,这样系统会根据不同的SQL方言做一些特别处理,例如命名参数的支持。
SQL方言列表:
方言 说明 sqlite sqlite mysql mysql postgresql postgresql oracle oracle mssql Microsoft SQL Server dm 达梦数据库 gaussdb 高斯数据库 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 数据库句柄 数据库会话句柄将会在以下函数中用到。
-
例子
[ec, db] := dbi_session("sqlite://:memory:");
if ec then println("error code:{} error message: {}", ec, db);
数据库会话对象的属性
属性 | 访问 | 说明 |
---|---|---|
maxFieldSize | 读写 | 字段最大尺寸 |
loginTimeout | 读写 | login超时设置 |
connectionTimeout | 读写 | 连接超时设置 |
queryTimeout | 读写 | 查询超时设置(ODBC才有) |
dbEncoding | 读写 | 编码设置(ODBC才有) |
autoCommit | 读写 | 自动提交设置 |
connector | 只读 | 数据库连接类型,例如"ODBC" |
dialect | 只读 | SQL方言 |
如果数据库连接不支持某些属性,会报错。
- 例子
dbi_close
dbi_close(db)
: 关闭数据库会话。
-
参数列表
参数 描述 db 数据库会话句柄 -
返回值 无
-
例子
注意
最新版本的dbi插件已经可以自动管理数据库会话,即使不用dbi_close也可以自动关闭数据库会话。
dbi_check
dbi_check(db)
: 检查数据库会话是否已连接。
-
参数列表
参数 描述 db 数据库会话句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1连接 或者 0没连接 -
例子
dbi_exec
dbi_exec(db, sql, [params...])
: 执行SQL语句并返回结果。
-
参数列表
参数 描述 db 数据库会话句柄 sql SQL语句 params 参数,可选参数,任意多个,支持数组 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 对于insert、update和delete语句,返回的结果是影响的记录数,对于select语句,返回的是查询结果 -
例子
多个参数:
[ec, rs] := dbi_exec(db, "insert into lang values (?, ?)"
, array(
("Fortran", 1957),
("Python", 1991),
("TSL", 2002),
("Go", 2009))
);
// 也可以是多个一维数组
a := array("Fortran", "Python", "TSL", "Go");
b := array(1957, 1991, 2002, 2009);
[ec, rs] := dbi_exec(db, "insert into lang values (?, ?)", a, b);
如何自己指定绑定参数参数的类型?
可以使用“魔法参数“,例如:
dbi_exec(db, "select x, y from mytable where z = ?", @date(z));
参数格式@<类型>(变量名)
支持的类型参见附录。
一般只需要对TSL的日期时间类型做指定参数绑定类型,例如:
dbi_exec(db, "select * from orders where orderDate = ?", @date(dt));
如何把查询结果返回变量中?
可以使用@@参数模式,例如要把整数放到变量x:
dbi_exec(db, "select 1", @@i32(x)) // x = 1
dbi_exec(db, "select 1", @@x) // x = 1,自动识别转换类型
可以有多个:
dbi_exec(db, "select 1, 2.0 ", @@x, @@y) // x = 1, y = 2.0
返回的结果可以是数组:
dbi_exec(db, "select name, first_appeared from lang", @@x, @@y);
一般放到查询的参数后面:
dbi_exec(db, "select name, first_appeared from lang where name = ?", "TSL", @@x, @@y);
如果使用@@方式,dbi_exe返回值将不包含结果,只有成功或者错误信息。
支持的数据类型参见附录。
如何设置存储过程的输入输出参数?
可以使用魔法参数的注解功能来标注参数的方向,例如:
// SQL Server
dbi_exec(db, "EXEC myproc_inputoutputparamaters ?", @i32(x) -> "in");
方向说明:
in input参数(默认值)
io input和output参数
out output参数
如何使用命名参数?
可以使用魔法参数的注解功能来标注参数名,例如:
一般在SQL中用":"来做命名参数。这时如果传递的参数不指定参数名称,就是按参数的次序来传递:
可以用魔法参数的注解来传递命名参数:
还可以同时指定参数输入输出的方向:
复杂的SQL语句可以通过使用命名参数让代码更清晰:
fundId := "MYFUND";
BeginDate := 20220101;
TDate := 20220501;
dbi_exec(db,
"
SELECT * FROM stock
WHERE fund_id = :fundId
AND date BETWEEN :BeginDate AND :TDATE
UNION
SELECT * FROM others
WHERE fund_id = :fundId
AND date BETWEEN :BeginDate AND :TDATE) t,
(SELECT * FROM instruction
WHERE fund_id = :fundId
AND date BETWEEN :BeginDate AND :TDATE
UNION
SELECT * FROM otherinstruction
WHERE fund_id = :fundId
AND date BETWEEN :BeginDate AND :TDATE) t1
"
, @fundId -> ":fundId"
, @BeginDate -> ":BeginDate"
, @TDate -> ":TDATE"
);
dbi_exec_async
dbi_exec_async(db, sql, [params...])
: 异步执行SQL语句。
参数说明见dbi_exec。
-
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 结果句柄, 结果句柄可以用来等待返回结果
dbi_exec_async不能使用@@参数模式来输出到变量。
dbi_wait
dbi_wait(handle, [timeout])
: 等待异步执行返回结果或者超时。
-
参数列表
参数 描述 handle 结果句柄或者结果句柄数组 timeout 超时设置,毫秒精度,可选参数 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 同dbi_exec的返回结果 如果参数是结果句柄数组,也会返回多个结果。
注意
- 等待超时后并没有取消异步执行,最终都会执行完,所以超时后还应不断尝试等待执行完成。
- 超时可以用来在等待过程中处理其他的事务。
例子
dbi_trans_begin
dbi_trans_begin(db)
: 开始事务。
-
参数列表
参数 描述 db 数据库会话句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1
dbi_commit
dbi_commit(db)
: 提交事务。
-
参数列表
参数 描述 db 数据库会话句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1
dbi_rollback
dbi_rollback(db)
: 回滚事务。
-
参数列表
参数 描述 db 数据库会话句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1
dbi_pool
dbi_pool(name, uri, [min=1], [max=32], [idle=60])
: 初始化连接池。
-
参数列表
参数 描述 name 连接池名称 uri 数据库配置,参见dbi_session min 最小保持连接数,可选参数,缺省是1 max 最大保持连接数,可选参数,缺省是32 idle 空闲时间,可选参数,缺省是60秒 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1 或者 0
说明
指定名称的连接池只会初始化一次,不管调用多少次都只初始化一次。
dbi_pool_session
dbi_pool_session(name)
: 从连接池中获取会话。
-
参数列表
参数 描述 name 连接池名称 -
返回值
同dbi_session。 如果连接池没达到上限,会立即返回已连接好的会话;否则会返回错误。
使用说明
- 连接池通常用在需要高并发的环境中,例如执行服务器或者web应用。
- 在多线程的环境下,可以包装一个getsession的函数,来初始化连接池并返回会话以方便使用。还可以通过加密这个函数来保护密码等敏感信息。
- dbi_pool_session还可以配合dbi_exec_async来做并发插入或更新数据来加快数据的处理。
- dbi_close关闭的连接池会话会被连接池回收以备重新使用。
dbi_stmt
dbi_stmt(db, sql, ...)
: 初始化SQL语句。
-
参数列表
参数 描述 db 数据库会话句柄 sql SQL语句 ... 参数,同dbi_exec的参数说明 -
额外支持的魔法参数:
- @limit(n) 最多获取N条记录。
- @limit_lower(n) 最少获取N条记录。
- @limit_upper(n) 最多获取N条记录。
- @range(n,m) @limit_lower(n),@limit_upper(m) 的组合。
-
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 SQL语句句柄
使用说明
主要功能是对一个大的结果集,可以每次获取一部分数据,可以一直执行下去,直到数据取完。
dbi_stmt_done
dbi_stmt_done(stmt)
: 检查SQL语句是否已经执行完。
-
参数列表
参数 描述 stmt SQL语句句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1 或者 0
dbi_stmt_exec
dbi_stmt_exec(stmt)
: 执行SQL语句。
-
参数列表
参数 描述 stmt SQL语句句柄 -
返回值
同dbi_exec。
- 例子
// 每次取一条记录,如果设置@@vec输出到数组会追加到结果变量中。
[ec, stmt] := dbi_stmt(db, "select name, first_appeared from lang", @@vec(x), @@vec(y), @limit(1));
while True do
begin
[ec, done] := dbi_stmt_done(stmt);
if ec or done then break;
dbi_stmt_exec(stmt);
println("x={},y={}", x, y);
end;
dbi_stmt_close(stmt);
打印:
x=array("C"),y=array(1972)
x=array("C","Fortran"),y=array(1972,1957)
x=array("C","Fortran","Python"),y=array(1972,1957,1991)
x=array("C","Fortran","Python","TSL"),y=array(1972,1957,1991,2002)
x=array("C","Fortran","Python","TSL","Go"),y=array(1972,1957,1991,2002,2009)
// 每次取一条记录,使用@@每次只返回当前取到的数据。
[ec, stmt] := dbi_stmt(db, "select name, first_appeared from lang", @@x, @@y, @limit(1));
while True do
begin
[ec, done] := dbi_stmt_done(stmt);
if ec or done then break;
dbi_stmt_exec(stmt);
println("x={},y={}", x, y);
end;
dbi_stmt_close(stmt);
打印:
x=C,y=1972
x=Fortran,y=1957
x=Python,y=1991
x=TSL,y=2002
x=Go,y=2009
dbi_stmt_close
dbi_stmt_close(stmt)
: 关闭SQL语句句柄。
-
参数列表
参数 描述 stmt SQL语句句柄 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 1
dbi_copy
dbi_copy(db, table, data)
: 拷贝数据到数据库中。
-
参数列表
参数 描述 db 数据库会话句柄 table 表名 data 数据, array类型 -
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 拷贝的数据条数 -
例子
[ec, db] := dbi_session("sqlite://:memory:");
[ec, rs] := dbi_exec(db, "create table lang (name, first_appeared)");
[ec, rs] := dbi_copy(db
, "lang"
, array(("name":"Fortran", "first_appeared":1957),
("name":"Python", "first_appeared":1991),
("name":"TSL", "first_appeared":2002),
("name":"Go", "first_appeared":2009))
);
[ec, rs] := dbi_exec(db, "select * from lang");
println("ec={}, rs={}", ec, rs);
dbi_close(db);
魔法参数
-
@merge(1)
: 如果记录的key有冲突,自动覆盖原有记录。 -
@create_table(1)
: 如果表不存在,根据数据自动创建表。 -
@date(...)
: 自动创建表的时候指定日期时间字段名。
data := array(
("VER":3383706156L,"UDATE":40006.50626157408,"NAME":"代码","UID":"system","TYPE":16385,"INFOKEY":"b4fac2eb-73797374656d-16385","PRIORITY":"","COMMENT":"","DATA":binary("系统排序"))
,("VER":3383706156L,"UDATE":40006.50626157408,"NAME":"成交金额","UID":"system","TYPE":16385,"INFOKEY":"b3c9bdbbbdf0b6ee-73797374656d-16385","PRIORITY":"","COMMENT":"","DATA":binary("系统排序"))
);
[err, db] := dbi_session("sqlite://:memory:");
[err, rs] := dbi_copy(db, "infodata", data, @create_table(1), @date("UDATE"), @merge(1));
[err, rs] := dbi_exec(db, "select * from infodata");
将会自动创建infodata表并插入数据。
数据组织形式说明
支持两种格式数组:
- 行格式数组,每行都包含键值数组,例如
array(("f1":1,"f2":2),("f1":3,"f2":4))
。 - 列格式数组,列名对应值数组,例如
array("f1":array(1,2), "f2": array(3,4))
。
用列格式数组可以加速入库操作(类似ArrayDML)。
dbi_copy_async
dbi_copy_async(db, table, data)
: 异步拷贝数据到数据库中,返回结果句柄,可以用dbi_wait来等待任务结束。通过同时调用多个dbi_copy_async可以实现并发入库的操作。
-
参数列表
参数 描述 db 数据库会话句柄 table 表名 data 数据, array类型 具体参数说明请参见
dbi_copy
。注意:做并发操作时,每个并发操作的db数据库会话句柄参数需要是独立的。
-
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 结果句柄 -
例子
同时并发5个入库操作:
[ec, wait1] := dbi_copy_async(mydb(), "mytable", data1);
[ec, wait2] := dbi_copy_async(mydb(), "mytable", data2);
[ec, wait3] := dbi_copy_async(mydb(), "mytable", data3);
[ec, wait4] := dbi_copy_async(mydb(), "mytable", data4);
[ec, wait5] := dbi_copy_async(mydb(), "mytable", data5);
dbi_wait(array(wait1, wait2, wait3, wait4, wait5));
function mydb();
begin
if [ec, db] := dbi_session("sqlite://test.db") then raise db;
return db;
end;
dbi_meta
dbi_meta(db, type, name)
: 获取数据库的元信息(目前暂时只支持ODBC的连接)。
-
参数列表
参数 描述 db 数据库会话句柄 type 类型,字符串类型 name 名称,字符串类型, 对于 "tables"
和"procs"
是可选参数type的值范围: |值|描述| |:--|:--| |table|数据库表| |proc|存储过程| |pk|主键| |fk|外键| |tables|所有表| |procs|所有存储过程|
-
返回值
数组类型,如果发生错误:
下标 值 0 错误代码 1 错误信息 没有错误:
下标 值 0 0 1 返回的数据,array类型 -
例子
返回的数据具体内容
-
"table"
下标 值 TABLE_CAT 目录名称 TABLE_SCHEM 架构名称 TABLE_NAME 表名 COLUMN_NAME 列名称 DATA_TYPE SQL数据类型 TYPE_NAME 数据源依赖数据类型名称 COLUMN_SIZE 列的最大长度(以字符为单位) BUFFER_LENGTH 数据长度(以字节为单位) DECIMAL_DIGITS 小数点右侧的有效数字总数 NUM_PREC_RADIX NULLABLE REMARKS 列的说明 COLUMN_DEF 列的默认值 SQL_DATA_TYPE SQL数据类型 SQL_DATETIME_SUB 日期时间数据类型和间隔数据类型的子类型代码 CHAR_OCTET_LENGTH 字符或二进制数据类型列的最大长度(以字节为单位) ORDINAL_POSITION 表中列的序号位置 IS_NULLABLE 参见。
-
"proc"
下标 值 PROCEDURE_CAT 过程目录名称 PROCEDURE_SCHEM 过程架构名称 PROCEDURE_NAME 过程名 COLUMN_NAME 过程列名称 COLUMN_TYPE DATA_TYPE SQL数据类型 COLUMN_SIZE 列的最大长度(以字符为单位) BUFFER_LENGTH 数据长度(以字节为单位) DECIMAL_DIGITS 小数点右侧的有效数字总数 NUM_PREC_RADIX NULLABLE REMARKS 列的说明 COLUMN_DEF 列的默认值 SQL_DATA_TYPE SQL数据类型 SQL_DATETIME_SUB 日期时间数据类型和间隔数据类型的子类型代码 CHAR_OCTET_LENGTH 字符或二进制数据类型列的最大长度(以字节为单位) ORDINAL_POSITION 表中列的序号位置 IS_NULLABLE 参见。
-
"pk"
下标 值 TABLE_NAME 主键表名称 COLUMN_NAME 主键列名称 KEY_SEQ 键 (以 1) 开头的列序列号 -
"fk"
下标 值 TABLE_NAME 外键表名称 COLUMN_NAME 外键列名称 KEY_SEQ 键 (以 1) 开头的列序列号
范例
基本功能
[err, db] := dbi_session("sqlite://:memory:");
dbi_exec(db, "create table lang (name, first_appeared)");
dbi_exec(db, "insert into lang values (?, ?)", "C", 1972);
dbi_exec(db, "insert into lang values (?, ?)"
, array(("Fortran", 1957),
("Python", 1991),
("TSL", 2002),
("Go", 2009))
);
rs := dbi_exec(db, "select * from lang");
echo tostn(rs);
dbi_close(db);
配合client插件保存数据
[err, c] := client_session("tsl.tinysoft.com.cn", 443, "user", "password");
magic_defer(g1, @client_destroy(c));
[err, db] := dbi_session("mysql://host=;port=;user=;password=;db=;");
magic_defer(g2, @dbi_close(db));
createTables(db);
[err, bk] := client_call(c, @getbk("A股"));
for k, s in bk do
inserteod(db, c, s, 20210101T, 20211231T);
function createTables(db);
begin
return dbi_exec(db, "create table if not exists eod
(
seq bigint auto_increment primary key,
tradeday date not null,
code varchar(64) not null,
pre_close double default 0 null,
open double default 0 null,
high double default 0 null,
low double default 0 null,
close double default 0 null,
vol double default 0 null,
amount double default 0 null,
cjbs int default 0 null,
syl1 double default 0 null,
syl2 double default 0 null
)");
end;
function inserteod(db, c, stk, beginT, endT);
begin
// 假设有预定义好的get_data函数:
code := "Function get_data(beginT, endT, stk);
begin
return select ['date'],['StockID'],['yclose'],['open'],['high'],['low'],
['close'],['vol'],['amount'],['cjbs'],['syl1'],['syl2']
from markettable datekey beginT to endT of stock end;
end;";
[err, res] := client_call(c, @get_data(beginT, endT, stk));
return dbi_exec(db, "insert into eod
(tradeday,code,pre_close,open,high,low,close,vol,amount,cjbs,syl1,syl2)
values(?,?,?,?,?,?,?,?,?,?,?,?)",
res, @datefield("date"));
end;
如果取到的数组下标排列顺序和要插入的字段顺序一致,可以直接使用,只需要设置日期类型字段即可。
将来会考虑修改TSL语言解释器以做到不需要再特别关注日期时间类型,可以自动转换成数据库对应的类型。
Oracle存储过程例子
存储过程输入输出参数的例子:
[err,rs] := dbi_exec(db, "CREATE OR REPLACE
FUNCTION storedFunction(param1 IN OUT NUMBER, param2 IN OUT NUMBER) RETURN NUMBER IS
temp NUMBER := param1;
BEGIN param1 := param2; param2 := temp; RETURN(param1+param2);
END storedFunction;");
x:=1;
y:=2;
[err, _] := dbi_exec(db, "{? = call storedFunction(?, ?)}", @i32(result) -> "out", @i32(x) -> "io", @i32(y) -> "io");
println("result={},x={},y={}", result, x, y);
打印:
result=3,x=2,y=1
存储过程返回结果是记录集的例子:
[err, rs] := dbi_exec(db, "CREATE TABLE Person (Name VARCHAR(30), Address VARCHAR(100), Age INTEGER)");
[err, rs] := dbi_exec(db, "INSERT INTO Person VALUES(?,?,?)",
array((L"张三",L"深圳", 10),
(L"李四",L"深圳", 11),
(L"王五",L"深圳", 12))
);
[err, rs] := dbi_exec(db, "CREATE OR REPLACE
FUNCTION storedCursorFunction(ageLimit IN NUMBER) RETURN SYS_REFCURSOR IS
ret SYS_REFCURSOR;
BEGIN
OPEN ret FOR
SELECT * FROM Person WHERE Age < ageLimit;
RETURN ret;
END storedCursorFunction;");
age:=13;
[err, _] := dbi_exec(db, "{call storedCursorFunction(?)}",
@i32(age), @@wstrvec(names), @@wstrvec(addresses), @@i32vec(ages));
println("{},\n{},\n{}", names, addresses, ages);
打印:
array(L"张三",L"李四",L"王五"),
array(L"深圳",L"深圳",L"深圳"),
array(10,11,12)
存储过程返回结果集可以用变量来接收。
当然,也可以用返回结果集:
[err, rs] := dbi_exec(db, "{call storedCursorFunction(?)}", @age);
println("err={},rs={}", err, rs);
打印:
err=0,rs=array(("NAME":"张三","ADDRESS":"深圳","AGE":10),("NAME":"李四","ADDRESS":"深圳","AGE":11),("NAME":"王五","ADDRESS":"深圳","AGE":12))
存储过程输出变量是结果集(例如oracle的sys_refcursor)的例子:
// oracle数据库
cf_proc := "create or replace procedure cf_test
(
out_errcode out number,
out_errmsg out varchar2,
out_cur_result out sys_refcursor,
out_cur_result2 out sys_refcursor,
in_qry_user_id in varchar2
)
As
v_errcode number(10); --错误代码
v_errmsg varchar2(255); --错误消息
v_user_name varchar2(32); --用户名称
v_user_role_set number(10); --用户角色集合
v_user_status varchar2(1); --用户状态
v_pwd_reset_flag varchar2(1); --密码重置标志
begin
--返回值
out_errcode := 0;
out_errmsg := '查询系统用户信息成功!';
--变量初始
v_errcode := 0;
v_errmsg := '';
--数据结果集
open out_cur_result for
select 'test' as USER_ID, 'testname' as USER_NAME from dual;
open out_cur_result2 for
select 'test' as USER_ID, 'testname' as USER_NAME from dual;
exception
when others then
rollback;
out_errcode := -9999;
out_errmsg := '执行失败!'|| sqlerrm;
return;
end;";
[err, rs] := dbi_exec(db, cf_proc);
in_qry_user_id:="1";
// 通过@result魔法参数接收输出的sys_refcursor
[err, rs] := dbi_exec(db, "{call cf_test(:out_errcode, :out_errmsg, :in_qry_user_id)}"
, @i32(errcode) -> ":out_errcode,out"
, @str(errmsg) -> ":out_errmsg,out"
, @in_qry_user_id -> ":in_qry_user_id,in"
, @result(cursor)
, @result(cursor2)
);
// errcode = 0, errmsg = "查询系统用户信息成功!"
// cursor = array(("USER_ID":"test","USER_NAME":"testname"))
// cursor2 = array(("USER_ID":"test","USER_NAME":"testname"))
// 也通过返回的结果集来接收,返回的变量中包含多个结果集:
[err, rs] := dbi_exec(db, "{call cf_test(:out_errcode, :out_errmsg, :in_qry_user_id)}"
, @i32(errcode) -> ":out_errcode,out"
, @str(errmsg) -> ":out_errmsg,out"
, @in_qry_user_id -> ":in_qry_user_id,in"
);
// rs 的值是:array((("USER_ID":"test","USER_NAME":"testname")),(("USER_ID":"test","USER_NAME":"testname")))
// errcode = 0, errmsg = "查询系统用户信息成功!"
附录
URL中数据库协议定义
URL协议 | 数据库 |
---|---|
sqlite:// | sqlite数据库 |
mysql:// | 使用MySQL数据库协议 |
postgresql:// | 使用postgresql数据库协议 |
odbc:// | 使用ODBC驱动连接数据库 |
mysql相关的配置参数
参数名称 | 含义 | 缺省值 |
---|---|---|
host | 主机名 | "localhost" |
port | 端口 | 3306 |
user | 用户名 | "" |
password | 密码 | "" |
db | 数据库名 | "" |
compress | 压缩 | "" |
auto-reconnect | 自动重连 | "" |
secure-auth | "" | |
character-set | 字符集 | "utf8" |
reset | "" | |
fail-readonly | "" | |
multi-statements | 支持多语句段 | false |
postgresql相关配置参数
参数名称 | 含义 | 缺省值 |
---|---|---|
host | 要链接的主机名。如果主机名以斜杠开头,则它声明使用Unix域套接字通讯而不是TCP/IP通讯;该值就是套接字文件所存储的目录。如果没有声明host,那么默认是与位于/tmp目录(或者安装GaussDB的时候声明的套接字目录)里面的Unix-域套接字链接。在没有Unix域套接字的机器上,默认与localhost链接。 | |
port | 主机服务器的端口号,或者在Unix域套接字链接时的套接字扩展文件名。 | |
user | 要链接的用户名,缺省是与运行该应用的用户操作系统名同名的用户。 | |
password | 数据库名,缺省和用户名相同。 | |
dbname | 如果服务器要求口令认证,所用的口令。 | |
connect_timeout | 链接的最大等待时间,以秒计(用十进制整数字符串书写),0或者不声明表示无穷。不建议把链接超时的值设置得小于2秒。 | |
hostaddr | 与之链接的主机的IP地址,是标准的IPv4地址格式,比如,172.28.40.9。如果机器支持IPv6,那么也可以使用IPv6的地址。 | |
client_encoding | 为这个链接设置client_encoding配置参数。除了对应的服务器选项接受的值,可以使用auto从客户端中的当前环境中确定正确的编码(Unix系统上是LC_CTYPE环境变量)。 | |
options | 添加命令行选项以在运行时发送到服务器。 | |
application_name | 为application_name配置参数指定一个值,表明当前用户身份。 | |
keepalives | 控制客户端侧的TCP保持激活是否使用。缺省值是1,意思为打开,但是如果不想要保持激活,可以更改为0,意思为关闭。通过Unix域套接字做的链接忽略这个参数。 | |
keepalives_idle | 在TCP应该发送一个保持激活的信息给服务器之后,控制不活动的秒数。0值表示使用系统缺省。通过Unix域套接字做的链接或者如果禁用了保持激活则忽略这个参数。 | |
keepalives_interval | 在TCP保持激活信息没有被应该传播的服务器承认之后,控制秒数。0值表示使用系统缺省。通过Unix域套接字做的链接或者如果禁用了保持激活则忽略这个参数。 | |
keepalives_count | 添加命令行选项以在运行时发送到服务器。例如,设置为-c comm_debug_mode=off设置guc参数comm_debug_mode参数的会话的值为off。 | |
ssl_mode | 启用SSL加密的方式:disable:不使用SSL安全连接。allow:如果数据库服务器要求使用,则可以使用SSL安全加密连接,但不验证数据库服务器的真实性。prefer:如果数据库支持,那么首选使用SSL安全加密连接,但不验证数据库服务器的真实性。require:必须使用SSL安全连接,但是只做了数据加密,而并不验证数据库服务器的真实性。verify-ca:必须使用SSL安全连接,当前windows odbc不支持cert方式认证。verify-full:必须使用SSL安全连接,当前windows odbc不支持cert方式认证。 | |
sslcompression | 如果设置为1(默认),SSL连接之上传送的数据将被压缩(这要求OpenSSL版本为0.9.8或更高)。如果设置为0,压缩将被禁用(这要求OpenSSL版本为1.0.0或更高)。 | |
sslcert | 这个参数指定客户端SSL证书的文件名,它替换默认的~/.postgresql/postgresql.crt。如果没有建立SSL连接,这个参数会被忽略。 | |
sslkey | 这个参数指定用于客户端证书的密钥位置。它能指定一个会被用来替代默认的~/.postgresql/postgresql.key的文件名,或者它能够指定一个从外部“引擎”(引擎是OpenSSL的可载入模块)得到的密钥。一个外部引擎说明应该由一个冒号分隔的引擎名称以及一个引擎相关的关键标识符组成。如果没有建立SSL连接,这个参数会被忽略。 | |
sslrootcert | 这个参数指定一个包含SSL证书机构(CA)证书的文件名称。如果该文件存在,服务器的证书将被验证是由这些机构之一签发。默认值是~/.postgresql/root.crt。 | |
sslcrl | 这个参数指定SSL证书撤销列表(CRL)的文件名。列在这个文件中的证书如果存在,在尝试认证该服务器证书时会被拒绝。默认值是~/.postgresql/root.crl。 | |
requirepeer | 这个参数指定服务器的操作系统用户,例如requirepeer=postgres。当建立一个Unix域套接字连接时,如果设置了这个参数,客户端在连接开始时检查服务器进程是否运行在指定的用户名之下。如果发现不是,该连接会被一个错误中断。这个参数能被用来提供与TCP/IP连接上SSL证书相似的服务器认证(注意,如果Unix域套接字在/tmp或另一个公共可写的位置,任何用户能启动一个在那里侦听的服务器。使用这个参数来保证你连接的是一个由可信用户运行的服务器)。这个选项只在实现了peer认证方法的平台上受支持。 | |
krbsrvname | 当用GSSAPI认证时,要使用的Kerberos服务名。为了让Kerberos认证成功,这必须匹配在服务器配置中指定的服务名。 | |
gsslib | 用于GSSAPI认证的GSS库。只用在Windows上。设置为gssapi可强制libpq用GSSAPI库来代替默认的SSPI进行认证。 | |
service | 用于附加参数的服务名。 |
特别备注:需要中文支持请配置 client_encoding=GBK
。
ODBC相关配置参数
最简单的方法是配置一个DSN
,然后在连接串中指定这个DSN
,例如:
如果不配置DSN
,相关的具体配置参数请参考各数据库的ODBC驱动的配置:
ORACLE:
可以设置环境变量NLS_LANG来指定中文字符集,例如:
export NLS_LANG=.ZHS16GBK
FreeTDS:
可以在连接串中指定ClientCharset,例如:
"odbc://DRIVER=FreeTDS;UID=;PWD=;DATABASE=;SERVER=;Port=;ClientCharset=GBK;"
gaussdb相关配置参数
请参见postgresql的相关配置参数。
注意:只在Linux下提供该接口,Windows和macOS请使用postgresq协议或者ODBC来连接gaussdb。
魔法参数支持的类型
i8 8位整数类型
i16 16位整数类型
i32 32位整数类型
i64 64位整数类型
u8 8位无符号整数类型
u16 16位无符号整数类型
u32 32位无符号整数类型
u64 64位无符号整数类型
f32 32位浮点数类型
f64 64位浮点数类型
str 字符串
wstr 宽字符串
blob blob类型,会转成TSL的binary类型
date 日期类型
time 时间类型,会转成TSL的字符串,例如"01:02:03"
datetime 日期时间类型
i8vec 8位整数类型数组
i16vec 16位整数类型数组
i32vec 32位整数类型数组
i64vec 64位整数类型数组
u8vec 8位无符号整数类型数组
u16vec 16位无符号整数类型数组
u32vec 32位无符号整数类型数组
u64vec 64位无符号整数类型数组
f32vec 32位浮点数数组
f64vec 64位浮点数数组
strvec 字符串数组
wstrvec 宽字符串数组
blocvec blob数组
datevec 日期数组
timevec 时间数组
datetimevec 日期时间数组
如何获取返回记录集的字段信息?
使用@meta魔法参数。例如:
[ec, res] := dbi_exec(db, "select * from infodata", @limit(1), @meta(meta));
println("{}", meta);
打印:
array(("ID","u32"),("UDATE","datetime"),("VER","i64"),("NAME","str"),("UID","str"),("TYPE","u32"),("INFOKEY","str"),("PRIORITY","str"),("COMMENT","str"),("DATA","blob"))
meta变量的内容是字段名和类型结对的数组。
字段类型有:
bool 布尔类型
i8 8位整数类型
i16 16位整数类型
i32 32位整数类型
i64 64位整数类型
u8 8位无符号整数类型
u16 16位无符号整数类型
u32 32位无符号整数类型
u64 64位无符号整数类型
f32 32位浮点数类型
f64 64位浮点数类型
str 字符串
wstr 宽字符串
clob clob类型
blob blob类型
date 日期类型
time 时间类型
datetime 日期时间类型
uuid uuid类型
unknown 未知类型
如何把结果集的字段名变成大写?
使用@upper魔法参数。例如:
如何把结果集的NULL转成0或者‘’?
使用@null魔法参数。例如:
如何把结果集的字符串类型转成unicode编码?
使用@unicode魔法参数。例如:
如何把结果集的字段名和字符串类型做编码转换?
使用@encoding魔法参数。例如: