#pragma implementation #include #include #include #include #include #include #include #include #include #include "/usr/include/mysql/mysql.h" #include "tlmpsql.h" #include "tlmpsql.m" #include struct NSQL_INTERNAL{ MYSQL my; bool connected; char *server; char *db; char *user; char *passwd; unsigned int port; char *socketpath; SSTREAM *sout; // Optional stream for SQL action only NSQL_INTERNAL() { server = NULL; db = NULL; user = NULL; passwd = NULL; connected = false; sout = NULL; port = 0; socketpath = NULL; } ~NSQL_INTERNAL() { free(server); free(db); free(user); free(passwd); free(socketpath); } }; PUBLIC NSQL::NSQL( const char *server, const char *db) { internal = new NSQL_INTERNAL; internal->server = strdup(server); internal->db = strdup(db); } PUBLIC NSQL::NSQL( const char *server, const char *db, const char *user, const char *passwd) { internal = new NSQL_INTERNAL; internal->server = strdup(server); internal->db = strdup(db); if (user != NULL && user[0] != '\0'){ internal->user = strdup(user); if (passwd != NULL && passwd[0] != '\0'){ internal->passwd = strdup(passwd); } } } /* Record the unix domain path to use to talk to the localhost mysql server */ PUBLIC void NSQL::setunixpath (const char *path) { free (internal->socketpath); internal->socketpath = strdup(path); } /* Record the TCP port used to reach the MySQL server */ PUBLIC void NSQL::settcpport (const char *port) { struct servent *s = getservbyname(port,"tcp"); if (s == NULL){ tlmp_error (MSG_U(E_IVLDTCPPORT,"Invalid TCP port %s\n"),port); }else{ internal->port = ntohs(s->s_port); } } PUBLIC void NSQL::settcpport (unsigned int port) { internal->port = port; } PUBLIC NSQL::NSQL( SSTREAM *sout) { internal = new NSQL_INTERNAL; internal->sout = sout; internal->connected = true; } PUBLIC NSQL::NSQL(NSQL_ARGS &args) { internal = new NSQL_INTERNAL; internal->server = strdup(args.server); internal->db = strdup(args.db); } PUBLIC NSQL::~NSQL() { disconnect(); delete internal; } PUBLIC int NSQL::disconnect() { int ret = 0; if (internal->connected && internal->sout == NULL){ mysql_close (&internal->my); internal->connected = false; } return ret; } PUBLIC int NSQL::connect() { if (!internal->connected){ mysql_init (&internal->my); if (mysql_real_connect(&internal->my ,internal->server,internal->user,internal->passwd ,internal->db,internal->port,internal->socketpath,0)){ internal->connected = true; } } return internal->connected ? 0 : -1; } PUBLIC int NSQL::query (const char *req) { int ret = -1; if (internal->sout != NULL){ tlmp_error (MSG_U(E_SQLOUTONLY,"NSQL: Only SQL action on this handle\n\t%s\n"),req); }else if (connect() != -1){ ret = mysql_query (&internal->my,req) ? -1 : 0; if (ret == -1){ tlmp_error (MSG_U(E_QUERY,"NSQL query error: %s\n(%s)\n") ,req,error()); } }else{ tlmp_error (MSG_U(E_CONNECT,"NSQL: No connection available\n")); syslog (LOG_ERR,MSG_U(E_MYSQLCON,"Connection failed to MySql: %s") ,error()); } return ret; } /* This is some kind of sprintf function. It first tries to do an sprintf in buf[]. If the output is too large, it does an vasprintf(). This allocate a buffer as needed "alloc" will either point to buf[] or to a dynamically allocated buffer. The caller must free alloc if it differs from buf. The goal is to provide an efficient way to format most query and use the slower vasprintf() for large one. For very large query, the application should probably do its own allocation and call the NSQL::query or NSQL::a_query directly. */ static int nsql_largeprintf ( char *&alloc, char buf[10000], const char *ctl, va_list list) { va_list list2; va_copy (list2,list); int ret = vsnprintf (buf,10000-1,ctl,list); if (ret == -1 || ret >= 10000-1){ // Ok, this was too long. older glibc returned -1, newer return // the expected amount ret = vasprintf (&alloc,ctl,list2); }else{ alloc = buf; } va_end (list2); return ret; } PUBLIC int NSQL::queryf (const char *ctl, ...) { va_list list; va_start (list,ctl); int ret = vqueryf (ctl,list); va_end (list); return ret; } PUBLIC int NSQL::vqueryf (const char *ctl, va_list list) { char *alloc; char buf[10000]; nsql_largeprintf (alloc,buf,ctl,list); int ret = query (alloc); if (alloc != buf) free (alloc); return ret; } /* Action query with no useful result set */ PUBLIC int NSQL::a_query (const char *req) { int ret = -1; if (internal->sout != NULL){ internal->sout->printf ("%s;\n",req); ret = 0; }else{ ret = query (req); if (ret != -1){ MYSQL_RES *res = store_result(); free_result(res); ret = mysql_affected_rows(&internal->my); } } return ret; } PUBLIC int NSQL::a_queryf (const char *ctl, ...) { va_list list; va_start (list,ctl); int ret = a_vqueryf (ctl,list); va_end (list); return ret; } PUBLIC int NSQL::a_vqueryf (const char *ctl, va_list list) { char *alloc; char buf[10000]; nsql_largeprintf (alloc,buf,ctl,list); int ret = a_query (alloc); if (alloc != buf) free (alloc); return ret; } PUBLIC const char * NSQL::error () { return mysql_error(&internal->my); } PUBLIC MYSQL_RES *NSQL::store_result() { return mysql_store_result(&internal->my); } PUBLIC void NSQL::free_result(MYSQL_RES *res) { if (res != NULL) mysql_free_result(res); } PUBLIC int NSQL::getlastid() { int ret = -1; if (internal->connected){ ret = mysql_insert_id(&internal->my); } return ret; } PUBLIC NSQL_ARGS::NSQL_ARGS() { server = db = NULL; } PUBLIC NSQL_ARGS::NSQL_ARGS(const char *_server, const char *_db) { server = db = NULL; setserver (_server); setdb (_db); } PUBLIC NSQL_ARGS::~NSQL_ARGS() { free (server); free (db); } PUBLIC void NSQL_ARGS::setserver( const char *s) { free (server); server = NULL; if (s != NULL) server = strdup(s); } PUBLIC void NSQL_ARGS::setdb ( const char *s) { free (db); db = NULL; if (s != NULL) db = strdup(s); } PUBLIC int NSQL_ARGS::isok() { return server != NULL && db != NULL; } int nsql_parseargs(int argc, char *argv[], NSQL_ARGS &ar) { int i; for (i=1; iadd (ss); ret = tmp; } return ret; } PUBLIC const char *NSQL_ENCODE::enc(const SSTRING &s) { return enc (s.get()); } PUBLIC const char *NSQL_ENCODE::enc(const SSTRING *s) { return enc (s->get()); }