From 0f310932301a40217efac6d83933718a6c1b184c Mon Sep 17 00:00:00 2001 From: Aki Tuomi Date: Sun, 5 Oct 2014 18:14:16 +0300 Subject: [PATCH] Switch gsql* and mydns backends to prepared statements Closes #1783 which is the PR this code came from. --- m4/pdns_with_oracle.m4 | 4 +- modules/bindbackend/bindbackend2.cc | 18 +- modules/bindbackend/bindbackend2.hh | 20 +- modules/bindbackend/binddnssec.cc | 199 +++- modules/gmysqlbackend/gmysqlbackend.cc | 122 +- modules/gmysqlbackend/smysql.cc | 331 +++++- modules/gmysqlbackend/smysql.hh | 13 +- modules/goraclebackend/Makefile.am | 2 +- modules/goraclebackend/goraclebackend.cc | 171 +-- modules/goraclebackend/goraclebackend.hh | 1 - modules/goraclebackend/soracle.cc | 625 ++++++---- modules/goraclebackend/soracle.hh | 29 +- modules/gpgsqlbackend/gpgsqlbackend.cc | 122 +- modules/gpgsqlbackend/spgsql.cc | 285 +++-- modules/gpgsqlbackend/spgsql.hh | 15 +- modules/gsqlite3backend/gsqlite3backend.cc | 162 ++- modules/gsqlite3backend/gsqlite3backend.hh | 3 - modules/mydnsbackend/mydnsbackend.cc | 694 ++++++----- modules/mydnsbackend/mydnsbackend.hh | 40 +- pdns/backends/gsql/gsqlbackend.cc | 1205 +++++++++++--------- pdns/backends/gsql/gsqlbackend.hh | 195 +++- pdns/backends/gsql/ssql.hh | 38 +- pdns/pdnssec.cc | 11 +- pdns/ssqlite3.cc | 254 +++-- pdns/ssqlite3.hh | 27 +- regression-tests/backends/goracle-master | 19 +- regression-tests/backends/goracle-slave | 3 + regression-tests/backends/gpgsql-master | 2 +- 28 files changed, 2846 insertions(+), 1764 deletions(-) diff --git a/m4/pdns_with_oracle.m4 b/m4/pdns_with_oracle.m4 index 08d73540d..d8428f9cb 100644 --- a/m4/pdns_with_oracle.m4 +++ b/m4/pdns_with_oracle.m4 @@ -50,9 +50,9 @@ AC_DEFUN([PDNS_WITH_ORACLE],[ # we have to check for client9 as well... # test -lclntsh old_LDFLAGS="$LDFLAGS" - LDFLAGS="-L$with_oracle_libs -lnnz11 -locci" + LDFLAGS="-L$with_oracle_libs -locci" AC_CHECK_LIB([clntsh],[OCIEnvInit], - [ORACLE_LIBS="-L$with_oracle_libs -lnnz11 -lclntsh -locci"], + [ORACLE_LIBS="-L$with_oracle_libs -lclntsh -locci"], AC_CHECK_LIB([client9], [OCIEnvInit], [ORACLE_LIBS="-L$with_oracle_libs -lclient9 -lclntsh9"], [AC_MSG_ERROR([Could not find client libraries])] diff --git a/modules/bindbackend/bindbackend2.cc b/modules/bindbackend/bindbackend2.cc index 3e737b674..cbef60a16 100644 --- a/modules/bindbackend/bindbackend2.cc +++ b/modules/bindbackend/bindbackend2.cc @@ -1,4 +1,4 @@ -/* + /* PowerDNS Versatile Database Driven Nameserver Copyright (C) 2002 - 2014 PowerDNS.COM BV @@ -587,6 +587,20 @@ string Bind2Backend::DLAddDomainHandler(const vector&parts, Utility::pid Bind2Backend::Bind2Backend(const string &suffix, bool loadZones) { + d_getAllDomainMetadataQuery_stmt = NULL; + d_getDomainMetadataQuery_stmt = NULL; + d_deleteDomainMetadataQuery_stmt = NULL; + d_insertDomainMetadataQuery_stmt = NULL; + d_getDomainKeysQuery_stmt = NULL; + d_deleteDomainKeyQuery_stmt = NULL; + d_insertDomainKeyQuery_stmt = NULL; + d_activateDomainKeyQuery_stmt = NULL; + d_deactivateDomainKeyQuery_stmt = NULL; + d_getTSIGKeyQuery_stmt = NULL; + d_setTSIGKeyQuery_stmt = NULL; + d_deleteTSIGKeyQuery_stmt = NULL; + d_getTSIGKeysQuery_stmt = NULL; + setArgPrefix("bind"+suffix); d_logprefix="[bind"+suffix+"backend]"; d_hybrid=mustDo("hybrid"); @@ -616,7 +630,7 @@ Bind2Backend::Bind2Backend(const string &suffix, bool loadZones) } Bind2Backend::~Bind2Backend() -{} +{ freeStatements(); } // deallocate statements void Bind2Backend::rediscover(string *status) { diff --git a/modules/bindbackend/bindbackend2.hh b/modules/bindbackend/bindbackend2.hh index 9ced301b9..2bbc04209 100644 --- a/modules/bindbackend/bindbackend2.hh +++ b/modules/bindbackend/bindbackend2.hh @@ -39,8 +39,9 @@ #include "pdns/lock.hh" #include "pdns/misc.hh" #include "pdns/dnsbackend.hh" - #include "pdns/namespaces.hh" +#include "pdns/backends/gsql/ssql.hh" + using namespace ::boost::multi_index; /** This struct is used within the Bind2Backend to store DNS information. @@ -237,6 +238,9 @@ public: private: void setupDNSSEC(); + void setupStatements(); + void freeStatements(); + void release(SSqlStatement**); static bool safeGetBBDomainInfo(int id, BB2DomainInfo* bbd); static void safePutBBDomainInfo(const BB2DomainInfo& bbd); static bool safeGetBBDomainInfo(const std::string& name, BB2DomainInfo* bbd); @@ -301,4 +305,18 @@ private: void doEmptyNonTerminals(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr); void loadConfig(string *status=0); static void nukeZoneRecords(BB2DomainInfo *bbd); + + SSqlStatement* d_getAllDomainMetadataQuery_stmt; + SSqlStatement* d_getDomainMetadataQuery_stmt; + SSqlStatement* d_deleteDomainMetadataQuery_stmt; + SSqlStatement* d_insertDomainMetadataQuery_stmt; + SSqlStatement* d_getDomainKeysQuery_stmt; + SSqlStatement* d_deleteDomainKeyQuery_stmt; + SSqlStatement* d_insertDomainKeyQuery_stmt; + SSqlStatement* d_activateDomainKeyQuery_stmt; + SSqlStatement* d_deactivateDomainKeyQuery_stmt; + SSqlStatement* d_getTSIGKeyQuery_stmt; + SSqlStatement* d_setTSIGKeyQuery_stmt; + SSqlStatement* d_deleteTSIGKeyQuery_stmt; + SSqlStatement* d_getTSIGKeysQuery_stmt; }; diff --git a/modules/bindbackend/binddnssec.cc b/modules/bindbackend/binddnssec.cc index f18060258..c5c63700c 100644 --- a/modules/bindbackend/binddnssec.cc +++ b/modules/bindbackend/binddnssec.cc @@ -74,6 +74,11 @@ bool Bind2Backend::deleteTSIGKey(const string& name) bool Bind2Backend::getTSIGKeys(std::vector< struct TSIGKey > &keys) { return false; } +void Bind2Backend::setupStatements() +{ return; } +void Bind2Backend::freeStatements() +{ return; } + #else #include "pdns/ssqlite3.hh" @@ -84,6 +89,7 @@ void Bind2Backend::setupDNSSEC() return; try { d_dnssecdb = shared_ptr(new SSQLite3(getArg("dnssec-db"))); + setupStatements(); } catch(SSqlException& se) { // this error is meant to kill the server dead - it makes no sense to continue.. @@ -93,6 +99,44 @@ void Bind2Backend::setupDNSSEC() d_dnssecdb->setLog(::arg().mustDo("query-logging")); } +void Bind2Backend::setupStatements() +{ + d_getAllDomainMetadataQuery_stmt = d_dnssecdb->prepare("select kind, content from domainmetadata where domain=:domain",1); + d_getDomainMetadataQuery_stmt = d_dnssecdb->prepare("select content from domainmetadata where domain=:domain and kind=:kind",2); + d_deleteDomainMetadataQuery_stmt = d_dnssecdb->prepare("delete from domainmetadata where domain=:domain and kind=:kind",2); + d_insertDomainMetadataQuery_stmt = d_dnssecdb->prepare("insert into domainmetadata (domain, kind, content) values (:domain,:kind,:content)",3); + d_getDomainKeysQuery_stmt = d_dnssecdb->prepare("select id,flags, active, content from cryptokeys where domain=:domain",1); + d_deleteDomainKeyQuery_stmt = d_dnssecdb->prepare("delete from cryptokeys where domain=:domain and id=:key_id",2); + d_insertDomainKeyQuery_stmt = d_dnssecdb->prepare("insert into cryptokeys (domain, flags, active, content) values (:domain, :flags, :active, :content)", 4); + d_activateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=1 where domain=:domain and id=:key_id", 2); + d_deactivateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=0 where domain=:domain and id=:key_id", 2); + d_getTSIGKeyQuery_stmt = d_dnssecdb->prepare("select algorithm, secret from tsigkeys where name=:key_name", 1); + d_setTSIGKeyQuery_stmt = d_dnssecdb->prepare("replace into tsigkeys (name,algorithm,secret) values(:key_name, :algorithm, :content)", 3); + d_deleteTSIGKeyQuery_stmt = d_dnssecdb->prepare("delete from tsigkeys where name=:key_name", 1); + d_getTSIGKeysQuery_stmt = d_dnssecdb->prepare("select name,algorithm,secret from tsigkeys", 0); +} + +void Bind2Backend::release(SSqlStatement** stmt) { + delete *stmt; + *stmt = NULL; +} + +void Bind2Backend::freeStatements() +{ + release(&d_getAllDomainMetadataQuery_stmt); + release(&d_getDomainMetadataQuery_stmt); + release(&d_deleteDomainMetadataQuery_stmt); + release(&d_insertDomainMetadataQuery_stmt); + release(&d_getDomainKeysQuery_stmt); + release(&d_deleteDomainKeyQuery_stmt); + release(&d_insertDomainKeyQuery_stmt); + release(&d_activateDomainKeyQuery_stmt); + release(&d_deactivateDomainKeyQuery_stmt); + release(&d_getTSIGKeyQuery_stmt); + release(&d_setTSIGKeyQuery_stmt); + release(&d_deleteTSIGKeyQuery_stmt); + release(&d_getTSIGKeysQuery_stmt); +} bool Bind2Backend::doesDNSSEC() { return d_dnssecdb || d_hybrid; @@ -128,14 +172,18 @@ bool Bind2Backend::getAllDomainMetadata(const string& name, std::mapdoQuery((fmt % d_dnssecdb->escape(name)).str()); + d_getAllDomainMetadataQuery_stmt-> + bind("domain", name)-> + execute(); - vector row; - while(d_dnssecdb->getRow(row)) { + SSqlStatement::row_t row; + while(d_getAllDomainMetadataQuery_stmt->hasNextRow()) { + d_getAllDomainMetadataQuery_stmt->nextRow(row); meta[row[0]].push_back(row[1]); } + + d_getAllDomainMetadataQuery_stmt->reset(); } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -150,14 +198,19 @@ bool Bind2Backend::getDomainMetadata(const string& name, const std::string& kind // cerr<<"Asked to get metadata for zone '"<doQuery((fmt % d_dnssecdb->escape(name) % d_dnssecdb->escape(kind)).str()); + d_getDomainMetadataQuery_stmt-> + bind("domain", name)-> + bind("kind", kind)-> + execute(); - vector row; - while(d_dnssecdb->getRow(row)) { + SSqlStatement::row_t row; + while(d_getDomainMetadataQuery_stmt->hasNextRow()) { + d_getDomainMetadataQuery_stmt->nextRow(row); meta.push_back(row[0]); } + + d_getDomainMetadataQuery_stmt->reset(); } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -170,12 +223,22 @@ bool Bind2Backend::setDomainMetadata(const string& name, const std::string& kind if(!d_dnssecdb || d_hybrid) return false; - boost::format fmt("delete from domainmetadata where domain='%s' and kind='%s'"); - boost::format fmt2("insert into domainmetadata (domain, kind, content) values ('%s','%s', '%s')"); try { - d_dnssecdb->doCommand((fmt % d_dnssecdb->escape(name) % d_dnssecdb->escape(kind)).str()); - if(!meta.empty()) - d_dnssecdb->doCommand((fmt2 % d_dnssecdb->escape(name) % d_dnssecdb->escape(kind) % d_dnssecdb->escape(meta.begin()->c_str())).str()); + d_deleteDomainMetadataQuery_stmt-> + bind("domain", name)-> + bind("kind", kind)-> + execute()-> + reset(); + if(!meta.empty()) { + BOOST_FOREACH(const string& value, meta) { + d_insertDomainMetadataQuery_stmt-> + bind("domain", name)-> + bind("kind", kind)-> + bind("content", value)-> + execute()-> + reset(); + } + } } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -189,18 +252,21 @@ bool Bind2Backend::getDomainKeys(const string& name, unsigned int kind, std::vec // cerr<<"Asked to get keys for zone '"<doQuery((fmt % d_dnssecdb->escape(name)).str()); + d_getDomainKeysQuery_stmt-> + bind("domain", name)-> + execute(); KeyData kd; - vector row; - while(d_dnssecdb->getRow(row)) { + SSqlStatement::row_t row; + while(d_getDomainKeysQuery_stmt->hasNextRow()) { + d_getDomainKeysQuery_stmt->nextRow(row); kd.id = atoi(row[0].c_str()); kd.flags = atoi(row[1].c_str()); kd.active = atoi(row[2].c_str()); kd.content = row[3]; keys.push_back(kd); } + d_getDomainKeysQuery_stmt->reset(); } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -216,9 +282,12 @@ bool Bind2Backend::removeDomainKey(const string& name, unsigned int id) // cerr<<"Asked to remove key "<doCommand((fmt % d_dnssecdb->escape(name) % id).str()); + d_deleteDomainKeyQuery_stmt-> + bind("domain", name)-> + bind("key_id", id)-> + execute()-> + reset(); } catch(SSqlException& se) { cerr<doCommand((fmt % d_dnssecdb->escape(name) % key.flags % key.active % d_dnssecdb->escape(key.content)).str()); + d_insertDomainKeyQuery_stmt-> + bind("domain", name)-> + bind("flags", key.flags)-> + bind("active", key.active)-> + bind("content", key.content)-> + execute()-> + reset(); } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -251,9 +325,12 @@ bool Bind2Backend::activateDomainKey(const string& name, unsigned int id) if(!d_dnssecdb || d_hybrid) return false; - boost::format fmt("update cryptokeys set active=1 where domain='%s' and id=%d"); try { - d_dnssecdb->doCommand((fmt % d_dnssecdb->escape(name) % id).str()); + d_activateDomainKeyQuery_stmt-> + bind("domain", name)-> + bind("key_id", id)-> + execute()-> + reset(); } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -268,9 +345,12 @@ bool Bind2Backend::deactivateDomainKey(const string& name, unsigned int id) if(!d_dnssecdb || d_hybrid) return false; - boost::format fmt("update cryptokeys set active=0 where domain='%s' and id=%d"); try { - d_dnssecdb->doCommand((fmt % d_dnssecdb->escape(name) % id).str()); + d_deactivateDomainKeyQuery_stmt-> + bind("domain", name)-> + bind("key_id", id)-> + execute()-> + reset(); } catch(SSqlException& se) { throw PDNSException("Error accessing DNSSEC database in BIND backend: "+se.txtReason()); @@ -283,36 +363,41 @@ bool Bind2Backend::getTSIGKey(const string& name, string* algorithm, string* con { if(!d_dnssecdb || d_hybrid) return false; - boost::format fmt("select algorithm, secret from tsigkeys where name='%s'"); try { - d_dnssecdb->doQuery( (fmt % d_dnssecdb->escape(name)).str()); + d_getTSIGKeyQuery_stmt-> + bind("key_name", name)-> + execute(); + SSqlStatement::row_t row; + content->clear(); + while(d_getTSIGKeyQuery_stmt->hasNextRow()) { + d_getTSIGKeyQuery_stmt->nextRow(row); + if(row.size() >= 2 && (algorithm->empty() || pdns_iequals(*algorithm, row[0]))) { + *algorithm = row[0]; + *content = row[1]; + } + } + d_getTSIGKeyQuery_stmt->reset(); } catch (SSqlException &e) { throw PDNSException("BindBackend unable to retrieve named TSIG key: "+e.txtReason()); } - - SSql::row_t row; - - content->clear(); - while(d_dnssecdb->getRow(row)) { - if(row.size() >= 2 && (algorithm->empty() || pdns_iequals(*algorithm, row[0]))) { - *algorithm = row[0]; - *content = row[1]; - } - } return !content->empty(); - } bool Bind2Backend::setTSIGKey(const string& name, const string& algorithm, const string& content) { if(!d_dnssecdb || d_hybrid) return false; - boost::format fmt("replace into tsigkeys (name,algorithm,secret) values('%s', '%s', '%s')"); + try { - d_dnssecdb->doCommand( (fmt % d_dnssecdb->escape(name) % d_dnssecdb->escape(algorithm) % d_dnssecdb->escape(content)).str() ); + d_setTSIGKeyQuery_stmt-> + bind("key_name", name)-> + bind("algorithm", algorithm)-> + bind("content", content)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("BindBackend unable to retrieve named TSIG key: "+e.txtReason()); @@ -325,10 +410,12 @@ bool Bind2Backend::deleteTSIGKey(const string& name) { if(!d_dnssecdb || d_hybrid) return false; - boost::format fmt("delete from tsigkeys where name='%s'"); try { - d_dnssecdb->doCommand( (fmt % d_dnssecdb->escape(name)).str() ); + d_deleteTSIGKeyQuery_stmt-> + bind("key_name", name)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("BindBackend unable to retrieve named TSIG key: "+e.txtReason()); @@ -343,20 +430,24 @@ bool Bind2Backend::getTSIGKeys(std::vector< struct TSIGKey > &keys) return false; try { - d_dnssecdb->doQuery( "select name,algorithm,secret from tsigkeys" ); + d_getTSIGKeysQuery_stmt-> + execute(); + + SSqlStatement::row_t row; + + while(d_getTSIGKeysQuery_stmt->hasNextRow()) { + d_getTSIGKeysQuery_stmt->nextRow(row); + struct TSIGKey key; + key.name = row[0]; + key.algorithm = row[1]; + key.key = row[2]; + keys.push_back(key); + } + + d_getTSIGKeysQuery_stmt->reset(); } catch (SSqlException &e) { - throw PDNSException("GSQLBackend unable to retrieve named TSIG key: "+e.txtReason()); - } - - SSql::row_t row; - - while(d_dnssecdb->getRow(row)) { - struct TSIGKey key; - key.name = row[0]; - key.algorithm = row[1]; - key.key = row[2]; - keys.push_back(key); + throw PDNSException("GSQLBackend unable to retrieve all TSIG keys: "+e.txtReason()); } return !keys.empty(); diff --git a/modules/gmysqlbackend/gmysqlbackend.cc b/modules/gmysqlbackend/gmysqlbackend.cc index 949194c5c..316e06035 100644 --- a/modules/gmysqlbackend/gmysqlbackend.cc +++ b/modules/gmysqlbackend/gmysqlbackend.cc @@ -52,77 +52,77 @@ public: string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE"; - declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type='%s' and name='%s'"); - declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type='%s' and name='%s' and domain_id=%d"); - declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name='%s'"); - declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name='%s' and domain_id=%d"); + declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=? and name=?"); + declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=? and name=? and domain_id=?"); + declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=?"); + declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=? and domain_id=?"); - declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR %d) and domain_id='%d' order by name, type"); - declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name='%s' OR name like '%s') and domain_id='%d'"); + declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR ?) and domain_id=? order by name, type"); + declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=? OR name like ?) and domain_id=?"); - declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id='%d' and type is null"); - declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values ('%d','%s',null,0,'1')"); - declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id='%d' and name='%s' and type is null"); + declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null"); + declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values (?,?,null,0,1)"); + declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=? and name=? and type is null"); - declare(suffix,"master-zone-query","Data", "select master from domains where name='%s' and type='SLAVE'"); + declare(suffix,"master-zone-query","Data", "select master from domains where name=? and type='SLAVE'"); - declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type from domains where name='%s'"); + declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type from domains where name=?"); declare(suffix,"info-all-slaves-query","","select id,name,master,last_check,type from domains where type='SLAVE'"); - declare(suffix,"supermaster-query","", "select account from supermasters where ip='%s' and nameserver='%s'"); - declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver='%s' and account='%s'"); - - declare(suffix,"insert-zone-query","", "insert into domains (type,name) values('NATIVE','%s')"); - declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE','%s','%s','%s')"); - - declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values ('%s',%d,%d,'%s',%d,%d,'%s','%d')"); - declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values ('%s',%d,%d,'%s',%d,%d,'%s','%s','%d')"); - declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,'%d',0,'%s','%d')"); - declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,'%d',0,'%s','%s','%d')"); - - declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select ordername, name from records where domain_id=%d and disabled=0 and ordername is not null order by 1 asc limit 1"); - declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where ordername <= '%s' and domain_id=%d and disabled=0 and ordername is not null order by 1 desc limit 1"); - declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select min(ordername) from records where ordername > '%s' and domain_id=%d and disabled=0 and ordername is not null"); - declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where ordername != '' and domain_id=%d and disabled=0 and ordername is not null order by 1 desc limit 1"); - declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername='%s',auth=%d where name='%s' and domain_id='%d' and disabled=0"); - declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=1 where domain_id='%d' and name='%s' and type='DS' and disabled=0"); - - declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=%d where domain_id='%d' and name='%s' and disabled=0"); - declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=0 where name='%s' and type='%s' and domain_id='%d' and disabled=0"); - - declare(suffix,"update-master-query","", "update domains set master='%s' where name='%s'"); - declare(suffix,"update-kind-query","", "update domains set type='%s' where name='%s'"); - declare(suffix,"update-serial-query","", "update domains set notified_serial=%d where id=%d"); - declare(suffix,"update-lastcheck-query","", "update domains set last_check=%d where id=%d"); - declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=%d"); + declare(suffix,"supermaster-query","", "select account from supermasters where ip=? and nameserver=?"); + declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?"); + + declare(suffix,"insert-zone-query","", "insert into domains (type,name) values('NATIVE',?)"); + declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE',?,?,?)"); + + declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values (?,?,?,?,?,?,?,?)"); + declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (?,?,?,?,?,?,?,?,?)"); + declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,?,0,?,?)"); + declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,?,0,?,?,?)"); + + declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select ordername, name from records where domain_id=? and disabled=0 and ordername is not null order by 1 asc limit 1"); + declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where ordername <= ? and domain_id=? and disabled=0 and ordername is not null order by 1 desc limit 1"); + declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select min(ordername) from records where ordername > ? and domain_id=? and disabled=0 and ordername is not null"); + declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where ordername != '' and domain_id=? and disabled=0 and ordername is not null order by 1 desc limit 1"); + declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername=?,auth=? where name=? and domain_id=? and disabled=0"); + declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=1 where domain_id=? and name=? and type='DS' and disabled=0"); + + declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0"); + declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=0 where name=? and type=? and domain_id=? and disabled=0"); + + declare(suffix,"update-master-query","", "update domains set master=? where name=?"); + declare(suffix,"update-kind-query","", "update domains set type=? where name=?"); + declare(suffix,"update-serial-query","", "update domains set notified_serial=? where id=?"); + declare(suffix,"update-lastcheck-query","", "update domains set last_check=? where id=?"); + declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=?"); declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'"); - declare(suffix,"delete-domain-query","", "delete from domains where name='%s'"); - declare(suffix,"delete-zone-query","", "delete from records where domain_id=%d"); - declare(suffix,"delete-rrset-query","","delete from records where domain_id=%d and name='%s' and type='%s'"); - declare(suffix,"delete-names-query","","delete from records where domain_id = %d and name='%s'"); - - declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, %d, %d, '%s' from domains where name='%s'"); - declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name='%s'"); - declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='%s'"); - declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='%s' and domainmetadata.kind='%s'"); - declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name='%s') and domainmetadata.kind='%s'"); - declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name='%s')"); - declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, '%s', '%s' from domains where name='%s'"); - declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name='%s')"); - declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name='%s'"); - declare(suffix,"set-tsig-key-query","", "replace into tsigkeys (name,algorithm,secret) values('%s','%s','%s')"); - declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name='%s'"); + declare(suffix,"delete-domain-query","", "delete from domains where name=?"); + declare(suffix,"delete-zone-query","", "delete from records where domain_id=?"); + declare(suffix,"delete-rrset-query","","delete from records where domain_id=? and name=? and type=?"); + declare(suffix,"delete-names-query","","delete from records where domain_id=? and name=?"); + + declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, ?, ?, ? from domains where name=?"); + declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?"); + declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?"); + declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?"); + declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?"); + declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?)"); + declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?"); + declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?"); + declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?"); + declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?"); + declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?)"); + declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=?"); + declare(suffix,"set-tsig-key-query","", "replace into tsigkeys (name,algorithm,secret) values(?,?,?)"); + declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name=?"); declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys"); - declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR %d"); + declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR ?"); - declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=%d"); - declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (%d, '%s', '%s', %d, '%s', '%s')"); - declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=%d AND name='%s' AND type='%s'"); - declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=%d"); + declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?"); + declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (?, ?, ?, ?, ?, ?)"); + declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=? AND name=? AND type=?"); + declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=?"); } DNSBackend *make(const string &suffix="") diff --git a/modules/gmysqlbackend/smysql.cc b/modules/gmysqlbackend/smysql.cc index 58ad89d63..6510dde46 100644 --- a/modules/gmysqlbackend/smysql.cc +++ b/modules/gmysqlbackend/smysql.cc @@ -13,6 +13,274 @@ bool SMySQL::s_dolog; pthread_mutex_t SMySQL::s_myinitlock = PTHREAD_MUTEX_INITIALIZER; +class SMySQLStatement: public SSqlStatement +{ +public: + SMySQLStatement(const string& query, bool dolog, int nparams, MYSQL* db) + { + int err; + d_db = db; + d_dolog = dolog; + d_query = query; + d_parnum = d_paridx = d_fnum = d_resnum = d_residx = 0; + d_req_bind = d_res_bind = NULL; + d_stmt = NULL; + + if (query.empty()) { + return; + } + + if ((d_stmt = mysql_stmt_init(d_db))==NULL) + throw SSqlException("Could not initialize mysql statement, out of memory"); + + if ((err = mysql_stmt_prepare(d_stmt, query.c_str(), query.size()))) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not prepare statement: " + error); + } + + if (static_cast(mysql_stmt_param_count(d_stmt)) != nparams) + throw SSqlException("Provided parameter count does not match statement"); + + d_parnum = nparams; + if (d_parnum>0) { + d_req_bind = new MYSQL_BIND[d_parnum]; + memset(d_req_bind, 0, sizeof(MYSQL_BIND)*d_parnum); + } + } + + SSqlStatement* bind(const string& name, bool value) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_TINY; + d_req_bind[d_paridx].buffer = new char[1]; + *((char*)d_req_bind[d_paridx].buffer) = (value?1:0); + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, int value) { + return bind(name, (long)value); + } + SSqlStatement* bind(const string& name, uint32_t value) { + return bind(name, (unsigned long)value); + } + SSqlStatement* bind(const string& name, long value) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG; + d_req_bind[d_paridx].buffer = new long[1]; + *((long*)d_req_bind[d_paridx].buffer) = value; + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, unsigned long value) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG; + d_req_bind[d_paridx].buffer = new unsigned long[1]; + d_req_bind[d_paridx].is_unsigned = 1; + *((unsigned long*)d_req_bind[d_paridx].buffer) = value; + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, long long value) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG; + d_req_bind[d_paridx].buffer = new long long[1]; + *((long long*)d_req_bind[d_paridx].buffer) = value; + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, unsigned long long value) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG; + d_req_bind[d_paridx].buffer = new unsigned long long[1]; + d_req_bind[d_paridx].is_unsigned = 1; + *((unsigned long long*)d_req_bind[d_paridx].buffer) = value; + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, const std::string& value) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_STRING; + d_req_bind[d_paridx].buffer = new char[value.size()+1]; + d_req_bind[d_paridx].length = new unsigned long[1]; + *d_req_bind[d_paridx].length = value.size(); + d_req_bind[d_paridx].buffer_length = *d_req_bind[d_paridx].length+1; + memset(d_req_bind[d_paridx].buffer, 0, value.size()+1); + value.copy((char*)d_req_bind[d_paridx].buffer, value.size()); + d_paridx++; + return this; + } + SSqlStatement* bindNull(const string& name) { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_NULL; + d_paridx++; + return this; + } + + SSqlStatement* execute() { + int err; + + if (!d_stmt) return this; + + if (d_dolog) { + L<(mysql_stmt_field_count(d_stmt)))>0) { + // prepare for result + if ((err = mysql_stmt_store_result(d_stmt))) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not store mysql statement: " + error); + } + d_resnum = mysql_stmt_num_rows(d_stmt); + + if (d_resnum>0 && d_res_bind == NULL) { + d_res_bind = new MYSQL_BIND[d_fnum]; + memset(d_res_bind, 0, sizeof(MYSQL_BIND)*d_fnum); + MYSQL_RES* meta = mysql_stmt_result_metadata(d_stmt); + MYSQL_FIELD* fields = mysql_fetch_fields(meta); + + for(int i = 0; i < d_fnum; i++) { + unsigned long len = std::max(fields[i].max_length, fields[i].length)+1; + d_res_bind[i].is_null = new my_bool[1]; + d_res_bind[i].error = new my_bool[1]; + d_res_bind[i].length = new unsigned long[1]; + d_res_bind[i].buffer = new char[len]; + d_res_bind[i].buffer_length = len; + d_res_bind[i].buffer_type = MYSQL_TYPE_STRING; + } + + mysql_free_result(meta); + + if ((err = mysql_stmt_bind_result(d_stmt, d_res_bind))) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not bind parameters to mysql statement: " + error); + } + } + } + + return this; + } + + bool hasNextRow() { + return d_residx < d_resnum; + } + + SSqlStatement* nextRow(row_t& row) { + int err; + row.clear(); + if (d_residx >= d_resnum) return this; + + if ((err =mysql_stmt_fetch(d_stmt))) { + if (err != MYSQL_DATA_TRUNCATED) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not fetch result: " + error); + } + } + + row.reserve(d_fnum); + + for(int i=0;i= 0); - - d_rres=0; } void SMySQL::setLog(bool state) @@ -82,72 +348,29 @@ SSqlException SMySQL::sPerrorException(const string &reason) return SSqlException(reason+string(": ")+mysql_error(&d_db)); } -int SMySQL::doCommand(const string &query) +SSqlStatement* SMySQL::prepare(const string& query, int nparams) { - return doQuery(query); + return new SMySQLStatement(query, s_dolog, nparams, &d_db); } -int SMySQL::doQuery(const string &query) +void SMySQL::execute(const string& query) { - if(d_rres) - throw SSqlException("Attempt to start new MySQL query while old one still in progress"); - if(s_dolog) L< +static OCIEnv* d_environmentHandle = 0; +static pthread_mutex_t s_goracle_lock=PTHREAD_MUTEX_INITIALIZER; + gOracleBackend::gOracleBackend(const string &mode, const string &suffix) : GSQLBackend(mode, suffix) { - try { - // set Oracle envionment variables + Lock gl(&s_goracle_lock); + if (d_environmentHandle == 0) { setenv("ORACLE_HOME", getArg("home").c_str(), 1); setenv("ORACLE_SID", getArg("sid").c_str(), 1); setenv("NLS_LANG", getArg("nls-lang").c_str(), 1); + + int err = OCIEnvCreate(&d_environmentHandle, OCI_THREADED, NULL, NULL, NULL, NULL, 0, NULL); + if (err) { + throw PDNSException("OCIEnvCraete failed"); + } + } + + try { + // set Oracle envionment variables setDB(new SOracle(getArg("tnsname"), getArg("user"), - getArg("password"))); - + getArg("password"), + mustDo("release-statements"), + d_environmentHandle)); } catch (SSqlException &e) { @@ -34,13 +48,6 @@ gOracleBackend::gOracleBackend(const string &mode, const string &suffix) : GSQL L< '%s ' and domain_id=%d and ordername is not null"); - declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select trim(ordername), name from records where disabled=0 and ordername != ' ' and domain_id=%d and ordername is not null and rownum=1 order by ordername desc"); - declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername='%s ',auth=%d where name='%s' and domain_id='%d' and disabled=0"); - declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=1 where domain_id='%d' and name='%s' and type='DS' and disabled=0"); - - declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=%d where domain_id='%d' and name='%s' and disabled=0"); - declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=0 where name='%s' and type='%s' and domain_id='%d' and disabled=0"); - - declare(suffix,"update-master-query","", "update domains set master='%s' where name='%s'"); - declare(suffix,"update-kind-query","", "update domains set type='%s' where name='%s'"); - declare(suffix,"update-serial-query","", "update domains set notified_serial=%d where id=%d"); - declare(suffix,"update-lastcheck-query","", "update domains set last_check=%d where id=%d"); - declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=%d"); - declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'"); - declare(suffix,"delete-domain-query","", "delete from domains where name='%s'"); - declare(suffix,"delete-zone-query","", "delete from records where domain_id=%d"); - declare(suffix,"delete-rrset-query","","delete from records where domain_id=%d and name='%s' and type='%s'"); - declare(suffix,"delete-names-query","","delete from records where domain_id=%d and name='%s'"); - - declare(suffix,"add-domain-key-query","", "insert into cryptokeys (id, domain_id, flags, active, content) select cryptokeys_id_sequence.nextval, id, %d, %d, '%s' from domains where name='%s'"); - declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name='%s'"); - declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='%s'"); - declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='%s' and domainmetadata.kind='%s'"); - declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name='%s') and domainmetadata.kind='%s'"); - declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name='%s')"); - declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (id, domain_id, kind, content) select domainmetadata_id_sequence.nextval, id, '%s', '%s' from domains where name='%s'"); - declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name='%s')"); - declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name='%s'"); - declare(suffix,"set-tsig-key-query","", "insert into tsigkeys (id,name,algorithm,secret) VALUES(tsigkeys_id_sequence.nextval,'%s','%s','%s')"); - declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name='%s'"); - declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys"); - - declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR 1=%d"); - - declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,\"comment\" FROM comments WHERE domain_id=%d"); - declare(suffix, "insert-comment-query", "", "INSERT INTO comments (id, domain_id, name, type, modified_at, account, \"comment\") VALUES (comments_id_sequence.nextval, %d, '%s', '%s', %d, '%s', '%s')"); - declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=%d AND name='%s' AND type='%s'"); - declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=%d"); + declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=:qtype and name=:qname"); + declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=:qtype and name=:qname and domain_id=:domain_id"); + declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=:qname"); + declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=:qname and domain_id=:domain_id"); + + declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR disabled=:include_disabled) and domain_id=:domain_id order by name, type"); + declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id"); + + declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null"); + declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (id,domain_id,name,type,disabled,auth) values (records_id_sequence.nextval,:domain_id,:qname,null,0,'1')"); + declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=:domain_id and name=:qname and type is null"); + + declare(suffix, "master-zone-query", "Data", "select master from domains where name=:domain and type='SLAVE'"); + + declare(suffix, "info-zone-query", "","select id,name,master,last_check,notified_serial,type from domains where name=:domain"); + + declare(suffix, "info-all-slaves-query", "","select id,name,master,last_check,type from domains where type='SLAVE'"); + declare(suffix, "supermaster-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver"); + declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=:nameserver and account=:account"); + declare(suffix, "insert-zone-query", "", "insert into domains (id,type,name) values(domains_id_sequence.nextval,'NATIVE',:domain)"); + declare(suffix, "insert-slave-query", "", "insert into domains (id,type,name,master,account) values(domains_id_sequence.nextval,'SLAVE',:domain,:masters,:account)"); + declare(suffix, "insert-record-query", "", "insert into records (id,content,ttl,prio,type,domain_id,disabled,name,auth) values (records_id_sequence.nextval,:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:auth)"); + declare(suffix, "insert-record-order-query", "", "insert into records (id,content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (records_id_sequence.nextval,:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:ordername || ' ',:auth)"); + declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (id,type,domain_id,disabled,name,auth) values (records_id_sequence.nextval,null,:domain_id,0,:qname,:auth)"); + declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (id,type,domain_id,disabled,name,ordername,auth) values (records_id_sequence.nextval,null,:domain_id,0,:qname,:ordername,:auth)"); + + declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select * FROM (select trim(ordername),name from records where disabled=0 and domain_id=:domain_id and ordername is not null order by ordername asc) where rownum=1"); + declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select * FROM (select trim(ordername), name from records where disabled=0 and ordername <= :ordername || ' ' and domain_id=:domain_id and ordername is not null order by ordername desc) where rownum=1"); + declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select trim(min(ordername)) from records where disabled=0 and ordername > :ordername || ' ' and domain_id=:domain_id and ordername is not null"); + declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select * from (select trim(ordername), name from records where disabled=0 and ordername != ' ' and domain_id=:domain_id and ordername is not null order by ordername desc) where rownum=1"); + declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername=:ordername || ' ',auth=:auth where name=:qname and domain_id=:domain_id and disabled=0"); + declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=1 where domain_id=:domain_id and name=:qname and type='DS' and disabled=0"); + + declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and disabled=0"); + declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=0 where name=:qname and type=:qtype and domain_id=:domain_id and disabled=0"); + + declare(suffix, "update-master-query", "", "update domains set master=:master where name=:domain"); + declare(suffix, "update-kind-query", "", "update domains set type=:kind where name=:domain"); + declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id"); + declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id"); + declare(suffix, "zone-lastchange-query", "", "select max(change_date) from records where domain_id=:domain_id"); + declare(suffix, "info-all-master-query", "", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'"); + declare(suffix, "delete-domain-query","", "delete from domains where name=:domain"); + declare(suffix, "delete-zone-query", "", "delete from records where domain_id=:domain_id"); + declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype"); + declare(suffix, "delete-names-query", "", "delete from records where domain_id=:domain_id and name=:qname"); + + declare(suffix, "add-domain-key-query","", "insert into cryptokeys (id, domain_id, flags, active, content) select cryptokeys_id_sequence.nextval, id, :flags,:active, :content from domains where name=:domain"); + declare(suffix, "list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=:domain"); + declare(suffix, "get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain"); + declare(suffix, "get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain and domainmetadata.kind=:kind"); + declare(suffix, "clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain) and domainmetadata.kind=:kind"); + declare(suffix, "clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain)"); + declare(suffix, "set-domain-metadata-query","", "insert into domainmetadata (id, domain_id, kind, content) select domainmetadata_id_sequence.nextval, id, :kind, :content from domains where name=:domain"); + declare(suffix, "activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id"); + declare(suffix, "deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id"); + declare(suffix, "remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id"); + declare(suffix, "clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain)"); + declare(suffix, "get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=:key_name"); + declare(suffix, "set-tsig-key-query","", "merge into tsigkeys tk using dual on (name = :key_name and algorithm = :algorithm) when not matched then insert (id, name, algorithm, secret) values(tsigkeys_id_sequence.nextval, :key_name, :algorithm, :content) when matched then update set secret = :content"); + declare(suffix, "delete-tsig-key-query","", "delete from tsigkeys where name=:key_name"); + declare(suffix, "get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys"); + + declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR records.disabled=:include_disabled"); + + declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,\"comment\" FROM comments WHERE domain_id=:domain_id"); + declare(suffix, "insert-comment-query", "", "INSERT INTO comments (id, domain_id, name, type, modified_at, account, \"comment\") VALUES (comments_id_sequence.nextval, :domain_id, :qname, :qtype, :modified_at, :account, :content)"); + declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=:domain_id AND name=:qname AND type=:qtype"); + declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=:domain_id"); + } DNSBackend* make(const string &suffix="") { diff --git a/modules/goraclebackend/goraclebackend.hh b/modules/goraclebackend/goraclebackend.hh index d8e9f6309..1ca3b8b05 100644 --- a/modules/goraclebackend/goraclebackend.hh +++ b/modules/goraclebackend/goraclebackend.hh @@ -10,5 +10,4 @@ class gOracleBackend : public GSQLBackend { public: gOracleBackend(const string &mode, const string &suffix); //!< Makes our connection to the database. Throws an exception if it fails. - virtual string sqlEscape(const string &name); }; diff --git a/modules/goraclebackend/soracle.cc b/modules/goraclebackend/soracle.cc index 926f96dcd..0759dfd29 100644 --- a/modules/goraclebackend/soracle.cc +++ b/modules/goraclebackend/soracle.cc @@ -7,295 +7,490 @@ #include "pdns/misc.hh" #include "pdns/logger.hh" #include "pdns/dns.hh" -#include #include "pdns/namespaces.hh" +#include "pdns/md5.hh" bool SOracle::s_dolog; +class SOracleStatement: public SSqlStatement { +public: + SOracleStatement(const string& query, bool dolog, int nparams, OCIEnv *ctx, OCISvcCtx *svc_ctx, bool release_stmt) { + d_query = query; + d_ctx = ctx; + d_svcctx = svc_ctx; + d_dolog = dolog; + d_res = NULL; + d_bind = NULL; + d_stmt = NULL; + d_err = NULL; + d_queryResult = OCI_NO_DATA; + d_paridx = d_parnum = d_resnum = d_residx = 0; + d_release_stmt = release_stmt; + d_non_null_ind = 0; + d_null_ind = -1; + d_init = false; + + if (query.size() == 0) return; + + // create a key + string key = pdns_md5sum(query); + d_stmt_keysize = std::min(key.size()*2, sizeof(d_stmt_key)); + for(string::size_type i = 0; i < key.size() && i*2 < d_stmt_keysize; i++) + snprintf((char*)&(d_stmt_key[i*2]), 3, "%02x", (unsigned char)key[i]); + d_stmt_key[d_stmt_keysize] = 0; + + if (OCIHandleAlloc(d_ctx, (dvoid**)&d_err, OCI_HTYPE_ERROR, 0, NULL)) + throw SSqlException("Cannot allocate statement error handle"); + + if (d_release_stmt) { + if (OCIStmtPrepare2(d_svcctx, &d_stmt, d_err, (text*)query.c_str(), query.size(), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) { + // failed. + throw SSqlException("Cannot prepare statement: " + OCIErrStr()); + } + d_init = true; + } else d_init = false; + + d_parnum = nparams; + d_bind = new struct obind[d_parnum]; + memset(d_bind, 0, sizeof(struct obind)*d_parnum); + // and we are done. + } -string SOracle::getOracleError() -{ - string mReason = "ORA-UNKNOWN"; - - if (d_errorHandle != NULL) { - text msg[512]; - sb4 errcode = 0; - - memset(msg, 0, 512); - - OCIErrorGet((dvoid*) d_errorHandle,1, NULL, &errcode, msg, sizeof(msg), OCI_HTYPE_ERROR); - if (errcode) { - char* p = (char*) msg; - while (*p++ != 0x00) { - if (*p == '\n' || *p == '\r') { - *p = ';'; - } + void prepareStatement() { + if (d_stmt) return; // no-op + if (d_query.size()==0) return; + if (d_init == false) { + if (OCIStmtPrepare2(d_svcctx, &d_stmt, d_err, (text*)d_query.c_str(), d_query.size(), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException("Cannot prepare statement: " + OCIErrStr()); + } + d_init = true; + } else { + if (OCIStmtPrepare2(d_svcctx, &d_stmt, d_err, (text*)d_query.c_str(), d_query.size(), d_stmt_key, d_stmt_keysize, OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException("Cannot prepare statement: " + OCIErrStr()); } + } + } - mReason = (char*) msg; + SSqlStatement* bind(const string& name, bool value) + { + return bind(name, (int)value); + } + SSqlStatement* bind(const string& name, int value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].val4 = value; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), &(d_bind[d_paridx].val4), sizeof(sb4), SQLT_INT, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); } + d_paridx++; + return this; } - return mReason; -} + SSqlStatement* bind(const string& name, uint32_t value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].val4 = value; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (ub4*)&(d_bind[d_paridx].val4), sizeof(ub4), SQLT_UIN, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, long value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].val4 = value; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (ub4*)&(d_bind[d_paridx].val4), sizeof(sb4), SQLT_INT, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, unsigned long value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].val4 = value; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (ub4*)&(d_bind[d_paridx].val4), sizeof(ub4), SQLT_UIN, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, long long value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].val8 = value; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (orasb8*)&(d_bind[d_paridx].val8), sizeof(orasb8), SQLT_INT, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, unsigned long long value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].val8 = value; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (oraub8*)&(d_bind[d_paridx].val8), sizeof(oraub8), SQLT_UIN, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_paridx++; + return this; + } + SSqlStatement* bind(const string& name, const std::string& value) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + d_bind[d_paridx].vals = new text[value.size()+1]; + memset(d_bind[d_paridx].vals, 0, value.size()+1); + value.copy((char*)d_bind[d_paridx].vals, value.size()); + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (text*)d_bind[d_paridx].vals, value.size()+1, SQLT_STR, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_paridx++; + return this; + } + SSqlStatement* bindNull(const string& name) + { + if (d_paridx >= d_parnum) + throw SSqlException("Attempt to bind more parameters than query has"); + prepareStatement(); + string zName = string(":") + name; + if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), NULL, 0, SQLT_STR, &d_null_ind, 0, 0, 0, 0, OCI_DEFAULT) != OCI_SUCCESS) { + throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr()); + } + d_bind[d_paridx].release = true; // remember to free this + d_paridx++; + return this; + } + SSqlStatement* execute() + { + if (d_query.size() == 0) return this; // do not execute empty queries + prepareStatement(); -SOracle::SOracle(const string &database, - const string &user, - const string &password) -{ - d_environmentHandle = NULL; - d_errorHandle = NULL; - d_serviceContextHandle = NULL; - d_handle = NULL; + if (d_dolog) + L< 0) { + ub2 o_attrtype; + OCIParam *parms = NULL; + d_res = new struct oresult[d_fnum]; + memset(d_res, 0, sizeof(struct oresult)*d_fnum); -void SOracle::setLog(bool state) -{ - s_dolog=state; -} + for(int i=0; i < d_fnum; i++) { + if (OCIParamGet(d_stmt, OCI_HTYPE_STMT, d_err, (dvoid**)&parms, (ub4)i+1) != OCI_SUCCESS) { + throw SSqlException("Cannot get statement result column information: " + OCIErrStr()); + } -SOracle::~SOracle() -{ - if (d_handle) { - OCIHandleFree(d_handle, OCI_HTYPE_STMT); - d_handle=0; - } + if (OCIAttrGet(parms, OCI_DTYPE_PARAM, (dvoid*)&(d_res[i].colsize), 0, OCI_ATTR_DATA_SIZE, d_err) != OCI_SUCCESS) { + throw SSqlException("Cannot get statement result column information: " + OCIErrStr()); + } + + if (d_res[i].colsize == 0) { + if (OCIAttrGet(parms, OCI_DTYPE_PARAM, (dvoid*)&o_attrtype, 0, OCI_ATTR_DATA_TYPE, d_err) != OCI_SUCCESS) { + throw SSqlException("Cannot get statement result column information: " + OCIErrStr()); + } + + // oracle 11g returns 0 for integer fields - we know oracle should return 22. + if (o_attrtype == OCI_TYPECODE_INTEGER || + o_attrtype == OCI_TYPECODE_SMALLINT || + o_attrtype == OCI_TYPECODE_REAL || + o_attrtype == OCI_TYPECODE_DOUBLE || + o_attrtype == OCI_TYPECODE_FLOAT || + o_attrtype == OCI_TYPECODE_NUMBER || + o_attrtype == OCI_TYPECODE_DECIMAL) d_res[i].colsize = 22; + } + d_res[i].content = new char[d_res[i].colsize+1]; + } + } - int err; - if (d_serviceContextHandle != NULL) { - err=OCILogoff(d_serviceContextHandle, d_errorHandle); - if (err) { - cerr<<"Problems logging out: "+getOracleError()< 0) { + for(int i=0;i=0) { + row.push_back(d_res[i].content); + } else { + row.push_back(""); + } } - return num; -} + d_queryResult = OCIStmtFetch2(d_stmt, d_err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT); -int SOracle::doQuery(const string &query) -{ - if (query=="begin") { // oracle does this implicitly - return 0; + d_residx++; + return this; } - if (s_dolog) { - L< +#include #ifndef dsword typedef sb4 dsword; @@ -17,36 +18,28 @@ class SOracle : public SSql public: SOracle(const string &database, const string &user="", - const string &password=""); + const string &password="", + bool releaseStatements=false, + OCIEnv* oraenv=NULL); ~SOracle(); SSqlException sPerrorException(const string &reason); - int doQuery(const string &query, result_t &result); - int doQuery(const string &query); - int doCommand(const string &query); - bool getRow(row_t &row); - string escape(const string &str); void setLog(bool state); + SSqlStatement* prepare(const string& query, int nparams); + void execute(const string& query); + + void startTransaction() {} + void commit() {} + void rollback() {} private: OCIEnv* d_environmentHandle; OCIError* d_errorHandle; OCISvcCtx* d_serviceContextHandle; - OCIStmt* d_statementHandles[10]; - - struct oresult { - char content[4000]; - sb2 indicator; - } d_fields[10]; - OCIStmt* d_handle; - - dsword d_queryResult; string getOracleError(); - static bool s_dolog; - int d_numfields; - // int getNumFields(const string& query); + bool d_release_stmt; }; #endif /* SSORACLE_HH */ diff --git a/modules/gpgsqlbackend/gpgsqlbackend.cc b/modules/gpgsqlbackend/gpgsqlbackend.cc index b1282c16d..cf3d8c8c4 100644 --- a/modules/gpgsqlbackend/gpgsqlbackend.cc +++ b/modules/gpgsqlbackend/gpgsqlbackend.cc @@ -46,77 +46,77 @@ public: string record_query = "SELECT content,ttl,prio,type,domain_id,disabled::int,name,auth::int FROM records WHERE"; - declare(suffix, "basic-query", "Basic query", record_query+" disabled=false and type='%s' and name=E'%s'"); - declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=false and type='%s' and name=E'%s' and domain_id=%d"); - declare(suffix, "any-query", "Any query", record_query+" disabled=false and name=E'%s'"); - declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=false and name=E'%s' and domain_id=%d"); + declare(suffix, "basic-query", "Basic query", record_query+" disabled=false and type=$1 and name=$2"); + declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=false and type=$1 and name=$2 and domain_id=$3"); + declare(suffix, "any-query", "Any query", record_query+" disabled=false and name=$1"); + declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=false and name=$1 and domain_id=$2"); - declare(suffix, "list-query", "AXFR query", record_query+" (disabled=false OR %d::bool) and domain_id='%d' order by name, type"); - declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=false and (name=E'%s' OR name like E'%s') and domain_id='%d'"); + declare(suffix, "list-query", "AXFR query", record_query+" (disabled=false OR $1) and domain_id=$2 order by name, type"); + declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=false and (name=$1 OR name like $2) and domain_id=$3"); - declare(suffix,"remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id='%d' and type is null"); - declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values ('%d','%s',null,false,true)"); - declare(suffix,"delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id='%d' and name='%s' and type is null"); + declare(suffix,"remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=$1 and type is null"); + declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values ($1,$2,null,false,true)"); + declare(suffix,"delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=$1 and name=$2 and type is null"); - declare(suffix,"master-zone-query","Data", "select master from domains where name=E'%s' and type='SLAVE'"); + declare(suffix,"master-zone-query","Data", "select master from domains where name=$1 and type='SLAVE'"); - declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type from domains where name=E'%s'"); + declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type from domains where name=$1"); declare(suffix,"info-all-slaves-query","","select id,name,master,last_check,type from domains where type='SLAVE'"); - declare(suffix,"supermaster-query","", "select account from supermasters where ip='%s' and nameserver=E'%s'"); - declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=E'%s' and account=E'%s'"); - - declare(suffix,"insert-zone-query","", "insert into domains (type,name) values('NATIVE',E'%s')"); - declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE',E'%s',E'%s',E'%s')"); - - declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values (E'%s',%d,%d,'%s',%d,%d::bool,E'%s','%d')"); - declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (E'%s',%d,%d,'%s',%d,%d::bool,E'%s',E'%s','%d')"); - declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,'%d',false,E'%s','%d')"); - declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,'%d',false,E'%s',E'%s','%d')"); - - declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=false and domain_id=%d and ordername is not null order by 1 using ~<~ limit 1"); - declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where disabled=false and ordername ~<=~ E'%s' and domain_id=%d and ordername is not null order by 1 using ~>~ limit 1"); - declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select ordername from records where disabled=false and ordername ~>~ E'%s' and domain_id=%d and ordername is not null order by 1 using ~<~ limit 1"); - declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=false and ordername != '' and domain_id=%d and ordername is not null order by 1 using ~>~ limit 1"); - declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername=E'%s',auth=%d::bool where name=E'%s' and domain_id='%d' and disabled=false"); - declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=true where domain_id='%d' and name='%s' and type='DS' and disabled=false"); - - declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=%d::bool where domain_id='%d' and name='%s' and disabled=false"); - declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=false where name=E'%s' and type=E'%s' and domain_id='%d' and disabled=false"); - - declare(suffix,"update-master-query","", "update domains set master='%s' where name='%s'"); - declare(suffix,"update-kind-query","", "update domains set type='%s' where name='%s'"); - declare(suffix,"update-serial-query","", "update domains set notified_serial=%d where id=%d"); - declare(suffix,"update-lastcheck-query","", "update domains set last_check=%d where id=%d"); - declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=%d"); + declare(suffix,"supermaster-query","", "select account from supermasters where ip=$1 and nameserver=$2"); + declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=$1 and account=$2"); + + declare(suffix,"insert-zone-query","", "insert into domains (type,name) values('NATIVE',$1)"); + declare(suffix,"insert-slave-query","", "insert into domains (type,name,master,account) values('SLAVE',$1,$2,$3)"); + + declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values ($1,$2,$3,$4,$5,$6,$7,$8)"); + declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values ($1,$2,$3,$4,$5,$6,$7,$8,$9)"); + declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,$1,false,$2,$3)"); + declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,$1,false,$2,$3,$4)"); + + declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=false and domain_id=$1 and ordername is not null order by 1 using ~<~ limit 1"); + declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where disabled=false and ordername ~<=~ $1 and domain_id=$2 and ordername is not null order by 1 using ~>~ limit 1"); + declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select ordername from records where disabled=false and ordername ~>~ $1 and domain_id=$2 and ordername is not null order by 1 using ~<~ limit 1"); + declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=false and ordername != '' and domain_id=$1 and ordername is not null order by 1 using ~>~ limit 1"); + declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername=$1,auth=$2 where name=$3 and domain_id=$4 and disabled=false"); + declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=true where domain_id=$1 and name=$2 and type='DS' and disabled=false"); + + declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=$1 where domain_id=$2 and name=$3 and disabled=false"); + declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=false where name=$1 and type=$2 and domain_id=$3 and disabled=false"); + + declare(suffix,"update-master-query","", "update domains set master=$1 where name=$2"); + declare(suffix,"update-kind-query","", "update domains set type=$1 where name=$2"); + declare(suffix,"update-serial-query","", "update domains set notified_serial=$1 where id=$2"); + declare(suffix,"update-lastcheck-query","", "update domains set last_check=$1 where id=$2"); + declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=$1"); declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'"); - declare(suffix,"delete-domain-query","", "delete from domains where name=E'%s'"); - declare(suffix,"delete-zone-query","", "delete from records where domain_id=%d"); - declare(suffix,"delete-rrset-query","","delete from records where domain_id=%d and name=E'%s' and type=E'%s'"); - declare(suffix,"delete-names-query","","delete from records where domain_id=%d and name=E'%s'"); - - declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, %d, (%d = 1), '%s' from domains where name=E'%s'"); - declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, case when active then 1 else 0 end as active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=E'%s'"); - declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=E'%s'"); - declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=E'%s' and domainmetadata.kind=E'%s'"); - declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=E'%s') and domainmetadata.kind=E'%s'"); - declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=E'%s')"); - declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, '%s', '%s' from domains where name=E'%s'"); - declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=true where domain_id=(select id from domains where name=E'%s') and cryptokeys.id=%d"); - declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=false where domain_id=(select id from domains where name=E'%s') and cryptokeys.id=%d"); - declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=E'%s') and cryptokeys.id=%d"); - declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=E'%s')"); - declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=E'%s'"); - declare(suffix,"set-tsig-key-query","", "insert into tsigkeys (name,algorithm,secret) values('%s','%s','%s')"); - declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name='%s'"); + declare(suffix,"delete-domain-query","", "delete from domains where name=$1"); + declare(suffix,"delete-zone-query","", "delete from records where domain_id=$1"); + declare(suffix,"delete-rrset-query","","delete from records where domain_id=$1 and name=$2 and type=$3"); + declare(suffix,"delete-names-query","","delete from records where domain_id=$1 and name=$2"); + + declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, $1, $2, $3 from domains where name=$4"); + declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, case when active then 1 else 0 end as active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=$1"); + declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=$1"); + declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=$1 and domainmetadata.kind=$2"); + declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=$1) and domainmetadata.kind=$2"); + declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=$1)"); + declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, $1, $2 from domains where name=$3"); + declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=true where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2"); + declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=false where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2"); + declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2"); + declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=$1)"); + declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=$1"); + declare(suffix,"set-tsig-key-query","", "insert into tsigkeys (name,algorithm,secret) values($1,$2,$3)"); + declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name=$1"); declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys"); - declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=false OR %d::bool"); + declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=false OR $1"); - declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=%d"); - declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (%d, E'%s', E'%s', %d, E'%s', E'%s')"); - declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=%d AND name=E'%s' AND type=E'%s'"); - declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=%d"); + declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=$1"); + declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES ($1, $2, $3, $4, $5, $6)"); + declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=$1 AND name=$2 AND type=$3"); + declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=$1"); } DNSBackend *make(const string &suffix="") diff --git a/modules/gpgsqlbackend/spgsql.cc b/modules/gpgsqlbackend/spgsql.cc index 84bff3ccc..f30a3dadd 100644 --- a/modules/gpgsqlbackend/spgsql.cc +++ b/modules/gpgsqlbackend/spgsql.cc @@ -7,6 +7,150 @@ #include "pdns/logger.hh" #include "pdns/dns.hh" #include "pdns/namespaces.hh" +#include +#include + +class SPgSQLStatement: public SSqlStatement +{ +public: + SPgSQLStatement(const string& query, bool dolog, int nparams, PGconn* db) { + struct timeval tv; + + d_query = query; + d_dolog = dolog; + d_db = db; + + // prepare a statement + gettimeofday(&tv,NULL); + this->d_stmt = string("stmt") + boost::lexical_cast(tv.tv_sec) + boost::lexical_cast(tv.tv_usec); + + d_nparams = nparams; + + PGresult* res = PQprepare(d_db, d_stmt.c_str(), d_query.c_str(), d_nparams, NULL); + ExecStatusType status = PQresultStatus(res); + string errmsg(PQresultErrorMessage(res)); + PQclear(res); + if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && status != PGRES_NONFATAL_ERROR) { + throw SSqlException("Fatal error during prepare: " + errmsg); + } + paramValues=NULL; + d_paridx=d_residx=d_resnum=0; + paramLengths=NULL; + d_res=NULL; + } + + SSqlStatement* bind(const string& name, bool value) { return bind(name, string(value ? "t" : "f")); } + SSqlStatement* bind(const string& name, int value) { return bind(name, boost::lexical_cast(value)); } + SSqlStatement* bind(const string& name, uint32_t value) { return bind(name, boost::lexical_cast(value)); } + SSqlStatement* bind(const string& name, long value) { return bind(name, boost::lexical_cast(value)); } + SSqlStatement* bind(const string& name, unsigned long value) { return bind(name, boost::lexical_cast(value)); } + SSqlStatement* bind(const string& name, long long value) { return bind(name, boost::lexical_cast(value)); } + SSqlStatement* bind(const string& name, unsigned long long value) { return bind(name, boost::lexical_cast(value)); } + SSqlStatement* bind(const string& name, const std::string& value) { + allocate(); + if (d_paridx>=d_nparams) + throw SSqlException("Attempt to bind more parameters than query has"); + paramValues[d_paridx] = new char[value.size()+1]; + memset(paramValues[d_paridx], 0, sizeof(char)*(value.size()+1)); + value.copy(paramValues[d_paridx], value.size()); + paramLengths[d_paridx] = value.size(); + d_paridx++; + return this; + } + SSqlStatement* bindNull(const string& name) { d_paridx++; return this; } // these are set null in allocate() + SSqlStatement* execute() { + if (d_dolog) { + L<=d_resnum || !d_res) return this; + row.reserve(PQnfields(d_res)); + for(i=0;i= d_resnum) { + PQclear(d_res); + d_res = NULL; + } + return this; + } + + SSqlStatement* getResult(result_t& result) { + result.clear(); + if (d_res == NULL) return this; + result.reserve(d_resnum); + row_t row; + while(hasNextRow()) { nextRow(row); result.push_back(row); } + return this; + } + + SSqlStatement* reset() { + int i; + if (d_res) + PQclear(d_res); + d_res = NULL; + d_paridx = d_residx = d_resnum = 0; + if (paramValues) + for(i=0;i= PQntuples(d_result)) { - PQclear(d_result); - return false; - } - - for(int i=0;idoQuery("PRAGMA synchronous="+getArg("pragma-synchronous"), res); + ptr->execute("PRAGMA synchronous="+getArg("pragma-synchronous")); } - if(mustDo("pragma-foreign-keys")) { - SSQLite3::result_t res; - ptr->doQuery("PRAGMA foreign_keys = ON", res); - } - } - catch( SSqlException & e ) + ptr->execute("PRAGMA foreign_keys = 1"); + } + catch( SSqlException & e ) { L << Logger::Error << mode << ": connection failed: " << e.txtReason() << std::endl; throw PDNSException( "Unable to launch " + mode + " connection: " + e.txtReason()); @@ -59,85 +55,85 @@ public: //! Declares all needed arguments. void declareArguments( const std::string & suffix = "" ) { - declare( suffix, "database", "Filename of the SQLite3 database", "powerdns.sqlite" ); - declare( suffix, "pragma-synchronous", "Set this to 0 for blazing speed", "" ); - declare( suffix, "pragma-foreign-keys", "Enable foreign key constraints", "no" ); + declare(suffix, "database", "Filename of the SQLite3 database", "powerdns.sqlite"); + declare(suffix, "pragma-synchronous", "Set this to 0 for blazing speed", ""); + declare(suffix, "pragma-foreign-keys", "Enable foreign key constraints", "no" ); declare(suffix, "dnssec", "Enable DNSSEC processing","no"); string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE"; - declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type='%s' and name='%s'"); - declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type='%s' and name='%s' and domain_id=%d"); - declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name='%s'"); - declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name='%s' and domain_id=%d"); + declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=:qtype and name=:qname"); + declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=:qtype and name=:qname and domain_id=:domain_id"); + declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=:qname"); + declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=:qname and domain_id=:domain_id"); - declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR %d) and domain_id='%d' order by name, type"); - declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name='%s' OR name like '%s') and domain_id=%d"); + declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type"); + declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id"); - declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id='%d' and type is null"); - declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values ('%d','%s',null,0,'1')"); - declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id='%d' and name='%s' and type is null"); + declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null"); + declare(suffix, "insert-empty-non-terminal-query", "insert empty non-terminal in zone", "insert into records (domain_id,name,type,disabled,auth) values (:domain_id,:qname,null,0,'1')"); + declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=:domain_id and name=:qname and type is null"); - declare( suffix, "master-zone-query", "Data", "select master from domains where name='%s' and type='SLAVE'"); - - declare( suffix, "info-zone-query", "","select id,name,master,last_check,notified_serial,type from domains where name='%s'"); - - declare( suffix, "info-all-slaves-query", "","select id,name,master,last_check,type from domains where type='SLAVE'"); - declare( suffix, "supermaster-query", "", "select account from supermasters where ip='%s' and nameserver='%s'"); - declare( suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver='%s' and account='%s'"); - - declare( suffix, "insert-zone-query", "", "insert into domains (type,name) values('NATIVE','%s')"); - declare( suffix, "insert-slave-query", "", "insert into domains (type,name,master,account) values('SLAVE','%s','%s','%s')"); - - declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values ('%s',%d,%d,'%s',%d,%d,'%s',%d)"); - declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values ('%s',%d,%d,'%s',%d,%d,'%s','%s','%d')"); - declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,'%d',0,'%s','%d')"); - declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,'%d',0,'%s','%s','%d')"); - - declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select ordername, name from records where disabled=0 and domain_id=%d and ordername is not null order by 1 asc limit 1"); - declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where disabled=0 and ordername <= '%s' and domain_id=%d and ordername is not null order by 1 desc limit 1"); - declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select min(ordername) from records where disabled=0 and ordername > '%s' and domain_id=%d and ordername is not null"); - declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=0 and ordername != '' and domain_id=%d and ordername is not null order by 1 desc limit 1"); - declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername='%s',auth=%d where name='%s' and domain_id='%d' and disabled=0"); - declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=1 where domain_id='%d' and name='%s' and type='DS' and disabled=0"); - - declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=%d where domain_id='%d' and name='%s' and disabled=0"); - declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=0 where name='%s' and type='%s' and domain_id='%d' and disabled=0"); - - declare( suffix, "update-master-query", "", "update domains set master='%s' where name='%s'"); - declare( suffix, "update-kind-query", "", "update domains set type='%s' where name='%s'"); - declare( suffix, "update-serial-query", "", "update domains set notified_serial=%d where id=%d"); - declare( suffix, "update-lastcheck-query", "", "update domains set last_check=%d where id=%d"); - declare (suffix, "zone-lastchange-query", "", "select max(change_date) from records where domain_id=%d"); - declare( suffix, "info-all-master-query", "", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'"); - declare(suffix,"delete-domain-query","", "delete from domains where name='%s'"); - declare( suffix, "delete-zone-query", "", "delete from records where domain_id=%d"); - declare( suffix, "delete-rrset-query", "", "delete from records where domain_id = %d and name='%s' and type='%s'"); - declare( suffix, "delete-names-query", "", "delete from records where domain_id = %d and name='%s'"); - - declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, %d, %d, '%s' from domains where name='%s'"); - declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name='%s'"); - declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='%s'"); - declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name='%s' and domainmetadata.kind='%s'"); - declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name='%s') and domainmetadata.kind='%s'"); - declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name='%s')"); - declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, '%s', '%s' from domains where name='%s'"); - declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name='%s') and cryptokeys.id=%d"); - declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name='%s')"); - declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name='%s'"); - declare(suffix,"set-tsig-key-query","", "replace into tsigkeys (name,algorithm,secret) values('%s','%s','%s')"); - declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name='%s'"); - declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys"); - - declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR %d"); - - declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=%d"); - declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (%d, '%s', '%s', %d, '%s', '%s')"); - declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=%d AND name='%s' AND type='%s'"); - declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=%d"); + declare(suffix, "master-zone-query", "Data", "select master from domains where name=:domain and type='SLAVE'"); + + declare(suffix, "info-zone-query", "","select id,name,master,last_check,notified_serial,type from domains where name=:domain"); + + declare(suffix, "info-all-slaves-query", "","select id,name,master,last_check,type from domains where type='SLAVE'"); + declare(suffix, "supermaster-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver"); + declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=:nameserver and account=:account"); + + declare(suffix, "insert-zone-query", "", "insert into domains (type,name) values('NATIVE',:domain)"); + declare(suffix, "insert-slave-query", "", "insert into domains (type,name,master,account) values('SLAVE',:domain,:masters,:account)"); + + declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,auth) values (:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:auth)"); + declare(suffix, "insert-record-order-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth) values (:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:ordername,:auth)"); + declare(suffix, "insert-ent-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,auth) values (null,:domain_id,0,:qname,:auth)"); + declare(suffix, "insert-ent-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth) values (null,:domain_id,0,:qname,:ordername,:auth)"); + + declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select ordername, name from records where disabled=0 and domain_id=:domain_id and ordername is not null order by 1 asc limit 1"); + declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where disabled=0 and ordername <= :ordername and domain_id=:domain_id and ordername is not null order by 1 desc limit 1"); + declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select min(ordername) from records where disabled=0 and ordername > :ordername and domain_id=:domain_id and ordername is not null"); + declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=0 and ordername != '' and domain_id=:domain_id and ordername is not null order by 1 desc limit 1"); + declare(suffix, "set-order-and-auth-query", "DNSSEC set ordering query", "update records set ordername=:ordername,auth=:auth where name=:qname and domain_id=:domain_id and disabled=0"); + declare(suffix, "set-auth-on-ds-record-query", "DNSSEC set auth on a DS record", "update records set auth=1 where domain_id=:domain_id and name=:qname and type='DS' and disabled=0"); + + declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and disabled=0"); + declare(suffix, "nullify-ordername-and-auth-query", "DNSSEC nullify ordername and auth query", "update records set ordername=NULL,auth=0 where name=:qname and type=:qtype and domain_id=:domain_id and disabled=0"); + + declare(suffix, "update-master-query", "", "update domains set master=:master where name=:domain"); + declare(suffix, "update-kind-query", "", "update domains set type=:kind where name=:domain"); + declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id"); + declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id"); + declare(suffix, "zone-lastchange-query", "", "select max(change_date) from records where domain_id=:domain_id"); + declare(suffix, "info-all-master-query", "", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'"); + declare(suffix, "delete-domain-query","", "delete from domains where name=:domain"); + declare(suffix, "delete-zone-query", "", "delete from records where domain_id=:domain_id"); + declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype"); + declare(suffix, "delete-names-query", "", "delete from records where domain_id=:domain_id and name=:qname"); + + declare(suffix, "add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, :flags,:active, :content from domains where name=:domain"); + declare(suffix, "list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=:domain"); + declare(suffix, "get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain"); + declare(suffix, "get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain and domainmetadata.kind=:kind"); + declare(suffix, "clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain) and domainmetadata.kind=:kind"); + declare(suffix, "clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain)"); + declare(suffix, "set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, :kind, :content from domains where name=:domain"); + declare(suffix, "activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id"); + declare(suffix, "deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id"); + declare(suffix, "remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id"); + declare(suffix, "clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain)"); + declare(suffix, "get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=:key_name"); + declare(suffix, "set-tsig-key-query","", "replace into tsigkeys (name,algorithm,secret) values(:key_name,:algorithm,:content)"); + declare(suffix, "delete-tsig-key-query","", "delete from tsigkeys where name=:key_name"); + declare(suffix, "get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys"); + + declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR :include_disabled"); + + declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=:domain_id"); + declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (:domain_id, :qname, :qtype, :modified_at, :account, :content)"); + declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=:domain_id AND name=:qname AND type=:qtype"); + declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=:domain_id"); } //! Constructs a new gSQLite3Backend object. @@ -163,12 +159,6 @@ public: } }; -string gSQLite3Backend::sqlEscape(const string &name) -{ - return boost::replace_all_copy(name, "'", "''"); -} - - //! Reports the backendloader to the UeberBackend. static gSQLite3Loader gsqlite3loader; diff --git a/modules/gsqlite3backend/gsqlite3backend.hh b/modules/gsqlite3backend/gsqlite3backend.hh index dc1fc415f..c58e26246 100644 --- a/modules/gsqlite3backend/gsqlite3backend.hh +++ b/modules/gsqlite3backend/gsqlite3backend.hh @@ -13,12 +13,9 @@ //! The gSQLiteBackend retrieves it's data from a SQLite database (http://www.sqlite.org/) class gSQLite3Backend : public GSQLBackend { -private: -protected: public: //! Constructs the backend, throws an exception if it failed.. gSQLite3Backend( const std::string & mode, const std::string & suffix ); - virtual string sqlEscape(const string &name); }; #endif // GSQLITEBACKEND_HH diff --git a/modules/mydnsbackend/mydnsbackend.cc b/modules/mydnsbackend/mydnsbackend.cc index b0953e627..a46e350d7 100644 --- a/modules/mydnsbackend/mydnsbackend.cc +++ b/modules/mydnsbackend/mydnsbackend.cc @@ -41,336 +41,426 @@ static string backendName="[MyDNSbackend]"; MyDNSBackend::MyDNSBackend(const string &suffix) { - setArgPrefix("mydns"+suffix); - - try { - d_db = new SMySQL(getArg("dbname"), - getArg("host"), - getArgAsNum("port"), - getArg("socket"), - getArg("user"), - getArg("password")); - - } - catch(SSqlException &e) { - L<setLog(::arg().mustDo("query-logging")); + } + catch(SSqlException &e) { + L<prepare(domainIdQuery, 1); + d_domainNoIdQuery_stmt = d_db->prepare(domainNoIdQuery, 1); + d_soaQuery_stmt = d_db->prepare(soaQuery, 1); + + string listQuery = "SELECT type, data, aux, ttl, zone, name FROM `"+rrtable+"` WHERE zone = ?"; + string basicQuery = "SELECT type, data, aux, ttl, zone FROM `"+rrtable+"` WHERE zone = ? AND (name = ? OR name = ?) AND type = ?"; + string anyQuery = "(SELECT type, data, aux, ttl, zone FROM `"+rrtable+"` WHERE zone = ? AND (name = ? OR name = ?)"; + + if (!rrwhere.empty()) { + listQuery += " AND "+rrwhere; + basicQuery += " AND " + rrwhere; + anyQuery += " AND " + rrwhere; + } + + d_listQuery_stmt = d_db->prepare(listQuery, 1); + + anyQuery += ") UNION (SELECT 'SOA' AS type, origin AS data, '0' AS aux, ttl, id AS zone FROM `"+soatable+"` WHERE id = ? AND origin = ?"; + + if (!soawhere.empty()) + anyQuery += " AND "+soawhere; + + basicQuery += " ORDER BY type,aux,data"; + anyQuery += ") ORDER BY type,aux,data"; + + d_basicQuery_stmt = d_db->prepare(basicQuery, 4); + d_anyQuery_stmt = d_db->prepare(anyQuery, 5); + } catch (SSqlException &e) { + L<doQuery(query); - } catch (SSqlException &e) { - throw PDNSException("Query failed: "+e.txtReason()); - } -} - bool MyDNSBackend::list(const string &target, int zoneId, bool include_disabled) { - string query; - string sname; - SSql::row_t rrow; - - d_db->setLog(::arg().mustDo("query-logging")); - - query = "select origin, minimum from "+d_soatable+" where id = "; - query+=itoa(zoneId); - if (!d_soawhere.empty()) - query+= " and "+d_soawhere; - - this->Query(query); - - if(!d_db->getRow(rrow)) - return false; // No such zone - - d_origin = rrow[0]; - if (d_origin[d_origin.length()-1] == '.') - d_origin.erase(d_origin.length()-1); - d_minimum = atol(rrow[1].c_str()); - - while (d_db->getRow(rrow)) { - L<Query(query); - - d_qname = ""; - return true; - + string query; + string sname; + SSqlStatement::row_t rrow; + + try { + d_domainIdQuery_stmt-> + bind("domain_id", zoneId)-> + execute()-> + getResult(d_result)-> + reset(); + } + catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to list domain_id "+itoa(zoneId)+": "+e.txtReason()); + } + + if (d_result.empty()) + return false; // No such zone + + d_origin = d_result[0][0]; + if (d_origin[d_origin.length()-1] == '.') + d_origin.erase(d_origin.length()-1); + d_minimum = atol(d_result[0][1].c_str()); + + if (d_result.size()>1) { + L< + bind("domain_id", zoneId)-> + execute(); + } + catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to list domain_id "+itoa(zoneId)+": "+e.txtReason()); + } + + d_qname = ""; + return true; } bool MyDNSBackend::getSOA(const string& name, SOAData& soadata, DNSPacket*) { - string query; - SSql::row_t rrow; - - d_db->setLog(::arg().mustDo("query-logging")); - - if (name.empty()) - return false; - - query = "select id, mbox, serial, ns, refresh, retry, expire, minimum, ttl from "+d_soatable+" where origin = '"; - - if (name.find_first_of("'\\")!=string::npos) - query+=d_db->escape(name); - else - query+=name; - - query+=".'"; - if (! d_soawhere.empty()) - query += " and "+d_soawhere; - - this->Query(query); - - if(!(d_db->getRow(rrow))) { - return false; - } - - soadata.qname = name; - soadata.domain_id = atol(rrow[0].c_str()); - soadata.hostmaster = rrow[1]; - soadata.serial = atol(rrow[2].c_str()); - soadata.nameserver = rrow[3]; - soadata.refresh = atol(rrow[4].c_str()); - soadata.retry = atol(rrow[5].c_str()); - soadata.expire = atol(rrow[6].c_str()); - soadata.default_ttl = atol(rrow[7].c_str()); - soadata.ttl = atol(rrow[8].c_str()); - if (d_useminimalttl && soadata.ttl < soadata.default_ttl) { - soadata.ttl = soadata.default_ttl; - } - soadata.db = this; - - while (d_db->getRow(rrow)) { - L< + bind("origin", dotname)-> + execute()-> + getResult(d_result)-> + reset(); + } + catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to get soa for domain "+name+": "+e.txtReason()); + } + + if (d_result.empty()) return false; + + rrow = d_result[0]; + + soadata.qname = name; + soadata.domain_id = atol(rrow[0].c_str()); + soadata.hostmaster = rrow[1]; + soadata.serial = atol(rrow[2].c_str()); + soadata.nameserver = rrow[3]; + soadata.refresh = atol(rrow[4].c_str()); + soadata.retry = atol(rrow[5].c_str()); + soadata.expire = atol(rrow[6].c_str()); + soadata.default_ttl = atol(rrow[7].c_str()); + soadata.ttl = atol(rrow[8].c_str()); + if (d_useminimalttl) { + soadata.ttl = std::min(soadata.ttl, soadata.default_ttl); + } + soadata.db = this; + + if (d_result.size()>1) { + L<setLog(::arg().mustDo("query-logging")); - - if (qname.empty()) - return; - - // Escape the name, after this point we only want to use it in queries - if (qname.find_first_of("'\\")!=string::npos) - sname=d_db->escape(qname); - else - sname = qname; - sname += "."; - - if (zoneId < 0) { - // First off we need to work out what zone we're working with - // MyDNS records aren't always fully qualified, so we need to work out the zone ID. - - size_t pos; - string sdom; - - pos = 0; - sdom = sname; - while (!sdom.empty() && pos != string::npos) { - query = "select id, origin, minimum from "+d_soatable+" where origin = '"+sdom+"'"; - if (!d_soawhere.empty()) - query += " and "+d_soawhere; - - this->Query(query); - if(d_db->getRow(rrow)) { - zoneIdStr=rrow[0]; - d_origin = rrow[1]; - if (d_origin[d_origin.length()-1] == '.') - d_origin.erase(d_origin.length()-1); - d_minimum = atol(rrow[2].c_str()); - found = true; - break; - } - - pos = sname.find_first_of(".",pos+1); - sdom = sname.substr(pos+1); - } - - } else { - query = "select origin, minimum from "+d_soatable+" where id = "; - query+=zoneIdStr; - if (!d_soawhere.empty()) - query+= " and "+d_soawhere; - - this->Query(query); - - if(!d_db->getRow(rrow)) { - throw PDNSException("lookup() passed zoneId = "+zoneIdStr+" but no such zone!"); - } - - found = true; - d_origin = rrow[0]; - if (d_origin[d_origin.length()-1] == '.') - d_origin.erase(d_origin.length()-1); - d_minimum = atol(rrow[1].c_str()); - } - - - if (found) { - - while (d_db->getRow(rrow)) { - L<escape(host); - - query = "select type, data, aux, ttl, zone from "+d_rrtable+" where zone = "; - query+= zoneIdStr; - query += " and (name = '"+host+"' or name = '"+sname+"')"; - - if(qtype.getCode()!=255) { // ANY - query+=" and type='"; - query+=qtype.getName(); - query+="'"; - - } - if (!d_rrwhere.empty()) - query += " and "+d_rrwhere; - - - if (qtype.getCode() == 255) { - query += " union select 'SOA' as type, origin as data, '0' as aux, ttl, id as zone from "+d_soatable+" where id= " + zoneIdStr + " and origin = '"+qname+".'"; - if (!d_soawhere.empty()) - query += " and " + d_soawhere; - } - query += " order by type,aux,data"; - - this->Query(query); - - d_qname = qname; - } + string query; + string sname; + string zoneIdStr = itoa(zoneId); + SSqlStatement::row_t rrow; + bool found = false; + + d_origin = ""; + + if (qname.empty()) + return; + + DLOG(L< + bind("domain", sdom)-> + execute()-> + getResult(d_result)-> + reset(); + } + catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to lookup "+qname+": "+e.txtReason()); + } + + if (d_result.empty() == false) { + rrow = d_result[0]; + zoneId = boost::lexical_cast(rrow[0]); + d_origin = rrow[1]; + if (d_origin[d_origin.length()-1] == '.') + d_origin.erase(d_origin.length()-1); + d_minimum = atol(rrow[2].c_str()); + found = true; + break; + } + + pos = sname.find_first_of(".",pos+1); + sdom = sname.substr(pos+1); + } + + } else { + try { + d_domainIdQuery_stmt-> + bind("domain_id", zoneId)-> + execute()-> + getResult(d_result)-> + reset(); + } + catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to lookup "+qname+": "+e.txtReason()); + } + + if(d_result.empty()) { + throw PDNSException("lookup() passed zoneId = "+zoneIdStr+" but no such zone!"); + } + + rrow = d_result[0]; + + found = true; + d_origin = rrow[0]; + if (d_origin[d_origin.length()-1] == '.') + d_origin.erase(d_origin.length()-1); + d_minimum = atol(rrow[1].c_str()); + } + + + if (found) { + + while (d_result.size()>1) { + L< + bind("domain_id", zoneId)-> + bind("host", host)-> + bind("qname", sname)-> + bind("domain_id", zoneId)-> // this is because positional arguments + bind("qname2", dotqname)-> + execute(); + } else { + DLOG(L< + bind("domain_id", zoneId)-> + bind("host", host)-> + bind("qname", sname)-> + bind("qtype", qtype.getName())-> + execute(); + } + } + catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to lookup "+qname+": "+e.txtReason()); + } + + d_qname = qname; + } } bool MyDNSBackend::get(DNSResourceRecord &rr) { - if (d_origin.empty()) { - // This happens if lookup() couldn't find the zone - return false; - } - - SSql::row_t rrow; - - if(!d_db->getRow(rrow)) { - return false; - } - - rr.qtype=rrow[0]; - rr.content = rrow[1]; - - if(!d_qname.empty()) { - // use this to distinguish between select with 'name' field (list()) and one without - rr.qname=d_qname; - } else { - rr.qname=rrow[5]; - if (!rr.qname.empty() && rr.qname[rr.qname.length()-1] == '.') { - rr.qname.erase(rr.qname.length()-1); // Fully qualified, nuke the last . - } else { - if (!rr.qname.empty()) - rr.qname += "."; - rr.qname += d_origin; // Not fully qualified - } - } - - if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode()==QType::MX || - rr.qtype.getCode() == QType::CNAME || rr.qtype.getCode() == QType::PTR) { - if (!rr.content.empty() && rr.content[rr.content.length()-1] == '.') { - if (rr.content.length() > 1) - rr.content.erase(rr.content.length()-1); // Fully qualified, nuke the last . - } else { - if (rr.content != ".") - rr.content += "."; - rr.content += d_origin; - } - } - - if (rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) - rr.content=rrow[2]+" "+rr.content; - rr.ttl = atol(rrow[3].c_str()); - if (d_useminimalttl && rr.ttl < d_minimum) - rr.ttl = d_minimum; - rr.domain_id=atol(rrow[4].c_str()); - - rr.last_modified=0; - - return true; - + if (d_origin.empty()) { + if (d_query_stmt) { + try { + d_query_stmt->reset(); + } catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to lookup "+d_qname+": "+e.txtReason()); + } + d_query_stmt = NULL; + } + // This happens if lookup() couldn't find the zone + return false; + } + + SSqlStatement::row_t rrow; + + if (d_query_stmt->hasNextRow()) { + try { + d_query_stmt->nextRow(rrow); + } catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to lookup "+d_qname+": "+e.txtReason()); + } + rr.qtype=rrow[0]; + rr.content = rrow[1]; + + if(!d_qname.empty()) { + // use this to distinguish between select with 'name' field (list()) and one without + rr.qname=d_qname; + } else { + rr.qname=rrow[5]; + if (!rr.qname.empty() && rr.qname[rr.qname.length()-1] == '.') { + rr.qname.erase(rr.qname.length()-1); // Fully qualified, nuke the last . + } else { + if (!rr.qname.empty()) + rr.qname += "."; + rr.qname += d_origin; // Not fully qualified + } + } + + if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode()==QType::MX || + rr.qtype.getCode() == QType::CNAME || rr.qtype.getCode() == QType::PTR) { + if (!rr.content.empty() && rr.content[rr.content.length()-1] == '.') { + if (rr.content.length() > 1) + rr.content.erase(rr.content.length()-1); // Fully qualified, nuke the last . + } else { + if (rr.content != ".") + rr.content += "."; + rr.content += d_origin; + } + } + + if (rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV) + rr.content=rrow[2]+" "+rr.content; + + rr.ttl = atol(rrow[3].c_str()); + if (d_useminimalttl) + rr.ttl = std::min(rr.ttl, d_minimum); + rr.domain_id=atol(rrow[4].c_str()); + + rr.last_modified=0; + + return true; + } + + try { + d_query_stmt->reset(); + } catch (SSqlException &e) { + throw PDNSException("MyDNSBackend unable to lookup "+d_qname+": "+e.txtReason()); + } + + d_query_stmt = NULL; + + return false; } class MyDNSFactory : public BackendFactory { public: - MyDNSFactory() : BackendFactory("mydns") {} - - void declareArguments(const string &suffix = "") { - declare(suffix,"dbname","Pdns backend database name to connect to","mydns"); - declare(suffix,"user","Pdns backend user to connect as","powerdns"); - declare(suffix,"host","Pdns backend host to connect to",""); - declare(suffix,"port","Pdns backend host to connect to",""); - declare(suffix,"password","Pdns backend password to connect with",""); - declare(suffix,"socket","Pdns backend socket to connect to",""); - declare(suffix,"rr-table","Name of RR table to use","rr"); - declare(suffix,"soa-table","Name of SOA table to use","soa"); - declare(suffix,"soa-where","Additional WHERE clause for SOA","1 = 1"); - declare(suffix,"rr-where","Additional WHERE clause for RR","1 = 1"); - declare(suffix,"soa-active","Use the active column in the SOA table","yes"); - declare(suffix,"rr-active","Use the active column in the RR table","yes"); - declare(suffix,"use-minimal-ttl","Setting this to 'yes' will make the backend behave like MyDNS on the TTL values. Setting it to 'no' will make it ignore the minimal-ttl of the zone.","yes"); - } - - MyDNSBackend *make(const string &suffix = "") { - return new MyDNSBackend(suffix); - } + MyDNSFactory() : BackendFactory("mydns") {} + + void declareArguments(const string &suffix = "") { + declare(suffix,"dbname","Pdns backend database name to connect to","mydns"); + declare(suffix,"user","Pdns backend user to connect as","powerdns"); + declare(suffix,"host","Pdns backend host to connect to",""); + declare(suffix,"port","Pdns backend host to connect to",""); + declare(suffix,"password","Pdns backend password to connect with",""); + declare(suffix,"socket","Pdns backend socket to connect to",""); + declare(suffix,"rr-table","Name of RR table to use","rr"); + declare(suffix,"soa-table","Name of SOA table to use","soa"); + declare(suffix,"soa-where","Additional WHERE clause for SOA","1 = 1"); + declare(suffix,"rr-where","Additional WHERE clause for RR","1 = 1"); + declare(suffix,"soa-active","Use the active column in the SOA table","yes"); + declare(suffix,"rr-active","Use the active column in the RR table","yes"); + declare(suffix,"use-minimal-ttl","Setting this to 'yes' will make the backend behave like MyDNS on the TTL values. Setting it to 'no' will make it ignore the minimal-ttl of the zone.","yes"); + } + + MyDNSBackend *make(const string &suffix = "") { + return new MyDNSBackend(suffix); + } }; class MyDNSLoader { public: - MyDNSLoader() { - BackendMakers().report(new MyDNSFactory()); - L << Logger::Info << "[mydnsbackend] This is the mydns backend version " VERSION " (" __DATE__ ", " __TIME__ ") reporting" << endl; - } + MyDNSLoader() { + BackendMakers().report(new MyDNSFactory()); + L << Logger::Info << "[mydnsbackend] This is the mydns backend version " VERSION " (" __DATE__ ", " __TIME__ ") reporting" << endl; + } }; static MyDNSLoader mydnsloader; diff --git a/modules/mydnsbackend/mydnsbackend.hh b/modules/mydnsbackend/mydnsbackend.hh index 5caa80be9..b0be17350 100644 --- a/modules/mydnsbackend/mydnsbackend.hh +++ b/modules/mydnsbackend/mydnsbackend.hh @@ -11,26 +11,30 @@ class MyDNSBackend : public DNSBackend { public: - MyDNSBackend(const string &suffix=""); - ~MyDNSBackend(); - - void lookup(const QType &, const string &qdomain, DNSPacket *p=0, int zoneId=-1); - bool list(const string &target, int domain_id, bool include_disabled=false); - bool get(DNSResourceRecord &r); - bool getSOA(const string& name, SOAData& soadata, DNSPacket*); - + MyDNSBackend(const string &suffix=""); + ~MyDNSBackend(); + + void lookup(const QType &, const string &qdomain, DNSPacket *p=0, int zoneId=-1); + bool list(const string &target, int domain_id, bool include_disabled=false); + bool get(DNSResourceRecord &r); + bool getSOA(const string& name, SOAData& soadata, DNSPacket*); + private: - void Query(const string& query); - SMySQL *d_db; + SMySQL *d_db; - string d_qname; - string d_rrtable; - string d_soatable; - string d_soawhere; - string d_rrwhere; - string d_origin; - bool d_useminimalttl; - unsigned int d_minimum; + string d_qname; + string d_origin; + bool d_useminimalttl; + unsigned int d_minimum; + SSqlStatement::result_t d_result; + + SSqlStatement* d_query_stmt; + SSqlStatement* d_domainIdQuery_stmt; + SSqlStatement* d_domainNoIdQuery_stmt; + SSqlStatement* d_listQuery_stmt; + SSqlStatement* d_soaQuery_stmt; + SSqlStatement* d_basicQuery_stmt; + SSqlStatement* d_anyQuery_stmt; }; #endif /* MYDNSBACKEND_HH */ diff --git a/pdns/backends/gsql/gsqlbackend.cc b/pdns/backends/gsql/gsqlbackend.cc index 4befdf896..bac0dc351 100644 --- a/pdns/backends/gsql/gsqlbackend.cc +++ b/pdns/backends/gsql/gsqlbackend.cc @@ -34,23 +34,161 @@ #include #include #include +#include +GSQLBackend::GSQLBackend(const string &mode, const string &suffix) +{ + setArgPrefix(mode+suffix); + d_db=0; + d_logprefix="["+mode+"Backend"+suffix+"] "; + + try + { + d_dnssecQueries = mustDo("dnssec"); + } + catch (ArgException e) + { + d_dnssecQueries = false; + } + + d_NoIdQuery=getArg("basic-query"); + d_IdQuery=getArg("id-query"); + d_ANYNoIdQuery=getArg("any-query"); + d_ANYIdQuery=getArg("any-id-query"); + + d_listQuery=getArg("list-query"); + d_listSubZoneQuery=getArg("list-subzone-query"); + + d_MasterOfDomainsZoneQuery=getArg("master-zone-query"); + d_InfoOfDomainsZoneQuery=getArg("info-zone-query"); + d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query"); + d_SuperMasterInfoQuery=getArg("supermaster-query"); + d_GetSuperMasterIPs=getArg("supermaster-name-to-ips"); + d_InsertZoneQuery=getArg("insert-zone-query"); + d_InsertSlaveZoneQuery=getArg("insert-slave-query"); + d_InsertRecordQuery=getArg("insert-record-query"); + d_InsertEntQuery=getArg("insert-ent-query"); + d_UpdateMasterOfZoneQuery=getArg("update-master-query"); + d_UpdateKindOfZoneQuery=getArg("update-kind-query"); + d_UpdateSerialOfZoneQuery=getArg("update-serial-query"); + d_UpdateLastCheckofZoneQuery=getArg("update-lastcheck-query"); + d_ZoneLastChangeQuery=getArg("zone-lastchange-query"); + d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query"); + d_DeleteDomainQuery=getArg("delete-domain-query"); + d_DeleteZoneQuery=getArg("delete-zone-query"); + d_DeleteRRSetQuery=getArg("delete-rrset-query"); + d_DeleteNamesQuery=getArg("delete-names-query"); + d_getAllDomainsQuery=getArg("get-all-domains-query"); + + d_removeEmptyNonTerminalsFromZoneQuery = getArg("remove-empty-non-terminals-from-zone-query"); + d_insertEmptyNonTerminalQuery = getArg("insert-empty-non-terminal-query"); + d_deleteEmptyNonTerminalQuery = getArg("delete-empty-non-terminal-query"); -boost::format GSQLformat(const string &query) { - boost::format format(query); - format.exceptions(boost::io::no_error_bits); - return format; + d_ListCommentsQuery = getArg("list-comments-query"); + d_InsertCommentQuery = getArg("insert-comment-query"); + d_DeleteCommentRRsetQuery = getArg("delete-comment-rrset-query"); + d_DeleteCommentsQuery = getArg("delete-comments-query"); + + d_InsertRecordOrderQuery=getArg("insert-record-order-query"); + d_InsertEntOrderQuery=getArg("insert-ent-order-query"); + + d_firstOrderQuery = getArg("get-order-first-query"); + d_beforeOrderQuery = getArg("get-order-before-query"); + d_afterOrderQuery = getArg("get-order-after-query"); + d_lastOrderQuery = getArg("get-order-last-query"); + d_setOrderAuthQuery = getArg("set-order-and-auth-query"); + d_nullifyOrderNameAndUpdateAuthQuery = getArg("nullify-ordername-and-update-auth-query"); + d_nullifyOrderNameAndAuthQuery = getArg("nullify-ordername-and-auth-query"); + d_setAuthOnDsRecordQuery = getArg("set-auth-on-ds-record-query"); + + d_AddDomainKeyQuery = getArg("add-domain-key-query"); + d_ListDomainKeysQuery = getArg("list-domain-keys-query"); + + d_GetAllDomainMetadataQuery = getArg("get-all-domain-metadata-query"); + d_GetDomainMetadataQuery = getArg("get-domain-metadata-query"); + d_ClearDomainMetadataQuery = getArg("clear-domain-metadata-query"); + d_ClearDomainAllMetadataQuery = getArg("clear-domain-all-metadata-query"); + d_SetDomainMetadataQuery = getArg("set-domain-metadata-query"); + + d_ActivateDomainKeyQuery = getArg("activate-domain-key-query"); + d_DeactivateDomainKeyQuery = getArg("deactivate-domain-key-query"); + d_RemoveDomainKeyQuery = getArg("remove-domain-key-query"); + d_ClearDomainAllKeysQuery = getArg("clear-domain-all-keys-query"); + + d_getTSIGKeyQuery = getArg("get-tsig-key-query"); + d_setTSIGKeyQuery = getArg("set-tsig-key-query"); + d_deleteTSIGKeyQuery = getArg("delete-tsig-key-query"); + d_getTSIGKeysQuery = getArg("get-tsig-keys-query"); + + d_NoIdQuery_stmt = NULL; + d_IdQuery_stmt = NULL; + d_ANYNoIdQuery_stmt = NULL; + d_ANYIdQuery_stmt = NULL; + d_listQuery_stmt = NULL; + d_listSubZoneQuery_stmt = NULL; + d_MasterOfDomainsZoneQuery_stmt = NULL; + d_InfoOfDomainsZoneQuery_stmt = NULL; + d_InfoOfAllSlaveDomainsQuery_stmt = NULL; + d_SuperMasterInfoQuery_stmt = NULL; + d_GetSuperMasterIPs_stmt = NULL; + d_InsertZoneQuery_stmt = NULL; + d_InsertSlaveZoneQuery_stmt = NULL; + d_InsertRecordQuery_stmt = NULL; + d_InsertEntQuery_stmt = NULL; + d_InsertRecordOrderQuery_stmt = NULL; + d_InsertEntOrderQuery_stmt = NULL; + d_UpdateMasterOfZoneQuery_stmt = NULL; + d_UpdateKindOfZoneQuery_stmt = NULL; + d_UpdateSerialOfZoneQuery_stmt = NULL; + d_UpdateLastCheckofZoneQuery_stmt = NULL; + d_InfoOfAllMasterDomainsQuery_stmt = NULL; + d_DeleteDomainQuery_stmt = NULL; + d_DeleteZoneQuery_stmt = NULL; + d_DeleteRRSetQuery_stmt = NULL; + d_DeleteNamesQuery_stmt = NULL; + d_ZoneLastChangeQuery_stmt = NULL; + d_firstOrderQuery_stmt = NULL; + d_beforeOrderQuery_stmt = NULL; + d_afterOrderQuery_stmt = NULL; + d_lastOrderQuery_stmt = NULL; + d_setOrderAuthQuery_stmt = NULL; + d_nullifyOrderNameAndUpdateAuthQuery_stmt = NULL; + d_nullifyOrderNameAndAuthQuery_stmt = NULL; + d_nullifyOrderNameAndAuthENTQuery_stmt = NULL; + d_setAuthOnDsRecordQuery_stmt = NULL; + d_removeEmptyNonTerminalsFromZoneQuery_stmt = NULL; + d_insertEmptyNonTerminalQuery_stmt = NULL; + d_deleteEmptyNonTerminalQuery_stmt = NULL; + d_AddDomainKeyQuery_stmt = NULL; + d_ListDomainKeysQuery_stmt = NULL; + d_GetAllDomainMetadataQuery_stmt = NULL; + d_GetDomainMetadataQuery_stmt = NULL; + d_ClearDomainMetadataQuery_stmt = NULL; + d_ClearDomainAllMetadataQuery_stmt = NULL; + d_SetDomainMetadataQuery_stmt = NULL; + d_RemoveDomainKeyQuery_stmt = NULL; + d_ActivateDomainKeyQuery_stmt = NULL; + d_DeactivateDomainKeyQuery_stmt = NULL; + d_ClearDomainAllKeysQuery_stmt = NULL; + d_getTSIGKeyQuery_stmt = NULL; + d_setTSIGKeyQuery_stmt = NULL; + d_deleteTSIGKeyQuery_stmt = NULL; + d_getTSIGKeysQuery_stmt = NULL; + d_getAllDomainsQuery_stmt = NULL; + d_ListCommentsQuery_stmt = NULL; + d_InsertCommentQuery_stmt = NULL; + d_DeleteCommentRRsetQuery_stmt = NULL; + d_DeleteCommentsQuery_stmt = NULL; } void GSQLBackend::setNotified(uint32_t domain_id, uint32_t serial) { - char output[1024]; - snprintf(output,sizeof(output)-1, - d_UpdateSerialOfZoneQuery.c_str(), - serial, domain_id); - try { - d_db->doCommand(output); + d_UpdateSerialOfZoneQuery_stmt-> + bind("serial", serial)-> + bind("domain_id", domain_id)-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -59,13 +197,12 @@ void GSQLBackend::setNotified(uint32_t domain_id, uint32_t serial) void GSQLBackend::setFresh(uint32_t domain_id) { - char output[1024]; - snprintf(output,sizeof(output)-1,d_UpdateLastCheckofZoneQuery.c_str(), - time(0), - domain_id); - try { - d_db->doCommand(output); + d_UpdateLastCheckofZoneQuery_stmt-> + bind("last_check", time(0))-> + bind("domain_id", domain_id)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -74,10 +211,12 @@ void GSQLBackend::setFresh(uint32_t domain_id) bool GSQLBackend::isMaster(const string &domain, const string &ip) { - string query = (GSQLformat(d_MasterOfDomainsZoneQuery) % sqlEscape(domain)).str(); - try { - d_db->doQuery(query, d_result); + d_MasterOfDomainsZoneQuery_stmt-> + bind("domain", domain)-> + execute()-> + getResult(d_result)-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason()); @@ -102,10 +241,12 @@ bool GSQLBackend::isMaster(const string &domain, const string &ip) bool GSQLBackend::setMaster(const string &domain, const string &ip) { - string query = (GSQLformat(d_UpdateMasterOfZoneQuery) % sqlEscape(ip) % sqlEscape(toLower(domain))).str(); - try { - d_db->doCommand(query); + d_UpdateMasterOfZoneQuery_stmt-> + bind("master", ip)-> + bind("domain", toLower(domain))-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to set master of domain \""+domain+"\": "+e.txtReason()); @@ -115,11 +256,12 @@ bool GSQLBackend::setMaster(const string &domain, const string &ip) bool GSQLBackend::setKind(const string &domain, const DomainInfo::DomainKind kind) { - string kind_str = toUpper(DomainInfo::getKindString(kind)); - string query = (GSQLformat(d_UpdateKindOfZoneQuery) % sqlEscape(kind_str) % sqlEscape(toLower(domain))).str(); - try { - d_db->doCommand(query); + d_UpdateKindOfZoneQuery_stmt-> + bind("kind", toUpper(DomainInfo::getKindString(kind)))-> + bind("domain", toLower(domain))-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to set kind of domain \""+domain+"\": "+e.txtReason()); @@ -131,11 +273,12 @@ bool GSQLBackend::getDomainInfo(const string &domain, DomainInfo &di) { /* fill DomainInfo from database info: id,name,master IP(s),last_check,notified_serial,type */ - char output[1024]; - snprintf(output,sizeof(output)-1,d_InfoOfDomainsZoneQuery.c_str(), - sqlEscape(domain).c_str()); try { - d_db->doQuery(output,d_result); + d_InfoOfDomainsZoneQuery_stmt-> + bind("domain", toLower(domain))-> + execute()-> + getResult(d_result)-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to retrieve information about a domain: "+e.txtReason()); @@ -175,7 +318,10 @@ void GSQLBackend::getUnfreshSlaveInfos(vector *unfreshDomains) /* list all domains that need refreshing for which we are slave, and insert into SlaveDomain: id,name,master IP,serial */ try { - d_db->doQuery(d_InfoOfAllSlaveDomainsQuery, d_result); + d_InfoOfAllSlaveDomainsQuery_stmt-> + execute()-> + getResult(d_result)-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to retrieve list of slave domains: "+e.txtReason()); @@ -211,7 +357,10 @@ void GSQLBackend::getUpdatedMasters(vector *updatedDomains) /* list all domains that need notifications for which we are master, and insert into updatedDomains id,name,master IP,serial */ try { - d_db->doQuery(d_InfoOfAllMasterDomainsQuery,d_result); + d_InfoOfAllMasterDomainsQuery_stmt-> + execute()-> + getResult(d_result)-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason()); @@ -242,107 +391,6 @@ void GSQLBackend::getUpdatedMasters(vector *updatedDomains) } } - -string GSQLBackend::sqlEscape(const string &name) -{ - string a; - - for(string::const_iterator i=name.begin();i!=name.end();++i) - if(*i=='\'' || *i=='\\'){ - a+='\\'; - a+=*i; - } - else - a+=*i; - return a; -} - - -GSQLBackend::GSQLBackend(const string &mode, const string &suffix) -{ - setArgPrefix(mode+suffix); - d_db=0; - d_logprefix="["+mode+"Backend"+suffix+"] "; - - try - { - d_dnssecQueries = mustDo("dnssec"); - } - catch (ArgException e) - { - d_dnssecQueries = false; - } - - d_NoIdQuery=getArg("basic-query"); - d_IdQuery=getArg("id-query"); - d_ANYNoIdQuery=getArg("any-query"); - d_ANYIdQuery=getArg("any-id-query"); - - d_listQuery=getArg("list-query"); - d_listSubZoneQuery=getArg("list-subzone-query"); - - d_MasterOfDomainsZoneQuery=getArg("master-zone-query"); - d_InfoOfDomainsZoneQuery=getArg("info-zone-query"); - d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query"); - d_SuperMasterInfoQuery=getArg("supermaster-query"); - d_GetSuperMasterIPs=getArg("supermaster-name-to-ips"); - d_InsertZoneQuery=getArg("insert-zone-query"); - d_InsertSlaveZoneQuery=getArg("insert-slave-query"); - d_InsertRecordQuery=getArg("insert-record-query"); - d_InsertEntQuery=getArg("insert-ent-query"); - d_UpdateMasterOfZoneQuery=getArg("update-master-query"); - d_UpdateKindOfZoneQuery=getArg("update-kind-query"); - d_UpdateSerialOfZoneQuery=getArg("update-serial-query"); - d_UpdateLastCheckofZoneQuery=getArg("update-lastcheck-query"); - d_ZoneLastChangeQuery=getArg("zone-lastchange-query"); - d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query"); - d_DeleteDomainQuery=getArg("delete-domain-query"); - d_DeleteZoneQuery=getArg("delete-zone-query"); - d_DeleteRRSetQuery=getArg("delete-rrset-query"); - d_DeleteNamesQuery=getArg("delete-names-query"); - d_getAllDomainsQuery=getArg("get-all-domains-query"); - - d_removeEmptyNonTerminalsFromZoneQuery = getArg("remove-empty-non-terminals-from-zone-query"); - d_insertEmptyNonTerminalQuery = getArg("insert-empty-non-terminal-query"); - d_deleteEmptyNonTerminalQuery = getArg("delete-empty-non-terminal-query"); - - d_ListCommentsQuery = getArg("list-comments-query"); - d_InsertCommentQuery = getArg("insert-comment-query"); - d_DeleteCommentRRsetQuery = getArg("delete-comment-rrset-query"); - d_DeleteCommentsQuery = getArg("delete-comments-query"); - - d_InsertRecordOrderQuery=getArg("insert-record-order-query"); - d_InsertEntOrderQuery=getArg("insert-ent-order-query"); - - d_firstOrderQuery = getArg("get-order-first-query"); - d_beforeOrderQuery = getArg("get-order-before-query"); - d_afterOrderQuery = getArg("get-order-after-query"); - d_lastOrderQuery = getArg("get-order-last-query"); - d_setOrderAuthQuery = getArg("set-order-and-auth-query"); - d_nullifyOrderNameAndUpdateAuthQuery = getArg("nullify-ordername-and-update-auth-query"); - d_nullifyOrderNameAndAuthQuery = getArg("nullify-ordername-and-auth-query"); - d_setAuthOnDsRecordQuery = getArg("set-auth-on-ds-record-query"); - - d_AddDomainKeyQuery = getArg("add-domain-key-query"); - d_ListDomainKeysQuery = getArg("list-domain-keys-query"); - - d_GetAllDomainMetadataQuery = getArg("get-all-domain-metadata-query"); - d_GetDomainMetadataQuery = getArg("get-domain-metadata-query"); - d_ClearDomainMetadataQuery = getArg("clear-domain-metadata-query"); - d_ClearDomainAllMetadataQuery = getArg("clear-domain-all-metadata-query"); - d_SetDomainMetadataQuery = getArg("set-domain-metadata-query"); - - d_ActivateDomainKeyQuery = getArg("activate-domain-key-query"); - d_DeactivateDomainKeyQuery = getArg("deactivate-domain-key-query"); - d_RemoveDomainKeyQuery = getArg("remove-domain-key-query"); - d_ClearDomainAllKeysQuery = getArg("clear-domain-all-keys-query"); - - d_getTSIGKeyQuery = getArg("get-tsig-key-query"); - d_setTSIGKeyQuery = getArg("set-tsig-key-query"); - d_deleteTSIGKeyQuery = getArg("delete-tsig-key-query"); - d_getTSIGKeysQuery = getArg("get-tsig-keys-query"); -} - bool GSQLBackend::updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth) { if(!d_dnssecQueries) @@ -355,11 +403,15 @@ bool GSQLBackend::updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output, sizeof(output)-1, d_setOrderAuthQuery.c_str(), sqlEscape(ordername).c_str(), auth, sqlEscape(qname).c_str(), domain_id); try { - d_db->doCommand(output); + d_setOrderAuthQuery_stmt-> + bind("ordername", ordername)-> + bind("auth", auth)-> + bind("qname", qname)-> + bind("domain_id", domain_id)-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to update ordername/auth for domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -371,11 +423,14 @@ bool GSQLBackend::nullifyDNSSECOrderNameAndUpdateAuth(uint32_t domain_id, const { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output, sizeof(output)-1, d_nullifyOrderNameAndUpdateAuthQuery.c_str(), auth, domain_id, sqlEscape(qname).c_str()); try { - d_db->doCommand(output); + d_nullifyOrderNameAndUpdateAuthQuery_stmt-> + bind("auth", auth)-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to nullify ordername and update auth for domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -387,11 +442,14 @@ bool GSQLBackend::nullifyDNSSECOrderNameAndAuth(uint32_t domain_id, const std::s { if(!d_dnssecQueries) return false; - char output[1024]; - - snprintf(output, sizeof(output)-1, d_nullifyOrderNameAndAuthQuery.c_str(), sqlEscape(qname).c_str(), sqlEscape(type).c_str(), domain_id); + try { - d_db->doCommand(output); + d_nullifyOrderNameAndAuthQuery_stmt-> + bind("qname", qname)-> + bind("qtype", type)-> + bind("domain_id", domain_id)-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to nullify ordername/auth for domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -403,11 +461,13 @@ bool GSQLBackend::setDNSSECAuthOnDsRecord(uint32_t domain_id, const std::string& { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output, sizeof(output)-1, d_setAuthOnDsRecordQuery.c_str(), domain_id, sqlEscape(qname).c_str()); try { - d_db->doCommand(output); + d_setAuthOnDsRecordQuery_stmt-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to set auth on DS record "+qname+" for domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -417,12 +477,12 @@ bool GSQLBackend::setDNSSECAuthOnDsRecord(uint32_t domain_id, const std::string& bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, const std::string& zonename, set& insert, set& erase, bool remove) { - char output[1024]; - if(remove) { - snprintf(output,sizeof(output)-1,d_removeEmptyNonTerminalsFromZoneQuery.c_str(), domain_id); try { - d_db->doCommand(output); + d_removeEmptyNonTerminalsFromZoneQuery_stmt-> + bind("domain_id", domain_id)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to delete empty non-terminal records from domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -432,9 +492,12 @@ bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, const std::string& else { BOOST_FOREACH(const string qname, erase) { - snprintf(output,sizeof(output)-1,d_deleteEmptyNonTerminalQuery.c_str(), domain_id, sqlEscape(qname).c_str()); try { - d_db->doCommand(output); + d_deleteEmptyNonTerminalQuery_stmt-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to delete empty non-terminal rr "+qname+" from domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -444,9 +507,12 @@ bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, const std::string& } BOOST_FOREACH(const string qname, insert) { - snprintf(output,sizeof(output)-1,d_insertEmptyNonTerminalQuery.c_str(), domain_id, sqlEscape(qname).c_str()); try { - d_db->doCommand(output); + d_insertEmptyNonTerminalQuery_stmt-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to insert empty non-terminal rr "+qname+" in domain_id "+itoa(domain_id)+": "+e.txtReason()); @@ -470,48 +536,56 @@ bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& after.clear(); string lcqname=toLower(qname); - SSql::row_t row; - - char output[1024]; - - snprintf(output, sizeof(output)-1, d_afterOrderQuery.c_str(), sqlEscape(lcqname).c_str(), id); + SSqlStatement::row_t row; try { - d_db->doQuery(output); + d_afterOrderQuery_stmt-> + bind("ordername", lcqname)-> + bind("domain_id", id)-> + execute(); + while(d_afterOrderQuery_stmt->hasNextRow()) { + d_afterOrderQuery_stmt->nextRow(row); + after=row[0]; + } + d_afterOrderQuery_stmt->reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to find before/after (after) for domain_id "+itoa(id)+": "+e.txtReason()); } - while(d_db->getRow(row)) { - after=row[0]; - } if(after.empty() && !lcqname.empty()) { - snprintf(output, sizeof(output)-1, d_firstOrderQuery.c_str(), id); try { - d_db->doQuery(output); + d_firstOrderQuery_stmt-> + bind("domain_id", id)-> + execute(); + while(d_firstOrderQuery_stmt->hasNextRow()) { + d_firstOrderQuery_stmt->nextRow(row); + after=row[0]; + } + d_firstOrderQuery_stmt->reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to find before/after (first) for domain_id "+itoa(id)+": "+e.txtReason()); } - while(d_db->getRow(row)) { - after=row[0]; - } } if (before.empty()) { unhashed.clear(); - snprintf(output, sizeof(output)-1, d_beforeOrderQuery.c_str(), sqlEscape(lcqname).c_str(), id); try { - d_db->doQuery(output); + d_beforeOrderQuery_stmt-> + bind("ordername", lcqname)-> + bind("domain_id", id)-> + execute(); + while(d_beforeOrderQuery_stmt->hasNextRow()) { + d_beforeOrderQuery_stmt->nextRow(row); + before=row[0]; + unhashed=row[1]; + } + d_beforeOrderQuery_stmt->reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to find before/after (before) for domain_id "+itoa(id)+": "+e.txtReason()); } - while(d_db->getRow(row)) { - before=row[0]; - unhashed=row[1]; - } if(! unhashed.empty()) { @@ -519,17 +593,20 @@ bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& return true; } - snprintf(output, sizeof(output)-1, d_lastOrderQuery.c_str(), id); try { - d_db->doQuery(output); + d_lastOrderQuery_stmt-> + bind("domain_id", id)-> + execute(); + while(d_lastOrderQuery_stmt->hasNextRow()) { + d_lastOrderQuery_stmt->nextRow(row); + before=row[0]; + unhashed=row[1]; + } + d_lastOrderQuery_stmt->reset(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend unable to find before/after (last) for domain_id "+itoa(id)+": "+e.txtReason()); } - while(d_db->getRow(row)) { - before=row[0]; - unhashed=row[1]; - } } else { before=lcqname; } @@ -541,12 +618,15 @@ int GSQLBackend::addDomainKey(const string& name, const KeyData& key) { if(!d_dnssecQueries) return -1; - char output[16384]; - snprintf(output,sizeof(output)-1,d_AddDomainKeyQuery.c_str(), - key.flags, (int)key.active, sqlEscape(key.content).c_str(), sqlEscape(toLower(name)).c_str()); try { - d_db->doCommand(output); + d_AddDomainKeyQuery_stmt-> + bind("flags", key.flags)-> + bind("active", key.active)-> + bind("content", key.content)-> + bind("domain", toLower(name))-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to store key: "+e.txtReason()); @@ -558,11 +638,13 @@ bool GSQLBackend::activateDomainKey(const string& name, unsigned int id) { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output,sizeof(output)-1,d_ActivateDomainKeyQuery.c_str(), sqlEscape(toLower(name)).c_str(), id); try { - d_db->doCommand(output); + d_ActivateDomainKeyQuery_stmt-> + bind("domain", toLower(name))-> + bind("key_id", id)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to activate key: "+e.txtReason()); @@ -574,11 +656,13 @@ bool GSQLBackend::deactivateDomainKey(const string& name, unsigned int id) { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output,sizeof(output)-1,d_DeactivateDomainKeyQuery.c_str(), sqlEscape(toLower(name)).c_str(), id); try { - d_db->doCommand(output); + d_DeactivateDomainKeyQuery_stmt-> + bind("domain", toLower(name))-> + bind("key_id", id)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to deactivate key: "+e.txtReason()); @@ -590,11 +674,13 @@ bool GSQLBackend::removeDomainKey(const string& name, unsigned int id) { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output,sizeof(output)-1,d_RemoveDomainKeyQuery.c_str(), sqlEscape(toLower(name)).c_str(), id); try { - d_db->doCommand(output); + d_RemoveDomainKeyQuery_stmt-> + bind("domain", toLower(name))-> + bind("key_id", id)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to remove key: "+e.txtReason()); @@ -604,35 +690,40 @@ bool GSQLBackend::removeDomainKey(const string& name, unsigned int id) bool GSQLBackend::getTSIGKey(const string& name, string* algorithm, string* content) { - char output[1024]; - snprintf(output,sizeof(output)-1,d_getTSIGKeyQuery.c_str(), sqlEscape(toLower(name)).c_str()); - try { - d_db->doQuery(output); + d_getTSIGKeyQuery_stmt-> + bind("key_name", toLower(name))-> + execute(); + + SSqlStatement::row_t row; + + content->clear(); + while(d_getTSIGKeyQuery_stmt->hasNextRow()) { + d_getTSIGKeyQuery_stmt->nextRow(row); + if(row.size() >= 2 && (algorithm->empty() || pdns_iequals(*algorithm, row[0]))) { + *algorithm = row[0]; + *content = row[1]; + } + } + + d_getTSIGKeyQuery_stmt->reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to retrieve named TSIG key: "+e.txtReason()); } - - SSql::row_t row; - - content->clear(); - while(d_db->getRow(row)) { - if(row.size() >= 2 && (algorithm->empty() || pdns_iequals(*algorithm, row[0]))) { - *algorithm = row[0]; - *content = row[1]; - } - } return !content->empty(); } bool GSQLBackend::setTSIGKey(const string& name, const string& algorithm, const string& content) { - char output[1024]; - snprintf(output,sizeof(output)-1,d_setTSIGKeyQuery.c_str(), sqlEscape(toLower(name)).c_str(), sqlEscape(toLower(algorithm)).c_str(), sqlEscape(content).c_str()); try { - d_db->doCommand(output); + d_setTSIGKeyQuery_stmt-> + bind("key_name", toLower(name))-> + bind("algorithm", toLower(algorithm))-> + bind("content", content)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to store named TSIG key: "+e.txtReason()); @@ -642,10 +733,11 @@ bool GSQLBackend::setTSIGKey(const string& name, const string& algorithm, const bool GSQLBackend::deleteTSIGKey(const string& name) { - char output[1024]; - snprintf(output,sizeof(output)-1,d_deleteTSIGKeyQuery.c_str(), sqlEscape(toLower(name)).c_str()); try { - d_db->doCommand(output); + d_deleteTSIGKeyQuery_stmt-> + bind("key_name", toLower(name))-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to store named TSIG key: "+e.txtReason()); @@ -655,26 +747,27 @@ bool GSQLBackend::deleteTSIGKey(const string& name) bool GSQLBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys) { - char output[1024]; - snprintf(output,sizeof(output)-1,"%s",d_getTSIGKeysQuery.c_str()); - try { - d_db->doQuery(output); + d_getTSIGKeysQuery_stmt-> + execute(); + + SSqlStatement::row_t row; + + while(d_getTSIGKeysQuery_stmt->hasNextRow()) { + d_getTSIGKeysQuery_stmt->nextRow(row); + struct TSIGKey key; + key.name = row[0]; + key.algorithm = row[1]; + key.key = row[2]; + keys.push_back(key); + } + + d_getTSIGKeysQuery_stmt->reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to retrieve TSIG keys: "+e.txtReason()); } - SSql::row_t row; - - while(d_db->getRow(row)) { - struct TSIGKey key; - key.name = row[0]; - key.algorithm = row[1]; - key.key = row[2]; - keys.push_back(key); - } - return keys.empty(); } @@ -682,29 +775,32 @@ bool GSQLBackend::getDomainKeys(const string& name, unsigned int kind, std::vect { if(!d_dnssecQueries) return false; - char output[1024]; - snprintf(output,sizeof(output)-1,d_ListDomainKeysQuery.c_str(), sqlEscape(toLower(name)).c_str()); try { - d_db->doQuery(output); + d_ListDomainKeysQuery_stmt-> + bind("domain", toLower(name))-> + execute(); + + SSqlStatement::row_t row; + // "select id, kind, active, content from domains, cryptokeys where domain_id=domains.id and name='%s'"; + KeyData kd; + while(d_ListDomainKeysQuery_stmt->hasNextRow()) { + d_ListDomainKeysQuery_stmt->nextRow(row); + //~ BOOST_FOREACH(const std::string& val, row) { + //~ cerr<<"'"<reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to list keys: "+e.txtReason()); } - - SSql::row_t row; - // "select id, kind, active, content from domains, cryptokeys where domain_id=domains.id and name='%s'"; - KeyData kd; - while(d_db->getRow(row)) { - //~ BOOST_FOREACH(const std::string& val, row) { - //~ cerr<<"'"< *ips) bool GSQLBackend::getAllDomainMetadata(const string& name, std::map >& meta) { - char output[1024]; - snprintf(output,sizeof(output)-1,d_GetAllDomainMetadataQuery.c_str(), sqlEscape(name).c_str()); - try { - d_db->doQuery(output); + d_GetAllDomainMetadataQuery_stmt-> + bind("domain", toLower(name))-> + execute(); + + SSqlStatement::row_t row; + + while(d_GetAllDomainMetadataQuery_stmt->hasNextRow()) { + d_GetAllDomainMetadataQuery_stmt->nextRow(row); + if (!isDnssecDomainMetadata(row[0])) + meta[row[0]].push_back(row[1]); + } + + d_GetAllDomainMetadataQuery_stmt->reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to list metadata: "+e.txtReason()); } - SSql::row_t row; - - while(d_db->getRow(row)) { - if (!isDnssecDomainMetadata(row[0])) - meta[row[0]].push_back(row[1]); - } - return true; } @@ -746,21 +844,25 @@ bool GSQLBackend::getDomainMetadata(const string& name, const std::string& kind, if(!d_dnssecQueries && isDnssecDomainMetadata(kind)) return false; - char output[1024]; - snprintf(output,sizeof(output)-1,d_GetDomainMetadataQuery.c_str(), sqlEscape(toLower(name)).c_str(), sqlEscape(kind).c_str()); - try { - d_db->doQuery(output); + d_GetDomainMetadataQuery_stmt-> + bind("domain", toLower(name))-> + bind("kind", kind)-> + execute(); + + SSqlStatement::row_t row; + + while(d_GetDomainMetadataQuery_stmt->hasNextRow()) { + d_GetDomainMetadataQuery_stmt->nextRow(row); + meta.push_back(row[0]); + } + + d_GetDomainMetadataQuery_stmt->reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to list metadata: "+e.txtReason()); } - - SSql::row_t row; - - while(d_db->getRow(row)) { - meta.push_back(row[0]); - } + return true; } @@ -769,16 +871,20 @@ bool GSQLBackend::setDomainMetadata(const string& name, const std::string& kind, if(!d_dnssecQueries && isDnssecDomainMetadata(kind)) return false; - char output[16384]; - string clearQuery = (GSQLformat(d_ClearDomainMetadataQuery) % sqlEscape(toLower(name)) % sqlEscape(kind)).str(); - try { - d_db->doCommand(clearQuery); + d_ClearDomainMetadataQuery_stmt-> + bind("domain", toLower(name))-> + bind("kind", kind)-> + execute()-> + reset(); if(!meta.empty()) { BOOST_FOREACH(const std::string & value, meta) { - snprintf(output,sizeof(output)-1,d_SetDomainMetadataQuery.c_str(), - sqlEscape(kind).c_str(), sqlEscape(value).c_str(), sqlEscape(toLower(name)).c_str()); - d_db->doCommand(output); + d_SetDomainMetadataQuery_stmt-> + bind("kind", kind)-> + bind("content", value)-> + bind("domain", toLower(name))-> + execute()-> + reset(); } } } @@ -793,36 +899,36 @@ void GSQLBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_ { string lcqname=toLower(qname); - string query; - if(qtype.getCode()!=QType::ANY) { - if(domain_id < 0) { - query = (GSQLformat(d_NoIdQuery) - % sqlEscape(qtype.getName()) - % sqlEscape(lcqname) - ).str(); - } else { - query = (GSQLformat(d_IdQuery) - % sqlEscape(qtype.getName()) - % sqlEscape(lcqname) - % domain_id - ).str(); - } - } else { - // qtype==ANY - if(domain_id < 0) { - query = (GSQLformat(d_ANYNoIdQuery) - % sqlEscape(lcqname) - ).str(); + try { + if(qtype.getCode()!=QType::ANY) { + if(domain_id < 0) { + d_query_stmt = d_NoIdQuery_stmt; + d_query_stmt-> + bind("qtype", qtype.getName())-> + bind("qname", lcqname); + } else { + d_query_stmt = d_IdQuery_stmt; + d_query_stmt-> + bind("qtype", qtype.getName())-> + bind("qname", lcqname)-> + bind("domain_id", domain_id); + } } else { - query = (GSQLformat(d_ANYIdQuery) - % sqlEscape(lcqname) - % domain_id - ).str(); + // qtype==ANY + if(domain_id < 0) { + d_query_stmt = d_ANYNoIdQuery_stmt; + d_query_stmt-> + bind("qname", lcqname); + } else { + d_query_stmt = d_ANYIdQuery_stmt; + d_query_stmt-> + bind("qname", lcqname)-> + bind("domain_id", domain_id); + } } - } - try { - d_db->doQuery(query); + d_query_stmt-> + execute(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend lookup query:"+e.txtReason()); @@ -835,13 +941,12 @@ bool GSQLBackend::list(const string &target, int domain_id, bool include_disable { DLOG(L<<"GSQLBackend constructing handle for list of domain id '"<doQuery(query); + d_query_stmt = d_listQuery_stmt; + d_query_stmt-> + bind("include_disabled", (int)include_disabled)-> + bind("domain_id", domain_id)-> + execute(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend list query: "+e.txtReason()); @@ -853,13 +958,14 @@ bool GSQLBackend::list(const string &target, int domain_id, bool include_disable bool GSQLBackend::listSubZone(const string &zone, int domain_id) { string wildzone = "%." + zone; - string query = (GSQLformat(d_listSubZoneQuery) - % sqlEscape(zone) - % sqlEscape(wildzone) - % domain_id - ).str(); + try { - d_db->doQuery(query); + d_query_stmt = d_listSubZoneQuery_stmt; + d_query_stmt-> + bind("zone", zone)-> + bind("wildzone", wildzone)-> + bind("domain_id", domain_id)-> + execute(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend listSubZone query: "+e.txtReason()); @@ -868,18 +974,64 @@ bool GSQLBackend::listSubZone(const string &zone, int domain_id) { return true; } +bool GSQLBackend::get(DNSResourceRecord &r) +{ + // L << "GSQLBackend get() was called for "<hasNextRow()) { + try { + d_query_stmt->nextRow(row); + } catch (SSqlException &e) { + throw PDNSException("GSQLBackend get: "+e.txtReason()); + } + if (row[1].empty()) + r.ttl = ::arg().asNum( "default-ttl" ); + else + r.ttl=atol(row[1].c_str()); + if(!d_qname.empty()) + r.qname=d_qname; + else + r.qname=row[6]; + r.qtype=row[3]; + + if (r.qtype==QType::MX || r.qtype==QType::SRV) + r.content=row[2]+" "+row[0]; + else + r.content=row[0]; + r.last_modified=0; + + if(d_dnssecQueries) + r.auth = !row[7].empty() && row[7][0]=='1'; + else + r.auth = 1; + + r.disabled = !row[5].empty() && row[5][0]=='1'; + + r.domain_id=atoi(row[4].c_str()); + return true; + } + + try { + d_query_stmt->reset(); + } catch (SSqlException &e) { + throw PDNSException("GSQLBackend get: "+e.txtReason()); + } + d_query_stmt = NULL; + return false; +} bool GSQLBackend::superMasterBackend(const string &ip, const string &domain, const vector&nsset, string *nameserver, string *account, DNSBackend **ddb) { - string format; - char output[1024]; - format = d_SuperMasterInfoQuery; // check if we know the ip/ns couple in the database for(vector::const_iterator i=nsset.begin();i!=nsset.end();++i) { try { - snprintf(output,sizeof(output)-1,format.c_str(),sqlEscape(ip).c_str(),sqlEscape(i->content).c_str()); - d_db->doQuery(output, d_result); + d_SuperMasterInfoQuery_stmt-> + bind("ip", ip)-> + bind("nameserver", i->content)-> + execute()-> + getResult(d_result)-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to search for a domain: "+e.txtReason()); @@ -897,9 +1049,11 @@ bool GSQLBackend::superMasterBackend(const string &ip, const string &domain, con bool GSQLBackend::createDomain(const string &domain) { - string query = (GSQLformat(d_InsertZoneQuery) % toLower(sqlEscape(domain))).str(); try { - d_db->doCommand(query); + d_InsertZoneQuery_stmt-> + bind("domain", toLower(domain))-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("Database error trying to insert new domain '"+domain+"': "+ e.txtReason()); @@ -909,21 +1063,21 @@ bool GSQLBackend::createDomain(const string &domain) bool GSQLBackend::createSlaveDomain(const string &ip, const string &domain, const string &nameserver, const string &account) { - string format; string name; string masters(ip); - - char output[1024]; try { if (!nameserver.empty()) { // figure out all IP addresses for the master - format = d_GetSuperMasterIPs; - snprintf(output,sizeof(output)-1,format.c_str(),sqlEscape(nameserver).c_str(),sqlEscape(account).c_str()); - d_db->doQuery(output, d_result); + d_GetSuperMasterIPs_stmt-> + bind("nameserver", nameserver)-> + bind("account", account)-> + execute()-> + getResult(d_result)-> + reset(); if (!d_result.empty()) { // collect all IP addresses vector tmp; - BOOST_FOREACH(SSql::row_t& row, d_result) { + BOOST_FOREACH(SSqlStatement::row_t& row, d_result) { if (account == row[1]) tmp.push_back(row[0]); } @@ -931,9 +1085,12 @@ bool GSQLBackend::createSlaveDomain(const string &ip, const string &domain, cons masters = boost::join(tmp, ", "); } } - format = d_InsertSlaveZoneQuery; - snprintf(output,sizeof(output)-1,format.c_str(),sqlEscape(domain).c_str(),sqlEscape(masters).c_str(),sqlEscape(account).c_str()); - d_db->doCommand(output); + d_InsertSlaveZoneQuery_stmt-> + bind("domain", toLower(domain))-> + bind("masters", masters)-> + bind("account", account)-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("Database error trying to insert new slave domain '"+domain+"': "+ e.txtReason()); @@ -943,28 +1100,32 @@ bool GSQLBackend::createSlaveDomain(const string &ip, const string &domain, cons bool GSQLBackend::deleteDomain(const string &domain) { - string sqlDomain = sqlEscape(toLower(domain)); - DomainInfo di; if (!getDomainInfo(domain, di)) { return false; } - string recordsQuery = (GSQLformat(d_DeleteZoneQuery) % di.id).str(); - string metadataQuery; - string keysQuery; - string commentsQuery = (GSQLformat(d_DeleteCommentsQuery) % di.id).str(); - string domainQuery = (GSQLformat(d_DeleteDomainQuery) % sqlDomain).str(); - - metadataQuery = (GSQLformat(d_ClearDomainAllMetadataQuery) % sqlDomain).str(); - keysQuery = (GSQLformat(d_ClearDomainAllKeysQuery) % sqlDomain).str(); - try { - d_db->doCommand(recordsQuery); - d_db->doCommand(metadataQuery); - d_db->doCommand(keysQuery); - d_db->doCommand(commentsQuery); - d_db->doCommand(domainQuery); + d_DeleteZoneQuery_stmt-> + bind("domain_id", di.id)-> + execute()-> + reset(); + d_ClearDomainAllMetadataQuery_stmt-> + bind("domain", toLower(domain))-> + execute()-> + reset(); + d_ClearDomainAllKeysQuery_stmt-> + bind("domain", toLower(domain))-> + execute()-> + reset(); + d_DeleteCommentsQuery_stmt-> + bind("domain_id", di.id)-> + execute()-> + reset(); + d_DeleteDomainQuery_stmt-> + bind("domain", toLower(domain))-> + execute()-> + reset(); } catch(SSqlException &e) { throw PDNSException("Database error trying to delete domain '"+domain+"': "+ e.txtReason()); @@ -975,114 +1136,79 @@ bool GSQLBackend::deleteDomain(const string &domain) void GSQLBackend::getAllDomains(vector *domains, bool include_disabled) { DLOG(L<<"GSQLBackend retrieving all domains."<doQuery(query); + d_getAllDomainsQuery_stmt-> + bind("include_disabled", (int)include_disabled)-> + execute(); + + SSqlStatement::row_t row; + while (d_getAllDomainsQuery_stmt->hasNextRow()) { + d_getAllDomainsQuery_stmt->nextRow(row); + DomainInfo di; + di.id = atol(row[0].c_str()); + di.zone = row[1]; + + if (!row[4].empty()) { + stringtok(di.masters, row[4], " ,\t"); + } + di.last_check=atol(row[6].c_str()); + + SOAData sd; + fillSOAData(row[2], sd); + di.serial = sd.serial; + if (!row[5].empty()) { + di.notified_serial = atol(row[5].c_str()); + } + + if (pdns_iequals(row[3], "MASTER")) + di.kind = DomainInfo::Master; + else if (pdns_iequals(row[3], "SLAVE")) + di.kind = DomainInfo::Slave; + else + di.kind = DomainInfo::Native; + + di.backend = this; + + domains->push_back(di); + } + d_getAllDomainsQuery_stmt->reset(); } catch (SSqlException &e) { throw PDNSException("Database error trying to retrieve all domains:" + e.txtReason()); } - - SSql::row_t row; - while (d_db->getRow(row)) { - - DomainInfo di; - di.id = atol(row[0].c_str()); - di.zone = row[1]; - - if (!row[4].empty()) { - stringtok(di.masters, row[4], " ,\t"); - } - di.last_check=atol(row[6].c_str()); - - SOAData sd; - fillSOAData(row[2], sd); - di.serial = sd.serial; - if (!row[5].empty()) { - di.notified_serial = atol(row[5].c_str()); - } - - if (pdns_iequals(row[3], "MASTER")) - di.kind = DomainInfo::Master; - else if (pdns_iequals(row[3], "SLAVE")) - di.kind = DomainInfo::Slave; - else - di.kind = DomainInfo::Native; - - di.backend = this; - - domains->push_back(di); - } -} - -bool GSQLBackend::get(DNSResourceRecord &r) -{ - // L << "GSQLBackend get() was called for "<getRow(row)) { - if (row[1].empty()) - r.ttl = ::arg().asNum( "default-ttl" ); - else - r.ttl=atol(row[1].c_str()); - if(!d_qname.empty()) - r.qname=d_qname; - else - r.qname=row[6]; - r.qtype=row[3]; - - if (r.qtype==QType::MX || r.qtype==QType::SRV) - r.content=row[2]+" "+row[0]; - else - r.content=row[0]; - - r.last_modified=0; - - if(d_dnssecQueries) - r.auth = !row[7].empty() && row[7][0]=='1'; - else - r.auth = 1; - - r.disabled = !row[5].empty() && row[5][0]=='1'; - - r.domain_id=atoi(row[4].c_str()); - return true; - } - - return false; } bool GSQLBackend::replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector& rrset) { - string query; - if (qt != QType::ANY) { - query = (GSQLformat(d_DeleteRRSetQuery) - % domain_id - % sqlEscape(qname) - % sqlEscape(qt.getName()) - ).str(); - } else { - query = (GSQLformat(d_DeleteNamesQuery) - % domain_id - % sqlEscape(qname) - ).str(); - } try { - d_db->doCommand(query); + if (qt != QType::ANY) { + d_DeleteRRSetQuery_stmt-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + bind("qtype", qt.getName())-> + execute()-> + reset(); + } else { + d_DeleteNamesQuery_stmt-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + execute()-> + reset(); + } } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to delete RRSet: "+e.txtReason()); } if (rrset.empty()) { - // zap comments for now non-existing rrset - query = (GSQLformat(d_DeleteCommentRRsetQuery) - % domain_id - % sqlEscape(qname) - % sqlEscape(qt.getName()) - ).str(); try { - d_db->doCommand(query); + d_DeleteCommentRRsetQuery_stmt-> + bind("domain_id", domain_id)-> + bind("qname", qname)-> + bind("qtype", qt.getName())-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to delete comment: "+e.txtReason()); @@ -1099,44 +1225,48 @@ bool GSQLBackend::feedRecord(const DNSResourceRecord &r, string *ordername) { int prio=0; string content(r.content); - - if(r.qtype == QType::MX || r.qtype == QType::SRV) { + if (r.qtype == QType::MX || r.qtype == QType::SRV) { prio=atoi(content.c_str()); - string::size_type pos = content.find_first_not_of("0123456789"); if(pos != string::npos) boost::erase_head(content, pos); trim_left(content); - } - - string query; - - if(d_dnssecQueries && ordername) - query = (GSQLformat(d_InsertRecordOrderQuery) - % sqlEscape(content) - % r.ttl - % prio - % sqlEscape(r.qtype.getName()) - % r.domain_id - % (int)r.disabled - % toLower(sqlEscape(r.qname)) - % sqlEscape(*ordername) - % (int)(r.auth) - ).str(); - else - query = (GSQLformat(d_InsertRecordQuery) - % sqlEscape(content) - % r.ttl - % prio - % sqlEscape(r.qtype.getName()) - % r.domain_id - % (int)r.disabled - % toLower(sqlEscape(r.qname)) - % (int)(r.auth || !d_dnssecQueries) - ).str(); + } try { - d_db->doCommand(query); + if(d_dnssecQueries && ordername) + { + d_InsertRecordOrderQuery_stmt-> + bind("content",content)-> + bind("ttl",r.ttl)-> + bind("priority",prio)-> + bind("qtype",r.qtype.getName())-> + bind("domain_id",r.domain_id)-> + bind("disabled",r.disabled)-> + bind("qname",toLower(r.qname)); + if (ordername == NULL) + d_InsertRecordOrderQuery_stmt->bindNull("ordername"); + else + d_InsertRecordOrderQuery_stmt->bind("ordername",*ordername); + d_InsertRecordOrderQuery_stmt-> + bind("auth",r.auth)-> + execute()-> + reset(); + } + else + { + d_InsertRecordQuery_stmt-> + bind("content",content)-> + bind("ttl",r.ttl)-> + bind("priority",prio)-> + bind("qtype",r.qtype.getName())-> + bind("domain_id",r.domain_id)-> + bind("disabled",r.disabled)-> + bind("qname",toLower(r.qname))-> + bind("auth", (r.auth || !d_dnssecQueries))-> + execute()-> + reset(); + } } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to feed record: "+e.txtReason()); @@ -1150,15 +1280,13 @@ bool GSQLBackend::feedEnts(int domain_id, map& nonterm) pair nt; BOOST_FOREACH(nt, nonterm) { - - query = (GSQLformat(d_InsertEntQuery) - % domain_id - % toLower(sqlEscape(nt.first)) - % (int)(nt.second || !d_dnssecQueries) - ).str(); - try { - d_db->doCommand(query); + d_InsertEntQuery_stmt-> + bind("domain_id",domain_id)-> + bind("qname",toLower(nt.first))-> + bind("auth",(nt.second || !d_dnssecQueries))-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e.txtReason()); @@ -1172,29 +1300,28 @@ bool GSQLBackend::feedEnts3(int domain_id, const string &domain, map nt; BOOST_FOREACH(nt, nonterm) { - - if(narrow || !nt.second) { - query = (GSQLformat(d_InsertEntQuery) - % domain_id - % toLower(sqlEscape(nt.first)) - % nt.second - ).str(); - } else { - ordername=toBase32Hex(hashQNameWithSalt(times, salt, nt.first)); - query = (GSQLformat(d_InsertEntOrderQuery) - % domain_id - % toLower(sqlEscape(nt.first)) - % toLower(sqlEscape(ordername)) - % nt.second - ).str(); - } - try { - d_db->doCommand(query); + if(narrow || !nt.second) { + d_InsertEntQuery_stmt-> + bind("domain_id",domain_id)-> + bind("qname",toLower(nt.first))-> + bind("auth", nt.second)-> + execute()-> + reset(); + } else { + ordername=toBase32Hex(hashQNameWithSalt(times, salt, nt.first)); + d_InsertEntOrderQuery_stmt-> + bind("domain_id",domain_id)-> + bind("qname",toLower(nt.first))-> + bind("ordername",toLower(ordername))-> + bind("auth",nt.second)-> + execute()-> + reset(); + } } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e.txtReason()); @@ -1205,13 +1332,14 @@ bool GSQLBackend::feedEnts3(int domain_id, const string &domain, map= 0) - snprintf(output,sizeof(output)-1,d_DeleteZoneQuery.c_str(),domain_id); try { - d_db->doCommand("begin"); - if(domain_id >= 0) - d_db->doCommand(output); + d_db->startTransaction(); + if(domain_id >= 0) { + d_DeleteZoneQuery_stmt-> + bind("domain_id", domain_id)-> + execute()-> + reset(); + } } catch (SSqlException &e) { throw PDNSException("Database failed to start transaction: "+e.txtReason()); @@ -1223,7 +1351,7 @@ bool GSQLBackend::startTransaction(const string &domain, int domain_id) bool GSQLBackend::commitTransaction() { try { - d_db->doCommand("commit"); + d_db->commit(); } catch (SSqlException &e) { throw PDNSException("Database failed to commit transaction: "+e.txtReason()); @@ -1234,7 +1362,7 @@ bool GSQLBackend::commitTransaction() bool GSQLBackend::abortTransaction() { try { - d_db->doCommand("rollback"); + d_db->rollback(); } catch(SSqlException &e) { throw PDNSException("Database failed to abort transaction: "+string(e.txtReason())); @@ -1249,21 +1377,19 @@ bool GSQLBackend::calculateSOASerial(const string& domain, const SOAData& sd, ti return DNSBackend::calculateSOASerial(domain, sd, serial); } - char output[1024]; - - snprintf(output, sizeof(output)-1, - d_ZoneLastChangeQuery.c_str(), - sd.domain_id); - try { - d_db->doQuery(output, d_result); + d_ZoneLastChangeQuery_stmt-> + bind("domain_id", sd.domain_id)-> + execute()-> + getResult(d_result)-> + reset(); } catch (const SSqlException& e) { //DLOG(L<<"GSQLBackend unable to calculate SOA serial: " << e.txtReason()<doQuery(query); + d_query_stmt = d_ListCommentsQuery_stmt; + d_query_stmt-> + bind("domain_id", domain_id)-> + execute(); } catch(SSqlException &e) { throw PDNSException("GSQLBackend list comments query: "+e.txtReason()); @@ -1289,12 +1414,23 @@ bool GSQLBackend::listComments(const uint32_t domain_id) bool GSQLBackend::getComment(Comment& comment) { - SSql::row_t row; + SSqlStatement::row_t row; - if (!d_db->getRow(row)) { + if (!d_query_stmt->hasNextRow()) { + try { + d_query_stmt->reset(); + } catch(SSqlException &e) { + throw PDNSException("GSQLBackend comment get: "+e.txtReason()); + } + d_query_stmt = NULL; return false; } + try { + d_query_stmt->nextRow(row); + } catch(SSqlException &e) { + throw PDNSException("GSQLBackend comment get: "+e.txtReason()); + } // domain_id,name,type,modified_at,account,comment comment.domain_id = atol(row[0].c_str()); comment.qname = row[1]; @@ -1308,17 +1444,16 @@ bool GSQLBackend::getComment(Comment& comment) void GSQLBackend::feedComment(const Comment& comment) { - string query = (GSQLformat(d_InsertCommentQuery) - % comment.domain_id - % toLower(sqlEscape(comment.qname)) - % sqlEscape(comment.qtype.getName()) - % comment.modified_at - % sqlEscape(comment.account) - % sqlEscape(comment.content) - ).str(); - try { - d_db->doCommand(query); + d_InsertCommentQuery_stmt-> + bind("domain_id",comment.domain_id)-> + bind("qname",toLower(comment.qname))-> + bind("qtype",comment.qtype.getName())-> + bind("modified_at",comment.modified_at)-> + bind("account",comment.account)-> + bind("content",comment.content)-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to feed comment: "+e.txtReason()); @@ -1327,15 +1462,13 @@ void GSQLBackend::feedComment(const Comment& comment) bool GSQLBackend::replaceComments(const uint32_t domain_id, const string& qname, const QType& qt, const vector& comments) { - string query; - query = (GSQLformat(d_DeleteCommentRRsetQuery) - % domain_id - % toLower(sqlEscape(qname)) - % sqlEscape(qt.getName()) - ).str(); - try { - d_db->doCommand(query); + d_DeleteCommentRRsetQuery_stmt-> + bind("domain_id",domain_id)-> + bind("qname",toLower(qname))-> + bind("qtype",qt.getName())-> + execute()-> + reset(); } catch (SSqlException &e) { throw PDNSException("GSQLBackend unable to delete comment: "+e.txtReason()); @@ -1347,3 +1480,7 @@ bool GSQLBackend::replaceComments(const uint32_t domain_id, const string& qname, return true; } + +SSqlStatement::~SSqlStatement() { +// make sure vtable won't break +} diff --git a/pdns/backends/gsql/gsqlbackend.hh b/pdns/backends/gsql/gsqlbackend.hh index e8acf757d..ed091e110 100644 --- a/pdns/backends/gsql/gsqlbackend.hh +++ b/pdns/backends/gsql/gsqlbackend.hh @@ -16,19 +16,147 @@ public: GSQLBackend(const string &mode, const string &suffix); //!< Makes our connection to the database. Throws an exception if it fails. virtual ~GSQLBackend() { + freeStatements(); if(d_db) - delete d_db; + delete d_db; } void setDB(SSql *db) { + freeStatements(); + delete d_db; d_db=db; if (d_db) { d_db->setLog(::arg().mustDo("query-logging")); + d_NoIdQuery_stmt = d_db->prepare(d_NoIdQuery, 2); + d_IdQuery_stmt = d_db->prepare(d_IdQuery, 3); + d_ANYNoIdQuery_stmt = d_db->prepare(d_ANYNoIdQuery, 1); + d_ANYIdQuery_stmt = d_db->prepare(d_ANYIdQuery, 2); + d_listQuery_stmt = d_db->prepare(d_listQuery, 2); + d_listSubZoneQuery_stmt = d_db->prepare(d_listSubZoneQuery, 3); + d_MasterOfDomainsZoneQuery_stmt = d_db->prepare(d_MasterOfDomainsZoneQuery, 1); + d_InfoOfDomainsZoneQuery_stmt = d_db->prepare(d_InfoOfDomainsZoneQuery, 1); + d_InfoOfAllSlaveDomainsQuery_stmt = d_db->prepare(d_InfoOfAllSlaveDomainsQuery, 0); + d_SuperMasterInfoQuery_stmt = d_db->prepare(d_SuperMasterInfoQuery, 2); + d_GetSuperMasterIPs_stmt = d_db->prepare(d_GetSuperMasterIPs, 2); + d_InsertZoneQuery_stmt = d_db->prepare(d_InsertZoneQuery, 1); + d_InsertSlaveZoneQuery_stmt = d_db->prepare(d_InsertSlaveZoneQuery, 3); + d_InsertRecordQuery_stmt = d_db->prepare(d_InsertRecordQuery, 8); + d_InsertEntQuery_stmt = d_db->prepare(d_InsertEntQuery, 3); + d_InsertRecordOrderQuery_stmt = d_db->prepare(d_InsertRecordOrderQuery, 9); + d_InsertEntOrderQuery_stmt = d_db->prepare(d_InsertEntOrderQuery, 4); + d_UpdateMasterOfZoneQuery_stmt = d_db->prepare(d_UpdateMasterOfZoneQuery, 2); + d_UpdateKindOfZoneQuery_stmt = d_db->prepare(d_UpdateKindOfZoneQuery, 2); + d_UpdateSerialOfZoneQuery_stmt = d_db->prepare(d_UpdateSerialOfZoneQuery, 2); + d_UpdateLastCheckofZoneQuery_stmt = d_db->prepare(d_UpdateLastCheckofZoneQuery, 2); + d_InfoOfAllMasterDomainsQuery_stmt = d_db->prepare(d_InfoOfAllMasterDomainsQuery, 0); + d_DeleteDomainQuery_stmt = d_db->prepare(d_DeleteDomainQuery, 1); + d_DeleteZoneQuery_stmt = d_db->prepare(d_DeleteZoneQuery, 1); + d_DeleteRRSetQuery_stmt = d_db->prepare(d_DeleteRRSetQuery, 3); + d_DeleteNamesQuery_stmt = d_db->prepare(d_DeleteNamesQuery, 2); + d_ZoneLastChangeQuery_stmt = d_db->prepare(d_ZoneLastChangeQuery, 1); + d_firstOrderQuery_stmt = d_db->prepare(d_firstOrderQuery, 1); + d_beforeOrderQuery_stmt = d_db->prepare(d_beforeOrderQuery, 2); + d_afterOrderQuery_stmt = d_db->prepare(d_afterOrderQuery, 2); + d_lastOrderQuery_stmt = d_db->prepare(d_lastOrderQuery, 1); + d_setOrderAuthQuery_stmt = d_db->prepare(d_setOrderAuthQuery, 4); + d_nullifyOrderNameAndUpdateAuthQuery_stmt = d_db->prepare(d_nullifyOrderNameAndUpdateAuthQuery, 3); + d_nullifyOrderNameAndAuthQuery_stmt = d_db->prepare(d_nullifyOrderNameAndAuthQuery, 3); + d_nullifyOrderNameAndAuthENTQuery_stmt = d_db->prepare(d_nullifyOrderNameAndAuthENTQuery, 0); + d_setAuthOnDsRecordQuery_stmt = d_db->prepare(d_setAuthOnDsRecordQuery, 2); + d_removeEmptyNonTerminalsFromZoneQuery_stmt = d_db->prepare(d_removeEmptyNonTerminalsFromZoneQuery, 1); + d_insertEmptyNonTerminalQuery_stmt = d_db->prepare(d_insertEmptyNonTerminalQuery, 2); + d_deleteEmptyNonTerminalQuery_stmt = d_db->prepare(d_deleteEmptyNonTerminalQuery, 2); + d_AddDomainKeyQuery_stmt = d_db->prepare(d_AddDomainKeyQuery, 4); + d_ListDomainKeysQuery_stmt = d_db->prepare(d_ListDomainKeysQuery, 1); + d_GetAllDomainMetadataQuery_stmt = d_db->prepare(d_GetAllDomainMetadataQuery, 1); + d_GetDomainMetadataQuery_stmt = d_db->prepare(d_GetDomainMetadataQuery, 2); + d_ClearDomainMetadataQuery_stmt = d_db->prepare(d_ClearDomainMetadataQuery, 2); + d_ClearDomainAllMetadataQuery_stmt = d_db->prepare(d_ClearDomainAllMetadataQuery, 1); + d_SetDomainMetadataQuery_stmt = d_db->prepare(d_SetDomainMetadataQuery, 3); + d_RemoveDomainKeyQuery_stmt = d_db->prepare(d_RemoveDomainKeyQuery, 2); + d_ActivateDomainKeyQuery_stmt = d_db->prepare(d_ActivateDomainKeyQuery, 2); + d_DeactivateDomainKeyQuery_stmt = d_db->prepare(d_DeactivateDomainKeyQuery, 2); + d_ClearDomainAllKeysQuery_stmt = d_db->prepare(d_ClearDomainAllKeysQuery, 1); + d_getTSIGKeyQuery_stmt = d_db->prepare(d_getTSIGKeyQuery, 1); + d_setTSIGKeyQuery_stmt = d_db->prepare(d_setTSIGKeyQuery, 3); + d_deleteTSIGKeyQuery_stmt = d_db->prepare(d_deleteTSIGKeyQuery, 1); + d_getTSIGKeysQuery_stmt = d_db->prepare(d_getTSIGKeysQuery, 0); + d_getAllDomainsQuery_stmt = d_db->prepare(d_getAllDomainsQuery, 1); + d_ListCommentsQuery_stmt = d_db->prepare(d_ListCommentsQuery, 1); + d_InsertCommentQuery_stmt = d_db->prepare(d_InsertCommentQuery, 6); + d_DeleteCommentRRsetQuery_stmt = d_db->prepare(d_DeleteCommentRRsetQuery, 3); + d_DeleteCommentsQuery_stmt = d_db->prepare(d_DeleteCommentsQuery, 1); } } + + void release(SSqlStatement **stmt) { + delete *stmt; + *stmt = NULL; + } - virtual string sqlEscape(const string &name); + void freeStatements() { + release(&d_NoIdQuery_stmt); + release(&d_IdQuery_stmt); + release(&d_ANYNoIdQuery_stmt); + release(&d_ANYIdQuery_stmt); + release(&d_listQuery_stmt); + release(&d_listSubZoneQuery_stmt); + release(&d_MasterOfDomainsZoneQuery_stmt); + release(&d_InfoOfDomainsZoneQuery_stmt); + release(&d_InfoOfAllSlaveDomainsQuery_stmt); + release(&d_SuperMasterInfoQuery_stmt); + release(&d_GetSuperMasterIPs_stmt); + release(&d_InsertZoneQuery_stmt); + release(&d_InsertSlaveZoneQuery_stmt); + release(&d_InsertRecordQuery_stmt); + release(&d_InsertEntQuery_stmt); + release(&d_InsertRecordOrderQuery_stmt); + release(&d_InsertEntOrderQuery_stmt); + release(&d_UpdateMasterOfZoneQuery_stmt); + release(&d_UpdateKindOfZoneQuery_stmt); + release(&d_UpdateSerialOfZoneQuery_stmt); + release(&d_UpdateLastCheckofZoneQuery_stmt); + release(&d_InfoOfAllMasterDomainsQuery_stmt); + release(&d_DeleteDomainQuery_stmt); + release(&d_DeleteZoneQuery_stmt); + release(&d_DeleteRRSetQuery_stmt); + release(&d_DeleteNamesQuery_stmt); + release(&d_ZoneLastChangeQuery_stmt); + release(&d_firstOrderQuery_stmt); + release(&d_beforeOrderQuery_stmt); + release(&d_afterOrderQuery_stmt); + release(&d_lastOrderQuery_stmt); + release(&d_setOrderAuthQuery_stmt); + release(&d_nullifyOrderNameAndUpdateAuthQuery_stmt); + release(&d_nullifyOrderNameAndAuthQuery_stmt); + release(&d_nullifyOrderNameAndAuthENTQuery_stmt); + release(&d_setAuthOnDsRecordQuery_stmt); + release(&d_removeEmptyNonTerminalsFromZoneQuery_stmt); + release(&d_insertEmptyNonTerminalQuery_stmt); + release(&d_deleteEmptyNonTerminalQuery_stmt); + release(&d_AddDomainKeyQuery_stmt); + release(&d_ListDomainKeysQuery_stmt); + release(&d_GetAllDomainMetadataQuery_stmt); + release(&d_GetDomainMetadataQuery_stmt); + release(&d_ClearDomainMetadataQuery_stmt); + release(&d_ClearDomainAllMetadataQuery_stmt); + release(&d_SetDomainMetadataQuery_stmt); + release(&d_RemoveDomainKeyQuery_stmt); + release(&d_ActivateDomainKeyQuery_stmt); + release(&d_DeactivateDomainKeyQuery_stmt); + release(&d_ClearDomainAllKeysQuery_stmt); + release(&d_getTSIGKeyQuery_stmt); + release(&d_setTSIGKeyQuery_stmt); + release(&d_deleteTSIGKeyQuery_stmt); + release(&d_getTSIGKeysQuery_stmt); + release(&d_getAllDomainsQuery_stmt); + release(&d_ListCommentsQuery_stmt); + release(&d_InsertCommentQuery_stmt); + release(&d_DeleteCommentRRsetQuery_stmt); + release(&d_DeleteCommentsQuery_stmt); + } + void lookup(const QType &, const string &qdomain, DNSPacket *p=0, int zoneId=-1); bool list(const string &target, int domain_id, bool include_disabled=false); bool get(DNSResourceRecord &r); @@ -90,7 +218,7 @@ public: private: string d_qname; SSql *d_db; - SSql::result_t d_result; + SSqlStatement::result_t d_result; string d_NoIdQuery; string d_IdQuery; @@ -163,6 +291,67 @@ private: string d_DeleteCommentRRsetQuery; string d_DeleteCommentsQuery; + SSqlStatement* d_query_stmt; + + SSqlStatement* d_NoIdQuery_stmt; + SSqlStatement* d_IdQuery_stmt; + SSqlStatement* d_ANYNoIdQuery_stmt; + SSqlStatement* d_ANYIdQuery_stmt; + SSqlStatement* d_listQuery_stmt; + SSqlStatement* d_listSubZoneQuery_stmt; + SSqlStatement* d_MasterOfDomainsZoneQuery_stmt; + SSqlStatement* d_InfoOfDomainsZoneQuery_stmt; + SSqlStatement* d_InfoOfAllSlaveDomainsQuery_stmt; + SSqlStatement* d_SuperMasterInfoQuery_stmt; + SSqlStatement* d_GetSuperMasterIPs_stmt; + SSqlStatement* d_InsertZoneQuery_stmt; + SSqlStatement* d_InsertSlaveZoneQuery_stmt; + SSqlStatement* d_InsertRecordQuery_stmt; + SSqlStatement* d_InsertEntQuery_stmt; + SSqlStatement* d_InsertRecordOrderQuery_stmt; + SSqlStatement* d_InsertEntOrderQuery_stmt; + SSqlStatement* d_UpdateMasterOfZoneQuery_stmt; + SSqlStatement* d_UpdateKindOfZoneQuery_stmt; + SSqlStatement* d_UpdateSerialOfZoneQuery_stmt; + SSqlStatement* d_UpdateLastCheckofZoneQuery_stmt; + SSqlStatement* d_InfoOfAllMasterDomainsQuery_stmt; + SSqlStatement* d_DeleteDomainQuery_stmt; + SSqlStatement* d_DeleteZoneQuery_stmt; + SSqlStatement* d_DeleteRRSetQuery_stmt; + SSqlStatement* d_DeleteNamesQuery_stmt; + SSqlStatement* d_ZoneLastChangeQuery_stmt; + SSqlStatement* d_firstOrderQuery_stmt; + SSqlStatement* d_beforeOrderQuery_stmt; + SSqlStatement* d_afterOrderQuery_stmt; + SSqlStatement* d_lastOrderQuery_stmt; + SSqlStatement* d_setOrderAuthQuery_stmt; + SSqlStatement* d_nullifyOrderNameAndUpdateAuthQuery_stmt; + SSqlStatement* d_nullifyOrderNameAndAuthQuery_stmt; + SSqlStatement* d_nullifyOrderNameAndAuthENTQuery_stmt; + SSqlStatement* d_setAuthOnDsRecordQuery_stmt; + SSqlStatement* d_removeEmptyNonTerminalsFromZoneQuery_stmt; + SSqlStatement* d_insertEmptyNonTerminalQuery_stmt; + SSqlStatement* d_deleteEmptyNonTerminalQuery_stmt; + SSqlStatement* d_AddDomainKeyQuery_stmt; + SSqlStatement* d_ListDomainKeysQuery_stmt; + SSqlStatement* d_GetAllDomainMetadataQuery_stmt; + SSqlStatement* d_GetDomainMetadataQuery_stmt; + SSqlStatement* d_ClearDomainMetadataQuery_stmt; + SSqlStatement* d_ClearDomainAllMetadataQuery_stmt; + SSqlStatement* d_SetDomainMetadataQuery_stmt; + SSqlStatement* d_RemoveDomainKeyQuery_stmt; + SSqlStatement* d_ActivateDomainKeyQuery_stmt; + SSqlStatement* d_DeactivateDomainKeyQuery_stmt; + SSqlStatement* d_ClearDomainAllKeysQuery_stmt; + SSqlStatement* d_getTSIGKeyQuery_stmt; + SSqlStatement* d_setTSIGKeyQuery_stmt; + SSqlStatement* d_deleteTSIGKeyQuery_stmt; + SSqlStatement* d_getTSIGKeysQuery_stmt; + SSqlStatement* d_getAllDomainsQuery_stmt; + SSqlStatement* d_ListCommentsQuery_stmt; + SSqlStatement* d_InsertCommentQuery_stmt; + SSqlStatement* d_DeleteCommentRRsetQuery_stmt; + SSqlStatement* d_DeleteCommentsQuery_stmt; protected: bool d_dnssecQueries; }; diff --git a/pdns/backends/gsql/ssql.hh b/pdns/backends/gsql/ssql.hh index dbad606a1..dbf81d859 100644 --- a/pdns/backends/gsql/ssql.hh +++ b/pdns/backends/gsql/ssql.hh @@ -12,7 +12,7 @@ #include #include #include "../../namespaces.hh" - +#include class SSqlException { @@ -29,18 +29,40 @@ public: private: string d_reason; }; - -class SSql + +class SSqlStatement { public: typedef vector row_t; typedef vector result_t; + + virtual SSqlStatement* bind(const string& name, bool value)=0; + virtual SSqlStatement* bind(const string& name, int value)=0; + virtual SSqlStatement* bind(const string& name, uint32_t value)=0; + virtual SSqlStatement* bind(const string& name, long value)=0; + virtual SSqlStatement* bind(const string& name, unsigned long value)=0; + virtual SSqlStatement* bind(const string& name, long long value)=0;; + virtual SSqlStatement* bind(const string& name, unsigned long long value)=0; + virtual SSqlStatement* bind(const string& name, const std::string& value)=0; + virtual SSqlStatement* bindNull(const string& name)=0; + virtual SSqlStatement* execute()=0;; + virtual bool hasNextRow()=0; + virtual SSqlStatement* nextRow(row_t& row)=0; + virtual SSqlStatement* getResult(result_t& result)=0; + virtual SSqlStatement* reset()=0; + virtual const std::string& getQuery()=0; + virtual ~SSqlStatement(); +}; + +class SSql +{ +public: virtual SSqlException sPerrorException(const string &reason)=0; - virtual int doQuery(const string &query, result_t &result)=0; - virtual int doQuery(const string &query)=0; - virtual int doCommand(const string &query)=0; - virtual bool getRow(row_t &row)=0; - virtual string escape(const string &name)=0; + virtual SSqlStatement* prepare(const string& query, int nparams)=0; + virtual void execute(const string& query)=0; + virtual void startTransaction()=0; + virtual void rollback()=0; + virtual void commit()=0; virtual void setLog(bool state){} virtual ~SSql(){}; }; diff --git a/pdns/pdnssec.cc b/pdns/pdnssec.cc index abcfd0c10..9d99b2d08 100644 --- a/pdns/pdnssec.cc +++ b/pdns/pdnssec.cc @@ -136,12 +136,15 @@ void loadMainConfig(const std::string& configdir) ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000"; ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR; ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom"; - + ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no"; + ::arg().set("loglevel","Amount of logging. Higher is more.")="0"; ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no"; ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3 ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")=""; ::arg().laxFile(configname.c_str()); + L.toConsole((Logger::Urgency)(::arg().asNum("loglevel"))); + BackendMakers().launch(::arg()["launch"]); // vrooooom! ::arg().laxFile(configname.c_str()); //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" < statements; stringtok(statements, sqlCreate, ";"); - BOOST_FOREACH(const string& statement, statements) - db.doCommand(statement); + BOOST_FOREACH(const string& statement, statements) { + db.execute(statement); + } } catch(SSqlException& se) { throw PDNSException("Error creating database in BIND backend: "+se.txtReason()); diff --git a/pdns/ssqlite3.cc b/pdns/ssqlite3.cc index 9fecceaaa..e98933aea 100644 --- a/pdns/ssqlite3.cc +++ b/pdns/ssqlite3.cc @@ -13,6 +13,126 @@ #include "misc.hh" #include +/* +** Set all the parameters in the compiled SQL statement to NULL. +* +* copied from sqlite 3.3.6 // cmouse +*/ +int pdns_sqlite3_clear_bindings(sqlite3_stmt *pStmt){ + int i; + int rc = SQLITE_OK; + for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){ + rc = sqlite3_bind_null(pStmt, i); + } + return rc; +} + +void my_trace(void *foo, const char *sql) { + L<d_query = query; + this->d_dolog = dolog; + d_db = db; +#if SQLITE_VERSION_NUMBER >= 3003009 + if (sqlite3_prepare_v2(d_db->db(), query.c_str(), -1, &d_stmt, &pTail ) != SQLITE_OK) +#else + if (sqlite3_prepare(d_db->db(), query.c_str(), -1, &d_stmt, &pTail ) != SQLITE_OK) +#endif + throw SSqlException(string("Unable to compile SQLite statement : ")+sqlite3_errmsg(d_db->db())); + if (pTail && strlen(pTail)>0) + L<0) { sqlite3_bind_int(d_stmt, idx, value ? 1 : 0); }; return this; } + SSqlStatement* bind(const string& name, int value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int(d_stmt, idx, value); }; return this; } + SSqlStatement* bind(const string& name, uint32_t value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; } + SSqlStatement* bind(const string& name, long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; } + SSqlStatement* bind(const string& name, unsigned long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; } + SSqlStatement* bind(const string& name, long long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; }; + SSqlStatement* bind(const string& name, unsigned long long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; } + SSqlStatement* bind(const string& name, const std::string& value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_text(d_stmt, idx, value.c_str(), value.size(), SQLITE_TRANSIENT); }; return this; } + SSqlStatement* bindNull(const string& name) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_null(d_stmt, idx); }; return this; } + + SSqlStatement* execute() { + int attempts = d_db->inTransaction(); // try only once + while(attempts < 2 && (d_rc = sqlite3_step(d_stmt)) == SQLITE_BUSY) attempts++; + + if (d_rc != SQLITE_ROW && d_rc != SQLITE_DONE) { + // failed. + if (d_rc == SQLITE_CANTOPEN) + throw SSqlException(string("CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: ")+string(sqlite3_errmsg(d_db->db()))); + throw SSqlException(string("Error while retrieving SQLite query results: ")+string(sqlite3_errmsg(d_db->db()))); + } + return this; + } + bool hasNextRow() { return d_rc == SQLITE_ROW; } + + SSqlStatement* nextRow(row_t& row) { + row.clear(); + int numCols = sqlite3_column_count(d_stmt); + row.reserve(numCols); // preallocate memory + // Another row received, process it. + for ( int i=0; i= 3003009 + sqlite3_clear_bindings(d_stmt); +#else + pdns_sqlite3_clear_bindings(d_stmt); +#endif + return this; + } + + ~SSQLite3Statement() { + // deallocate if necessary + if (d_stmt) + sqlite3_finalize(d_stmt); + } + + const string& getQuery() { return d_query; }; +private: + string d_query; + sqlite3_stmt* d_stmt; + int d_rc; + SSQLite3* d_db; + bool d_dolog; +}; + // Constructor. SSQLite3::SSQLite3( const std::string & database, bool creat ) { @@ -23,13 +143,15 @@ SSQLite3::SSQLite3( const std::string & database, bool creat ) if ( sqlite3_open( database.c_str(), &m_pDB)!=SQLITE_OK ) throw sPerrorException( "Could not connect to the SQLite database '" + database + "'" ); - m_pStmt = 0; m_dolog = 0; + m_in_transaction = false; sqlite3_busy_handler(m_pDB, busyHandler, 0); } void SSQLite3::setLog(bool state) -{ +{ + if (state) + sqlite3_trace(m_pDB, my_trace, NULL); m_dolog=state; } @@ -39,60 +161,31 @@ SSQLite3::~SSQLite3() int ret; for(int n = 0; n < 2 ; ++n) { if((ret =sqlite3_close( m_pDB )) != SQLITE_OK) { - if(n || !m_pStmt || ret != SQLITE_BUSY) { // if we have SQLITE_BUSY, and a working m_Pstmt, try finalize + if(n || ret != SQLITE_BUSY) { // if we have SQLITE_BUSY, and a working m_Pstmt, try finalize cerr<<"Unable to close down sqlite connection: "<= 3003009 - if ( sqlite3_prepare_v2( m_pDB, query.c_str(), -1, &m_pStmt, &pTail ) != SQLITE_OK ) -#else - if ( sqlite3_prepare( m_pDB, query.c_str(), -1, &m_pStmt, &pTail ) != SQLITE_OK ) -#endif - throw sPerrorException( string("Unable to compile SQLite statement : ")+ sqlite3_errmsg( m_pDB ) ); - - return 0; +void SSQLite3::execute(const string& query) { + char *errmsg; + int rc; + if (sqlite3_exec(m_pDB, query.c_str(), NULL, NULL, &errmsg) == SQLITE_BUSY) { + if (m_in_transaction) { + throw("Failed to execute query: " + string(errmsg)); + } else { + if ((rc = sqlite3_exec(m_pDB, query.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) && rc != SQLITE_DONE && rc != SQLITE_ROW) + throw("Failed to execute query: " + string(errmsg)); + } + } } int SSQLite3::busyHandler(void*, int) @@ -101,66 +194,23 @@ int SSQLite3::busyHandler(void*, int) return 1; } -// Returns a row from the result set. -bool SSQLite3::getRow( row_t & row ) -{ - int numCols; - int rc; - const char *pData; - - row.clear(); - - rc = sqlite3_step( m_pStmt ); - - if ( rc == SQLITE_ROW ) - { - numCols = sqlite3_column_count( m_pStmt ); - // Another row received, process it. - for ( int i = 0; i < numCols; i++ ) - { - pData = (const char*) sqlite3_column_text( m_pStmt, i ); - row.push_back( pData ? pData : "" ); // NULL value to "". - } - - return true; - } - - if ( rc == SQLITE_DONE ) - { - // We're done, clean up. - sqlite3_finalize( m_pStmt ); - m_pStmt = NULL; - return false; - } - - if(rc == SQLITE_CANTOPEN) { - string error ="CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: "+string(sqlite3_errmsg(m_pDB)); - sqlite3_finalize(m_pStmt); - m_pStmt = 0; - throw sPerrorException(error); - } - - // Something went wrong, complain. - throw sPerrorException( "Error while retrieving SQLite query results: "+string(sqlite3_errmsg(m_pDB) )); +void SSQLite3::startTransaction() { + execute("begin"); + m_in_transaction = true; +} - // Prevent some compilers from complaining. - return false; +void SSQLite3::rollback() { + execute("rollback"); + m_in_transaction = false; } +void SSQLite3::commit() { + execute("commit"); + m_in_transaction = false; +} -// Escape a SQL query. -std::string SSQLite3::escape( const std::string & name) +// Constructs a SSqlException object. +SSqlException SSQLite3::sPerrorException( const std::string & reason ) { - std::string a; - - for( std::string::const_iterator i = name.begin(); i != name.end(); ++i ) - { - if( *i == '\'' || *i == '\\' ) - a += '\\'; - - a += *i; - } - - return a; + return SSqlException( reason ); } - diff --git a/pdns/ssqlite3.hh b/pdns/ssqlite3.hh index 02670af56..13b6e45cb 100644 --- a/pdns/ssqlite3.hh +++ b/pdns/ssqlite3.hh @@ -20,7 +20,7 @@ private: sqlite3_stmt *m_pStmt; bool m_dolog; - + bool m_in_transaction; static int busyHandler(void*, int); protected: public: @@ -30,26 +30,17 @@ public: //! Destructor. ~SSQLite3(); - //! Performs a query and puts answers in result - int doQuery( const std::string & query, result_t & result ); - - //! Performs a query, caller can retrieve answers with getRow - int doQuery( const std::string & query ); + SSqlStatement* prepare(const string& query, int nparams); + void execute(const string& query); + void setLog(bool state); - //! Performs a command that does not return rows - int doCommand( const std::string & query ) - { - result_t result; - return doQuery(query, result); // 'result' is necessary to force doQuery to do the work, closing Debian bug 280359 - } - - //! Returns a row from a result set. - bool getRow( row_t & row ); + void startTransaction(); + void commit(); + void rollback(); - //! Escapes the SQL query. - std::string escape( const std::string & query ); + sqlite3 *db() { return this->m_pDB; }; - void setLog(bool state); + bool inTransaction() { return m_in_transaction; }; //! Used to create an backend specific exception message. SSqlException sPerrorException( const std::string & reason ); diff --git a/regression-tests/backends/goracle-master b/regression-tests/backends/goracle-master index a67298687..173d20a5a 100644 --- a/regression-tests/backends/goracle-master +++ b/regression-tests/backends/goracle-master @@ -1,13 +1,26 @@ source ./backends/gsql-common +set +e +SQLPLUS=`which sqlplus` +if [ ! -x "$SQLPLUS" ]; then + SQLPLUS=`which sqlplus64` +fi +if [ ! -x "$SQLPLUS" ]; then + echo "Cannot find sqlplus or sqlplus64 in path" + exit 1 +fi +set -e +if [ "x$NLS_LANG" = "x" ]; then + NLS_LANG="AMERICAN_AMERICA.AL32UTF8" +fi case $context in goracle-nodnssec | goracle | goracle-nsec3 | goracle-nsec3-optout | goracle-nsec3-narrow) [ -z "$GORACLEUSER" ] && GORACLEUSER=pdns [ -z "$GORACLEPASSWD" ] && GORACLEPASSWD=pdns - echo "START ../modules/goraclebackend/drop-schema.goracle.sql;" | sqlplus -S $GORACLEUSER/$GORACLEPASSWD@xe > goracle.log - echo "START ../modules/goraclebackend/schema.goracle.sql;" | sqlplus -S $GORACLEUSER/$GORACLEPASSWD@xe >> goracle.log - tosql goracle | sqlplus -S $GORACLEUSER/$GORACLEPASSWD@xe >> goracle.log + echo "START ../modules/goraclebackend/drop-schema.goracle.sql;" | $SQLPLUS -S $GORACLEUSER/$GORACLEPASSWD@xe > goracle.log + echo "START ../modules/goraclebackend/schema.goracle.sql;" | $SQLPLUS -S $GORACLEUSER/$GORACLEPASSWD@xe >> goracle.log + tosql goracle | $SQLPLUS -S $GORACLEUSER/$GORACLEPASSWD@xe >> goracle.log cat > pdns-goracle.conf << __EOF__ module-dir=./modules diff --git a/regression-tests/backends/goracle-slave b/regression-tests/backends/goracle-slave index cd0d2315c..55dfb0e5f 100644 --- a/regression-tests/backends/goracle-slave +++ b/regression-tests/backends/goracle-slave @@ -1,3 +1,6 @@ +if [ "x$NLS_LANG" = "x" ]; then + NLS_LANG="AMERICAN_AMERICA.AL32UTF8" +fi context=${context}-presigned-goracle [ -z "$GORACLE2USER" ] && GORACLE2USER=pdns2 [ -z "$GORACLE2PASSWD" ] && GORACLE2PASSWD=pdns diff --git a/regression-tests/backends/gpgsql-master b/regression-tests/backends/gpgsql-master index edb188db2..741e4dd7a 100644 --- a/regression-tests/backends/gpgsql-master +++ b/regression-tests/backends/gpgsql-master @@ -8,8 +8,8 @@ case $context in dropdb --user="$GPGSQLUSER" "$GPGSQLDB" || echo ignoring mysqladmin drop failure createdb --user="$GPGSQLUSER" "$GPGSQLDB" || echo ignoring mysqladmin drop failure psql --user="$GPGSQLUSER" "$GPGSQLDB" < ../modules/gpgsqlbackend/schema.pgsql.sql - tosql gpgsql | psql --user="$GPGSQLUSER" "$GPGSQLDB" 2>&1 | uniq -c + psql --user="$GPGSQLUSER" "$GPGSQLDB" -c "ANALYZE" cat > pdns-gpgsql.conf << __EOF__ module-dir=./modules -- 2.49.0