Pro*C中使用Unicode字符


What is Pro*C

Pro*C语言是Oracle开发的一种基于C语言并可以内嵌SQL的编程语言. 它通过Pro*C预编译器将Pro*C源码文件(后缀是.cp)转译成C源码文件, 后者可通过C编译器(gcc)编译为可执行程序.

Environment setup

1. header file and library

编写Pro*c所需要的头文件和C库均包含在oracle数据库的instantclient中. 请准备如下Makefile

INCLUDE=-I${ORACLE_HOME}/sdk/include/ -I${ORACLE_HOME}/precomp/public
LIBS=-L${ORACLE_HOME}/lib/ -L${ORACLE_HOME}/precomp/lib
main.c:main.pc
        proc $^ oname=$@
main:main.c
        gcc -ggdb -o main main.c ${INCLUDE} ${LIBS} -lclntsh

2. precompiler config

预编译器设置位于instantclient的$ORACLE_HOME/precomp/admin/pcscfg.cfg中, 可用如下设置

sys_include=($ORACLE_HOME/precomp/public,/usr/include)
sys_include=/usr/lib/gcc/x86_64-linux-gnu/13/include
sys_include=/usr/lib/gcc/x86_64-linux-gnu/14/include
sys_include=/usr/include/x86_64-linux-gnu/
sys_include=$ORACLE_HOME/sdk/include
ltype=short
define=__x86_64__
code=ansi_c

Let’s coding

Pro*C长这样:

#include <assert.h>
#include <sqlca.h>
#include <sqlcpr.h>
#include <sqlda.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// runtime error checking, i steal this code from demo
void sql_error(char *msg) {
  char err_msg[512];
  size_t buf_len, msg_len;
  EXEC SQL WHENEVER SQLERROR CONTINUE;
  printf("\n%s\n", msg);
  buf_len = sizeof(err_msg);
  sqlglm(err_msg, &buf_len, &msg_len);
  printf("%.*s\n", (int)msg_len, err_msg);
  EXEC SQL ROLLBACK RELEASE;
  exit(EXIT_FAILURE);
}

int main() {
  assert(setenv("NLS_NCHAR", "AL32UTF8", 0) ==
         0); // set this env var when working with unicode

  char *ezconn = "SYS/[email protected]:21521/PDB";

  EXEC SQL WHENEVER SQLERROR DO sql_error("ORACLE error--");

  // if you work with unicode, declare variable like thie.
  char character set nchar_cs str[64] = {0};
  char tmp[64] = "こんにちは";
  memcpy(str, tmp, 64);

  EXEC SQL CONNECT : ezconn in sysdba mode;

  EXEC SQL drop table if exists test; // 23c supports this syntax

  EXEC SQL create table test(txt varchar2(128));
  EXEC SQL insert into test values( : str);

  EXEC SQL select txt into : str from test;
  EXEC SQL COMMIT WORK RELEASE;
  printf("%s\n", str);
}
  • sql_error函数可以用来捕获oracle数据库返回的报错
  • 在Pro*C中使用Unicode需要设置NLS_NCHAR环境变量来设置字符集
  • 声明指定字符集的字符串需要char character set nchar_cs *var来声明var
  • 内嵌SQL中使用C变量像是在用绑定变量

Result

karl@karl:~/Projects/proc_unicode$ make main
proc main.pc oname=main.c

Pro*C/C++: Release 23.26.1.0.0 - Production on Wed Sep 16 20:06:11 2026
Version 23.26.1.0.0

Copyright (c) 1982, 2026, Oracle and/or its affiliates.  All rights reserved.

System default option values taken from: /opt/oracle/product/23.26.1/client_1/precomp/admin/pcscfg.cfg

gcc -ggdb -o main main.c -I/opt/oracle/product/23.26.1/client_1/sdk/include/ -I/opt/oracle/product/23.26.1/client_1/precomp/public -L/opt/oracle/product/23.26.1/client_1/lib/ -L/opt/oracle/product/23.26.1/client_1/precomp/lib -lclntsh
karl@karl:~/Projects/proc_unicode$ ./main
こんにちは