目录
一、环境安装
二、环境配置
三、编写程序
1.PostgreSQL10.23 X64(应该哪个版本都行);
(1)由于使用 EXEC SQL 这种嵌入方式已经非常古老,近些年的Mysql和SQL Server都已经不支持这种嵌入,因此使用 PostgreSQL。
(2)SQL Server 2000 版本似乎可以,但没试过。
(3)下载及安装查看:https://www.runoob.com/postgresql/windows-install-postgresql.html
2.Microsoft Viusal Studio 2017(vs其他版本、dev-cpp、codeblocks也行)。
1.打开项目属性
2.将 [调试] 中的 [环境] 改为 bin 文件夹地址
3.将 [C++-常规] 中的 [附加库包含目录] 改为 include 文件夹地址
4.将 [链接器-常规] 中的 [附加库目录] 改为 lib 文件夹地址
5.将 [链接器-输入] 中的 [附加依赖项] 加上 libecpg.lib 的地址
6.在 PostgreSQL 的安装目录下,找到 bin 文件夹,从 bin 文件夹中拷贝下面七个 dll 至项目文件夹
7.将运行平台修改为 X64
1.先了解一些东西
(1)EXEC SQL 这种嵌入方式,是不能写在任何一种高级程序语言中的。
因此DBMS会采用预编译方法处理。他们通常提供一个预处理器(.exe),当我们写好了预处理文件后,使用预处理器将预处理文件转换成宿主语言的标准文件,这个时候就可以使用高级语言的编译器运行了。
(2)不同的 DBMS 有不同的预处理文件格式,我们即将使用的 PostgreSQL 就是以(.pgc)作为格式。预处理器将该种文件处理过后,就会生成(.c)文件。
PostgreSQL 的预处理命令:(按照自己的路径去写即可)
(3)总结上面两点:当我们写好 预处理文件,就使用 预处理器 进行编译,接着运行预处理器产生的主语言程序即可。
2.编写程序
(1)首先我们知道,每一次 EXEC SQL 都相当于在命令行中写入一条语句。
(2)在预处理文件中,只要与 EXEC SQL 语句沾点边的变量,都必须在 main() 前进行声明,也就是主变量声明。
(3)在 PostgreSQL 中,连接到一个数据库后,只能对这个数据库内的表操作。
(4)其余看代码注释,下面是 预处理文件.pgc
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
// 相当于高级程序语言的全局变量定义
EXEC SQL BEGIN DECLARE SECTION; // 主变量声明开始
const char* target1 = "postgres@localhost:5432"; // 数据库1
const char* user1 = "postgres";
const char* passwd1 = "123456";
const char* target2 = "spj@localhost:5432"; // 数据库2
const char* user2 = "postgres";
const char* passwd2 = "123456";
int rows = 0; // 表行数
char sno[10]; // s表的四个属性(s表是自定义的)
char sname[20];
int status;
char city[20];
EXEC SQL END DECLARE SECTION; // 主变量声明结束
int main() {
EXEC SQL WHENEVER SQLERROR SQLPRINT; // error 时输出错误信息
// 连接至数据库1
EXEC SQL CONNECT TO :target1 USER :user1 USING :passwd1;
printf("\n已连接%s\n", target1);
EXEC SQL drop database if exists spj; // 删除 spj 数据库
EXEC SQL create database spj; // 创建 spj 数据库
// 断开数据库1
EXEC SQL DISCONNECT CURRENT; // 这个不写也能运行,不知道有没有风险
printf("\n已断开%s\n", target1);
// 连接至数据库2
EXEC SQL CONNECT TO :target2 USER :user2 USING :passwd2;
printf("\n已连接%s\n", target2);
// 下面五条exec sql,建表及插入
EXEC SQL drop table if exists s;
EXEC SQL CREATE TABLE IF NOT EXISTS s(sno char(10) primary key, sname char(20) unique, status int, city char(20));
EXEC SQL insert into s(sno, sname, status, city) values('s1', 'APEX LEGEND', 114514, 'Wuhan');
EXEC SQL insert into s(sno, sname, status, city) values('s2', 'DEVIL MAY CRY5', 616161, 'Wuhan');
EXEC SQL insert into s(sno, sname, status, city) values('s3', 'WARFRAME', 123456, 'Wuhan');
// 写入中文,数据库内是utf8,控制台输出的是gbk,会乱码
EXEC SQL BEGIN; // BEGIN 事务块,DECLARE只能在事务块中使用
// 定义游标,相当于每次读表的一行
EXEC SQL DECLARE iterator CURSOR FOR
select sno, sname, status, city
from s;
EXEC SQL OPEN iterator; // 打开游标
EXEC SQL select count(*) into :rows from s; // 获取行数,只有主变量能被sql赋值
int flag = 0;
while (rows --) {
EXEC SQL fetch iterator into :sno, :sname, :status, :city; // fetch 获取一行元组
if (flag ++ == 0) { // 第一次把列名输出
printf("\n%-10s %-20s %-10s %-20s \n", "sno", "sname", "status", "city");
}
printf("%-10s %-20s %-10d %-20s \n", sno, sname, status, city);
}
EXEC SQL CLOSE iterator; // 关闭游标
EXEC SQL END; // 结束事务块
EXEC SQL DISCONNECT CURRENT; // 断开数据库2
printf("\n已断开%s\n", target2);
return 0;
}
含动态SQL操作的代码:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
// 相当于高级程序语言的全局变量定义
EXEC SQL BEGIN DECLARE SECTION; // 主变量声明开始
const char* target = "postgres@localhost:5432"; // 数据库
const char* user = "postgres";
const char* passwd = "123456";
int rows = 0; // 表行数
// game表的属性(game表是自定义的)
char name[20];
int id;
const char *stmt = "insert into game values(?, ?);";
EXEC SQL END DECLARE SECTION; // 主变量声明结束
int main() {
EXEC SQL WHENEVER SQLERROR SQLPRINT; // error 时输出错误信息
// 连接至数据库
EXEC SQL CONNECT TO :target USER :user USING :passwd;
printf("\n已连接%s\n", target);
EXEC SQL drop table if exists game;
EXEC SQL create table game(id int primary key, name char(20));
EXEC SQL prepare mystmt from :stmt;
EXEC SQL execute mystmt using 1, 'Apex Legend';
EXEC SQL execute mystmt using 2, 'Genshin';
EXEC SQL BEGIN; // BEGIN 事务块,DECLARE只能在事务块中使用
// 定义游标,相当于每次读表的一行
EXEC SQL DECLARE iterator CURSOR FOR
select id, name
from game;
EXEC SQL OPEN iterator; // 打开游标
EXEC SQL select count(*) into :rows from game; // 获取行数,只有主变量能被sql赋值
int flag = 0;
while (rows --) {
EXEC SQL fetch iterator into :id, :name; // fetch 获取一行元组
if (flag ++ == 0) { // 第一次把列名输出
printf("\n%-10s %-20s \n", "id", "name");
}
printf("%-10d %-20s \n", id, name);
}
EXEC SQL CLOSE iterator; // 关闭游标
EXEC SQL END; // 结束事务块
EXEC SQL DISCONNECT CURRENT; // 断开数据库2
printf("\n已断开%s\n", target);
return 0;
}
本文介绍了二十几年前的嵌入式操作,欢迎纠错。