最近搞个MYBATIS-PLUS里面的MAPPER DAO方法审计.就是把里面的SQL提取出来,然后使用SQL质量工具进行审计!
SQLE 在这方面功能强大,就是细节不够完美,它有SCANDR工具可以把某个目录下XML文件扫描并上传到SQLE里面进行审计.
通过自由裁剪的MYSQL 审核规则,一条条SQL进行! 问题是那么多SQL,不符合规范的是来之哪个文件,哪个方法?
像这样子就满意了
我通过提示方式来判断这个SQL来之哪里
SCANDER工具 它扫描 上传 显示是否通过,不通过显示是哪条规则,最后总是报个错误出来.
社区版也就这样,功能超强,细节不完美,要完美估计要买企业版.
所以作为一个初级程序员 之 C 就只好自己动手丰衣足食了!
经过3周,3个周的工作日,加班2个小时到8点,才初步成型. 上班时间要干其它活,只要下班,才能专心写代码,调试代码.
下面一段是用直接IO读写文件,就是绕过LINUX的系统缓存.
PG一大BUG 就是使用双缓存,导致某些SQL执行时快时慢,对DBA要精细调整两边的缓存比! MYSQL和ORACLE不这样干!
PG ACE 大部分没有代码动手的能力,有PPT,文档编辑能力以及演讲口才能力.
要使用DIO需要3个小条件
1 需要堆上分配
2 需要512字节对齐
3 需要4KB整数倍写入文件
下面代码开始大部分是在程序当前目录下创建一个XXX.SQL文件,
有就只写,追加,直接,同步方式写入数据.
int fd = open(filePath, O_CREAT | O_APPEND | O_WRONLY | O_DIRECT | O_SYNC, 0644);
从双层MAP对象里提取出SQL
MAP<STRING,MAP<STRING,STRING>> OBJECT;
这个对象保存了 文件名,方法名,SQL的对应关系
定义个通用类型的内存地址变量 memAddr_buf
memAddr_buf = memalign(512, 512 * 8); 通过这个函数进行512字节对齐,对4096字节,它自动在堆上分配4096字节
memcpy(memAddr_buf, it->second.c_str(), it->second.size()); 通过内存CP函数把MAP里的SQL拷贝进去*(char*)((char*)memAddr_buf + sql_size) = '\n'; 这段内容后面添加个换行符号,有意思的代码.是AI浣熊告知的. 然后就写入文件一次必须4KB字节倍数,成功返回写入字节,错误返回-1int ret = write(fd, memAddr_buf, 4096);free(memAddr_buf); 最后就是释放内存. 这4个函数OPEN,WRITE,MEMALIGN,FREE都是LINUX系统提供的函数.
char current_dir[PATH_MAX]; //创建文件 并导出SQL语句到文件里
char fileName[]="ParseXMLFetchSQL.sql";
char filePath[PATH_MAX];
if(getcwd(current_dir,sizeof(current_dir)) != NULL)
{
if (is_debug) {printf("Current Working Directory:%s\n",current_dir);}
strcpy(filePath, current_dir);
strcat(filePath, "/");
strcat(filePath, fileName);
if (is_debug) {printf("filePath:%s\n",filePath);}
int fd = open(filePath, O_CREAT | O_APPEND | O_WRONLY | O_DIRECT | O_SYNC, 0644);
if (fd == -1)
{
printf("Error Open File %s\n",filePath);
close(fd);
return 1;
}
else
{
if (is_debug) {printf("fileName Number:%d\n",filename_sql_map.size());}
for (auto it = filename_sql_map.begin(); it != filename_sql_map.end(); ++it)
{
std::map<std::string,std::string> read_sql_map;
read_sql_map = it->second;
if (is_debug) {printf("SQL Number:%d\n",read_sql_map.size());}
void* memAddr_buf;
memAddr_buf = memalign(512, 512 * 8);
if (!memAddr_buf) { printf("Failed to alloc write buffer\n"); free(memAddr_buf); }
for(auto it = read_sql_map.begin(); it != read_sql_map.end(); ++it)
{
unsigned int sql_size=it->second.size();
memset(memAddr_buf,'\0',4096);
memcpy(memAddr_buf, it->second.c_str(), it->second.size());
*(char*)((char*)memAddr_buf + sql_size) = '\n';
int ret = write(fd, memAddr_buf, 4096);
if (ret == -1)
{
printf("Error Write File %s\n",filePath);
close(fd);
free(memAddr_buf);
return 1;
}
} // for sql map
free(memAddr_buf);
}//for filename_sql_map
}
}
下面是头文件. 有兴趣的朋友可以试试
/*
By Sharkz(小凡仙) 曾凡坤 2024-07-08
*/
/* Standard C++ headers */
#include <iostream> //输入输出流
#include <fstream> //文件流
//#include <sstream> //字符串流
#include <stdexcept> //标准异常
#include <map> //MAP 类
#include <string> //字符串类
//#include <chrono> //获得纳秒时间 Calc_time_diff
#include <vector> //动态数组
#include <cstdlib>
//C LANGE LIB
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
//Liunx sys lib
#include <fcntl.h> //linux 文件库
#include <unistd.h> //进程库
#include <dirent.h> //posix
/*
g++ -g main.cpp -std=c++11 -o main.exe
./main.exe -d /home/shark/projects/CPP_Projects/ParseXmlSql > run.log
*/
using namespace std;
写后文件内容是这样的,两个SQL中间一大段是NULL
哎 搞到高兴之处,把生产的14个SQL的文件传给SQLE进行审核,居然说语法不支持,开始我以为HINT放的位置不对, 另外SQLE还说SQL太长了,要分成多个SQL的提示. 以前直接审计XML文件,对有些超长的方法也是这样报错,我以为想当然. 直到看到一个DELETE语句 不到50个字母,也这样说,就忽然明白了什么. SQLE没有去空. 我写文件一次写入4096个字节,也可以说字符,大部分提取的SQL顶多是1500个字母,后面好几千都NULL.
哎 搞得我要放弃这段DIO,直接写文件的代码.
心里不是个滋味!