首页 > 数据库 >lightdb plpgsql函数in/inout参数示例

lightdb plpgsql函数in/inout参数示例

时间:2023-07-15 17:55:22浏览次数:44  
标签:square postgres zjh int 示例 inout str plpgsql lightdb

  lightdb支持oracle pl/sql以及开源postgresql Plpgsql两种过程性(增强)语言。本文讲解pgpgsql函数出参的典型用法及限制。

  注:匿名块实际上走的是plorasql,而非plpgsql,即使调用的是plpgsql过程。

  本文我们假设对于函数、存储过程的调用是进行逻辑处理,而不是返回结果集或游标,这通常是两种上下文场景。

1、如果有多个出参,则不能带return预定义类型或必须return record

zjh@postgres=# CREATE OR REPLACE FUNCTION public.f_square(inout v_a int, inout v_str varchar) returns int
    LANGUAGE 'plpgsql'
AS $BODY$
declare  
    lv_result int; 
begin    
    v_a := v_a * v_a;
v_str := v_str || '..ret';
end                  
$BODY$;
CREATE FUNCTION
zjh@postgres=# select f_square(10,'a');                                                                 
ERROR:  invalid input syntax for type integer: "(100,a..ret)"
CONTEXT:  PL/pgSQL function f_square(integer,character varying) while casting return value to function's return type
除了事务外,该限制和oracle存在明显的不兼容性。
zjh@postgres=# CREATE OR REPLACE FUNCTION public.f_square(inout v_a int) returns int
    LANGUAGE 'plpgsql'
AS $BODY$
declare  
    lv_result int; 
begin    
    v_a := v_a * v_a;
-- v_str := v_str || '..ret';
end                  
$BODY$;
CREATE FUNCTION
zjh@postgres=# 
zjh@postgres=# 
zjh@postgres=# select f_square(10);
 f_square 
----------
      100
(1 row)
zjh@postgres=# CREATE OR REPLACE FUNCTION public.f_square(inout v_a int, inout v_str varchar) returns record
    LANGUAGE 'plpgsql'
AS $BODY$
declare  
    lv_result int; 
begin    
    v_a := v_a * v_a;
v_str := v_str || '..ret';
end                  
$BODY$;
CREATE FUNCTION
zjh@postgres=# select f_square(10,'a');
   f_square   
--------------
 (100,a..ret)
(1 row)

2、plpgsql匿名块或过程中使用perform调用函数未修改出参值

zjh@postgres=# CREATE OR REPLACE FUNCTION public.f_square(inout v_a int, inout v_str varchar) returns record
    LANGUAGE 'plpgsql'
AS $BODY$
declare  
    lv_result int; 
begin    
    v_a := v_a * v_a;
    v_str := v_str || '..ret';
raise notice 'v_str=%',v_str; end $BODY$; CREATE FUNCTION zjh@postgres=# declare v_a int :=10; v_str varchar(100) := 'b'; begin perform f_square(v_a,v_str);
raise notice 'v_a=%,v_str=%',v_a,v_str; end; / NOTICE: v_str=b..ret NOTICE: v_a=10,v_str=b DO
zjh@postgres=# declare
  v_a int :=10;
  v_str varchar(100) := 'b';
begin
  select * into v_a,v_str from f_square(v_a,v_str);
raise notice 'v_a=%,v_str=%',v_a,v_str; end; / NOTICE: v_str=b..ret NOTICE: v_a=100,v_str=b..ret DO

  为什么通过perform调用不生效,直接select 函数(v1,v2),select into o1,o2 from 函数(v1,v2)能返回呢?因为本质上in/out/inout都是传值处理,所有的出参事实上都是通过return scalar或return record实现。exec_stmt_execsql处理完了into才丢弃SPI_tuptable,exec_stmt_perform则立刻丢弃。

  postgresql函数OUT和INOUT使用方法 https://blog.csdn.net/llj318/article/details/122387617

实现oracle的v_ret := fnc(in a, out b,inout c);调用兼容支持

declare                                                                                      
  v_a int :=10;
  v_str varchar(100) := 'b';
  v_ret int;
begin
  v_ret := f_square(v_a,v_str); -- 因为pg不支持带出参返回非record的函数定义,所以自然也就不支持oracle的这种调用。
  raise notice 'v_a=%,v_str=%',v_a,v_str;
end;

