examples/MySQL2openGauss/src/ProcOdbc.cpp

994 lines
29 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <sqlext.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <string.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include "ProcOdbc.h"
#define SQLK_CREATE_TABLE "CREATE TABLE "
#define SQLK_UNIQUE_KEY "UNIQUE KEY "
#define SQLK_PRIMARY_KEY "PRIMARY KEY "
#define SQLK_FOREIGN_KEY "FOREIGN KEY "
#define SQLK_KEY "KEY "
#define SQLK_COMMENT " COMMENT '"
#define SQLK_BYTEA_START " bytea("
#define SQLK_BYTEA_END ")"
#define SQLK_BYTEA " bytea"
#define SQLK_SET_START " set("
#define SQLK_SET_END ")"
#define SQLK_TEXT " text"
#define SQLK_PROCEDURE "PROCEDURE"
#define SQLK_PROCEDURE_DEF_END ")"
#define SQLK_FUNCTION "FUNCTION"
#define SQLK_FUNCTION_DEF_END "\n"
#define SQLK_INSERT_INTO "\nINSERT INTO \""
#define SQLK_DOUBLE_BRACKET " double("
#define SQLK_DOUBLE_BRACKET_END ")"
#define DATA_NOT_SEND_ERROR "could not send data"
#define NO_CONNECTION_ERROR "no connection"
#define NULL_STRING_ERROR "violates not-null constraint"
#define TABLE_ALREADY_EXIST_ERROR "\" already exists;"
#define INFO_LOG_LEVEL 3
#define WARN_LOG_LEVEL 4
#define ERROR_LOG_LEVEL 5
namespace DMODBC {
struct ReplaceKV {
std::string key;
std::string value;
};
struct DBInfo {
SQLHENV V_OD_Env; // Handle ODBC environment
SQLHSTMT V_OD_hstmt; // Handle statement
SQLHDBC V_OD_hdbc; // Handle connection
char sqlattr[100];
SQLINTEGER V_OD_erg;
SQLINTEGER V_OD_buffer;
SQLINTEGER V_OD_err;
SQLINTEGER V_OD_id;
};
static void printDBError(SQLSMALLINT type, SQLHDBC hdbc,
struct DBError *dbError) {
char status[16];
int buflen = 1024;
char *msg = (char *)malloc(buflen);
msg[0] = '\0';
SQLSMALLINT sqlmsglen;
SQLINTEGER sqlerr;
SQLGetDiagRec(type, hdbc, 1, (SQLCHAR *)status, &sqlerr, (SQLCHAR *)msg,
buflen - 1, &sqlmsglen);
if (buflen < sqlmsglen) {
free(msg);
buflen = sqlmsglen;
msg = (char *)malloc(buflen);
msg[0] = '\0';
SQLGetDiagRec(type, hdbc, 1, (SQLCHAR *)status, &sqlerr, (SQLCHAR *)msg,
buflen - 1, &sqlmsglen);
}
printf("%s: %s\n", status, msg);
if (dbError != NULL) {
dbError->error = status;
dbError->error += ": ";
dbError->error += msg;
if (strstr(msg, TABLE_ALREADY_EXIST_ERROR)) {
dbError->alreadyExistError = true;
} else {
dbError->alreadyExistError = false;
}
}
free(msg);
}
static bool isConnectionError(SQLSMALLINT type, SQLHDBC hdbc) {
bool ret = false;
char status[16];
int buflen = 1024;
char *msg = (char *)malloc(buflen);
msg[0] = '\0';
SQLSMALLINT sqlmsglen;
SQLINTEGER sqlerr;
SQLGetDiagRec(type, hdbc, 1, (SQLCHAR *)status, &sqlerr, (SQLCHAR *)msg,
buflen - 1, &sqlmsglen);
if (buflen < sqlmsglen) {
free(msg);
buflen = sqlmsglen;
msg = (char *)malloc(buflen);
msg[0] = '\0';
SQLGetDiagRec(type, hdbc, 1, (SQLCHAR *)status, &sqlerr, (SQLCHAR *)msg,
buflen - 1, &sqlmsglen);
}
if (strstr(msg, DATA_NOT_SEND_ERROR) || strstr(msg, NO_CONNECTION_ERROR)) {
ret = true;
}
free(msg);
return ret;
}
static bool isNullStringError(SQLSMALLINT type, SQLHDBC hdbc) {
bool ret = false;
char status[16];
int buflen = 1024;
char *msg = (char *)malloc(buflen);
msg[0] = '\0';
SQLSMALLINT sqlmsglen;
SQLINTEGER sqlerr;
SQLGetDiagRec(type, hdbc, 1, (SQLCHAR *)status, &sqlerr, (SQLCHAR *)msg,
buflen - 1, &sqlmsglen);
if (buflen < sqlmsglen) {
free(msg);
buflen = sqlmsglen;
msg = (char *)malloc(buflen);
msg[0] = '\0';
SQLGetDiagRec(type, hdbc, 1, (SQLCHAR *)status, &sqlerr, (SQLCHAR *)msg,
buflen - 1, &sqlmsglen);
}
if (strstr(msg, NULL_STRING_ERROR)) {
ret = true;
}
free(msg);
return ret;
}
static void replace(std::string &src, const char *orgstr, const char *newstr) {
std::string::size_type pos = src.find(orgstr);
while (pos != std::string::npos) {
src.replace(pos, strlen(orgstr), newstr);
pos = src.find(orgstr);
}
}
static bool replaceonce(std::string &src, const char *orgstr,
const char *newstr) {
bool ret = false;
std::string::size_type pos = src.find(orgstr);
if (pos != std::string::npos) {
src.replace(pos, strlen(orgstr), newstr);
ret = true;
}
return ret;
}
static std::string trim(const std::string &s) {
static const char *whiteSpace = " \t\r\n";
if (s.empty()) {
return s;
}
std::string::size_type b = s.find_first_not_of(whiteSpace);
if (std::string::npos == b) {
return "";
}
std::string::size_type e = s.find_last_not_of(whiteSpace);
return std::string(s, b, e - b + 1);
}
static int getLine(std::istream &in, std::string &strLine) {
strLine = "";
int count = 0;
bool lineFlag = false;
char ch;
do {
ch = in.get();
if (!in.good()) {
if (count > 0) {
return count;
} else {
return -1;
}
}
switch (ch) {
case '\r':
break;
case '\n':
lineFlag = true;
break;
default:
strLine += ch;
count++;
break;
}
} while (!lineFlag);
return count;
}
static void loadKvList(std::istream &in, std::list<ReplaceKV> &replaceKvList) {
std::string fullLine, command;
std::string leftSide, rightSide;
std::string::size_type length;
while (getLine(in, fullLine) != -1) {
length = fullLine.find('#');
if (std::string::npos == length) {
command = fullLine;
} else if (length > 0) {
command = fullLine.substr(0, length);
} else {
continue;
}
command = trim(command);
length = command.find('=');
if (std::string::npos != length) {
if ((length + 1) != command.size()) {
leftSide = trim(command.substr(0, length));
rightSide = trim(command.substr(length + 1));
} else {
leftSide = trim(command.substr(0, length));
rightSide = "";
}
} else {
continue;
}
ReplaceKV replaceKv;
replaceKv.key = leftSide;
replaceKv.value = rightSide;
replaceKvList.push_back(replaceKv);
}
}
static void loadKvList(const char *kvListFile,
std::list<ReplaceKV> &replaceKvList) {
std::ifstream inputStream;
inputStream.open(kvListFile);
if (!inputStream.fail()) {
loadKvList(inputStream, replaceKvList);
inputStream.close();
} else {
printf("cannot open kv file %s\n", kvListFile);
}
}
static void loadKvMap(std::istream &in,
std::map<std::string, std::string> &replaceKvMap) {
std::string fullLine, command;
std::string leftSide, rightSide;
std::string::size_type length;
while (getLine(in, fullLine) != -1) {
length = fullLine.find('#');
if (std::string::npos == length) {
command = fullLine;
} else if (length > 0) {
command = fullLine.substr(0, length);
} else {
continue;
}
command = trim(command);
length = command.find('=');
if (std::string::npos != length) {
if ((length + 1) != command.size()) {
leftSide = trim(command.substr(0, length));
rightSide = trim(command.substr(length + 1, command.size() - length));
} else {
leftSide = trim(command.substr(0, length));
}
} else {
continue;
}
replaceKvMap[leftSide] = rightSide;
}
}
static void loadKvMap(const char *kvListFile,
std::map<std::string, std::string> &replaceKvMap) {
std::ifstream inputStream;
inputStream.open(kvListFile);
if (!inputStream.fail()) {
loadKvMap(inputStream, replaceKvMap);
inputStream.close();
} else {
printf("cannot open kv file %s\n", kvListFile);
}
}
static std::list<ReplaceKV> getCreateTableReplaceKV() {
std::list<ReplaceKV> ret;
std::string replaceKvFile;
const char *homedir = getenv(MYSQL_TO_OPENGAUSS_HOME_DIR);
if (!homedir) {
return ret;
}
replaceKvFile = homedir;
replaceKvFile += "/conf/createtablerkv.prop";
loadKvList(replaceKvFile.c_str(), ret);
return ret;
}
static std::list<ReplaceKV> getCreateFunctionReplaceKV() {
std::list<ReplaceKV> ret;
std::string replaceKvFile;
const char *homedir = getenv(MYSQL_TO_OPENGAUSS_HOME_DIR);
if (!homedir) {
return ret;
}
replaceKvFile = homedir;
replaceKvFile += "/conf/createfunctionrkv.prop";
loadKvList(replaceKvFile.c_str(), ret);
return ret;
}
static std::list<ReplaceKV> getCreateFunctionTypeKV() {
std::list<ReplaceKV> ret;
std::string replaceKvFile;
const char *homedir = getenv(MYSQL_TO_OPENGAUSS_HOME_DIR);
if (!homedir) {
return ret;
}
replaceKvFile = homedir;
replaceKvFile += "/conf/createfunctiontkv.prop";
loadKvList(replaceKvFile.c_str(), ret);
return ret;
}
ProcOdbc::ProcOdbc(const char *datasource)
: isconn_(false), loglevel_(INFO_LOG_LEVEL) {
strcpy(datasource_, datasource);
dbinfo_ = new DBInfo;
currentArgc_ = 4;
currentArgv_ = (char **)malloc(sizeof(char *) * currentArgc_);
currentArgv_[0] = (char *)malloc(256);
strcpy(currentArgv_[0], "mysqltoopengauss");
currentArgv_[1] = (char *)malloc(256);
strcpy(currentArgv_[1], "--compatible=postgresql");
currentArgv_[2] = (char *)malloc(256);
strcpy(currentArgv_[2], "--default-character-set=utf8");
currentArgv_[3] = (char *)malloc(256);
currentArgv_[3][0] = '\0';
}
ProcOdbc::~ProcOdbc() {
disConnect();
delete (DBInfo *)dbinfo_;
freeCurrentArgv();
}
struct MysqlInfo ProcOdbc::getMysqlInfo() {
std::string confFile;
std::map<std::string, std::string> confMap;
struct MysqlInfo ret;
const char *homedir = getenv(MYSQL_TO_OPENGAUSS_HOME_DIR);
if (!homedir) {
return ret;
}
confFile = homedir;
confFile += "/conf/mysql2opengauss.prop";
loadKvMap(confFile.c_str(), confMap);
ret.host = confMap["mysql_host"];
ret.port = atoi(confMap["mysql_port"].c_str());
ret.username = confMap["mysql_username"];
ret.password = confMap["mysql_password"];
ret.database = confMap["mysql_database"];
ret.loglevel = atoi(confMap["loglevel"].c_str());
ret.dsthost = confMap["opengauss_host"];
ret.dstport = atoi(confMap["opengauss_port"].c_str());
ret.dstdatabase = confMap["opengauss_database"];
printf("from MySQL %s:%d database %s to openGauss %s:%d database %s\n",
confMap["mysql_host"].c_str(), atoi(confMap["mysql_port"].c_str()),
confMap["mysql_database"].c_str(), confMap["opengauss_host"].c_str(),
atoi(confMap["opengauss_port"].c_str()),
confMap["opengauss_database"].c_str());
return ret;
}
bool ProcOdbc::isConnected() { return isconn_; }
bool ProcOdbc::connect() {
if (isconn_) {
// 已经连接
return isconn_;
}
DBInfo *dbinfo = (DBInfo *)dbinfo_;
// 1. 申请环境句柄
dbinfo->V_OD_erg =
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &dbinfo->V_OD_Env);
if ((dbinfo->V_OD_erg != SQL_SUCCESS) &&
(dbinfo->V_OD_erg != SQL_SUCCESS_WITH_INFO)) {
printf("Error AllocHandle SQL_HANDLE_ENV\n");
return isconn_;
}
// 2. 设置环境属性(版本信息)
SQLSetEnvAttr(dbinfo->V_OD_Env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3,
0);
// 3. 申请连接句柄
dbinfo->V_OD_erg =
SQLAllocHandle(SQL_HANDLE_DBC, dbinfo->V_OD_Env, &dbinfo->V_OD_hdbc);
if ((dbinfo->V_OD_erg != SQL_SUCCESS) &&
(dbinfo->V_OD_erg != SQL_SUCCESS_WITH_INFO)) {
SQLFreeHandle(SQL_HANDLE_ENV, dbinfo->V_OD_Env);
printf("Error AllocHandle SQL_HANDLE_DBC\n");
printDBError(SQL_HANDLE_ENV, dbinfo->V_OD_Env, NULL);
return isconn_;
}
// 4. 设置连接属性
SQLSetConnectAttr(dbinfo->V_OD_hdbc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_ON, 0);
// 5.
// odbc.ini文件中已经配置了用户名密码那么这里可以留空""但是不建议这么做因为一旦odbc.ini权限管理不善将导致数据库用户密码泄露。
printf("datasource: %s\n", datasource_);
dbinfo->V_OD_erg =
SQLConnect(dbinfo->V_OD_hdbc, (SQLCHAR *)datasource_, SQL_NTS,
(SQLCHAR *)"", SQL_NTS, (SQLCHAR *)"", SQL_NTS);
if ((dbinfo->V_OD_erg != SQL_SUCCESS) &&
(dbinfo->V_OD_erg != SQL_SUCCESS_WITH_INFO)) {
printf("Error SQLConnect %d\n", (int)(dbinfo->V_OD_erg));
printDBError(SQL_HANDLE_DBC, dbinfo->V_OD_hdbc, NULL);
SQLFreeHandle(SQL_HANDLE_ENV, dbinfo->V_OD_Env);
return isconn_;
}
printf("Connected !\n");
// 6. 设置语句属性
SQLSetStmtAttr(dbinfo->V_OD_hstmt, SQL_ATTR_QUERY_TIMEOUT, (SQLPOINTER *)3,
0);
// 7. 申请语句句柄
SQLAllocHandle(SQL_HANDLE_STMT, dbinfo->V_OD_hdbc, &dbinfo->V_OD_hstmt);
isconn_ = true;
return isconn_;
}
void ProcOdbc::disConnect() {
if (!isconn_) {
// 没有连接,直接返回
return;
}
isconn_ = false;
DBInfo *dbinfo = (DBInfo *)dbinfo_;
// 16. 断开数据源连接并释放句柄资源
SQLFreeHandle(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt);
SQLDisconnect(dbinfo->V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, dbinfo->V_OD_hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, dbinfo->V_OD_Env);
}
bool ProcOdbc::reConnect() {
disConnect();
return connect();
}
std::list<std::string> ProcOdbc::procCreateTableSql(const char *sql,
const char *incrementkey) {
std::string retsql = sql;
std::string ik;
if (incrementkey != NULL) {
ik = incrementkey;
}
replaceCreateTableSql(retsql);
return procCreateTableSqlLine(retsql, ik);
}
std::string ProcOdbc::procProcedureFunctionSql(const char *sql,
bool &isfunction) {
static std::list<ReplaceKV> funrkv;
static std::list<ReplaceKV> funtkv;
std::string ret;
std::string sqlstr = sql;
replace(sqlstr, "`", "\"");
replace(sqlstr, "\r", "");
std::string::size_type pos = sqlstr.find(SQLK_PROCEDURE);
std::string::size_type pos2 = sqlstr.find(SQLK_PROCEDURE_DEF_END, pos + 1);
if ((pos != std::string::npos) && (pos2 != std::string::npos)) {
isfunction = false;
ret = "CREATE ";
ret += sqlstr.substr(pos, pos2 - pos + 1);
ret += " IS ";
ret += sqlstr.substr(pos2 + 1);
} else {
isfunction = true;
if (funrkv.empty()) {
funrkv = getCreateFunctionReplaceKV();
funtkv = getCreateFunctionTypeKV();
}
// 替换一般信息,只换一次
for (std::list<ReplaceKV>::iterator iter = funrkv.begin();
iter != funrkv.end(); iter++) {
if (replaceonce(sqlstr, iter->key.c_str(), iter->value.c_str())) {
break;
}
}
// 替换类型,只换一次
for (std::list<ReplaceKV>::iterator iter = funtkv.begin();
iter != funtkv.end(); iter++) {
if (replaceonce(sqlstr, iter->key.c_str(), iter->value.c_str())) {
break;
}
}
pos = sqlstr.find(SQLK_FUNCTION);
pos2 = sqlstr.find(SQLK_FUNCTION_DEF_END, pos + 1);
if ((pos != std::string::npos) && (pos2 != std::string::npos)) {
ret = "CREATE ";
ret += sqlstr.substr(pos, pos2 - pos + 1);
ret += " AS $$ ";
ret += sqlstr.substr(pos2 + 1);
ret += "; $$ LANGUAGE plpgsql";
}
}
return ret;
}
std::string &ProcOdbc::replaceCreateTableSql(std::string &sql) {
static std::list<ReplaceKV> replaceKVs;
if (replaceKVs.empty()) {
replaceKVs = getCreateTableReplaceKV();
}
for (std::list<ReplaceKV>::iterator iter = replaceKVs.begin();
iter != replaceKVs.end(); iter++) {
replace(sql, iter->key.c_str(), iter->value.c_str());
}
formatByteaAtCreateTableSql(sql);
formatSetAtCreateTableSql(sql);
return sql;
}
std::list<std::string> ProcOdbc::procCreateTableSqlLine(
const std::string &sql, const std::string &incrementkey) {
std::list<std::string> ret;
std::string table;
std::string outputsql;
std::string tmp;
std::string tmp2;
std::string::size_type tmppos;
std::string::size_type tmppos2;
std::string::size_type tmppos3;
std::string::size_type tmppos4;
std::string::size_type pos = 0;
std::string::size_type nextpos;
bool iskeyline;
int createTableLen = strlen(SQLK_CREATE_TABLE);
int uniqueKeyLen = strlen(SQLK_UNIQUE_KEY);
int keyLen = strlen(SQLK_KEY);
int commentLen = strlen(SQLK_COMMENT);
int doubleBracketLen = strlen(SQLK_DOUBLE_BRACKET);
nextpos = sql.find('\n', pos);
while (nextpos != std::string::npos) {
iskeyline = false;
tmp = sql.substr(pos, nextpos - pos);
// CREATE TABLE
tmppos = tmp.find(SQLK_CREATE_TABLE);
if (tmppos != std::string::npos) {
tmppos2 = tmp.find('(');
if (tmppos2 != std::string::npos) {
table = tmp.substr(tmppos + createTableLen,
tmppos2 - tmppos - createTableLen - 1);
}
iskeyline = true;
} else {
// double bracket
tmppos = tmp.find(SQLK_DOUBLE_BRACKET);
if (tmppos != std::string::npos) {
tmppos2 = tmp.find(SQLK_DOUBLE_BRACKET_END, tmppos + doubleBracketLen);
if (tmppos2 != std::string::npos) {
tmp2 = tmp.substr(0, tmppos);
tmp2 += " double precision ";
tmp2 += tmp.substr(tmppos2 + strlen(SQLK_DOUBLE_BRACKET_END));
tmp = tmp2;
}
}
// COMMENT
tmppos = tmp.find(SQLK_COMMENT);
if (tmppos != std::string::npos) {
tmppos2 = tmp.find('\'', tmppos + commentLen);
tmppos3 = tmp.find('"');
tmppos4 = tmp.find('"', tmppos3 + 2);
if ((tmppos2 != std::string::npos) && (tmppos3 != std::string::npos) &&
(tmppos4 != std::string::npos)) {
tmp2 = "COMMENT ON COLUMN ";
tmp2 += table + ".";
tmp2 += tmp.substr(tmppos3, tmppos4 - tmppos3 + 1);
tmp2 += " IS ";
tmp2 += tmp.substr(tmppos + commentLen - 1,
tmppos2 + 2 - tmppos - commentLen);
ret.push_back(tmp2);
}
tmp = tmp.substr(0, tmppos) + ",";
} else {
// UNIQUE KEY
tmppos = tmp.find(SQLK_UNIQUE_KEY);
if (tmppos != std::string::npos) {
tmppos2 = tmp.find('(');
if (tmppos2 != std::string::npos) {
tmp2 = " CONSTRAINT";
tmp2 += " \"";
tmp2 += table.substr(1, table.size() - 2);
tmp2 += "_";
tmp2 += tmp.substr(tmppos + uniqueKeyLen + 1,
tmppos2 - tmppos - uniqueKeyLen - 1);
tmp2 += "UNIQUE ";
tmp2 += tmp.substr(tmppos2);
tmp = tmp2;
}
iskeyline = true;
} else {
// PRIMARY KEY
tmppos = tmp.find(SQLK_PRIMARY_KEY);
if (tmppos != std::string::npos) {
// PRIMARY KEY不需要处理
iskeyline = true;
} else {
// FOREIGN KEY
tmppos = tmp.find(SQLK_FOREIGN_KEY);
if (tmppos != std::string::npos) {
// FOREIGN KEY不需要处理
iskeyline = true;
} else {
// KEY
tmppos = tmp.find(SQLK_KEY);
if (tmppos != std::string::npos) {
tmppos2 = tmp.find('(');
if (tmppos2 != std::string::npos) {
tmppos3 = tmp.find(')', tmppos2);
if (tmppos3 != std::string::npos) {
tmp2 = "CREATE INDEX";
tmp2 += " \"";
tmp2 += table.substr(1, table.size() - 2);
tmp2 += "_";
tmp2 += tmp.substr(tmppos + keyLen + 1,
tmppos2 - tmppos - keyLen - 2);
tmp2 += " ON ";
tmp2 += table;
tmp2 += tmp.substr(tmppos2, tmppos3 - tmppos2 + 1);
ret.push_back(tmp2);
tmp = "";
}
}
iskeyline = true;
}
}
}
}
}
}
if (!tmp.empty()) {
if (!iskeyline && !incrementkey.empty()) {
if (tmp.find(incrementkey) != std::string::npos) {
// 自增主键
tmppos = tmp.rfind(",");
if (tmppos != std::string::npos) {
tmp = tmp.substr(0, tmppos) + " default nextval('seq_" +
table.substr(1, table.size() - 2) + "_" +
incrementkey.substr(1, incrementkey.size() - 2) + "'),";
} else {
tmp = tmp.substr(0, tmppos) + " default nextval('seq_" +
table.substr(1, table.size() - 2) + "_" +
incrementkey.substr(1, incrementkey.size() - 2) + "')";
}
}
}
outputsql += tmp + "\n";
}
pos = nextpos + 1;
nextpos = sql.find('\n', pos);
}
if (outputsql.at(outputsql.size() - 2) == ',') {
outputsql = outputsql.substr(0, outputsql.size() - 2) + "\n";
}
outputsql += sql.substr(pos);
ret.push_front(outputsql);
if (!incrementkey.empty()) {
// 如果有自增主键,增加自增主键创建语句
outputsql = "create SEQUENCE seq_";
outputsql += table.substr(1, table.size() - 2) + "_" +
incrementkey.substr(1, incrementkey.size() - 2);
outputsql += " cache 100";
ret.push_front(outputsql);
outputsql = "alter SEQUENCE seq_";
outputsql += table.substr(1, table.size() - 2) + "_" +
incrementkey.substr(1, incrementkey.size() - 2);
outputsql += " OWNED by ";
outputsql += table;
outputsql += ".";
outputsql += incrementkey;
ret.push_back(outputsql);
}
return ret;
}
std::string &ProcOdbc::formatByteaAtCreateTableSql(std::string &sql) {
std::string::size_type pos1 = sql.find(SQLK_BYTEA_START);
std::string::size_type pos2;
while (pos1 != std::string::npos) {
pos2 = sql.find(SQLK_BYTEA_END, pos1 + 1);
if (pos2 == std::string::npos) {
break;
}
sql.replace(pos1, pos2 - pos1 + strlen(SQLK_BYTEA_END), SQLK_BYTEA);
pos1 = sql.find(SQLK_BYTEA_START);
}
return sql;
}
std::string &ProcOdbc::formatSetAtCreateTableSql(std::string &sql) {
std::string::size_type pos1 = sql.find(SQLK_SET_START);
std::string::size_type pos2;
while (pos1 != std::string::npos) {
pos2 = sql.find(SQLK_SET_END, pos1 + 1);
if (pos2 == std::string::npos) {
break;
}
sql.replace(pos1, pos2 - pos1 + strlen(SQLK_SET_END), SQLK_TEXT);
pos1 = sql.find(SQLK_SET_START);
}
return sql;
}
char **ProcOdbc::getCurrentArgv() { return currentArgv_; }
int ProcOdbc::getCurrentArgc() { return currentArgc_ - 1; }
void ProcOdbc::setLoglevel(int loglevel) { loglevel_ = loglevel; };
bool ProcOdbc::executeCreateTableSql(const char *sql, DBError *dbError) {
bool ret = true;
DBInfo *dbinfo = (DBInfo *)dbinfo_;
// 直接执行SQL语句。
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("start: execute sql %s\n", sql);
}
int execret = execSqlStably(sql);
if ((execret != SQL_SUCCESS) && (execret != SQL_SUCCESS_WITH_INFO)) {
printf("finished error(%d): execute sql %s\n", (int)execret, sql);
printDBError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt, dbError);
ret = false;
// if (dbError) {
// if (!dbError->alreadyExistError) {
// errcreatetablesqls_.push_back(sql);
// }
//}
} else {
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("finished successfully: execute sql %s\n", sql);
}
}
return ret;
}
bool ProcOdbc::executeInsertSql(const char *sql, DBError *dbError) {
bool ret = true;
int insertIntoLen = strlen(SQLK_INSERT_INTO);
std::string sqlstr = sql;
std::string insertSql;
// 拆分成多条sql语句
std::string::size_type pos = 0;
std::string::size_type pos2 = sqlstr.find(SQLK_INSERT_INTO, insertIntoLen);
while (true) {
if (pos2 == std::string::npos) {
insertSql = sqlstr.substr(pos);
ret = executeInsertSql(insertSql.c_str(), "' '", dbError);
break;
} else {
insertSql = sqlstr.substr(pos, pos2 - pos);
ret = executeInsertSql(insertSql.c_str(), "' '", dbError);
}
pos = pos2 + 1;
pos2 = sqlstr.find(SQLK_INSERT_INTO, pos + insertIntoLen);
}
return ret;
}
bool ProcOdbc::executeInsertSql(const char *sql, const char *replaceNullStr,
DBError *dbError) {
bool ret = true;
std::string sqlstr;
DBInfo *dbinfo = (DBInfo *)dbinfo_;
// 直接执行SQL语句。
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("start: execute sql %s\n", sql);
}
int execret = execSqlStably(sql);
if ((execret != SQL_SUCCESS) && (execret != SQL_SUCCESS_WITH_INFO)) {
if (isNullStringError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt)) {
// 非空字符串约束,把''改成replaceNullStr并重试一次
printDBError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt, dbError);
printf("replace '' by %s and retry\n", replaceNullStr);
sqlstr = sql;
replace(sqlstr, "''", replaceNullStr);
execret = execSqlStably(sqlstr.c_str());
}
}
if ((execret != SQL_SUCCESS) && (execret != SQL_SUCCESS_WITH_INFO)) {
printf("finished error(%d): execute sql %s\n", (int)execret, sql);
printDBError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt, dbError);
ret = false;
} else {
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("finished successfully: execute sql %s\n", sql);
}
}
return ret;
}
bool ProcOdbc::executeCreateViewSql(const char *sql, DBError *dbError) {
bool ret = true;
DBInfo *dbinfo = (DBInfo *)dbinfo_;
// 直接执行SQL语句。
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("start: execute sql %s\n", sql);
}
int execret = execSqlStably(sql);
if ((execret != SQL_SUCCESS) && (execret != SQL_SUCCESS_WITH_INFO)) {
printf("finished error(%d): execute sql %s\n", (int)execret, sql);
printDBError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt, dbError);
ret = false;
} else {
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("finished successfully: execute sql %s\n", sql);
}
}
return ret;
}
bool ProcOdbc::executeGeneralSql(const char *sql, DBError *dbError) {
bool ret = true;
DBInfo *dbinfo = (DBInfo *)dbinfo_;
// 直接执行SQL语句。
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("start: execute sql %s\n", sql);
}
int execret = execSqlStably(sql);
if ((execret != SQL_SUCCESS) && (execret != SQL_SUCCESS_WITH_INFO)) {
printf("finished error(%d): execute sql %s\n", (int)execret, sql);
printDBError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt, dbError);
ret = false;
} else {
if (loglevel_ <= INFO_LOG_LEVEL) {
printf("finished successfully: execute sql %s\n", sql);
}
}
return ret;
}
int ProcOdbc::execSqlStably(const char *sql) {
int retry = 30;
DBInfo *dbinfo = (DBInfo *)dbinfo_;
SQLINTEGER execret;
while (retry-- > 0) {
execret = SQLExecDirect(dbinfo->V_OD_hstmt, (SQLCHAR *)sql, SQL_NTS);
if ((execret != SQL_SUCCESS) && (execret != SQL_SUCCESS_WITH_INFO)) {
if (isConnectionError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt)) {
// 连接错误,重新连接,并重试
printDBError(SQL_HANDLE_STMT, dbinfo->V_OD_hstmt, NULL);
if (retry > 0) {
printf("reconnect and retry(%d)...", retry);
sleep(2);
}
reConnect();
} else {
// 其他错误,退出循环
break;
}
} else {
// 执行成功,退出循环
break;
}
}
return (int)execret;
}
bool ProcOdbc::isBinaryBlobChar(unsigned char ch) {
return (ch <= 31) || (ch >= 127) /*&& (ch <= 255)*/ || (ch == 39) ||
(ch == 92);
}
std::list<std::string> ProcOdbc::clearAndGetErrCreateTableSqls() {
std::list<std::string> tmp;
std::list<std::string> ret = errcreatetablesqls_;
errcreatetablesqls_ = tmp;
return ret;
}
bool ProcOdbc::executeLeftErrorSqls() {
bool ret = true;
if (!executeLeftErrorCreateTableSqls()) {
ret = false;
}
return ret;
}
bool ProcOdbc::executeLeftErrorCreateTableSqls() {
std::list<std::string> sqls = clearAndGetErrCreateTableSqls();
int retry = 1000;
struct DBError dbError;
while (sqls.size() > 0) {
// 有错误sql时不断执行
printf("retry...\n");
for (std::list<std::string>::iterator iter = sqls.begin();
iter != sqls.end(); iter++) {
printf("retry sql %s\n", iter->c_str());
executeCreateTableSql(iter->c_str(), &dbError);
}
if (--retry == 0) {
if (hasErrorCreateTableSqls()) {
// 还仍然有错误
printErrorCreateTableSqls();
}
break;
}
sqls = clearAndGetErrCreateTableSqls();
}
return !hasErrorCreateTableSqls();
}
bool ProcOdbc::hasErrorSqls() { return hasErrorCreateTableSqls(); }
bool ProcOdbc::hasErrorCreateTableSqls() {
return errcreatetablesqls_.size() > 0;
}
void ProcOdbc::printErrorSqls() { printErrorCreateTableSqls(); }
void ProcOdbc::printErrorCreateTableSqls() {
if (errcreatetablesqls_.size() > 0) {
printf("error sql count: %d\n", (int)errcreatetablesqls_.size());
for (std::list<std::string>::iterator iter = errcreatetablesqls_.begin();
iter != errcreatetablesqls_.end(); iter++) {
printf(" %s\n", iter->c_str());
}
}
}
void ProcOdbc::freeCurrentArgv() {
for (int index = 0; index < currentArgc_; index++) {
free(currentArgv_[index]);
}
free(currentArgv_);
}
}; // namespace DMODBC