You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/lib/sqlite3db.cpp

404 lines
9.9 KiB

#include "proxysql.h"
#include "cpp.h"
#include "SpookyV2.h"
#define USLEEP_SQLITE_LOCKED 100
SQLite3DB::SQLite3DB() {
db=NULL;
url=NULL;
assert_on_error=0;
#ifdef PROXYSQL_SQLITE3DB_PTHREAD_MUTEX
pthread_rwlock_init(&rwlock, NULL);
#else
spinlock_rwlock_init(&rwlock);
#endif
}
SQLite3DB::~SQLite3DB() {
if (db) {
// close db
int rc;
rc=sqlite3_close_v2(db);
if (rc!=SQLITE_OK) {
proxy_debug(PROXY_DEBUG_SQLITE, 1, "SQLITE: Error on sqlite3_close_v2(): %s\n", sqlite3_errmsg(db));
if (assert_on_error) {
assert(rc==0);
}
}
}
if (url) {free(url); url=NULL;}
}
int SQLite3DB::open(char *__url, int flags) {
// we shouldn't call open if url is not NULL
assert(url==NULL); // we always assert() here
assert(db==NULL);
url=strdup(__url);
int rc;
rc=sqlite3_open_v2(url, &db, flags , NULL);
if (rc) {
proxy_debug(PROXY_DEBUG_SQLITE, 1, "SQLITE: Error on sqlite3_open_v2(): %s\n", sqlite3_errmsg(db));
if (assert_on_error) {
assert(rc==0);
}
proxy_error("SQLITE CRITICAL error: Unable to open %s. Shutting down.\n", url);
exit(EXIT_SUCCESS);
}
return 0;
}
bool SQLite3DB::execute(const char *str) {
assert(url);
assert(db);
char *err=NULL;
int rc=0;
do {
rc=sqlite3_exec(db, str, NULL, 0, &err);
// fprintf(stderr,"%d : %s\n", rc, str);
if(err!=NULL) {
if (rc!=SQLITE_LOCKED && rc!=SQLITE_BUSY) {
proxy_error("SQLITE error: %s --- %s\n", err, str);
if (assert_on_error) {
assert(err==0);
}
}
sqlite3_free(err);
err=NULL;
}
if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) { // the execution of sqlite3_exec() failed because locked
usleep(USLEEP_SQLITE_LOCKED);
}
} while (rc==SQLITE_LOCKED || rc==SQLITE_BUSY);
if (rc==SQLITE_OK) {
return true;
}
return false;
}
int SQLite3DB::prepare_v2(const char *str, sqlite3_stmt **statement) {
int rc;
do {
rc = sqlite3_prepare_v2(db, str, -1, statement, 0);
if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) { // the execution of the prepared statement failed because locked
usleep(USLEEP_SQLITE_LOCKED);
}
} while (rc==SQLITE_LOCKED || rc==SQLITE_BUSY);
return rc;
}
bool SQLite3DB::execute_statement(const char *str, char **error, int *cols, int *affected_rows, SQLite3_result **resultset) {
int rc;
sqlite3_stmt *statement=NULL;
*error=NULL;
bool ret=false;
VALGRIND_DISABLE_ERROR_REPORTING;
do {
rc = sqlite3_prepare_v2(db, str, -1, &statement, 0);
if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) { // the execution of the prepared statement failed because locked
usleep(USLEEP_SQLITE_LOCKED);
}
} while (rc==SQLITE_LOCKED || rc==SQLITE_BUSY);
if (rc == SQLITE_OK) {
} else {
*error=strdup(sqlite3_errmsg(db));
goto __exit_execute_statement;
}
VALGRIND_ENABLE_ERROR_REPORTING;
*cols = sqlite3_column_count(statement);
if (*cols==0) { // not a SELECT
*resultset=NULL;
do {
rc=sqlite3_step(statement);
if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) { // the execution of the prepared statement failed because locked
usleep(USLEEP_SQLITE_LOCKED);
}
} while (rc==SQLITE_LOCKED || rc==SQLITE_BUSY);
if (rc==SQLITE_DONE) {
*affected_rows=sqlite3_changes(db);
ret=true;
} else {
*error=strdup(sqlite3_errmsg(db));
goto __exit_execute_statement;
}
} else {
*affected_rows=0;
*resultset=new SQLite3_result(statement);
ret=true;
}
__exit_execute_statement:
sqlite3_finalize(statement);
return ret;
}
bool SQLite3DB::execute_statement_raw(const char *str, char **error, int *cols, int *affected_rows, sqlite3_stmt **statement) {
int rc;
//sqlite3_stmt *statement=NULL;
*error=NULL;
bool ret=false;
VALGRIND_DISABLE_ERROR_REPORTING;
if(sqlite3_prepare_v2(db, str, -1, statement, 0) != SQLITE_OK) {
*error=strdup(sqlite3_errmsg(db));
goto __exit_execute_statement;
}
VALGRIND_ENABLE_ERROR_REPORTING;
*cols = sqlite3_column_count(*statement);
if (*cols==0) { // not a SELECT
//*resultset=NULL;
do {
rc=sqlite3_step(*statement);
if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) { // the execution of the prepared statement failed because locked
usleep(USLEEP_SQLITE_LOCKED);
}
} while (rc==SQLITE_LOCKED || rc==SQLITE_BUSY);
if (rc==SQLITE_DONE) {
*affected_rows=sqlite3_changes(db);
ret=true;
} else {
*error=strdup(sqlite3_errmsg(db));
goto __exit_execute_statement;
}
} else {
*affected_rows=0;
//*resultset=new SQLite3_result(statement);
ret=true;
}
__exit_execute_statement:
// NOTE: the caller MUST call sqlite3_finalize()
//sqlite3_finalize(statement);
return ret;
}
int SQLite3DB::return_one_int(const char *str) {
char *error=NULL;
int cols=0;
int affected_rows=0;
int ret=0;
SQLite3_result *resultset=NULL;
execute_statement(str, &error , &cols , &affected_rows , &resultset);
if (error) {
proxy_error("Error on %s : %s\n", str, error);
free(error);
} else {
for (std::vector<SQLite3_row *>::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) {
SQLite3_row *r=*it;
ret=atoi(r->fields[0]);
break;
}
}
if (resultset) delete resultset;
return ret;
}
int SQLite3DB::check_table_structure(char *table_name, char *table_def) {
const char *q1="SELECT COUNT(*) FROM sqlite_master WHERE type=\"table\" AND name=\"%s\" AND sql=\"%s\"";
int count=0;
int l=strlen(q1)+strlen(table_name)+strlen(table_def)+1;
sqlite3_stmt *statement;
char *buff=(char *)calloc(1,l);
sprintf(buff, q1, table_name , table_def);
if(sqlite3_prepare_v2(db, buff, -1, &statement, 0) != SQLITE_OK) {
proxy_debug(PROXY_DEBUG_SQLITE, 1, "SQLITE: Error on sqlite3_prepare_v2() running query \"%s\" : %s\n", buff, sqlite3_errmsg(db));
sqlite3_finalize(statement);
free(buff);
assert(0);
}
int result=0;
while ((result=sqlite3_step(statement))==SQLITE_ROW) {
count+=sqlite3_column_int(statement,0);
}
sqlite3_finalize(statement);
free(buff);
return count;
}
bool SQLite3DB::build_table(char *table_name, char *table_def, bool dropit) {
bool rc;
if (dropit) {
const char *q2="DROP TABLE IF EXISTS %s";
int l=strlen(q2)+strlen(table_name)+1;
char *buff=(char *)calloc(1,l);
sprintf(buff,q2,table_name);
proxy_debug(PROXY_DEBUG_SQLITE, 5, "SQLITE: dropping table: %s\n", buff);
rc=execute(buff);
free(buff);
if (rc==false) return rc;
}
proxy_debug(PROXY_DEBUG_SQLITE, 5, "SQLITE: creating table: %s\n", table_def);
rc=execute(table_def);
return rc;
}
bool SQLite3DB::check_and_build_table(char *table_name, char *table_def) {
int rci;
bool rcb;
rci=check_table_structure(table_name,table_def);
if (rci) return true;
rcb=build_table(table_name,table_def,true);
return rcb;
}
void SQLite3DB::rdlock() {
#ifdef PROXYSQL_SQLITE3DB_PTHREAD_MUTEX
pthread_rwlock_rdlock(&rwlock);
#else
spin_wrlock(&rwlock);
#endif
}
void SQLite3DB::rdunlock() {
#ifdef PROXYSQL_SQLITE3DB_PTHREAD_MUTEX
pthread_rwlock_unlock(&rwlock);
#else
spin_wrunlock(&rwlock);
#endif
}
void SQLite3DB::wrlock() {
#ifdef PROXYSQL_SQLITE3DB_PTHREAD_MUTEX
pthread_rwlock_wrlock(&rwlock);
#else
spin_wrlock(&rwlock);
#endif
}
void SQLite3DB::wrunlock() {
#ifdef PROXYSQL_SQLITE3DB_PTHREAD_MUTEX
pthread_rwlock_unlock(&rwlock);
#else
spin_wrunlock(&rwlock);
#endif
}
uint64_t SQLite3_result::raw_checksum() {
if (this->rows_count==0) return 0;
uint64_t hash1, hash2;
SpookyHash myhash;
myhash.Init(19,3);
for (std::vector<SQLite3_row *>::iterator it=rows.begin() ; it!=rows.end(); ++it) {
SQLite3_row *r=*it;
for (int i=0; i<columns;i++) {
if (r->fields[i]) {
myhash.Update(r->fields[i],r->sizes[i]);
} else {
myhash.Update("",0);
}
}
}
myhash.Final(&hash1, &hash2);
return hash1;
}
char *SQLite3_result::checksum() {
uint64_t hash1=raw_checksum();
char buf[128];
memset(buf,'0',128);
uint32_t d32[2];
memcpy(&d32,&hash1,sizeof(hash1));
sprintf(buf,"0x%X%X", d32[0], d32[1]);
return strdup(buf);
}
void SQLite3_result::dump_to_stderr() {
if (columns == 0) return;
size_t *columns_lengths = (size_t *)malloc(sizeof(size_t)*columns);
int i = 0;
for (i = 0; i<columns; i++) {
columns_lengths[i] = 0;
}
i = 0;
for (std::vector<SQLite3_column *>::iterator it=column_definition.begin() ; it!=column_definition.end(); ++it) {
SQLite3_column *r=*it;
size_t len = strlen(r->name);
if (len > columns_lengths[i]) {
columns_lengths[i] = len;
i++;
}
}
for (std::vector<SQLite3_row *>::iterator it=rows.begin() ; it!=rows.end(); ++it) {
SQLite3_row *r=*it;
for (int i=0; i<columns;i++) {
if (r->fields[i]) {
if ((unsigned int)r->sizes[i] > columns_lengths[i]) {
columns_lengths[i] = r->sizes[i];
}
} else {
if (columns_lengths[i] < 4) {
columns_lengths[i] = 4; // NULL
}
}
}
}
string s;
s = "+";
for (i=0; i<columns; i++) {
unsigned int j;
for (j=0; j < columns_lengths[i] + 2; j++) {
s.append("-");
}
s.append("+");
}
fprintf(stderr,"%s\n",s.c_str());
s = "|";
i = 0;
for (std::vector<SQLite3_column *>::iterator it=column_definition.begin() ; it!=column_definition.end(); ++it) {
SQLite3_column *r=*it;
size_t len = strlen(r->name);
s.append(" ");
s.append(r->name);
unsigned int j;
for (j=0; j < columns_lengths[i] - len + 1 ; j++) {
s.append(" ");
}
s.append("|");
i++;
}
fprintf(stderr,"%s\n",s.c_str());
s = "+";
for (i=0; i<columns; i++) {
unsigned int j;
for (j=0; j < columns_lengths[i] + 2 ; j++) {
s.append("-");
}
s.append("+");
}
fprintf(stderr,"%s\n",s.c_str());
for (std::vector<SQLite3_row *>::iterator it=rows.begin() ; it!=rows.end(); ++it) {
SQLite3_row *r=*it;
s = "|";
i = 0;
for (int i=0; i<columns;i++) {
s.append(" ");
int len = 0;
if (r->fields[i]) {
len = r->sizes[i];
s.append(r->fields[i]);
} else {
len = 4;
s.append("NULL");
}
unsigned int j;
for (j=0; j < columns_lengths[i] - len + 1 ; j++) {
s.append(" ");
}
s.append("|");
}
fprintf(stderr,"%s\n",s.c_str());
}
s = "+";
for (i=0; i<columns; i++) {
unsigned int j;
for (j=0; j < columns_lengths[i] + 2 ; j++) {
s.append("-");
}
s.append("+");
}
fprintf(stderr,"%s\n",s.c_str());
free(columns_lengths);
}