其实只要实现PLpgSQL_execstate.retval即可(因为record存储在SPITupleTable *eval_tuptable成员中,所以不存在破坏)。
typedef struct PLpgSQL_execstate
{
    PLpgSQL_function *func;        /* function being executed */

    TriggerData *trigdata;        /* if regular trigger, data about firing */
    EventTriggerData *evtrigdata;    /* if event trigger, data about firing */

    Datum        retval;
    bool        retisnull;
    Oid            rettype;        /* type of current retval */
    /* temporary state for results from evaluation of query or expr */
    SPITupleTable *eval_tuptable;
    uint64        eval_processed;

lightdb将在23.3版本支持该兼容性。

调用存储过程获取出参

zjh@postgres=# create or replace procedure proce_inouttest(in nD1 bigint, inout szD varchar, out nD2 integer)
zjh@postgres-# as 
zjh@postgres$# $$
zjh@postgres$# begin
zjh@postgres$#     nD1:=99;
zjh@postgres$#     szD:='qaz';
zjh@postgres$#     nD2:=88;
zjh@postgres$# end;
zjh@postgres$# $$
zjh@postgres-# language plpgsql;

zjh@postgres=# call proce_inouttest(1,'3',1);
 szd | nd2 
-----+-----
 qaz |  88
(1 row)

CALL executes a procedure.

If the procedure has any output parameters, then a result row will be returned, containing the values of those parameters.

zjh@postgres=# DO $$
zjh@postgres$# DECLARE myvar int := 5;
zjh@postgres$# BEGIN
zjh@postgres$#   CALL triple(myvar);
zjh@postgres$#   RAISE NOTICE 'myvar = %', myvar;  -- prints 15
zjh@postgres$# END;
zjh@postgres$# $$;
NOTICE:  myvar = 15

  在plpgsql中,存储过程是支持出参赋值的。参见http://www.light-pg.com/docs/lightdb/13.8-22.3/plpgsql-control-structures.html#PLPGSQL-STATEMENTS-CALLING-PROCEDURE。在请求返回的时候,OUT重新赋值回去的。这一点存储过程和函数的行为不一样。

libpq调用存储过程

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include "libpq-fe.h"
 
/* for ntohl/htonl */
#include <netinet/in.h>
#include <arpa/inet.h>
 
 
static void
exit_nicely(PGconn *conn)
{
    PQfinish(conn);
    exit(1);
}
 
void test_call_sp()
{
    const char *conninfo;
    PGconn       *conn;
    PGresult   *res;
    const char *paramValues[3];
    int            paramLengths[3];
    int            paramFormats[3];
    uint32_t    binaryIntVal;
    uint64_t    bigbinaryIntVal;
    int            nFields;
    int            i,
                j;
 
 
    conninfo = "postgresql:///postgres?host=localhost&port=18888";
    /* Make a connection to the database */
    conn = PQconnectdb(conninfo);
 
    /* Check to see that the backend connection was successfully made */
    if (PQstatus(conn) != CONNECTION_OK)
    {
        fprintf(stderr, "Connection to database failed: %s",
                PQerrorMessage(conn));
        exit_nicely(conn);
    }
 
    /* Convert integer value "2" to network byte order */
    binaryIntVal = htonl((uint32_t) 2);
    bigbinaryIntVal = htonl((uint64_t) 2);
 
    /* Set up parameter arrays for PQexecParams */
    paramValues[0] = (char *) &bigbinaryIntVal;
    paramLengths[0] = sizeof(bigbinaryIntVal);
    paramFormats[0] = 1;        /* binary */
 
    paramValues[1] = "2";
    paramLengths[1] = 1;
    paramFormats[1] = 0;        /* test */
 
    paramValues[2] = (char *) &binaryIntVal;
    paramLengths[2] = sizeof(binaryIntVal);
    paramFormats[2] = 1;        /* binary */
 
    res = PQexecParams(conn,
                       "call proce_inouttest($1,$2,$3)",
                       3,        /* one param */
                       NULL,    /* let the backend deduce param type */
                       paramValues,
                       paramLengths,
                       paramFormats,
                       0);        /* ask for text results */
 
    if (PQresultStatus(res) != PGRES_TUPLES_OK)
    {
        fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
        PQclear(res);
        exit_nicely(conn);
    }
    nFields = PQnfields(res);
    for (i = 0; i < nFields; i++)
        printf("%-15s", PQfname(res, i));
    printf("\n\n");
 
    /* next, print out the instances */
    for (i = 0; i < PQntuples(res); i++)
    {
        for (j = 0; j < nFields; j++)
            printf("%-15s", PQgetvalue(res, i, j));
        printf("\n");
    }
 
    PQclear(res);
 
    /* close the connection to the database and cleanup */
    PQfinish(conn);
 
    return 0;
}
create or replace procedure proce_inouttest(in nD1 bigint, inout szD varchar, out nD2 integer)
as 
$$
begin
    nD1:=99;
    szD:='qaz';
    nD2:=88;
end;
$$
language plpgsql;

SQL(注意不是psql)对于存储过程out/inout参数返回值的处理,与一般的select查询返回值处理一样,使用PQnfields、PQntuples、PQgetvalue等函数对结果PGresult结构体进行处理。

输出如下:

szd nd2

qaz 88      --名字为啥是qaz?

其它

  注:postgresql不支持oracle的select bulk collect和fetch bulk collect,但是如果返回多行,没有指定strict的情况下,只返回第1行,但是不会报错。

通过数组也可以支持该特性。

标签:square,postgres,zjh,int,示例,inout,str,plpgsql,lightdb
From: https://www.cnblogs.com/lightdb/p/17556599.html

相关文章

  • API接口技术开发分享案例,拼多多获得搜索词推荐,接口支持高并发,PHP语言演示案例,支持对语
    ​接口获取数据响应参数接入pinduoduo.item_search_suggest-获得搜索词推荐 公共参数名称类型必须描述keyString是调用key(必须以GET方式拼接在URL中)secretString是调用密钥api_name......
  • 对 Golang 中 reflect 反射包的示例
    引子//由于反射是基于类型系统(typesystem)的,所以先简单了解下类型系统typeMyIntintREADMEvariintvarjMyInt//上面的i是int类型,j是MyInt类型,i和j是不同的静态类型,尽管他们都有相同的相关类型(这里是int)//它们不能互相赋值,除非通过强制的类型转换......
  • diff 与 patch 命令的示例
    diff#diff以逐行的方式,比较文本文件的异同处,特别是比较两个版本不同的文件,如果指定要比较目录,则比较目录中相同文件名的文件,但不会比较其中子目录#diff的输出描述两个文件的不同,告诉用户怎样改变第一个文件之后与第二个文件保持一致(它是以"行"为单位进行比较的)##-r对比......
  • LightDB分布式高可用+负载均衡部署
    软件版本LightDB13.8-22.3安装分布式多机单实例模式根据LightDB安装文档6.3节,安装分布式多机单实例模式。安装后,确认环境变量$LTDATA,$LTHOME正确配置,工作节点正确添加。本文假设CN(协调节点,primary)安装在机器186,两个DN(数据节点)安装在机器192,193,端口均为15858。本文之......
  • 使用Patroni管理LightDB高可用
    使用Patroni管理LightDB高可用测试环境CPU:海光x86OS:KylinAdvancedServerV10SP1LightDB:13.8-22.3Patroni:2.1.3etcd:3.5.4安装部署etcd集群需要3台机器。centos/RHEL等可以从epel获取etcd。麒麟ky10,ky10sp1没有etcd包,可以使用lightdb预编译的etcd-3.5.4。......
  • 设计模式-桥接模式在Java中的使用示例
    场景桥接模式情境引入假如我们需要大中小3种型号的画笔,能够绘制12种不同的颜色,如果使用蜡笔,需要准备3×12=36支,但如果使用毛笔的话,只需要提供3种型号的毛笔,外加12个颜料盒即可,涉及到的对象个数仅为3+12=15,远小于36,却能实现与36支蜡笔同样的功能。如果增加一种新型号的画......
  • mongodb 入门 和 php示例
    内容太多了,感觉不好写,就写点入门的吧,其他参考参考_MonogDB中文网(mongodb.net.cn)虽然内容是机器翻译的,但也还好,基本能看. 相关概念: database数据库collection集合,相当于数据库表document文档,相当于数据记录行 dockerrun-d--namemongo-p27017:27......
  • 设计模式-建造者模式在Java中使用示例
    场景建造者模式复杂对象的组装与创建没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。建造者模式又称为生成器模式,它是一种较为复杂、使用......
  • rabbitmq php 代码示例
    交换机类型direct:直连交换机,根据路由键投递到与绑定键匹配的队列。fanout:扇形交换机,采用广播模式,投递到所有与之绑定的队列。topic :主题交换机,对路由键与绑定键进行模式匹配后再投递到相应的队列。headers:头交换机,不处理路由键,而是根据发送的消息内容中的heade......
  • C# 选择文件选择设置类型示例
     例子:OpenFileDialogdialog=newOpenFileDialog();dialog.Multiselect=false;//该值确定是否可以选择多个文件dialog.Title="请选择文件";dialog.Filter="图像文件(*.jpg;*.png;*.bmp)|*.jpg;*.png;*.bmp;*.jpg......