Closes #1783 which is the PR this code came from.
# 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])]
-/*
+ /*
PowerDNS Versatile Database Driven Nameserver
Copyright (C) 2002 - 2014 PowerDNS.COM BV
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");
}
Bind2Backend::~Bind2Backend()
-{}
+{ freeStatements(); } // deallocate statements
void Bind2Backend::rediscover(string *status)
{
#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.
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);
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;
};
bool Bind2Backend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
{ return false; }
+void Bind2Backend::setupStatements()
+{ return; }
+void Bind2Backend::freeStatements()
+{ return; }
+
#else
#include "pdns/ssqlite3.hh"
return;
try {
d_dnssecdb = shared_ptr<SSQLite3>(new SSQLite3(getArg("dnssec-db")));
+ setupStatements();
}
catch(SSqlException& se) {
// this error is meant to kill the server dead - it makes no sense to continue..
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;
// cerr<<"Asked to get metadata for zone '"<<name<<"'|"<<kind<<"\n";
- boost::format fmt("select kind, content from domainmetadata where domain='%s'");
try {
- d_dnssecdb->doQuery((fmt % d_dnssecdb->escape(name)).str());
+ d_getAllDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ execute();
- vector<string> 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());
// cerr<<"Asked to get metadata for zone '"<<name<<"'|"<<kind<<"\n";
- boost::format fmt("select content from domainmetadata where domain='%s' and kind='%s'");
try {
- d_dnssecdb->doQuery((fmt % d_dnssecdb->escape(name) % d_dnssecdb->escape(kind)).str());
+ d_getDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ bind("kind", kind)->
+ execute();
- vector<string> 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());
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());
// cerr<<"Asked to get keys for zone '"<<name<<"'\n";
if(!d_dnssecdb || d_hybrid)
return false;
- boost::format fmt("select id,flags, active, content from cryptokeys where domain='%s'");
try {
- d_dnssecdb->doQuery((fmt % d_dnssecdb->escape(name)).str());
+ d_getDomainKeysQuery_stmt->
+ bind("domain", name)->
+ execute();
KeyData kd;
- vector<string> 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());
// cerr<<"Asked to remove key "<<id<<" in zone '"<<name<<"'\n";
- boost::format fmt("delete from cryptokeys where domain='%s' and id=%d");
try {
- d_dnssecdb->doCommand((fmt % d_dnssecdb->escape(name) % id).str());
+ d_deleteDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
}
catch(SSqlException& se) {
cerr<<se.txtReason() <<endl;
//cerr<<"Asked to add a key to zone '"<<name<<"'\n";
- boost::format fmt("insert into cryptokeys (domain, flags, active, content) values ('%s', %d, %d, '%s')");
try {
- d_dnssecdb->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());
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());
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());
{
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());
{
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());
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();
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="")
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<int>(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<<Logger::Warning<<"Query: " << d_query <<endl;
+ }
+
+ if ((err = mysql_stmt_bind_param(d_stmt, d_req_bind))) {
+ string error(mysql_stmt_error(d_stmt));
+ throw SSqlException("Could not bind mysql statement: " + error);
+ }
+
+ if ((err = mysql_stmt_execute(d_stmt))) {
+ string error(mysql_stmt_error(d_stmt));
+ throw SSqlException("Could not execute mysql statement: " + error);
+ }
+
+ if ((d_fnum = static_cast<int>(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<d_fnum;i++) {
+ if (*d_res_bind[i].error) {
+ L<<Logger::Warning<<"Result field at row " << d_residx << " column " << i << " has errno " << *d_res_bind[i].error << endl;
+ }
+ if (*d_res_bind[i].is_null) {
+ row.push_back("");
+ continue;
+ } else {
+ row.push_back(string((char*)d_res_bind[i].buffer, std::min(d_res_bind[i].buffer_length, *d_res_bind[i].length)));
+ }
+ }
+
+ d_residx++;
+ return this;
+ }
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ result.reserve(d_resnum);
+ row_t row;
+
+ while(hasNextRow()) {
+ nextRow(row);
+ result.push_back(row);
+ }
+
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ if (!d_stmt) return this;
+
+ mysql_stmt_reset(d_stmt);
+ if (d_req_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_req_bind[i].buffer) delete [] (char*)d_req_bind[i].buffer;
+ if (d_req_bind[i].length) delete [] d_req_bind[i].length;
+ }
+ memset(d_req_bind, 0, sizeof(MYSQL_BIND)*d_parnum);
+ }
+ d_residx = d_resnum = 0;
+ d_paridx = 0;
+ return this;
+ }
+
+ const std::string& getQuery() { return d_query; }
+
+ ~SMySQLStatement() {
+ if (d_stmt)
+ mysql_stmt_close(d_stmt);
+ d_stmt = NULL;
+ if (d_req_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_req_bind[i].buffer) delete [] (char*)d_req_bind[i].buffer;
+ if (d_req_bind[i].length) delete [] d_req_bind[i].length;
+ }
+ delete [] d_req_bind;
+ d_req_bind = NULL;
+ }
+ if (d_res_bind) {
+ for(int i=0;i<d_fnum;i++) {
+ if (d_res_bind[i].buffer) delete [] (char*)d_res_bind[i].buffer;
+ if (d_res_bind[i].length) delete [] d_res_bind[i].length;
+ if (d_res_bind[i].is_null) delete [] d_res_bind[i].is_null;
+ }
+ delete [] d_res_bind;
+ d_res_bind = NULL;
+ }
+ }
+private:
+ MYSQL* d_db;
+
+ MYSQL_STMT* d_stmt;
+ MYSQL_BIND* d_req_bind;
+ MYSQL_BIND* d_res_bind;
+
+ string d_query;
+
+ bool d_dolog;
+ int d_parnum;
+ int d_paridx;
+ int d_fnum;
+ int d_resnum;
+ int d_residx;
+};
+
SMySQL::SMySQL(const string &database, const string &host, uint16_t port, const string &msocket, const string &user,
const string &password, const string &group, bool setIsolation)
{
retry=-1;
}
} while (retry >= 0);
-
- d_rres=0;
}
void SMySQL::setLog(bool state)
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<<Logger::Warning<<"Query: "<<query<<endl;
int err;
if((err=mysql_query(&d_db,query.c_str())))
throw sPerrorException("Failed to execute mysql_query, perhaps connection died? Err="+itoa(err));
-
- return 0;
}
-int SMySQL::doQuery(const string &query, result_t &result)
-{
- result.clear();
- doQuery(query);
-
- row_t row;
- while(getRow(row))
- result.push_back(row);
-
- return result.size();
+void SMySQL::startTransaction() {
+ execute("begin");
}
-bool SMySQL::getRow(row_t &row)
-{
- row.clear();
- if(!d_rres)
- if(!(d_rres = mysql_use_result(&d_db)))
- throw sPerrorException("Failed on mysql_use_result");
-
- MYSQL_ROW rrow;
-
- if((rrow = mysql_fetch_row(d_rres))) {
- for(unsigned int i=0;i<mysql_num_fields(d_rres);i++)
- row.push_back(rrow[i] ?: "");
- return true;
- }
- mysql_free_result(d_rres);
-
- while (mysql_next_result(&d_db) == 0) {
- if ((d_rres = mysql_use_result(&d_db))) {
- mysql_free_result(d_rres);
- }
- }
-
- d_rres=0;
- return false;
+void SMySQL::commit() {
+ execute("commit");
}
-string SMySQL::escape(const string &name)
-{
- string a;
-
- for(string::const_iterator i=name.begin();i!=name.end();++i) {
- if(*i=='\'' || *i=='\\')
- a+='\\';
- a+=*i;
- }
- return a;
+void SMySQL::rollback() {
+ execute("rollback");
}
~SMySQL();
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:
MYSQL d_db;
- MYSQL_RES *d_rres;
static bool s_dolog;
static pthread_mutex_t s_myinitlock;
};
-AM_CPPFLAGS += $(ORACLE_CFLAGS)
+AM_CPPFLAGS += $(ORACLE_CFLAGS) $(POLARSSL_CFLAGS)
pkglib_LTLIBRARIES = libgoraclebackend.la
#include "pdns/pdnsexception.hh"
#include "pdns/logger.hh"
#include "pdns/arguments.hh"
+#include "pdns/lock.hh"
#include "goraclebackend.hh"
#include "soracle.hh"
#include <sstream>
+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) {
L<<Logger::Info << mode << " Connection successful" << endl;
}
-
-string gOracleBackend::sqlEscape(const string &name)
-{
- return boost::replace_all_copy(name, "'", "''");
-}
-
-
class gOracleFactory : public BackendFactory
{
public:
declare(suffix,"password","Pdns backend password to connect with","");
declare(suffix,"dnssec","Enable DNSSEC processing","no");
+ declare(suffix,"release-statements","Release statements between executions, uses less resources","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, "list-query", "AXFR query", record_query+" (disabled=0 OR 1=%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, "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 (id,domain_id,name,type,disabled,auth) values (records_id_sequence.nextval,'%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,"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 (id, type, name) values(domain_id_sequence.nextval, 'NATIVE','%s')");
- declare(suffix,"insert-slave-query","", "insert into domains (id, type,name,master,account) values(domain_id_sequence.nextval, 'SLAVE','%s','%s','%s')");
-
- declare(suffix, "insert-record-query", "", "insert into records (id, content,ttl,prio,type,domain_id,disabled,name,auth) values (records_id_sequence.nextval, '%s',%d,%d,'%s',%d,%d,'%s','%d')");
- 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, '%s',%d,%d,'%s',%d,%d,'%s','%s ','%d')");
- 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,'%d',0,'%s','%d')");
- 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,'%d',0,'%s','%s','%d')");
-
- declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select trim(ordername),name from records where disabled=0 and domain_id=%d and ordername is not null and rownum=1 order by ordername asc");
- declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select trim(ordername), name from records where disabled=0 and ordername <= '%s ' and domain_id=%d and ordername is not null and rownum=1 order by ordername desc");
- declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select trim(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 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="") {
{
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);
};
#include "pdns/misc.hh"
#include "pdns/logger.hh"
#include "pdns/dns.hh"
-#include <regex.h>
#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<<Logger::Warning<<"Query: "<<d_query<<endl;
+ ub2 fntype;
+ ub4 iters;
- int err = OCIInitialize(OCI_THREADED, 0, NULL, NULL, NULL);
- if (err) {
- throw sPerrorException("OCIInitialize");
- }
+ if (OCIAttrGet(d_stmt, OCI_HTYPE_STMT, (dvoid*)&fntype, 0, OCI_ATTR_STMT_TYPE, d_err))
+ throw SSqlException("Cannot get statement type: " + OCIErrStr());
- err = OCIEnvInit(&d_environmentHandle, OCI_DEFAULT, 0, 0);
- if (err) {
- throw sPerrorException("OCIEnvInit");
- }
+ if (fntype == OCI_STMT_SELECT) iters = 0;
+ else iters = 1;
- // Allocate an error handle
+ d_queryResult = OCIStmtExecute(d_svcctx, d_stmt, d_err, iters, 0, NULL, NULL, OCI_DEFAULT);
+ if (d_queryResult != OCI_NO_DATA && d_queryResult != OCI_SUCCESS && d_queryResult != OCI_SUCCESS_WITH_INFO) {
+ throw SSqlException("Cannot execute statement: " + OCIErrStr());
+ }
- err = OCIHandleAlloc(d_environmentHandle, (dvoid**) &d_errorHandle, OCI_HTYPE_ERROR, 0, NULL);
- if (err) {
- throw sPerrorException("OCIHandleAlloc");
- }
+ d_resnum = d_residx = 0;
- // Logon to the database
+ if (fntype == OCI_STMT_SELECT) {
+ ub4 o_fnum;
+ ub4 o_resnum;
- const char* username = user.c_str();
+ // figure out what the result looks like
+ if (OCIAttrGet(d_stmt, OCI_HTYPE_STMT, (dvoid*)&o_resnum, 0, OCI_ATTR_ROW_COUNT, d_err))
+ throw SSqlException("Cannot get statement result row count: " + OCIErrStr()); // this returns 0
+ if (OCIAttrGet(d_stmt, OCI_HTYPE_STMT, (dvoid*)&o_fnum, 0, OCI_ATTR_PARAM_COUNT, d_err))
+ throw SSqlException("Cannot get statement result column count: " + OCIErrStr());
- err = OCILogon(d_environmentHandle, d_errorHandle, &d_serviceContextHandle, (OraText*) username, strlen(username),
- (OraText*) password.c_str(), strlen(password.c_str()), (OraText*) database.c_str(), strlen(database.c_str()));
+ d_residx = 0;
+ d_resnum = o_resnum;
+ d_fnum = o_fnum;
- if (err) {
- throw sPerrorException("Loging in to Oracle gave error: " + getOracleError());
- }
-}
+ if (d_res == NULL && d_fnum > 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()<<endl;
+ if (d_fnum > 0) {
+ for(int i=0;i<d_fnum;i++) {
+ if (OCIDefineByPos(d_stmt, &(d_res[i].handle), d_err, i+1, d_res[i].content, d_res[i].colsize+1, SQLT_STR, (dvoid*)&(d_res[i].ind), NULL, NULL, OCI_DEFAULT))
+ throw SSqlException("Cannot bind result column: " + OCIErrStr());
+ }
+ }
+
+ d_queryResult = OCIStmtFetch2(d_stmt, d_err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
}
+
+ return this;
}
- if (d_errorHandle != NULL) {
- OCIHandleFree(d_errorHandle, OCI_HTYPE_ERROR);
- d_errorHandle = NULL;
+ string OCIErrStr()
+ {
+ string mReason = "ORA-UNKNOWN";
+ if (d_err != NULL) {
+ text msg[512];
+ sb4 errcode = 0;
+ memset(msg, 0, 512);
+ OCIErrorGet((dvoid*) d_err,1, NULL, &errcode, msg, sizeof(msg), OCI_HTYPE_ERROR);
+ if (errcode) {
+ char* p = (char*) msg;
+ while (*p++ != 0x00) {
+ if (*p == '\n' || *p == '\r') {
+ *p = ';';
+ }
+ }
+ mReason = (char*) msg;
+ }
+ }
+ return mReason;
}
- if (d_environmentHandle != NULL) {
- OCIHandleFree(d_environmentHandle, OCI_HTYPE_ENV);
- d_environmentHandle = NULL;
+ bool hasNextRow() {
+ if (d_queryResult == OCI_NO_DATA) return false;
+ return true;
}
-}
-SSqlException SOracle::sPerrorException(const string &reason)
-{
- return SSqlException(reason);
-}
+ SSqlStatement* nextRow(row_t& row) {
+ row.clear();
-int SOracle::doCommand(const string &query)
-{
- int retval = doQuery(query);
- if (d_handle) {
- OCIHandleFree(d_handle, OCI_HTYPE_STMT);
- d_handle=0;
- }
+ if (d_stmt == NULL) return this;
- return retval;
-}
+ if (d_queryResult == OCI_NO_DATA) return this;
-int getNumFields(const string &query)
-{
- string lquery=toLower(query);
- const char* delim[]= {" from ", "\tfrom\t", "\tfrom ", " from\t", 0};
- int n=0;
- string::size_type pos;
- for (n=0; delim[n] && (pos=lquery.find(delim[n]))==string::npos; ++n)
- ;
-
- if (!delim[n]) {
- return -1;
- }
+ if (d_queryResult != OCI_SUCCESS && d_queryResult != OCI_SUCCESS_WITH_INFO) {
+ throw SSqlException("Cannot get next row: " + OCIErrStr());
+ }
+
+ row.reserve(d_fnum);
- unsigned int num=1;
+ for (int i=0; i < d_fnum ; i++) {
- for (unsigned int n=0; n < pos; ++n)
- if (lquery[n]==',') {
- num++;
+ if (d_res[i].ind>=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<<Logger::Warning<<"Query: "<<query<<endl;
- }
+ SSqlStatement* getResult(result_t& result) {
+ row_t row;
- int err = OCIHandleAlloc(d_environmentHandle, (dvoid**) &d_handle, OCI_HTYPE_STMT, 0, NULL);
+ result.reserve(d_resnum);
+ while(hasNextRow()) {
+ nextRow(row);
+ result.push_back(row);
+ }
- if (err) {
- throw sPerrorException("Allocating a query handle: "+getOracleError());
+ return this;
}
- err = OCIStmtPrepare(d_handle, d_errorHandle, (text*) query.c_str(), strlen(query.c_str()),
- OCI_NTV_SYNTAX, OCI_DEFAULT);
+ SSqlStatement* reset() {
+ d_paridx = 0;
+ d_residx = d_resnum = 0;
- if (err) {
- throw sPerrorException("Preparing statement: "+getOracleError());
+ if (d_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_bind[i].vals && d_bind[i].release) delete [] (text*)d_bind[i].vals;
+ }
+ }
+ d_bind = new struct obind[d_parnum];
+ memset(d_bind, 0, sizeof(struct obind)*d_parnum);
+
+ if (d_release_stmt) {
+ if (OCIStmtRelease(d_stmt, d_err, (text*)d_stmt_key, d_stmt_keysize, OCI_DEFAULT) != OCI_SUCCESS)
+ throw SSqlException("Could not release statement: " + OCIErrStr());
+ d_stmt = NULL;
+ }
+ return this;
}
- ub4 prefetch=1000;
- err=OCIAttrSet(d_handle, (ub4) OCI_HTYPE_STMT,
- (dvoid*) &prefetch, (ub4) sizeof(ub4),
- (ub4) OCI_ATTR_PREFETCH_ROWS, d_errorHandle);
+ const std::string& getQuery() {
+ return d_query;
+ }
- if (err) {
- throw sPerrorException("setting prefetch: "+getOracleError());
+ ~SOracleStatement() {
+ if (d_stmt)
+ OCIStmtRelease(d_stmt, d_err, d_stmt_key, d_stmt_keysize, OCI_STRLS_CACHE_DELETE);
+ if (d_err)
+ OCIHandleFree(d_err, OCI_HTYPE_ERROR);
+ if (d_res) {
+ for(int i=0;i<d_fnum;i++)
+ if (d_res[i].content) delete [] d_res[i].content;
+ delete [] d_res;
+ }
+ if (d_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_bind[i].vals && d_bind[i].release) delete [] (text*)d_bind[i].vals;
+ }
+ }
}
+private:
+ string d_query;
+ OCIEnv *d_ctx;
+ OCISvcCtx *d_svcctx;
+ bool d_dolog;
+ bool d_release_stmt;
+ bool d_init;
+ OCIStmt* d_stmt;
+ OCIError* d_err;
+ int d_parnum;
+ int d_paridx;
+ int d_resnum;
+ int d_residx;
+ int d_fnum;
+ dsword d_queryResult;
+ struct oresult {
+ OCIDefine *handle;
+ char* content;
+ sb4 ind;
+ ub4 colsize;
+ }* d_res;
+ struct obind {
+ OCIBind *handle;
+ ub4 val4;
+ oraub8 val8;
+ void* vals;
+ bool release;
+ }* d_bind;
+
+ sb4 d_non_null_ind;
+ sb4 d_null_ind;
+ text d_stmt_key[64];
+ size_t d_stmt_keysize;
+};
- // cerr<<"Done preparing '"<<query<<"'"<<endl;
- d_numfields=getNumFields(query);
+SOracle::SOracle(const string &database,
+ const string &user,
+ const string &password,
+ bool releaseStatements,
+ OCIEnv* oraenv)
+{
+ d_environmentHandle = oraenv;
+ d_errorHandle = NULL;
+ d_serviceContextHandle = NULL;
+ d_release_stmt = releaseStatements;
- for (int n=0; n < d_numfields ; ++n) {
- // cerr<<"bind: "<<n<<endl;
- OCIDefine* theDefineHandle = NULL;
- err = OCIDefineByPos(d_handle, &theDefineHandle, d_errorHandle, n+1, d_fields[n].content,
- sizeof(d_fields[n].content) - 1, SQLT_STR, (dvoid*) &d_fields[n].indicator, NULL, NULL, OCI_DEFAULT);
+ // Allocate an error handle
- if (err) {
- throw sPerrorException("Error binding returns: "+getOracleError());
- }
+ int err = OCIHandleAlloc(d_environmentHandle, (dvoid**) &d_errorHandle, OCI_HTYPE_ERROR, 0, NULL);
+ if (err) {
+ throw sPerrorException("OCIHandleAlloc(errorHandle)");
}
- // cerr<<"Done binding fields"<<endl;
-
- d_queryResult = OCIStmtExecute(d_serviceContextHandle, d_handle, d_errorHandle, 1, 0,
- (OCISnapshot*)NULL, (OCISnapshot*) NULL, OCI_DEFAULT);
-
- if (d_queryResult != OCI_SUCCESS && d_queryResult != OCI_SUCCESS_WITH_INFO && d_queryResult != OCI_NO_DATA) {
- throw sPerrorException("executing oracle query: "+getOracleError());
+ err = OCILogon2(d_environmentHandle, d_errorHandle, &d_serviceContextHandle, (OraText*)user.c_str(), user.size(),
+ (OraText*) password.c_str(), strlen(password.c_str()), (OraText*) database.c_str(), strlen(database.c_str()), OCI_LOGON2_STMTCACHE);
+ // increase statement cache to 100
+ if (err) {
+ throw sPerrorException("OCILogon2");
}
- // cerr<<"Done executing: "<<d_queryResult<<endl;
-
-
+ ub4 cacheSize = 100;
+ err = OCIAttrSet(d_serviceContextHandle, OCI_HTYPE_SVCCTX, &cacheSize, sizeof(ub4), OCI_ATTR_STMTCACHESIZE, d_errorHandle);
+ if (err) {
+ throw sPerrorException("OCIAttrSet(stmtcachesize)");
+ }
- return 0;
}
-int SOracle::doQuery(const string &query, result_t &result)
+void SOracle::setLog(bool state)
{
- result.clear();
- doQuery(query);
-
- row_t row;
- while (getRow(row)) {
- result.push_back(row);
- }
-
- return result.size();
+ s_dolog=state;
}
-bool SOracle::getRow(row_t &row)
+SOracle::~SOracle()
{
- row.clear();
-
- if (d_queryResult == OCI_NO_DATA) {
- OCIHandleFree(d_handle, OCI_HTYPE_STMT);
- d_handle=0;
- return false;
- } else {
- for (int n=0; n < d_numfields ; ++n)
- if (!d_fields[n].indicator) {
- row.push_back(d_fields[n].content);
- } else {
- row.push_back("");
- }
+ int err;
+ if (d_serviceContextHandle != NULL) {
+ err=OCILogoff(d_serviceContextHandle, d_errorHandle);
+ if (err) {
+ L<<Logger::Warning<<"Problems logging out: "+getOracleError()<<endl;
+ }
}
- d_queryResult = OCIStmtFetch(d_handle, d_errorHandle, 1, 0, 0);
- if (d_queryResult != OCI_SUCCESS && d_queryResult != OCI_SUCCESS_WITH_INFO && d_queryResult != OCI_NO_DATA) {
- throw sPerrorException("fetching next row of oracle query: "+getOracleError());
+ if (d_errorHandle != NULL) {
+ OCIHandleFree(d_errorHandle, OCI_HTYPE_ERROR);
+ d_errorHandle = NULL;
}
-
-
- return true;
}
-string SOracle::escape(const string &name)
+SSqlException SOracle::sPerrorException(const string &reason)
{
- string a;
+ return SSqlException(reason);
+}
- for (string::const_iterator i=name.begin(); i!=name.end(); ++i) {
- if (*i=='\\' || *i=='\'') {
- a+='\\';
- }
- a+=*i;
- }
- return a;
+SSqlStatement* SOracle::prepare(const string& query, int nparams) {
+ return new SOracleStatement(query, s_dolog, nparams, d_environmentHandle, d_serviceContextHandle, d_release_stmt);
}
-#if 0
+void SOracle::execute(const string& query) {
+ SOracleStatement(query, s_dolog, 0, d_environmentHandle, d_serviceContextHandle, true).execute();
+}
-int main(int argc, char** argv)
+string SOracle::getOracleError()
{
- for (int outer=0; outer<2; ++outer) {
- try {
- SOracle s(argv[1],"",0,"",argv[2],argv[3]);
-
- cerr<<"Ready to do queries"<<endl;
- time_t then=time(0);
-
- int loops;
- for (loops=0; loops < 6; ++loops) {
- s.doQuery("select id, content from records");
-
- SSql::row_t row;
-
- while (s.getRow(row)) {
- for (SSql::row_t::const_iterator j=row.begin(); j!=row.end(); ++j) {
- cout <<"'"<< *j<<"', ";
- }
- cout<<"\n";
+ 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 = ';';
}
}
- time_t spent=time(0)-then;
- if (spent) {
- cerr<<"Loops per second: "<< loops/spent<<endl;
- }
- } catch (string &e) {
- cerr<<"fatal: "<<e<<endl;
- } catch (SSqlException &e) {
- cerr<<e.txtReason()<<endl;
- }
- }
+ mReason = (char*) msg;
+ }
+ }
+ return mReason;
}
-
-#endif
#include "pdns/backends/gsql/ssql.hh"
#include "pdns/utility.hh"
#include <oci.h>
+#include <oratypes.h>
#ifndef dsword
typedef sb4 dsword;
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 */
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="")
#include "pdns/logger.hh"
#include "pdns/dns.hh"
#include "pdns/namespaces.hh"
+#include <algorithm>
+#include <boost/foreach.hpp>
+
+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<string>(tv.tv_sec) + boost::lexical_cast<string>(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<string>(value)); }
+ SSqlStatement* bind(const string& name, uint32_t value) { return bind(name, boost::lexical_cast<string>(value)); }
+ SSqlStatement* bind(const string& name, long value) { return bind(name, boost::lexical_cast<string>(value)); }
+ SSqlStatement* bind(const string& name, unsigned long value) { return bind(name, boost::lexical_cast<string>(value)); }
+ SSqlStatement* bind(const string& name, long long value) { return bind(name, boost::lexical_cast<string>(value)); }
+ SSqlStatement* bind(const string& name, unsigned long long value) { return bind(name, boost::lexical_cast<string>(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<<Logger::Warning<<"Query: "<<d_query<<endl;
+ }
+ d_res = PQexecPrepared(d_db, d_stmt.c_str(), d_nparams, paramValues, paramLengths, NULL, 0);
+ ExecStatusType status = PQresultStatus(d_res);
+ string errmsg(PQresultErrorMessage(d_res));
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && status != PGRES_NONFATAL_ERROR) {
+ string errmsg(PQresultErrorMessage(d_res));
+ PQclear(d_res);
+ d_res = NULL;
+ throw SSqlException("Fatal error during query: " + errmsg);
+ }
+ d_resnum = PQntuples(d_res);
+ return this;
+ }
+
+ bool hasNextRow()
+ {
+ return d_residx<d_resnum;
+ }
+
+ SSqlStatement* nextRow(row_t& row) {
+ int i;
+ row.clear();
+ if (d_residx>=d_resnum || !d_res) return this;
+ row.reserve(PQnfields(d_res));
+ for(i=0;i<PQnfields(d_res);i++) {
+ if (PQgetisnull(d_res, d_residx, i)) {
+ row.push_back("");
+ } else {
+ row.push_back(string(PQgetvalue(d_res, d_residx, i)));
+ }
+ }
+ d_residx++;
+ if (d_residx >= 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<d_nparams;i++)
+ if (paramValues[i]) delete [] paramValues[i];
+ delete [] paramValues;
+ paramValues = NULL;
+ delete [] paramLengths;
+ paramLengths = NULL;
+ return this;
+ }
+
+ const std::string& getQuery() { return d_query; }
+
+ ~SPgSQLStatement() {
+ reset();
+ }
+private:
+ void allocate() {
+ if (paramValues != NULL) return;
+ paramValues = new char*[d_nparams];
+ paramLengths = new int[d_nparams];
+ memset(paramValues, 0, sizeof(char*)*d_nparams);
+ memset(paramLengths, 0, sizeof(int)*d_nparams);
+ }
+
+ string d_query;
+ string d_stmt;
+ PGconn *d_db;
+ PGresult *d_res;
+ bool d_dolog;
+ int d_nparams;
+ int d_paridx;
+ char **paramValues;
+ int *paramLengths;
+ int d_residx;
+ int d_resnum;
+};
bool SPgSQL::s_dolog;
d_connectstr+=" password="+password;
}
- ensureConnect();
-}
-
-void SPgSQL::setLog(bool state)
-{
- s_dolog=state;
-}
-
-SPgSQL::~SPgSQL()
-{
- PQfinish(d_db);
-}
-
-SSqlException SPgSQL::sPerrorException(const string &reason)
-{
- return SSqlException(reason+string(": ")+(d_db ? PQerrorMessage(d_db) : "no connection"));
-}
-
-void SPgSQL::ensureConnect()
-{
- if(d_db)
- PQfinish(d_db);
d_db=PQconnectdb(d_connectstr.c_str());
if (!d_db || PQstatus(d_db)==CONNECTION_BAD) {
}
}
-int SPgSQL::doCommand(const string &query)
+void SPgSQL::setLog(bool state)
{
- if(s_dolog)
- L<<Logger::Warning<<"Command: "<<query<<endl;
-
- bool first = true;
-
- retry:
-
- if(!(d_result=PQexec(d_db,query.c_str())) || PQresultStatus(d_result)!=PGRES_COMMAND_OK) {
- string error("unknown reason");
- if(d_result) {
- error=PQresultErrorMessage(d_result);
- PQclear(d_result);
- }
-
- if(PQstatus(d_db)==CONNECTION_BAD) {
- ensureConnect();
- if(first) {
- first = false;
- goto retry;
- }
- }
-
- throw SSqlException("PostgreSQL failed to execute command: "+error);
- }
- if(d_result)
- PQclear(d_result);
- d_count=0;
- return 0;
+ s_dolog=state;
}
-
-int SPgSQL::doQuery(const string &query)
+SPgSQL::~SPgSQL()
{
- if(s_dolog)
- L<<Logger::Warning<<"Query: "<<query<<endl;
-
- bool first = true;
-retry:
- if(!(d_result=PQexec(d_db,query.c_str())) || PQresultStatus(d_result)!=PGRES_TUPLES_OK) {
- string error("unknown reason");
- if(d_result) {
- error=PQresultErrorMessage(d_result);
- PQclear(d_result);
- }
- if(PQstatus(d_db)==CONNECTION_BAD) {
- ensureConnect();
- if(first) {
- first = false;
- goto retry;
- }
- }
-
- throw SSqlException("PostgreSQL failed to execute command: "+error);
- }
+ PQfinish(d_db);
+}
- d_count=0;
- return 0;
+SSqlException SPgSQL::sPerrorException(const string &reason)
+{
+ return SSqlException(reason+string(": ")+(d_db ? PQerrorMessage(d_db) : "no connection"));
}
-int SPgSQL::doQuery(const string &query, result_t &result)
+void SPgSQL::execute(const string& query)
{
- result.clear();
- if(s_dolog)
- L<<Logger::Warning<<"Query: "<<query<<endl;
-
- if(!(d_result=PQexec(d_db,query.c_str())) || PQresultStatus(d_result)!=PGRES_TUPLES_OK) {
- string error("unknown reason");
- if(d_result) {
- error=PQresultErrorMessage(d_result);
- PQclear(d_result);
- }
- throw SSqlException("PostgreSQL failed to execute command: "+error);
+ PGresult* res = PQexec(d_db, query.c_str());
+ ExecStatusType status = PQresultStatus(res);
+ string errmsg(PQresultErrorMessage(res));
+ PQclear(res);
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && status != PGRES_NONFATAL_ERROR) {
+ throw sPerrorException("Fatal error during query: " + errmsg);
}
-
- d_count=0;
-
- row_t row;
- while(getRow(row))
- result.push_back(row);
-
- return result.size();
}
-bool SPgSQL::getRow(row_t &row)
+SSqlStatement* SPgSQL::prepare(const string& query, int nparams)
{
- row.clear();
+ return new SPgSQLStatement(query, s_dolog, nparams, d_db);
+}
- if(d_count >= PQntuples(d_result)) {
- PQclear(d_result);
- return false;
- }
-
- for(int i=0;i<PQnfields(d_result);i++)
- row.push_back(PQgetvalue(d_result,d_count,i) ?: "");
- d_count++;
- return true;
+void SPgSQL::startTransaction() {
+ execute("begin");
}
-string SPgSQL::escape(const string &name)
-{
- string a;
+void SPgSQL::commit() {
+ execute("commit");
+}
- for(string::const_iterator i=name.begin();i!=name.end();++i) {
- if(*i=='\'' || *i=='\\')
- a+='\\';
- a+=*i;
- }
- return a;
+void SPgSQL::rollback() {
+ execute("rollback");
}
~SPgSQL();
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 rollback();
+ void commit();
+
private:
- void ensureConnect();
PGconn* d_db;
string d_connectstr;
string d_connectlogstr;
- PGresult* d_result;
- int d_count;
static bool s_dolog;
};
try
{
SSQLite3 *ptr = new SSQLite3( getArg( "database" ));
- setDB( ptr);
+ setDB(ptr);
if(!getArg("pragma-synchronous").empty()) {
- SSQLite3::result_t res;
- ptr->doQuery("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());
//! 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.
}
};
-string gSQLite3Backend::sqlEscape(const string &name)
-{
- return boost::replace_all_copy(name, "'", "''");
-}
-
-
//! Reports the backendloader to the UeberBackend.
static gSQLite3Loader gsqlite3loader;
//! 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
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<<Logger::Error<<backendName<<" Connection failed: "<<e.txtReason()<<endl;
- throw PDNSException(backendName+"Unable to launch connection: "+e.txtReason());
- }
-
- d_rrtable=getArg("rr-table");
- d_soatable=getArg("soa-table");
- d_rrwhere=(mustDo("rr-active")?"(active = '1' or active = 'Y') and ":"")+getArg("rr-where");
- d_soawhere=(mustDo("soa-active")?"(active = '1' or active = 'Y') and ":"")+getArg("soa-where");
- d_useminimalttl=mustDo("use-minimal-ttl");
- d_minimum=0;
-
- L<<Logger::Warning<<backendName<<" Connection successful"<<endl;
+ setArgPrefix("mydns"+suffix);
+
+ d_domainIdQuery_stmt = NULL;
+ d_domainNoIdQuery_stmt = NULL;
+ d_listQuery_stmt = NULL;
+ d_soaQuery_stmt = NULL;
+ d_basicQuery_stmt = NULL;
+ d_anyQuery_stmt = NULL;
+ d_query_stmt = NULL;
+
+ try {
+ d_db = new SMySQL(getArg("dbname"),
+ getArg("host"),
+ getArgAsNum("port"),
+ getArg("socket"),
+ getArg("user"),
+ getArg("password"));
+ d_db->setLog(::arg().mustDo("query-logging"));
+ }
+ catch(SSqlException &e) {
+ L<<Logger::Error<<backendName<<" Connection failed: "<<e.txtReason()<<endl;
+ throw PDNSException(backendName+"Unable to launch connection: "+e.txtReason());
+ }
+
+ string rrtable=getArg("rr-table");
+ string soatable=getArg("soa-table");
+ string rrwhere=(mustDo("rr-active")?"(active = '1' or active = 'Y') and ":"")+getArg("rr-where");
+ string soawhere=(mustDo("soa-active")?"(active = '1' or active = 'Y') and ":"")+getArg("soa-where");
+
+ if (soatable.empty()) { throw PDNSException("SOA Table must not be empty"); }
+ if (rrtable.empty()) { throw PDNSException("Records table must not be empty"); }
+
+ d_useminimalttl=mustDo("use-minimal-ttl");
+ d_minimum=0;
+
+ L<<Logger::Warning<<backendName<<" Connection successful"<<endl;
+
+ try {
+
+ string domainIdQuery = "SELECT origin, minimum FROM `"+soatable+"` WHERE id = ?";
+ string domainNoIdQuery = "SELECT id, origin, minimum FROM `"+soatable+"` WHERE origin = ?";
+ string soaQuery = "SELECT id, mbox, serial, ns, refresh, retry, expire, minimum, ttl FROM `"+soatable+"` WHERE origin = ?";
+
+ if (!soawhere.empty()) {
+ domainIdQuery += " AND " + soawhere;
+ domainNoIdQuery += " AND " + soawhere;
+ soaQuery += " AND "+soawhere;
+ }
+
+ d_domainIdQuery_stmt = d_db->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<<Logger::Error<<"Cannot prepare statements: " << e.txtReason() <<endl;
+ throw PDNSException("Cannot prepare statements: " + e.txtReason());
+ }
}
MyDNSBackend::~MyDNSBackend() {
- if (d_db)
- delete(d_db);
+ delete d_domainIdQuery_stmt;
+ d_domainIdQuery_stmt = NULL;
+ delete d_domainNoIdQuery_stmt;
+ d_domainNoIdQuery_stmt = NULL;
+ delete d_listQuery_stmt;
+ d_listQuery_stmt = NULL;
+ delete d_soaQuery_stmt;
+ d_soaQuery_stmt = NULL;
+ delete d_basicQuery_stmt;
+ d_basicQuery_stmt = NULL;
+ delete d_anyQuery_stmt;
+ d_anyQuery_stmt = NULL;
+ delete(d_db);
}
-void MyDNSBackend::Query(const string &query) {
- try {
- d_db->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<<Logger::Warning<<backendName<<" Found more than one matching origin for zone ID: "<<zoneId<<endl;
- };
-
- query = "select type, data, aux, ttl, zone, name from "+d_rrtable+" where zone = ";
- query+=itoa(zoneId);
- if (!d_rrwhere.empty())
- query += " and "+d_rrwhere;
-
-
- this->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<<Logger::Warning<<backendName<<" Found more than one matching origin for zone ID: "<<zoneId<<endl;
+ };
+
+ try {
+ d_query_stmt = d_listQuery_stmt;
+ d_query_stmt->
+ 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<<Logger::Warning<<backendName<<" Found more than one matching zone for: "+name<<endl;
- };
-
- return true;
+ string query;
+ SSqlStatement::row_t rrow;
+
+ if (name.empty())
+ return false;
+
+ string dotname = name+".";
+
+ try {
+ d_soaQuery_stmt->
+ 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<<Logger::Warning<<backendName<<" Found more than one matching zone for: "+name<<endl;
+ };
+
+ return true;
}
void MyDNSBackend::lookup(const QType &qtype, const string &qname, DNSPacket *p, int zoneId) {
- string query;
- string sname;
- string zoneIdStr = itoa(zoneId);
- SSql::row_t rrow;
- bool found = false;
-
- d_origin = "";
-
- d_db->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<<Logger::Warning<<backendName<<" Found more than one matching zone for: "+d_origin<<endl;
- };
- // We found the zoneId, so we can work out how to find our rr
- string host;
-
- // The host part of the query is the name less the origin
- if (qname.length() == d_origin.length())
- host = "";
- else
- host = qname.substr(0, (qname.length() - d_origin.length())-1);
-
- if (host.find_first_of("'\\")!=string::npos)
- host=d_db->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<<Logger::Debug<<"MyDNSBackend::lookup(" << qtype.getName() << "," << qname << ",p," << zoneId << ")" << endl);
+
+ 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) {
+ try {
+ d_domainNoIdQuery_stmt->
+ 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<int>(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<<Logger::Warning<<backendName<<" Found more than one matching zone for: "+d_origin<<endl;
+ };
+ // We found the zoneId, so we can work out how to find our rr
+ string host;
+
+ // The host part of the query is the name less the origin
+ if (qname.length() == d_origin.length())
+ host = "";
+ else
+ host = qname.substr(0, (qname.length() - d_origin.length())-1);
+
+ try {
+
+ if (qtype.getCode()==QType::ANY) {
+ string dotqname = qname+".";
+ d_query_stmt = d_anyQuery_stmt;
+ d_query_stmt->
+ 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<<Logger::Debug<<"Running d_basicQuery_stmt with " << zoneId << ", " << host << ", " << sname << ", " << qtype.getName() << endl);
+ d_query_stmt = d_basicQuery_stmt;
+ d_query_stmt->
+ 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;
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 */
#include <sstream>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
+#include <boost/scoped_ptr.hpp>
+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());
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());
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());
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());
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());
{
/* 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());
/* 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());
/* 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());
}
}
-
-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)
{
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());
{
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());
{
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());
{
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());
bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, const std::string& zonename, set<string>& insert, set<string>& 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());
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());
}
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());
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())
{
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;
}
{
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());
{
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());
{
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());
{
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());
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());
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());
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();
}
{
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<<"'"<<val<<"'"<<endl;
+ //~ }
+ 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_ListDomainKeysQuery_stmt->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<<"'"<<val<<"'"<<endl;
- //~ }
- 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);
- }
return true;
}
bool GSQLBackend::getAllDomainMetadata(const string& name, std::map<std::string, std::vector<std::string> >& 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;
}
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;
}
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();
}
}
}
{
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());
{
DLOG(L<<"GSQLBackend constructing handle for list of domain id '"<<domain_id<<"'"<<endl);
- string query = (GSQLformat(d_listQuery)
- % (int)include_disabled
- % domain_id
- ).str();
-
try {
- d_db->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());
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());
return true;
}
+bool GSQLBackend::get(DNSResourceRecord &r)
+{
+ // L << "GSQLBackend get() was called for "<<qtype.getName() << " record: ";
+ SSqlStatement::row_t row;
+ if(d_query_stmt->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<DNSResourceRecord>&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<DNSResourceRecord>::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());
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());
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<string> 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]);
}
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());
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());
void GSQLBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled)
{
DLOG(L<<"GSQLBackend retrieving all domains."<<endl);
- string query = (GSQLformat(d_getAllDomainsQuery) % (int)include_disabled).str();
try {
- d_db->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 "<<qtype.getName() << " record: ";
- SSql::row_t row;
- if(d_db->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<DNSResourceRecord>& 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());
{
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());
pair<string,bool> 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());
if(!d_dnssecQueries)
return false;
- string ordername, query;
+ string ordername;
pair<string,bool> 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());
bool GSQLBackend::startTransaction(const string &domain, int domain_id)
{
- char output[1024];
- if(domain_id >= 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());
bool GSQLBackend::commitTransaction()
{
try {
- d_db->doCommand("commit");
+ d_db->commit();
}
catch (SSqlException &e) {
throw PDNSException("Database failed to commit transaction: "+e.txtReason());
bool GSQLBackend::abortTransaction()
{
try {
- d_db->doCommand("rollback");
+ d_db->rollback();
}
catch(SSqlException &e) {
throw PDNSException("Database failed to abort transaction: "+string(e.txtReason()));
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()<<endl);
return false;
}
-
- if (not d_result.empty()) {
+
+ if (!d_result.empty()) {
serial = atol(d_result[0][0].c_str());
return true;
}
bool GSQLBackend::listComments(const uint32_t domain_id)
{
- string query = (GSQLformat(d_ListCommentsQuery)
- % domain_id
- ).str();
-
try {
- d_db->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());
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];
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());
bool GSQLBackend::replaceComments(const uint32_t domain_id, const string& qname, const QType& qt, const vector<Comment>& 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());
return true;
}
+
+SSqlStatement::~SSqlStatement() {
+// make sure vtable won't break
+}
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);
private:
string d_qname;
SSql *d_db;
- SSql::result_t d_result;
+ SSqlStatement::result_t d_result;
string d_NoIdQuery;
string d_IdQuery;
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;
};
#include <string>
#include <vector>
#include "../../namespaces.hh"
-
+#include <inttypes.h>
class SSqlException
{
private:
string d_reason;
};
-
-class SSql
+
+class SSqlStatement
{
public:
typedef vector<string> row_t;
typedef vector<row_t> 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(){};
};
::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"] <<"'" <<endl;
::arg().set("soa-refresh-default","Default SOA refresh")="10800";
::arg().set("soa-retry-default","Default SOA retry")="3600";
::arg().set("soa-expire-default","Default SOA expire")="604800";
- ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
UeberBackend::go();
SSQLite3 db(cmds[1], true); // create=ok
vector<string> 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());
#include "misc.hh"
#include <unistd.h>
+/*
+** 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<<Logger::Warning<< "Query: " << sql << endl;
+}
+
+class SSQLite3Statement: public SSqlStatement
+{
+public:
+ SSQLite3Statement(SSQLite3 *db, bool dolog, const string& query)
+ {
+ const char *pTail;
+ this->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<<Logger::Warning<<"Sqlite3 command partially processed. Unprocessed part: "<<pTail<<endl;
+ }
+
+ int name2idx(const string& name) {
+ string zName = string(":")+name;
+ return sqlite3_bind_parameter_index(d_stmt, zName.c_str());
+ // XXX: support @ and $?
+ }
+
+ SSqlStatement* bind(const string& name, bool value) { int idx = name2idx(name); if (idx>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<numCols; i++)
+ {
+ if (sqlite3_column_type(d_stmt,i) == SQLITE_NULL) {
+ row.push_back("");
+ } else {
+ const char *pData = (const char*) sqlite3_column_text(d_stmt, i);
+ row.push_back(string(pData, sqlite3_column_bytes(d_stmt, i)));
+ }
+ }
+ d_rc = sqlite3_step(d_stmt);
+ return this;
+ }
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ while(hasNextRow()) {
+ row_t row;
+ nextRow(row);
+ result.push_back(row);
+ }
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ sqlite3_reset(d_stmt);
+#if SQLITE_VERSION_NUMBER >= 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 )
{
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;
}
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: "<<ret<<endl;
abort();
}
- else {
- sqlite3_finalize(m_pStmt);
- }
}
else
break;
}
}
-
-// Constructs a SSqlException object.
-SSqlException SSQLite3::sPerrorException( const std::string & reason )
-{
- return SSqlException( reason );
-}
-
-
-// Performs a query.
-int SSQLite3::doQuery( const std::string & query, result_t & result )
-{
- result.clear();
-
- doQuery( query );
-
- row_t row;
- while( getRow( row ))
- result.push_back( row );
-
- return result.size();
+SSqlStatement* SSQLite3::prepare(const string& query, int nparams __attribute__((unused))) {
+ return new SSQLite3Statement(this, m_dolog, query);
}
-
-// Performs a query.
-int SSQLite3::doQuery( const std::string & query )
-{
- const char *pTail;
-
- if(m_dolog)
- L<<Logger::Warning<<"Query: "<<query<<endl;
-
- // Execute the query.
-
-#if SQLITE_VERSION_NUMBER >= 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)
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 );
}
-
sqlite3_stmt *m_pStmt;
bool m_dolog;
-
+ bool m_in_transaction;
static int busyHandler(void*, int);
protected:
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 );
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
+if [ "x$NLS_LANG" = "x" ]; then
+ NLS_LANG="AMERICAN_AMERICA.AL32UTF8"
+fi
context=${context}-presigned-goracle
[ -z "$GORACLE2USER" ] && GORACLE2USER=pdns2
[ -z "$GORACLE2PASSWD" ] && GORACLE2PASSWD=pdns
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