华为云用户手册

  • 选择分布列 Hash分布表的分布列选取至关重要,需要满足以下原则: 列值应比较离散,以便数据能够均匀分布到各个DN。例如,考虑选择表的主键为分布列,如在人员信息表中选择身份证号码为分布列。 在满足第一条原则的情况下尽量不要选取存在常量filter的列。例如,表dwcjk相关的部分查询中出现dwcjk的列zqdh存在常量的约束(例如zqdh=’000001’),那么就应当尽量不用zqdh做分布列。 在满足前两条原则的情况,考虑选择查询中的连接条件为分布列,以便Join任务能够下推到DN中执行,且减少DN之间的通信数据量。 对于Hash分表策略,如果分布列选择不当,可能导致数据倾斜,查询时出现部分DN的I/O短板,从而影响整体查询性能。因此在采用Hash分表策略之后需对表的数据进行数据倾斜性检查,以确保数据在各个DN上是均匀分布的。可以使用以下SQL检查数据倾斜性 12345 select xc_node_id, count(1) from tablename group by xc_node_id order by xc_node_id desc; 其中xc_node_id对应DN,一般来说,不同DN的数据量相差5%以上即可视为倾斜,如果相差10%以上就必须要调整分布列。 GaussDB 支持多分布列特性,可以更好地满足数据分布的均匀性要求。 Range/List分布表的分布列由用户根据实际需要进行选择。除了需要选择合适的分布列,还需要注意分布规则对数据分布的影响。 父主题: 审视和修改表定义
  • 使用分区表 分区表是把逻辑上的一张表根据某种方案分成几张物理块进行存储。这张逻辑上的表称之为分区表,物理块称之为分区。分区表是一张逻辑表,不存储数据,数据实际是存储在分区上的。分区表和普通表相比具有以下优点: 改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索效率。 增强可用性:如果分区表的某个分区出现故障,表在其他分区的数据仍然可用。 方便维护:如果分区表的某个分区出现故障,需要修复数据,只修复该分区即可。 GaussDB支持的分区表为范围分区表,列表分区表,哈希分区表。 范围分区表:将数据基于范围映射到每一个分区。这个范围是由创建分区表时指定的分区键决定的。分区键经常采用日期,例如将销售数据按照月份进行分区。 列表分区表:将数据中包含的键值分别存储在不同的分区中,依次将数据映射到每一个分区,分区中包含的键值由创建分区表时指定。 哈希分区表:将数据根据内部哈希算法依次映射到每一个分区中,包含的分区个数由创建分区表时指定 父主题: 审视和修改表定义
  • 选择数据类型 高效数据类型,主要包括以下三方面: 尽量使用执行效率比较高的数据类型 一般来说整型数据运算(包括=、>、<、≧、≦、≠等常规的比较运算,以及group by)的效率比字符串、浮点数要高。比如某客户场景中对列存表进行点查询,filter条件在一个numeric列上,执行时间为10+s;修改numeric为int类型之后,执行时间缩短为1.8s左右。 尽量使用短字段的数据类型 长度较短的数据类型不仅可以减小数据文件的大小,提升I/O性能;同时也可以减小相关计算时的内存消耗,提升计算性能。比如对于整型数据,如果可以用smallint就尽量不用int,如果可以用int就尽量不用bigint。 使用一致的数据类型 表关联列尽量使用相同的数据类型。如果表关联列数据类型不同,数据库必须动态地转化为相同的数据类型进行比较,这种转换会带来一定的性能开销。 父主题: 审视和修改表定义
  • 选择分布方式 复制表(Replication)方式将表中的全量数据在集群的每一个DN实例上保留一份。主要适用于记录集较小的表。这种存储方式的优点是每个DN上都有该表的全量数据,在join操作中可以避免数据重分布操作,从而减小网络开销,同时减少了plan segment(每个plan segment都会起对应的线程);缺点是每个DN都保留了表的完整数据,造成数据的冗余。一般情况下只有较小的维度表才会定义为Replication表。 哈希(Hash)表将表中某一个或几个字段进行hash运算后,生成对应的hash值,根据DN实例与哈希值的映射关系获得该元组的目标存储位置。对于Hash分布表,在读/写数据时可以利用各个节点的IO资源,大大提升表的读/写速度。一般情况下大表定义为Hash表。 范围(Range)和列表(List)分布是由用户自定义的分布策略,根据分布列的取值落入满足一定范围或者具体值的对应目标DN,这两种分布方式便于用户灵活地进行数据管理,但对用户本身的数据抽象能力有一定的要求。 策略 描述 适用场景 Hash 表数据通过hash方式散列到集群中的所有DN实例上。 数据量较大的事实表。 Replication 集群中每一个DN实例上都有一份全量表数据。 小表、维度表。 Range 表数据对指定列按照范围进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 List 表数据对指定列按照具体值进行映射,分布到对应DN。 用户需要自定义分布规则的场景。 如图1所示,复制表如图中的表T1,哈希表如图中的表T2。 图1 复制表和哈希表 父主题: 审视和修改表定义
  • 选择存储模型 进行数据库设计时,表设计上的一些关键项将严重影响后续整库的查询性能。表设计对数据存储也有影响:好的表设计能够减少I/O操作及最小化内存使用,进而提升查询性能。 表的存储模型选择是表定义的第一步。客户业务属性是表的存储模型的决定性因素,依据下面表格选择适合当前业务的存储模型。 存储模型 适用场景 行存 点查询(返回记录少,基于索引的简单查询)。 增删改比较多的场景。 列存 统计分析类查询 (group , join多的场景)。 父主题: 审视和修改表定义
  • 调试 用户可以根据自己的需要,通过修改实例数据目录下的postgresql.conf文件中特定的配置参数来控制日志的输出,从而更好的了解数据库的运行状态。 可调整的配置参数请参见表1。 表1 配置参数 参数名称 描述 取值范围 备注 client_min_messages 配置发送到客户端信息的级别。 DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 LOG NOTICE WARNING ERROR FATAL PANIC 默认值:NOTICE 。 设置级别后,发送到客户端的信息包含所设级别及以下所有低级别会发送的信息。级别越低,发送的信息越少。 log_min_messages 配置写到服务器日志里信息的级别。 DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 INFO NOTICE WARNING ERROR LOG FATAL PANIC 默认值:WARNING。 指定某一级别后,写到日志的信息包含所有更高级别会输出的信息。级别越高,服务器日志的信息越少。 log_min_error_statement 配置写到服务器日志中错误SQL语句的级别。 DEBUG5 DEBUG4 DEBUG3 DEBUG2 DEBUG1 INFO NOTICE WARNING ERROR FATAL PANIC 缺省值:ERROR。 所有导致一个特定级别(或者更高级别)错误的SQL语句都将记录在服务器日志中。 只有系统管理员可以修改该参数。 log_min_duration_statement 配置语句执行持续的最短时间。如果某个语句的持续时间大于或者等于设置的毫秒数,则会在日志中记录该语句及其持续时间。打开这个选项可以方便地跟踪需要优化的查询。 INT类型。 默认值:-1。 单位:毫秒。 设置为-1表示关闭这个功能。 只有系统管理员可以修改该参数。 log_connections/log_disconnections 配置是否在每次会话连接或结束时向服务器日志里打印一条信息。 on:每次会话连接或结束时向日志里打印一条信息。 off:每次会话连接或结束时不向日志里打印信息。 默认值:off。 - log_duration 配置是否记录每个已完成语句的持续时间。 on:记录每个已完成语句的持续时间。 off:不记录已完成语句的持续时间。 默认值:off。 只有系统管理员可以修改该参数。 log_statement 配置日志中记录哪些SQL语句。 none:不记录任何SQL语句。 ddl:记录数据定义语句。 mod:记录数据定义语句和数据操作语句。 all :记录所有语句。 默认值: none。 只有系统管理员可以修改该参数。 log_hostname 配置是否记录主机名。 on:记录主机名。 off:不记录主机名。 默认值:off。 缺省时,连接日志只记录所连接主机的IP地址。打开这个选项会同时记录主机名。 该参数同时影响查看审计结果、GS_WLM_SESSION_HISTORY、PG_STAT_ACTIVITY和GUC参数log_line_prefix。 上表有关参数级别的说明请参见表2。 表2 日志级别参数说明 级别 说明 DEBUG[1-5] 提供开发人员使用的信息。5级为最高级别,依次类推,1级为最低级别。 INFO 提供用户隐含要求的信息。如在VACUUM VERBOSE过程中的信息。 NOTICE 提供可能对用户有用的信息。如长标识符的截断,作为主键一部分创建的索引。 WARNING 提供给用户的警告。如在事务块范围之外的COMMIT。 ERROR 报告导致当前命令退出的错误。 LOG 报告一些管理员感兴趣的信息。如检查点活跃性。 FATAL 报告导致当前会话终止的原因。 PANIC 报告导致所有会话退出的原因。 父主题: 应用程序开发教程
  • 审视和修改表定义概述 在分布式框架下,数据分布在各个DN上。一个或者几个DN的数据存在一块物理存储设备上,好的表定义至少需要达到以下几个目标: 表数据均匀分布在各个DN上,以防止单个DN对应的存储设备空间不足造成集群有效容量下降。选择合适分布列,避免数据分布倾斜可以实现该点。 表Scan压力均匀分散在各个DN上,以避免单DN的Scan压力过大,形成Scan的单节点瓶颈。分布列不选择基表上等值filter中的列可以实现该点。 减少扫描数据量。通过分区的剪枝机制可以实现该点。 尽量减少随机IO。通过聚簇/局部聚簇可以实现该点。 尽量避免数据shuffle,减小网络压力。通过选择join-condition或者group by列为分布列可以最大程度的实现这点。 从上述描述来看表定义中最重要的一点是分布列的选择。创建表定义一般遵循图1所示流程。表定义在数据库设计阶段创建,在SQL调优过程中进行审视和修改。 图1 表定义流程 父主题: 审视和修改表定义
  • 背景信息 ANALYZE语句可收集与数据库中表内容相关的统计信息,统计结果存储在系统表PG_STATISTIC中。查询优化器会使用这些统计数据,以生成最有效的执行计划。 建议在执行了大批量插入/删除操作后,例行对表或全库执行ANALYZE语句更新统计信息。目前默认收集统计信息的采样比例是30000行(即:guc参数default_statistics_target默认设置为100),如果表的总行数超过一定行数(大于1600000),建议设置guc参数default_statistics_target为-2,即按2%收集样本估算统计信息。 对于在批处理脚本或者存储过程中生成的中间表,也需要在完成数据生成之后显式的调用ANALYZE。 对于表中多个列有相关性且查询中有同时基于这些列的条件或分组操作的情况,可尝试收集多列统计信息,以便查询优化器可以更准确地估算行数,并生成更有效的执行计划。 若表上存在全局二级索引,则需要对基表执行ANALYZE之后再对全局二级索引执行ANALYZE。
  • 操作步骤 收集SQL中涉及到的所有表的统计信息。在数据库中,统计信息是规划器生成计划的源数据。没有收集统计信息或者统计信息陈旧往往会造成执行计划严重劣化,从而导致性能问题。从经验数据来看,10%左右性能问题是因为没有收集统计信息。具体请参见更新统计信息。 通过查看执行计划来查找原因。如果SQL长时间运行未结束,通过EXPLAIN命令查看执行计划,进行初步定位。如果SQL可以运行出来,则推荐使用EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看执行计划及实际运行情况,以便更精准地定位问题原因。有关执行计划的详细介绍请参见SQL执行计划介绍。 审视和修改表定义。 针对EXPLAIN或EXPLAIN PERFORMANCE信息,定位SQL慢的具体原因以及改进措施,具体参见典型SQL调优点。 通常情况下,有些SQL语句可以通过查询重写转换成等价的,或特定场景下等价的语句。重写后的语句比原语句更简单,且可以简化某些执行步骤达到提升性能的目的。查询重写方法在各个数据库中基本是通用的。经验总结:SQL语句改写规则介绍了几种常用的通过改写SQL进行调优的方法。
  • 调优手段之统计信息 GaussDB优化器是典型的基于代价的优化 (Cost-Based Optimization,简称CBO)。在这种优化器模型下,数据库根据表的元组数、字段宽度、NULL记录比率、distinct值、MCV值、HB值等表的特征值,以及一定的代价计算模型,计算出每一个执行步骤的不同执行方式的输出元组数和执行代价(cost),进而选出整体执行代价最小/首元组返回代价最小的执行方式进行执行。这些特征值就是统计信息。从上面描述可以看出统计信息是查询优化的核心输入,准确的统计信息将帮助规划器选择最合适的查询规划,一般来说我们通过analyze语法收集整个表或者表的若干个字段的统计信息,周期性地运行ANALYZE,或者在对表的大部分内容做了更改之后马上运行它是个好习惯。
  • 调优手段之GUC参数 查询优化的主要目的是为查询语句选择高效的执行方式。 如下SQL语句: 12 select count(1) from customer inner join store_sales on (ss_customer_sk = c_customer_sk); 在执行customer inner join store_sales的时候,GaussDB支持Nested Loop、Merge Join和Hash Join三种不同的Join方式。优化器会根据表customer和表store_sales的统计信息估算结果集的大小以及每种Join方式的执行代价,然后对比选出执行代价最小的执行计划。 正如前面所说,执行代价计算都是基于一定的模型和统计信息进行估算,当因为某些原因代价估算不能反映真实的cost的时候,我们就需要通过GUC参数设置的方式让执行计划倾向更优规划。
  • SQL调优指南 SQL调优的唯一目的是“资源利用最大化”,即CPU、内存、磁盘IO、网络IO四种资源利用最大化。所有调优手段都是围绕资源使用开展的。所谓资源利用最大化是指SQL语句尽量高效,节省资源开销,以最小的代价实现最大的效益。比如做典型点查询的时候,可以用seqscan+filter(即读取每一条元组和点查询条件进行匹配)实现,也可以通过indexscan实现,显然indexscan可以以更小的代价实现相同的效果。 根据硬件资源和客户的业务特征确定合理的集群部署方案和表定义是数据库在多数情况下满足性能要求的基础。下文的调优说明假设您已根据“软件安装”指引在安装过程中按照合理的集群方案完成了安装,且已经根据“开发设计建议”的指引进行了数据库设计。 Query执行流程 SQL执行计划介绍 调优流程 更新统计信息 审视和修改表定义 典型SQL调优点 经验总结:SQL语句改写规则 SQL调优关键参数调整 使用Plan Hint进行调优 检查隐式转换的性能问题 使用向量化执行引擎进行调优 使用SQL PATCH进行调优 实际调优案例
  • 执行计划显示信息 除了设置不同的执行计划显示格式外,还可以通过不同的EXPLAIN用法,显示不同详细程度的执行计划信息。常见有如下几种,关于更多用法请参见EXPLAIN语法说明。 EXPLAIN statement: 只生成执行计划,不实际执行。其中statement代表SQL语句。 EXPLAIN ANALYZE statement:生成执行计划,进行执行,并显示执行的概要信息。显示中加入了实际的运行时间统计,包括在每个规划节点内部花掉的总时间(以毫秒计)和它实际返回的行数。 EXPLAIN PERFORMANCE statement:生成执行计划,进行执行,并显示执行期间的全部信息。 为了测量运行时在执行计划中每个节点的开销,EXPLAIN ANALYZE或EXPLAIN PERFORMANCE会在当前查询执行上增加性能分析的开销。在一个查询上运行EXPLAIN ANALYZE或EXPLAIN PERFORMANCE有时会比普通查询明显的花费更多的时间。超支的数量依赖于查询的本质和使用的平台。 因此,当定位SQL运行慢问题时,如果SQL长时间运行未结束,建议通过EXPLAIN命令查看执行计划,进行初步定位。如果SQL可以运行出来,则推荐使用EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看执行计划及其实际的运行信息,以便更精准地定位问题原因。
  • type ColumnType type ColumnType如下表所示。 方法 描述 返回值 (ci *ColumnType)DatabaseTypeName() 返回列类型的数据库系统名称。返回空字符串表示该驱动类型名字并未被支持。 error (ci *ColumnType)DecimalSize() 返回小数类型的范围和精度。 返回值ok的值为false时,说明给定的类型不可用或者不支持。 precision, scale int64, ok bool (ci *ColumnType)Length() 返回数据列类型长度。返回值ok的值为false时,说明给定的类型不存在长度。 length int64, ok bool (ci *ColumnType)ScanType() 返回一种Go类型,该类型能够在Rows.scan进行扫描时使用。 reflect.Type (ci *ColumnType)Name() 返回数据列的名字。 string 父主题: Go接口参考
  • 参数说明 参数 参数说明 ctx 表示给定的上下文。 query 被执行的sql语句。 args 被执行sql语句需要绑定的参数。支持按位置绑定和按名称绑定,详情见如下示例。 opts 事务隔离级别和事务访问模式,其中事务隔离级别(opts.Isolation)支持范围为sql.LevelReadUncommitted,sql.LevelReadCommitted,sql.LevelRepeatableRead,sql.LevelSerializable。事务访问模式(opts.ReadOnly)支持范围为true(read only)和false(read write)。
  • 参数 表1 数据库连接参数 参数名称 参数说明 host 主机IP地址,也可通过环境变量${PGHOST}来指定。 port 主机服务器的端口号,也可通过环境变量${PGPORT}来指定。 dbname 数据库名,也可通过环境变量${PGDATABASE}来指定。 user 要连接的用户名,也可通过环境变量${PGUSER}来指定。 password 要连接用户对应的连接密码。 connect_timeout 用于连接服务器操作的超时值,也可通过环境变量${PGCONNECT_TIMEOUT}来指定。 sslmode 启用SSL加密的方式,也可通过环境变量${PGSSLMODE}来指定。 参数取值范围: disable:不使用ssl安全连接。 allow:如果数据库服务器要求使用,则可以使用SSL安全加密连接,但不验证数据库服务器的真实性。 prefer:如果数据库支持,那么首选使用SSL安全加密连接,但不验证数据库服务器的真实性。 require:必须使用SSL安全连接,但是只做了 数据加密 ,而并不验证数据库服务器的真实性。 verify-ca:必须使用SSL安全连接,并验证服务器是否具有由可信任的证书机构签发的证书。 verify-full:必须使用SSL安全连接,并且验证服务器是否具有由可信任的证书机构签发的证书,以及验证服务器主机名是否与证书中的一致。 sslkey 指定用于客户端证书的密钥位置,如果需要走SSL连接,并且该参数未指定,可通过设置环境变量${PGSSLKEY}来指定。 sslcert 指定客户端SSL证书的文件名,或者通过设置环境变量${PGSSLCERT}来指定。 sslrootcert 指定一个包含SSL证书机构(CA)证书的文件名称,或者通过设置环境变量${PGSSLROOTCERT}来指定。 sslcrl 指定ssl证书撤销列表(CRL)的文件名。列在这个文件中的证书如果存在,在尝试认证该服务器证书时会被拒绝,从而连接失败。也可通过环境变量${PGSSLCRL}来指定。 sslpassword 指定对秘钥解密成明文的密码短语,当指定该参数的时候表示sslkey是一个加密存储的文件,当前sslkey支持des/aes加密方式。 说明: DES加密算法安全性低,存在安全风险,建议使用更安全的加密算法。 disable_prepared_binary_result 字符串类型,若设置为yes,表示此连接在从预准备语句接收查询结果时不应使用二进制格式。该参数仅用于调试。 取值范围:yes/no。 binary_parameters 字符串类型,该参数表示是否始终以二进制形式发送[]byte。取值范围:yes/no。若该参数设置为yes,建议绑定参数按照[]byte绑定,可以减少内部类型转换。 target_session_attrs 指定数据库的连接类型,该参数用于识别主备节点,也可通过环境变量${PGTARGETSESSIONATTRS}来指定。默认值为“any”,共有六种:any、master、slave、preferSlave、read-write、read-only。 any:尝试连接URL连接串中的任何一个数据节点。 master:尝试连接到URL连接串中的主节点,如果找不到就抛出异常。 slave:尝试连接到URL连接串中的备节点,如果找不到就抛出异常。 preferSlave:尝试连接到URL连接串中的备数据节点(如果有可用的话),否则连接到主数据节点。 read-write:读写模式,表示只能连接主节点。 read-only:只读模式,表示只能连接备节点。 loggerLevel 日志级别,打印相关调试信息,也可通过环境变量${PGLOGGERLEVEL}来指定。 支持trace/debug/info/warn/error/none,级别从高到低。 application_name 设置正在使用连接的GO驱动的名称。缺省值为go-driver,该参数不建议用户配置。 RuntimeParams 要在连接上设置为会话默认值的运行时参数。例如参数名search_path,application_name,timezone等。各参数的详细介绍参见客户端连接缺省设置,可通过show语法查看参数是否设置成功。 autoBalance 字符串类型,分布式环境下,使用该参数开启负载均衡连接。默认值为false,共有六种:true、balance、roundrobin、shuffle、priorityn、false。 设置为true、balance或roundrobin时,表示开启go sql负载均衡功能,将应用程序的多个连接均衡到数据库集群中各个可用的CN。 例如:gauss://user:password@host1:port1,host2:port2/database?autoBalance=true Driver将定期获取(周期刷新可使用参数refreshCNIpsTime配置,默认为10s)整个集群可用CN列表,比如获取到的列表为:host1:port1,host2:port2,host3:port3,host4:port4。 host1和host2在autoBalance启用时,仅在首次连接做高可用用途,后续Driver将从host3,host4,host1,host2中依次选择可用的CN刷新可用CN列表,后续用户调用的Connector.Connect将使用RoundRobin算法从host1,host2,host3,host4选取CN主机进行连接。 设置为priorityn表示开启Driver优先级负载均衡功能,将应用程序的多个连接首先均衡到url上配置的前n个中可用的CN数据库节点,当url上配置前n个节点全部不可用时,连接会随机分配到数据库集群中其他可用CN数据库节点。n为数字,不小于0,且小于url上配置的CN数量。 例如:gauss://user:password@host1:port1,host2:port2,host3:port3/database?autoBalance=priority2 Driver将定期获取(周期按refreshCNIpsTime定义)整个集群可用CN列表,比如获取到的列表为:host1:port1,host2:port2,host3:port3,host4:port4,host5:port5,host6:port6,其中host1和host2处于AZ1,host3和host4处于AZ2。 Driver将从优先从host1,host2中做负载均衡,host1和host2全部不可用才从host3, host4, host5, host6中随机选择CN主机连接。 设置为shuffle表示开启Driver随机负载均衡功能,将应用程序的多个连接随机均衡到数据库集群中的各个可用CN。 例如:gauss://user:password@host1:port1,host2:port2,host3:port3/database?autoBalance=shuffle Driver将定期获取(周期刷新可使用参数refreshCNIpsTime配置,默认为10S)整个集群的可用CN列表,比如获取到的列表为:host1:port1,host2:port2,host3:port3,host4:port4。 host1:port1,host2:port2,host3:port3,仅在首次连接做高可用,后续连接将在刷新后的CN列表中,使用shuffle算法随机选用一个CN节点进行连接。 设置为false时为集中式场景,不开启Driver负载均衡功能和优先级负载均衡功能。默认为false。 注意: 负载均衡是基于连接级别,不是基于事务级别。如果连接是长连接,并且连接上的负载不均衡,无法保证CN主机上的负载是均衡的。 负载均衡仅能在分布式场景下使用,集中式环境中不可使用。 recheckTime integer类型,定期检测数据库集群中CN状态,获取可用CN的IP列表的时间间隔,取值范围为5到60秒,默认为10秒。 usingEip boolean类型。此值用于控制是否使用弹性公网IP做负载均衡。默认值为true,表示使用弹性公网IP做负载均衡;false表示使用数据IP做负载均衡。
  • 客户端配置 上传证书文件,将在服务端配置(服务端配置请联系管理员)操作中生成的文件client.key、client.crt、cacert.pem放置在客户端。 示例一: // 以双向认证为例func main() { dsnStr := "host=127.0.0.1,127.0.0.2 port=1611,1622 user=testuser password=XXXXXX dbname=postgres autoBalance=shuffle sslcert=certs/client.crt sslkey=certs/client.key sslpassword=XXXXXXXX " parameters := []string { " sslmode=require", " sslmode=verify-ca sslrootcert=certs/cacert.pem", } for _, param := range parameters { db, err:= sql.Open("opengauss", dsnStr+param) if err != nil { log.Fatal(err) } var f1 int err = db.QueryRow("select 1").Scan(&f1) if err != nil { log.Fatal(err) } else { fmt.Printf("RESULT: select 1: %d\n", f1) } db.Close() }} 示例二: // 以验证sslpassword为主func main() { dsnStr := "host=127.0.0.1,127.0.0.2 port=1611,1622 user=testuser password=XXXXXXXX dbname=postgres autoBalance=shuffle" connStrs := []string { " sslmode=verify-ca sslcert=certs/client_rsa.crt sslkey=certs/client_rsa.key sslpassword=XXXXXXXX sslrootcert=certs/cacert_rsa.pem", " sslmode=verify-ca sslcert=certs/client_ecdsa.crt sslkey=certs/client_ecdsa.key sslpassword=XXXXXXXX sslrootcert=certs/cacert_ecdsa.pem", } for _, connStr := range connStrs { db, err := sql.Open("opengauss", dsnStr + connStr) if err != nil { log.Fatal(err) } var f1 int err = db.QueryRow("select 1").Scan(&f1) if err != nil { if !strings.HasPrefix(err.Error(), "connect failed.") { log.Fatal(err) } } db.Close() }}
  • sqlca 嵌入式SQL接口提供了sqlca(SQL通信区)的全局变量。sqlca包含告警和错误信息。如果在语句执行期间发生多个告警和错误,那么sqlca将只保存最后一个信息。在一个多线程的程序中,每一个线程会自动得到它的sqlca副本。 数据结构如下: struct { char sqlcaid[8]; long sqlabc; long sqlcode; struct { int sqlerrml; char sqlerrmc[SQLERRMC_LEN]; } sqlerrm; char sqlerrp[8]; long sqlerrd[6]; char sqlwarn[8]; char sqlstate[5]; } sqlca; 如果SQL语句没有发生错误,则sqlca.sqlcode为0,sqlca.sqlstate为"00000"。如果发生了告警或者错误,那么sqlca.sqlcode是负数并且sqlca.sqlstate不同于"00000"。SQLSTATE与SQLCODE的具体值可参考SQLSTATE与SQLCODE章节。 如果SQL语句正确执行,那么sqlca.sqlerrd[1]包含被处理行的OID,并且sqlca.sqlerrd[2]包含被处理或返回的行数。 在发生错误或告警时,sqlca.sqlerrm.sqlerrmc将包含描述该错误的字符串。sqlca.sqlerrm.sqlerrml包含存储在sqlca.sqlerrm.sqlerrmc中错误消息的长度(strlen()的结果)。注意:一些消息可能无法适应定长的sqlerrmc数组,它们将被截断。 在发生告警时,sqlca.sqlwarn[2]被设置为W。 sqlcaid、sqlabc、sqlerrp、sqlwarn以及sqlerrd的剩余元素目前未包含有用的信息。 示例如下: /* 整合WHENEVER和sqlca实现错误处理 */EXEC SQL WHENEVER SQLERROR SQLCALL print_sqlca(); void print_sqlca() { fprintf(stderr, "==== sqlca ====\n"); fprintf(stderr, "sqlcode: %ld\n", sqlca.sqlcode); fprintf(stderr, "sqlerrm.sqlerrml: %d\n", sqlca.sqlerrm.sqlerrml); fprintf(stderr, "sqlerrm.sqlerrmc: %s\n", sqlca.sqlerrm.sqlerrmc); fprintf(stderr, "sqlerrd: %ld %ld %ld %ld %ld %ld\n", sqlca.sqlerrd[0],sqlca.sqlerrd[1],sqlca.sqlerrd[2], sqlca.sqlerrd[3],sqlca.sqlerrd[4],sqlca.sqlerrd[5]); fprintf(stderr, "sqlwarn: %d %d %d %d %d %d %d %d\n", sqlca.sqlwarn[0], sqlca.sqlwarn[1], sqlca.sqlwarn[2], sqlca.sqlwarn[3], sqlca.sqlwarn[4], sqlca.sqlwarn[5], sqlca.sqlwarn[6], sqlca.sqlwarn[7]); fprintf(stderr, "sqlstate: %5s\n", sqlca.sqlstate); fprintf(stderr, "===============\n"); } 输出结果形如(此处的错误是一个拼写表名错误): ==== sqlca ==== sqlcode: -400 sqlerrm.sqlerrml: 49 sqlerrm.sqlerrmc: relation "pg_databasep" does not exist on line 38 sqlerrd: 0 0 0 0 0 0 sqlwarn: 0 0 0 0 0 0 0 0 sqlstate: 42P01 =============== 父主题: 错误处理
  • 基于ecpg开发 ecpg(embedded SQL C preprocessor for GaussDB Kernel)是一种用于C语言程序的嵌入式SQL预处理器。一个嵌入式SQL程序由一种普通编程语言编写的代码(此处为C语言)和SQL命令共同组成。要构建该程序,源代码(*.pgc)首先通过嵌入式SQL预处理器,将源代码转换成一个普通C语言程序(*.c),然后再通过编译器处理。转换过的ecpg应用通过嵌入式SQL库(ecpglib)调用libpq库中的函数,与GaussDB Kernel服务器使用普通的前端/后端协议通信。 嵌入式SQL程序是插入了数据库相关动作的特殊代码的C语言程序。这种特殊代码形式通常如下: EXEC SQL ...; 这些语句在语法上取代了一个C语句,可以出现在全局或者是一个函数中。嵌入式SQL语句遵循普通SQL代码的大小写敏感规则,也允许嵌套的C语言代码风格注释(SQL标准的一部分)。不过,程序的C语言部分遵循C语言程序的标准,不支持嵌套注释。 开发流程 ecpg组件介绍 ecpg预处理以及编译执行 管理数据库连接 执行SQL命令 查询结果集 关闭数据库连接 宿主变量 执行动态SQL语句 错误处理 预处理指令 使用库函数 SQL描述符区域 常用示例 ecpg接口参考 父主题: 应用程序开发教程
  • 环境类 Go环境配置 用户需要在环境变量中配置以下参数: GO111MODULE:用户使用在线导入的方式安装Go驱动时需要设置GO111MODULE为on;如果不希望进行go mod工程的改造,需将GO111MODULE设置为off,并手动下载依赖包,依赖包与驱动根目录和业务代码保持同级。 GOPROXY:用户使用在线导入时需配置包含Go驱动包的路径。 用户可以根据自己场景参数配置Go其他相关环境变量。 通过go env查看Go环境变量配置结果,并且查看Go版本是否在1.13或以上。 go驱动安装 通过在线导入方式安装,目前Go驱动已上传至https://cmc.centralrepo.rnd.huawei.com/go/,用户可以通过配置GOPROXY获取Go驱动代码。配置好环境变量(参考•Go环境配置)后,直接执行go mod tidy更新并下载Go驱动代码包及相关依赖。 下载Go驱动包到本地,进入Go驱动代码根路径,执行go mod tidy下载相关依赖。需要配置GOPATH=${Go所在目录},go.mod里面需要添加一行“通过replace将Go驱动包替换为本地Go驱动包地址”,表示代码里面所有的import Go驱动包都是走本地路径, 同时依赖也不会从代理里下载。 通过go mod tidy下载相关依赖时可能会下载为某个依赖的低版本,如果依赖的低版本存在漏洞,可以通过更改go.mod文件中对应依赖的版本号,更新依赖到漏洞修复后的版本来规避风险。
  • 命名SQL描述符区域 一个命名SQL描述符区域由一个头部以及一个或多个条目描述符区域构成。头部包含与整个描述区域相关的信息,而条目描述符区域则描述结果行中的某一列。 在使用SQL描述符区域之前,需要分配一个SQL描述符区域: EXEC SQL ALLOCATE DESCRIPTOR identifier; 当不再需要这个描述符区域时,应及时释放: EXEC SQL DEALLOCATE DESCRIPTOR identifier; 要使用一个描述符区域,需要使用INTO子句声明: EXEC SQL FETCH NEXT FROM mycursor INTO SQL DESCRIPTOR mydesc; 如果结果集为空,该描述符区域仍会包含查询的元数据。 对于还没有执行的预备查询,可以使用DESCRIBE得到其结果集的元数据。 EXEC SQL BEGIN DECLARE SECTION; char *sql_stmt = "SELECT * FROM table1"; EXEC SQL END DECLARE SECTION; EXEC SQL PREPARE stmt1 FROM :sql_stmt; EXEC SQL DESCRIBE stmt1 INTO SQL DESCRIPTOR mydesc; 在DESCRIBE和FETCH语句中,INTO和USING关键词的使用相似:它们产生结果集以及一个描述符区域的元数据。 从头部检索一个描述符区域的值并且将其存储到一个宿主变量中: EXEC SQL GET DESCRIPTOR name :hostvar = field; 当前只定义了一个头部描述符区域COUNT,它存放描述符区域的条目(即结果集中包含多少列),宿主变量为一个整数类型,需从条目描述符区域中得到一个具体值: EXEC SQL GET DESCRIPTOR name VALUE num :hostvar = field; num可以是一个字符整数或者一个包含整数的宿主变量。可能的类型如下: CARDINALITY(整数):结果集中的行数 DATA:实际的数据项(这个范围的实际数据类型取决于查询) DATETIME_INTERVAL_CODE(整数):当TYPE是9时,DATETIME_INTERVAL_CODE将具有以下值之一:1表示DATE,2表示TIME,3表示TIMESTAMP,4表示TIME WITH TIME ZONE,5表示TIMESTAMP WITH TIME ZONE。 INDICATOR(整数):指示符(表示一个空值或者一个值截断) LENGTH(整数):以字符计的数据长度 NAME(string):列名 OCTET_LENGTH(整数):以字节计的数据字符表达的长度 PRECISION(整数):精度(用于类型numeric) RETURNED_LENGTH(整数):以字符计的数据长度 RETURNED_OCTET_LENGTH(整数):以字节计的数据字符表达的长度 SCALE(整数):比例(用于类型numeric) TYPE(整数):列的数据类型的数字编码 要检索字段数值并且把它存储到一个宿主变量里,使用下面的命令: EXEC SQL GET DESCRIPTOR mydesc VALUE num :hostvar = field num可以是一个字符整数或者一个包含整数的宿主变量。可能的字段有: DATA 实际数据项(因此,这个字段的数据类型依赖于这个查询) NAME(string) 字段名称 手动建立一个描述符区域为一个查询或游标提供输入参数,使用如下命令: EXEC SQL SET DESCRIPTOR name VALUE numfield = :hostvar; 在一个FETCH语句中检索多行记录且用数组类型的宿主变量来存储数据,示例如下: EXEC SQL BEGIN DECLARE SECTION; int id[5]; EXEC SQL END DECLARE SECTION; EXEC SQL FETCH 5 FROM mycursor INTO SQL DESCRIPTOR mydesc; EXEC SQL GET DESCRIPTOR mydesc VALUE 1 :id = DATA; 父主题: SQL描述符区域
  • SQLSTATE与SQLCODE SQLSTATE是一个由五个字符组成的数组。这五个字符包含数字或大写字母,它表示多种错误或告警情况的代码。SQLSTATE具有一种层次模式:前两个字符表示情况的总体分类,后三个字符表示总体情况的子类。例如:代码00000表示成功状态。 SQLCODE是一个简单的整数形式。值为0表示成功,一个正值表示带附加信息的成功,一个负值表示错误。SQL标准只定义了正值+100,它表示上一个命令返回或者影响了零行,且没有特定的负值。 表1 SQLSTATE与SQLCODE对应关系表 SQLCODE值 SQLSTATE值 含义 0 (ECPG_NO_ERROR) SQLSTATE 00000 表示没有错误。 100 (ECPG_NOT_FOUND) SQLSTATE 02000 一种无害情况,它表示上一个命令检索或者处理了零行,或者已到达游标的末尾。 在循环中处理游标时,可以使用这个代码来检测何时中止该循环,示例如下: while (1) { EXEC SQL FETCH ... ; if (sqlca.sqlcode == ECPG_NOT_FOUND) break; } 实际上WHENEVER NOT FOUND DO BREAK也会在内部这样做,所以一般不会直接使用这种方法。 -12 (ECPG_OUT_OF_MEMORY) SQLSTATE YE001 虚拟内存已被耗尽,数字值被定义为-ENOMEM。 -200 (ECPG_UNSUPPORTED) SQLSTATE YE000 预处理器产生了一些该库无法识别的内容。 -201 (ECPG_TOO_MANY_ARGUMENTS) SQLSTATE 07001 或 07002 表示命令指定的宿主变量数量超过该命令预期。 -202 (ECPG_TOO_FEW_ARGUMENTS) SQLSTATE 07001 或 07002 表示命令指定的宿主变量数量低于该命令的预期。 -203 (ECPG_TOO_MANY_MATCHES) SQLSTATE 21000 表示一个查询已经返回了多个行,但是该语句只准备存储一个结果行。 -204 (ECPG_INT_FORMAT) SQLSTATE 42804 宿主变量是类型int而数据库中的数据是一种不同的类型并且含有不能被解释为int的值。该库使用strtol()进行这种转换。 -205 (ECPG_UINT_FORMAT) SQLSTATE 42804 宿主变量是类型unsigned int而数据库中的数据是一种不同的类型并且含有不能被解释为unsigned int的值。该库使用strtoul()进行这种转换。 -206 (ECPG_FLOAT_FORMAT) SQLSTATE 42804 宿主变量是类型float而数据库中的数据是另一种类型并且含有不能被解释为float的值。该库使用strtod()进行这种转换。 -207 (ECPG_NUMERIC_FORMAT) SQLSTATE 42804 宿主变量是类型numeric而数据库中的数据是另一种类型并且含有不能被解释为numeric的值。 -208 (ECPG_INTERVAL_FORMAT) SQLSTATE 42804 宿主变量是类型interval而数据库中的数据是另一种类型并且含有一个不能被解释为interval的值。 -209 (ECPG_DATE_FORMAT) SQLSTATE 42804 宿主变量是类型date而数据库中的数据是另一种类型并且含有不能被解释为date的值。 -210 (ECPG_TIMESTAMP_FORMAT) SQLSTATE 42804 宿主变量是类型timestamp而数据库中的数据是另一种类型并且含有不能被解释为timestamp的值。 -211 (ECPG_CONVERT_BOOL) SQLSTATE 42804 宿主变量是类型bool而数据库中的数据既不是't'也不是'f'。 -212 (ECPG_EMPTY) SQLSTATE YE000 发送给SQL服务器的语句是空的(通常在一个嵌入式SQL程序中不会发生,因此它可能指向一个内部错误)。 -213 (ECPG_MISSING_INDICATOR) SQLSTATE 22002 返回了一个空值并且没有提供空值指示符。 -214 (ECPG_NO_ARRAY) SQLSTATE 42804 在要求一个数组的地方使用了一个普通变量。 -215 (ECPG_DATA_NOT_ARRAY) SQLSTATE 42804 在一个要求数组值的地方数据库返回了一个普通变量。 -220 (ECPG_NO_CONN) SQLSTATE 08003 程序尝试访问一个不存在的连接。 -221 (ECPG_NOT_CONN) SQLSTATE YE000 程序尝试访问一个存在的连接但是它没有打开(这是一个内部错误)。 -230 (ECPG_INVALID_STMT) SQLSTATE 26000 尝试使用的语句还没有被准备好。 -239 (ECPG_INFORMIX_DUPLICATE_KEY) SQLSTATE 23505 重复键错误,违背唯一约束。 -240 (ECPG_UNKNOWN_DESCRIPTOR) SQLSTATE 33000 没有找到指定的描述符,尝试使用的语句还没有被准备好。 -241 (ECPG_INVALID_DESCRIPTOR_INDEX) SQLSTATE 07009 指定的描述符超出范围。 -242 (ECPG_UNKNOWN_DESCRIPTOR_ITEM) SQLSTATE YE000 请求了一个非法的描述符(这是一个内部错误)。 -243 (ECPG_VAR_NOT_NUMERIC) SQLSTATE 07006 在执行一个动态语句期间,数据库返回了一个numeric值而宿主变量不是numeric类型的。 -244 (ECPG_VAR_NOT_CHAR) SQLSTATE 07006 在执行一个动态语句期间,数据库返回了一个非numeric值而宿主变量是numeric类型的。 -284 (ECPG_INFORMIX_SUBSELECT_NOT_ONE) SQLSTATE 21000 子查询的结果不是单一行。 -400 (ECPG_PGSQL) - SQL服务器导致了某个错误。该消息包含来自SQL服务器的错误消息。 -401 (ECPG_TRANS) SQLSTATE 08007 SQL服务器通知我们不能启动、提交或回滚事务。 -402 (ECPG_CONNECT) SQLSTATE 08001 无法建立数据库连接。 -403 (ECPG_DUPLICATE_KEY) SQLSTATE 23505 重复键错误,违背唯一约束。 -404 (ECPG_SUBSELECT_NOT_ONE) SQLSTATE 21000 子查询的结果不是单一行。 -602 (ECPG_WARNING_UNKNOWN_PORTAL) SQLSTATE 34000 指定了一个非法的游标名。 -603 (ECPG_WARNING_IN_TRANSACTION) SQLSTATE 25001 事务正在进行。 -604 (ECPG_WARNING_NO_TRANSACTION) SQLSTATE 25P01 没有活动(正在进行)的事务。 -605 (ECPG_WARNING_PORTAL_EXISTS) SQLSTATE 42P03 指定了一个现有的游标名。 ecpg为嵌入式SQL新增加的SQLSTATE码有:22002,07001,07002,07006,07009,33000,42601,42804,42P03,YE000,YE001。其余SQLSTATE码沿用内核SQLSTATE码。 SQLSCODE为-400表示ecpg检测到内核服务器返回错误,其SQLSTATE为内核相应错误的SQLSTATE。 父主题: 错误处理
  • ifdef,ifndef,else,elif和endif指令 ecpg提供了ifdef、ifndef、else、elif和endif条件编译指令。在预处理时,按照不同的条件去编译程序的不同部分,使用时,需要添加EXEC SQL前缀关键字。 示例如下: EXEC SQL ifndef TZVAR; EXEC SQL SET TIMEZONE TO 'GMT'; EXEC SQL elif TZNAME; EXEC SQL SET TIMEZONE TO TZNAME; EXEC SQL else; EXEC SQL SET TIMEZONE TO TZVAR; EXEC SQL endif; 父主题: 预处理指令
  • define和undef指令 嵌入式SQL具有类似于C语言中#define指令: EXEC SQL DEFINE name;EXEC SQL DEFINE name value;EXEC SQL UNDEF name; 示例如下: /* 定义名称 */EXEC SQL DEFINE HAVE_FEATURE;/* 定义常量 */EXEC SQL DEFINE MYNUMBER 12;EXEC SQL DEFINE MYSTRING 'abc';/* 使用 UNDEF 移除定义 */EXEC SQL UNDEF MYNUMBER; 在嵌入式SQL程序中也可以使用C语言版本的#define和#undef。区别在于定义的值会在哪里被计算,如果使用EXEC SQL DEFINE,那么ecpg预处理阶段会计算这些定义并替换值。如下示例,ecpg对其进行替换并且编译器不会解析名为MYNUMBER的任何名称或标识符: EXEC SQL DEFINE MYNUMBER 12; ... EXEC SQL UPDATE Tbl SET col = MYNUMBER; 不能把#define用于一个将要在一个嵌入式SQL查询中使用的变量,因为在这种情况下嵌入式SQL预编译器不能看到这个声明。 父主题: 预处理指令
  • 设置回调 设置回调操作,当告警或者错误发生时,直接执行具体操作进行处理,设置回调命令如下: EXEC SQL WHENEVER condition action; condition取值范围: SQLERROR:当在SQL语句执行期间发生错误时,调用指定操作。 SQLWARNING:当在SQL语句执行期间发生告警时,调用指定操作。 NOT FOUND:当SQL语句检索或者影响零行,则调用指定操作。 action取值范围: CONTINUE:忽略回调错误条件,继续执行,通常可以用来停止break包含条件,为缺省值。 GOTO label/GO TO label:跳转到指定标签(使用C语言goto语句)。 SQLPRINT:输出消息到标准错误。 STOP:调用exit(1),终止程序。 DO BREAK:执行C语句break,只有在循环中或者switch语句中使用。 SQLCALL name (args) / DO name (args):调用具有指定参数的指定C语言函数。 示例如下: /* 当出现一个告警时它打印一个消息,发生一个错误时中止程序。 */EXEC SQL WHENEVER SQLWARNING SQLPRINT; EXEC SQL WHENEVER SQLERROR STOP; 语句EXEC SQL WHENEVER是SQL预处理器的一个指令,而非一个C语言语句。不管C语言程序的流程如何,该语句设置的错误或告警动作都适用于位于处理程序设置点之后的嵌入式SQL语句,除非第一个EXEC SQL WHENEVER语句和导致错误或告警情况发生的SQL语句之间为同一个情况设置了不同的动作。因此下面的两个C语言程序都不会得到预期的效果: /* * 错误 */ int main(int argc, char *argv[]) { ... if (verbose) { EXEC SQL WHENEVER SQLWARNING SQLPRINT; } ... EXEC SQL SELECT ...; ... } /* * 错误 */ int main(int argc, char *argv[]) { ... set_error_handler(); ... EXEC SQL SELECT ...; ... } static void set_error_handler(void) { EXEC SQL WHENEVER SQLERROR STOP; } 当使用DO BREAK时只能用于while/for/switch场景,且用完需要使用CONTINUE语句忽略。 父主题: 错误处理
  • 执行具有输入参数的语句 准备一个普通语句,通过替换参数(在想要替换参数的地方写上问号)执行它的特定版本。使用EXECUTE语句通过USING子句给定参数执行准备语句。示例如下: EXEC SQL BEGIN DECLARE SECTION; const char *stmt = "INSERT INTO test1 VALUES(?, ?);";EXEC SQL END DECLARE SECTION; /* PREPARE 准备一个语句用于执行 */ EXEC SQL PREPARE mystmt FROM :stmt; ... /* 单引号为有效字符,若用字符串需用双引号 */ EXEC SQL EXECUTE mystmt USING 42, 'foobar'; /* 当你不再需要预备语句时,你应该释放它 */ EXEC SQL DEALLOCATE PREPARE name; 父主题: 执行动态SQL语句
  • 执行没有结果集的语句 执行EXECUTE IMMEDIATE命令示例如下: EXEC SQL BEGIN DECLARE SECTION; const char *stmt = "CREATE TABLE test1 (...);";EXEC SQL END DECLARE SECTION; EXEC SQL EXECUTE IMMEDIATE :stmt; EXECUTE IMMEDIATE可以用于不返回结果集的SQL语句,比如:DDL,INSERT,UPDATE,DELETE语句。但不能用这种方式执行检索数据的语句,比如:SELECT语句。 父主题: 执行动态SQL语句
  • 类型映射 当ecpg应用程序在GaussDB Kernel服务器和C语言程序之间交换值时(例如:从服务器检索查询结果或者执行带有输入参数的SQL语句),在GaussDB Kernel数据类型和宿主语言变量类型(具体的C语言数据类型)之间需要进行值的转换。有两种数据类型可以使用:一些简单的GaussDB Kernel数据类型,如integer和text,可以直接被应用程序读取和写入;其他GaussDB Kernel数据类型,如timestamp和numeric,只能通过特殊库函数进行访问,参见ecpg接口参考章节。 表1 GaussDB Kernel数据类型和C变量类型之间的映射 GaussDB Kernel数据类型 宿主变量数据类型 smallint short integer int bigint long long int boolean bool character(n), varchar(n), text char[n+1], VARCHAR[n+1] double precision double real float smallserial short serial int bigserial long long int oid unsigned int name char[NAMEDATALEN] date date [a] timestamp timestamp [a] interval interval [a] decimal decimal [a] numeric numeric [a] [a]这种类型可以通过访问特殊数据类型访问。 当前仅支持对于C语言的基本数据类型的使用或者组合,不支持C++语言中string数据类型用作宿主变量数据类型。 当前ecpg仅对GaussDB Kernel SQL的常用数据类型做映射,具体支持项可参考表1。 父主题: 宿主变量
  • 处理字符串 处理SQL字符串数据类型(例如:varchar、text),有两种方式来声明宿主变量: 方式一:使用char[](一个char字符串),C语言程序中处理字符数据最常见的方式。 EXEC SQL BEGIN DECLARE SECTION; char str[50];EXEC SQL END DECLARE SECTION; 注意字符串必须控制长度,如果上述示例的宿主变量用作存放查询结果且查询命令返回的字符串长度超过49字节,那么将会发生缓冲区溢出。 方式二:使用VARCHAR类型,ecpg提供的一种特殊类型。在一个VARCHAR类型数组上的定义会被转变成一个struct类型。如下声明: VARCHAR var[180]; 会被转变成: struct varchar_var { int len; char arr[180]; } var; 要在一个VARCHAR宿主变量中存储一个字符串,该宿主变量必须被声明为包含零字节为终止符长度的字符串。字段arr存放以零字节为终止符的字符串,字段len保存存储在arr中的字符串的长度,计算长度时不包括终止符。当宿主变量被用于一个查询的输入时,如果strlen(arr)和len结果不同,将使用较短的那一个。 VARCHAR可以被写成大写或小写形式,但是不能大小写混合。 char和VARCHAR类型宿主变量也可以保存其他SQL类型的值,它们将被存储为字符串形式。 父主题: 宿主变量
  • 声明段 要实现嵌入式SQL-C程序和数据库间的数据交互(例如:从SQL-C程序把查询语句中的参数传递给数据库,或者从数据库向嵌入式SQL-C程序传回数据),需要在特殊的标记段里面声明包含此数据的C语言变量,以便预处理器能够识别。 标记段以下面的代码开始: EXEC SQL BEGIN DECLARE SECTION; 以下面的代码结束: EXEC SQL END DECLARE SECTION; 在此之间,必须有常规的C语言变量声明,比如: int x = 4;char foo[16], bar[16]; 标记段代码开始和结束之间声明的宿主变量类型必须为当前支持的数据类型,详见表1。 可以隐式地创建一个声明段声明变量:EXEC SQL int i = 4。 那些不在SQL命令里使用的变量可以在这些特殊的声明段外面声明。 结构体或者联合体的定义也必须在DECLARE段中列出。否则预处理器就无法处理这些类型,因为它不知道定义。 父主题: 宿主变量
共100000条