ETL应用:一种处理接口的Pro*C实现方法
2007年,当时项目所有ETL采用C编写,实现了ETL基本功能。当接口很多时,为保证文件获取效率,做好接口可配置;文件维护中经常会出现接口晚到情况,需要有一种方法能将接口晚到信息写入数据库,便于短信告警。当时刚学习Pro*C不久,就实现了该方法, 如下
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/wait.h>
#include <errno.h>
#include <sys/types.h>
#include <limits.h>
#include <sqlda.h>
#include <sqlcpr.h>
/*定义数据库连接信息*/
#define USERNAME "masaetl"
#define PASSWORD "masaetl"
#define ORACLESID "DWDB2"
#define MAX_MSG_LENGTH 128
#define MAX_CMD_LENGTH 1024
#define TRUE 1
/*定义告警文件生成目录*/
const char *alarm_path="/ETL_FS/etlfs/interface/toptea";
/*定义处理日期,内部链接的静态变量*/
static char filedate[];
/*调试代码时使用*/
#ifndef DEBUG
#define DEBUG // 定义调试开关
#endif
/*SQL语句返回值定义*/
/*定义返回值,成功为0,错误<0,警告>0 */
#define SQLCODE sqlca.sqlcode
/*SQL语句返回错误解释 */
#define SQLERRMC sqlca.sqlerrm.sqlerrmc
/*包含数据库信息*/
EXEC SQL INCLUDE sqlca;
EXEC SQL INCLUDE sqlda; /*SQL语句返回值定义*/
/*定义返回值,成功为0,错误<0,警告>0*/
#define SQLCODE sqlca.sqlcode
/*SQL语句返回错误解释*/
#define SQLERRMC sqlca.sqlerrm.sqlerrmc
/*执行应用程序说明*/
/*getlinkdata程序每执行一次得到最后提供的晚到接口后都会执行*/
const char * getlinkfile="/ETL_FS/etlfs/interface/service/public/proc/getlinkdata";
/*getlatefile.sh根据得到的晚到接口列表自动提取接口文件并进行链接*/
const char * getlatefile="/ETL_FS/etlfs/interface/service/public/proc/getlatefile.sh";
void sqlerror(); /*处理SQL错误*/
int ConnectDataBase(); /*链接数据库*/
void DisConnectDataBase(); /*断开数据库连接*/
char *getYestDate(char *szDate); /*得到前一天的日期,格式"YYYYMMDD"*/
char *getFileName(const char *szFilePath,char *szFileName); /*从字符串中得到文件名*/
int getAlarmFile(const char *alarmFile); /*生成告警文件*/
char *substitute(char *src,const char *sMatch,const char *sReplace); /*将源字符串中子字符串替换*/
/**************************************
*** 功能: 提取运行在数据库级报错信息
*** 输入变量:
*** 输出变量:
***************************************/
void sqlerror()
{
/*为了避免错误处理时发生死循环,应给出此说明*/
EXEC SQL WHENEVER SQLERROR CONTINUE;
printf("\n Oracle error detected: ");
printf("\n%s",SQLERRMC); /*错误信息*/ /*断开数据库链接*/
EXEC SQL ROLLBACK WORK RELEASE;
exit();
}
/**************************************
*** 功能: 连接数据库
*** 输入变量:
*** 输出变量: -1 连接数据库失败 0 成功
***************************************/
int ConnectDataBase()
{
EXEC SQL BEGIN DECLARE SECTION;
char username[];
char password[];
char oraclesid[];
EXEC SQL END DECLARE SECTION; strcpy(username,USERNAME); /*用户名*/
//username.len=strlen(username.arr); strcpy(password,PASSWORD); /*密码*/
//password.len=strlen(password.arr); strcpy(oraclesid,ORACLESID); /*Oralce SID*/
//oraclesid.len=strlen(oraclesid.arr); /*链接数据库*/
EXEC SQL CONNECT :username IDENTIFIED BY :password USING :oraclesid;
if( SQLCODE ) { return -;
}
return ;
}
/**************************************
*** 功能: 断开数据库连接
*** 输入变量:
*** 输出变量:
***************************************/
void DisConnectDataBase()
{
/*断开连接*/
EXEC SQL ROLLBACK WORK RELEASE;
exit();
}
/***************************************
** 功能 : 得到前一天的日期
*** 输入变量:
*** 输出变量:
****************************************/
char *getYestDate(char *szDate)
{
time_t yest;
struct tm ptime={'\0'};
char szChar[]; //若输入的参数为空,默认提取系统前一天的日期
if ( *szDate =='\0' ){ yest=time(NULL)-(time_t)(**);
strftime(szDate,,"%Y%m%d",localtime(&yest)); return szDate;
}
//提取年
memset(szChar,,sizeof(szChar));
strncpy(szChar,szDate,);
ptime.tm_year=atoi(szChar)-; //提取月
memset(szChar,,sizeof(szChar));
strncpy(szChar,szDate+,);
ptime.tm_mon=atoi(szChar)-; //提取日
memset(szChar,,sizeof(szChar));
strncpy(szChar,szDate+,);
ptime.tm_mday=atoi(szChar); yest=mktime(&ptime)-(time_t)(**);
strftime(szDate,,"%Y%m%d",localtime(&yest)); return szDate;
}
/****************************************
** 功能: 判断当日是否有接口文件晚到
** 有,则将接口晚到信息写入告警文件中
** 输入参数: 告警文件名称
** 输出参数: 接口晚到个数
*****************************************/
int getAlarmFile(const char *alarmFile)
{
FILE *pf; /*申明接口编号,接口处理日期*/
EXEC SQL BEGIN DECLARE SECTION;
char szSql[MAX_CMD_LENGTH];
char szDate[];
int v_count=;
long order_id;
EXEC SQL END DECLARE SECTION; /*得到日期*/
strcpy(szDate,filedate); /*连接数据库*/
if( ConnectDataBase() < ){ printf("连接数据库失败,失败原因[%d][%s]",SQLCODE,SQLERRMC);
return -;
}
/*得到接口晚到个数*/
EXEC SQL SELECT COUNT(DISTINCT A.ORDER_ID) INTO :v_count
FROM MASAETL.ETL_INTERFACE_ALARM A,
(SELECT * FROM MASAETL.ETL_LINK_FILE WHERE FILEDATE=:szDate) B
WHERE A.ORDER_ID=B.ORDER_ID(+) AND B.ORDER_ID IS NULL AND A.IF_ALARM=; /*检查SQL是否可以正常执行*/
if(SQLCODE)
{
printf("line%d:执行检查接口晚到数目SQL失败,错误号:[%d][%s]\n", __LINE__, SQLCODE, SQLERRMC);
return ;
} /*判断当日是否有接口晚到*/
if ( v_count > ){ /*只有在有接口未到时才生成告警文件*/
if ( ( pf=fopen(alarmFile,"a+") ) ==NULL ){ printf("创建当日告警文件失败.\n");
exit();
} /*申明游标*/
EXEC SQL DECLARE later_cursor CURSOR FOR
SELECT DISTINCT A.ORDER_ID
FROM MASAETL.ETL_INTERFACE_ALARM A,
(SELECT * FROM MASAETL.ETL_LINK_FILE WHERE FILEDATE=:szDate) B
WHERE A.ORDER_ID=B.ORDER_ID(+) AND B.ORDER_ID IS NULL AND A.IF_ALARM=; /*打开游标*/
EXEC SQL OPEN later_cursor;
EXEC SQL WHENEVER NOT FOUND DO break; while ( TRUE ){ /*提取记录*/
EXEC SQL FETCH later_cursor INTO :order_id; /*任务记录完,退出while循环*/
if ( SQLCODE == ){ printf("提取记录为空!!!!\n");
break;
}
else if (SQLCODE){ printf("无法正常取得接口编号,退出!!!!\n");
printf("错误原因 SQLCODE=[%d][%s]\n", SQLCODE, SQLERRMC);
continue;
}
/*将告警信息写入文件*/
fprintf(pf,"%ld|",order_id); }
/*关闭游标*/
EXEC SQL CLOSE later_cursor;
/*关闭文件*/
fclose(pf);
} /*断开数据库连接*/
DisConnectDataBase(); return v_count;
}
/****************************************
** 功能: 将字符串中的模式字段替换成日期
** 字段,这里处理的是日接口,模式是固定的YYYYMMDD
** 输入参数:
** src 需要替换的源字符串
** subpattern 为YYYYMMDD
** subdest 为日期变量filedate
** 输出参数: 替换后字符串
*****************************************/
char *substitute(char *src,const char *sMatch,const char *sReplace)
{
int stringLen;
char sNewString[MAX_MSG_LENGTH];
char *FindPos =NULL; FindPos=strstr(src, sMatch); while( FindPos ){ memset(sNewString, , sizeof(sNewString));
stringLen = FindPos - src;
strncpy(sNewString, src, stringLen);
strcat(sNewString, sReplace);
strcat(sNewString, FindPos + strlen(sMatch));
strcpy(src, sNewString);
FindPos = strstr(src, sMatch);
} return src;
}
/***************************************
** 功能 : 主程序
****************************************/
int main(int argc,char **argv)
{
char alarmfile[]; /*告警文件格式,IYYYYMMDD.chk*/
const char *moduel="YYYYMMDD"; /*字符串替换模式*/
char cmdString[MAX_CMD_LENGTH]; /*shell字符串*/ pid_t pid; /*子进程ID*/
int status; /*子进程终止状态*/ EXEC SQL BEGIN DECLARE SECTION;
char pDate[]; long order_id; /*接口编号*/
char file_pattern[]; /*文件模式*/
char source_ip[]; /*源文件IP地址*/
char source_username[]; /*源主机用户名*/
char source_password[]; /*源主机用户密码*/
char source_path[]; /*源主机文件所在目录*/
char destination_path[]; /*目的主机文件目录*/
char link_path[]; /*目的文件主机链接目录*/ short ind_file_pattern;
short ind_source_ip;
short ind_source_username;
short ind_source_password;
short ind_source_path;
short ind_destination_path;
short ind_link_path;
EXEC SQL END DECLARE SECTION; /*得到处理日期,就是上一天的日期*/
getYestDate(filedate);
strcpy(pDate,filedate); sprintf(alarmfile,"%s/IB%s.chk",alarm_path,filedate);
#ifdef DEBUG
printf("告警文件名:[%s].\n",alarmfile);
#endif
/*调用getlinkfile得到最新的系统文件信息*/
if ( system(getlinkfile) < ){ printf("执行getlinkfile应用程序失败.\n");
exit();
} /*使用子进程,第一次执行时将FTP下来后生成告警文件,后面无需再处理告警文件*/
if( ( pid =fork() ) == ){ if ( access(alarmfile,F_OK) < ){ if ( getAlarmFile(alarmfile) == ){ printf("当日无接口晚到.\n");
}
}
}
/*等待子进程结束*/
if( wait(&status)!=pid ){ perror((char *)status);
} /*连接数据库*/
if( ConnectDataBase() < ){ printf("连接数据库失败,失败原因[%d][%s]",SQLCODE,SQLERRMC);
return -;
} /*使用游标得到数据库记录*/
EXEC SQL DECLARE ftp_cursor CURSOR FOR
SELECT A.ORDER_ID, A.FILE_PATTERN,A.SOURCE_IP,A.SOURCE_USERNAME,
A.SOURCE_PASSWORD,A.SOURCE_PATH,A.DESTINATION_PATH,A.LINK_PATH
FROM MASAETL.ETL_INTERFACE_ALARM A,
(SELECT * FROM MASAETL.ETL_LINK_FILE WHERE FILEDATE=:pDate) B
WHERE A.ORDER_ID=B.ORDER_ID(+) AND B.ORDER_ID IS NULL AND A.IF_CHECK=; /*检查SQL执行情况*/
if( SQLCODE )
{
printf("执行提取晚到接口SQL失败,失败原因:[%d][%s].\n", SQLCODE, SQLERRMC);
exit();
} /*打开游标*/
EXEC SQL OPEN ftp_cursor;
EXEC SQL WHENEVER NOT FOUND DO break; while ( TRUE )
{
/*提取记录*/
EXEC SQL FETCH ftp_cursor INTO :order_id, :file_pattern:ind_file_pattern, :source_ip:ind_source_ip,
:source_username:ind_source_username, :source_password:ind_source_password,
:source_path:ind_source_path, :destination_path:ind_destination_path, :link_path:ind_link_path; /*任务记录完,退出while循环*/
if ( SQLCODE ){ printf("提取接口编号失败,错误原因 SQLCODE=[%d][%s]\n", SQLCODE, SQLERRMC);
continue;
} /*判断记录的有效性*/
if (ind_file_pattern==-){ printf("文件模式为空.\n");
continue;
}
if (ind_source_ip==-){ printf("源IP地址为空.\n");
continue;
}
if (ind_source_username==-){ printf("源主机用户名为空.\n");
continue;
}
if (ind_source_password==-){ printf("源主机密码为空.\n");
continue;
}
if (ind_source_path==-){ printf("源主机目录为空.\n");
continue;
}
if (ind_destination_path==-){ printf("目的主机目录为空.\n");
continue;
}
if (ind_link_path==-){ printf("目录链接目录为空.\n");
continue;
} /*对文件模式字段进行字符串替换*/
substitute(file_pattern,moduel,filedate); /*对源主机目录字段进行字符串替换*/
substitute(destination_path,moduel,filedate); /*执行shell程序ftp数据文件*/
memset(cmdString,,sizeof(cmdString));
sprintf(cmdString,"%s %s %s %s %s %s %s %s",getlatefile,source_ip,source_username,source_password,
source_path,file_pattern,destination_path,link_path);
#ifdef DEBUG
printf("生成提取接口文件命令[%s].\n",cmdString);
#endif /*执行文件提取及链接*/
if ( system(cmdString) < ){ printf("获取接口[%ld]文件失败.\n",order_id);
} }
/*关闭游标*/
EXEC SQL CLOSE ftp_cursor; /*断开数据库连接*/
DisConnectDataBase(); return ;
}
:
ETL应用:一种处理接口的Pro*C实现方法的更多相关文章
- 【转载】JAVA中综合接口和抽象类实现的一种“抽象接口”
Muscleape个人总结:(这里的抽象接口是指:使用一个抽象类实现一个接口,是两部分结构) 使用一个抽象类直接实现接口,将接口中的方法区分为实现类必须要实现的和选择性实现的,其他需要实现接口的类型通 ...
- 【转载】认识SSD的SATA、mSATA 、PCIe和M.2四种主流接口
认识SSD的SATA.mSATA .PCIe和M.2四种主流接口 2018-09-25 • 工具 • 评论关闭 认识SSD的SATA.mSATA .PCIe和M.2四种主流接口
- C# IComparable接口、IComparer接口和CompareTo(Object x)方法、Compare()方法
在项目中经常会用到字符串比较,但是有时候对字符串的操作比较多,规则各异.比如有的地方我们需要用排序规则,有的地方需要忽略大小写,我们该如何写一个比较容易操作的比较方法呢?重新实现IComparer接口 ...
- Cloneable接口和Object的clone()方法
为什么要克隆 为什么要使用克隆,这其实反映的是一个很现实的问题,假如我们有一个对象: public class SimpleObject implements Cloneable { private ...
- 【JPA】两种不同的实现jpa的配置方法
两种不同的实现jpa的配置方法 第一种: com.mchange.v2.c3p0.ComboPooledDataSource datasource.connection.driver_class=co ...
- 一种快速查询多点DS18B20温度的方法(转)
源:http://hi.baidu.com/james_xiao/item/79b961c90623093e45941623 一种快速查询多点DS18B20温度的方法 引言 为了满足实时性要 ...
- java接口中成员变量和方法的默认修饰符(转)
Java的interface中,成员变量的默认修饰符为:public static final 所以我们在interface中定义成员变量的时候,可以 1:public static final St ...
- PatentTips -- 一种在CoAP网络中注册的方法及装置
技术领域 [0001] 本发明涉及一种在CoAP网络中注册的方法及装置,属于网络通信技术领域. 背景技术 [0002] (Internet of Things,物联网)作为新一代的信息技术,越来越受到 ...
- Java多线程(1):3种常用的实现多线程类的方法
(1) 继承java.lang.Thread类(Thread也实现了Runnable接口) 继承Thread类的方法是比较常用的一种,如果说你只是想起一条线程.没有什么其它特殊的要求,那么可以使用Th ...
随机推荐
- 【Mac + Python3.6 + ATX基于facebook-wda】之IOS自动化(一):WebDriverAgent安装
此篇介绍如何安装WebDriverAgent,下一篇介绍facebook-wda库的安装使用以及自动化脚本的开发. 前言: 对于iOS的应用的测试,如果不需要用到图像识别,推荐使用这个项目facebo ...
- 【Mac + Appium + Python3.6学习(三)】之IOS自动化测试环境配置
在做这一节之前先配置我的另一篇文章所需要安装的前提准备条件:<[Mac + Appium学习(一)]之安装Appium环境前提准备> 一.安装IOS自动化测试环境 配置环境: Appium ...
- Hibernate每个具体类一张表映射(使用注释)
在每个类创建一张表的情况下, 表中不使用Null值的列. 这种方法的缺点是在子类表中创建了重复的列. 在这里,我们需要在父类中使用@Inheritance(strategy = Inheritance ...
- MEF笔记 之延迟加载
文章参考:在MEF中实现延迟加载部件 作者:TianFang 仅有一个服务提供者时候 using System; using System.Collections.Generic; using Sy ...
- 怎么在Word中找MathType菜单
一些用户朋友在使用word的过程中,发现自己突然找不到MathType公式编辑器菜单项了,而这个时候又急着编写公式,所以会特别的着急.下面我们就来针对这个问题好好的给大家分析一下,并提供解决方案.请关 ...
- python各种库、框架的安装和卸载
才疏学浅,努力深入,逐步更新,有问题敬请留言告知,谢谢. 关于python第三方库的安装最好少使用 easy_install,因为 easy_install 只能安装不能卸载,如果要卸载需要进入到 p ...
- 解决erlang R17无法识别中文问题
erlang更新到R17已有一段时间了.公司项目打算从旧版的erlang迁移到R17,却不料有不少的困扰,当中一个问题是中文问题. 这个问题非常easy重现:新建一个文件t.erl.保存为utf-8无 ...
- js 时间戳转换为指定的日期格式
function formatDate(date, fmt) { if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFul ...
- C语言-数组篇
C语言数组 一.数组的概念 用来存储一组数据的构造数据类型 特点:只能存放一种类型的数据,如全部是int型或者全部是char型,数组里的数据成为元素. 二.数组的定义 格式: 类型 数组名[元素个数] ...
- You can add an index on a column that can have NULL values if you are using the MyISAM, InnoDB, or MEMORY storage engine.
w https://dev.mysql.com/doc/refman/5.7/en/create-index.html MySQL :: MySQL 5.7 Reference Manual :: B ...