]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/backends/gsql/gsqlbackend.cc
Include config.h only in .cc files
[thirdparty/pdns.git] / pdns / backends / gsql / gsqlbackend.cc
1 /*
2 PowerDNS Versatile Database Driven Nameserver
3 Copyright (C) 2002-2011 PowerDNS.COM BV
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation
8
9 Additionally, the license of this program contains a special
10 exception which allows to distribute the program in binary form when
11 it is linked against OpenSSL.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "pdns/dns.hh"
27 #include "pdns/dnsbackend.hh"
28 #include "gsqlbackend.hh"
29 #include "pdns/dnspacket.hh"
30 #include "pdns/ueberbackend.hh"
31 #include "pdns/pdnsexception.hh"
32 #include "pdns/logger.hh"
33 #include "pdns/arguments.hh"
34 #include "pdns/base32.hh"
35 #include "pdns/dnssecinfra.hh"
36 #include <boost/algorithm/string.hpp>
37 #include <sstream>
38 #include <boost/foreach.hpp>
39 #include <boost/format.hpp>
40 #include <boost/scoped_ptr.hpp>
41
42 GSQLBackend::GSQLBackend(const string &mode, const string &suffix)
43 {
44 setArgPrefix(mode+suffix);
45 d_db=0;
46 d_logprefix="["+mode+"Backend"+suffix+"] ";
47
48 try
49 {
50 d_dnssecQueries = mustDo("dnssec");
51 }
52 catch (ArgException e)
53 {
54 d_dnssecQueries = false;
55 }
56
57 d_NoIdQuery=getArg("basic-query");
58 d_IdQuery=getArg("id-query");
59 d_ANYNoIdQuery=getArg("any-query");
60 d_ANYIdQuery=getArg("any-id-query");
61
62 d_listQuery=getArg("list-query");
63 d_listSubZoneQuery=getArg("list-subzone-query");
64
65 d_MasterOfDomainsZoneQuery=getArg("master-zone-query");
66 d_InfoOfDomainsZoneQuery=getArg("info-zone-query");
67 d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query");
68 d_SuperMasterInfoQuery=getArg("supermaster-query");
69 d_GetSuperMasterIPs=getArg("supermaster-name-to-ips");
70 d_InsertZoneQuery=getArg("insert-zone-query");
71 d_InsertSlaveZoneQuery=getArg("insert-slave-query");
72 d_InsertRecordQuery=getArg("insert-record-query");
73 d_InsertEntQuery=getArg("insert-ent-query");
74 d_UpdateMasterOfZoneQuery=getArg("update-master-query");
75 d_UpdateKindOfZoneQuery=getArg("update-kind-query");
76 d_UpdateSerialOfZoneQuery=getArg("update-serial-query");
77 d_UpdateLastCheckofZoneQuery=getArg("update-lastcheck-query");
78 d_UpdateAccountOfZoneQuery=getArg("update-account-query");
79 d_ZoneLastChangeQuery=getArg("zone-lastchange-query");
80 d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query");
81 d_DeleteDomainQuery=getArg("delete-domain-query");
82 d_DeleteZoneQuery=getArg("delete-zone-query");
83 d_DeleteRRSetQuery=getArg("delete-rrset-query");
84 d_DeleteNamesQuery=getArg("delete-names-query");
85 d_getAllDomainsQuery=getArg("get-all-domains-query");
86
87 d_removeEmptyNonTerminalsFromZoneQuery = getArg("remove-empty-non-terminals-from-zone-query");
88 d_insertEmptyNonTerminalQuery = getArg("insert-empty-non-terminal-query");
89 d_deleteEmptyNonTerminalQuery = getArg("delete-empty-non-terminal-query");
90
91 d_ListCommentsQuery = getArg("list-comments-query");
92 d_InsertCommentQuery = getArg("insert-comment-query");
93 d_DeleteCommentRRsetQuery = getArg("delete-comment-rrset-query");
94 d_DeleteCommentsQuery = getArg("delete-comments-query");
95
96 d_InsertRecordOrderQuery=getArg("insert-record-order-query");
97 d_InsertEntOrderQuery=getArg("insert-ent-order-query");
98
99 d_firstOrderQuery = getArg("get-order-first-query");
100 d_beforeOrderQuery = getArg("get-order-before-query");
101 d_afterOrderQuery = getArg("get-order-after-query");
102 d_lastOrderQuery = getArg("get-order-last-query");
103 d_setOrderAuthQuery = getArg("set-order-and-auth-query");
104 d_nullifyOrderNameAndUpdateAuthQuery = getArg("nullify-ordername-and-update-auth-query");
105 d_nullifyOrderNameAndAuthQuery = getArg("nullify-ordername-and-auth-query");
106 d_setAuthOnDsRecordQuery = getArg("set-auth-on-ds-record-query");
107
108 d_AddDomainKeyQuery = getArg("add-domain-key-query");
109 d_ListDomainKeysQuery = getArg("list-domain-keys-query");
110
111 d_GetAllDomainMetadataQuery = getArg("get-all-domain-metadata-query");
112 d_GetDomainMetadataQuery = getArg("get-domain-metadata-query");
113 d_ClearDomainMetadataQuery = getArg("clear-domain-metadata-query");
114 d_ClearDomainAllMetadataQuery = getArg("clear-domain-all-metadata-query");
115 d_SetDomainMetadataQuery = getArg("set-domain-metadata-query");
116
117 d_ActivateDomainKeyQuery = getArg("activate-domain-key-query");
118 d_DeactivateDomainKeyQuery = getArg("deactivate-domain-key-query");
119 d_RemoveDomainKeyQuery = getArg("remove-domain-key-query");
120 d_ClearDomainAllKeysQuery = getArg("clear-domain-all-keys-query");
121
122 d_getTSIGKeyQuery = getArg("get-tsig-key-query");
123 d_setTSIGKeyQuery = getArg("set-tsig-key-query");
124 d_deleteTSIGKeyQuery = getArg("delete-tsig-key-query");
125 d_getTSIGKeysQuery = getArg("get-tsig-keys-query");
126
127 d_query_stmt = NULL;
128 d_NoIdQuery_stmt = NULL;
129 d_IdQuery_stmt = NULL;
130 d_ANYNoIdQuery_stmt = NULL;
131 d_ANYIdQuery_stmt = NULL;
132 d_listQuery_stmt = NULL;
133 d_listSubZoneQuery_stmt = NULL;
134 d_MasterOfDomainsZoneQuery_stmt = NULL;
135 d_InfoOfDomainsZoneQuery_stmt = NULL;
136 d_InfoOfAllSlaveDomainsQuery_stmt = NULL;
137 d_SuperMasterInfoQuery_stmt = NULL;
138 d_GetSuperMasterIPs_stmt = NULL;
139 d_InsertZoneQuery_stmt = NULL;
140 d_InsertSlaveZoneQuery_stmt = NULL;
141 d_InsertRecordQuery_stmt = NULL;
142 d_InsertEntQuery_stmt = NULL;
143 d_InsertRecordOrderQuery_stmt = NULL;
144 d_InsertEntOrderQuery_stmt = NULL;
145 d_UpdateMasterOfZoneQuery_stmt = NULL;
146 d_UpdateKindOfZoneQuery_stmt = NULL;
147 d_UpdateSerialOfZoneQuery_stmt = NULL;
148 d_UpdateLastCheckofZoneQuery_stmt = NULL;
149 d_UpdateAccountOfZoneQuery_stmt = NULL;
150 d_InfoOfAllMasterDomainsQuery_stmt = NULL;
151 d_DeleteDomainQuery_stmt = NULL;
152 d_DeleteZoneQuery_stmt = NULL;
153 d_DeleteRRSetQuery_stmt = NULL;
154 d_DeleteNamesQuery_stmt = NULL;
155 d_ZoneLastChangeQuery_stmt = NULL;
156 d_firstOrderQuery_stmt = NULL;
157 d_beforeOrderQuery_stmt = NULL;
158 d_afterOrderQuery_stmt = NULL;
159 d_lastOrderQuery_stmt = NULL;
160 d_setOrderAuthQuery_stmt = NULL;
161 d_nullifyOrderNameAndUpdateAuthQuery_stmt = NULL;
162 d_nullifyOrderNameAndAuthQuery_stmt = NULL;
163 d_nullifyOrderNameAndAuthENTQuery_stmt = NULL;
164 d_setAuthOnDsRecordQuery_stmt = NULL;
165 d_removeEmptyNonTerminalsFromZoneQuery_stmt = NULL;
166 d_insertEmptyNonTerminalQuery_stmt = NULL;
167 d_deleteEmptyNonTerminalQuery_stmt = NULL;
168 d_AddDomainKeyQuery_stmt = NULL;
169 d_ListDomainKeysQuery_stmt = NULL;
170 d_GetAllDomainMetadataQuery_stmt = NULL;
171 d_GetDomainMetadataQuery_stmt = NULL;
172 d_ClearDomainMetadataQuery_stmt = NULL;
173 d_ClearDomainAllMetadataQuery_stmt = NULL;
174 d_SetDomainMetadataQuery_stmt = NULL;
175 d_RemoveDomainKeyQuery_stmt = NULL;
176 d_ActivateDomainKeyQuery_stmt = NULL;
177 d_DeactivateDomainKeyQuery_stmt = NULL;
178 d_ClearDomainAllKeysQuery_stmt = NULL;
179 d_getTSIGKeyQuery_stmt = NULL;
180 d_setTSIGKeyQuery_stmt = NULL;
181 d_deleteTSIGKeyQuery_stmt = NULL;
182 d_getTSIGKeysQuery_stmt = NULL;
183 d_getAllDomainsQuery_stmt = NULL;
184 d_ListCommentsQuery_stmt = NULL;
185 d_InsertCommentQuery_stmt = NULL;
186 d_DeleteCommentRRsetQuery_stmt = NULL;
187 d_DeleteCommentsQuery_stmt = NULL;
188 }
189
190 void GSQLBackend::setNotified(uint32_t domain_id, uint32_t serial)
191 {
192 try {
193 d_UpdateSerialOfZoneQuery_stmt->
194 bind("serial", serial)->
195 bind("domain_id", domain_id)->
196 execute()->
197 reset();
198 }
199 catch(SSqlException &e) {
200 throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
201 }
202 }
203
204 void GSQLBackend::setFresh(uint32_t domain_id)
205 {
206 try {
207 d_UpdateLastCheckofZoneQuery_stmt->
208 bind("last_check", time(0))->
209 bind("domain_id", domain_id)->
210 execute()->
211 reset();
212 }
213 catch (SSqlException &e) {
214 throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
215 }
216 }
217
218 bool GSQLBackend::isMaster(const string &domain, const string &ip)
219 {
220 try {
221 d_MasterOfDomainsZoneQuery_stmt->
222 bind("domain", domain)->
223 execute()->
224 getResult(d_result)->
225 reset();
226 }
227 catch (SSqlException &e) {
228 throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason());
229 }
230
231 if(!d_result.empty()) {
232
233 // we can have multiple masters separated by commas
234 vector<string> masters;
235 stringtok(masters, d_result[0][0], " ,\t");
236
237 BOOST_FOREACH(const string master, masters) {
238 const ComboAddress caMaster(master);
239 if(ip == caMaster.toString())
240 return true;
241 }
242 }
243
244 // no matching master
245 return false;
246 }
247
248 bool GSQLBackend::setMaster(const string &domain, const string &ip)
249 {
250 try {
251 d_UpdateMasterOfZoneQuery_stmt->
252 bind("master", ip)->
253 bind("domain", toLower(domain))->
254 execute()->
255 reset();
256 }
257 catch (SSqlException &e) {
258 throw PDNSException("GSQLBackend unable to set master of domain \""+domain+"\": "+e.txtReason());
259 }
260 return true;
261 }
262
263 bool GSQLBackend::setKind(const string &domain, const DomainInfo::DomainKind kind)
264 {
265 try {
266 d_UpdateKindOfZoneQuery_stmt->
267 bind("kind", toUpper(DomainInfo::getKindString(kind)))->
268 bind("domain", toLower(domain))->
269 execute()->
270 reset();
271 }
272 catch (SSqlException &e) {
273 throw PDNSException("GSQLBackend unable to set kind of domain \""+domain+"\": "+e.txtReason());
274 }
275 return true;
276 }
277
278 bool GSQLBackend::setAccount(const string &domain, const string &account)
279 {
280 try {
281 d_UpdateAccountOfZoneQuery_stmt->
282 bind("account", account)->
283 bind("domain", toLower(domain))->
284 execute()->
285 reset();
286 }
287 catch (SSqlException &e) {
288 throw PDNSException("GSQLBackend unable to set account of domain \""+domain+"\": "+e.txtReason());
289 }
290 return true;
291 }
292
293 bool GSQLBackend::getDomainInfo(const string &domain, DomainInfo &di)
294 {
295 /* fill DomainInfo from database info:
296 id,name,master IP(s),last_check,notified_serial,type,account */
297 try {
298 d_InfoOfDomainsZoneQuery_stmt->
299 bind("domain", toLower(domain))->
300 execute()->
301 getResult(d_result)->
302 reset();
303 }
304 catch(SSqlException &e) {
305 throw PDNSException("GSQLBackend unable to retrieve information about a domain: "+e.txtReason());
306 }
307
308 int numanswers=d_result.size();
309 if(!numanswers)
310 return false;
311
312 di.id=atol(d_result[0][0].c_str());
313 di.zone=d_result[0][1];
314 stringtok(di.masters, d_result[0][2], " ,\t");
315 di.last_check=atol(d_result[0][3].c_str());
316 di.notified_serial = atol(d_result[0][4].c_str());
317 string type=d_result[0][5];
318 di.account=d_result[0][6];
319 di.backend=this;
320
321 di.serial = 0;
322 try {
323 SOAData sd;
324 if(!getSOA(domain,sd))
325 L<<Logger::Notice<<"No serial for '"<<domain<<"' found - zone is missing?"<<endl;
326 else
327 di.serial = sd.serial;
328 }
329 catch(PDNSException &ae){
330 L<<Logger::Error<<"Error retrieving serial for '"<<domain<<"': "<<ae.reason<<endl;
331 }
332
333 di.kind = DomainInfo::stringToKind(type);
334
335 return true;
336 }
337
338 void GSQLBackend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
339 {
340 /* list all domains that need refreshing for which we are slave, and insert into SlaveDomain:
341 id,name,master IP,serial */
342 try {
343 d_InfoOfAllSlaveDomainsQuery_stmt->
344 execute()->
345 getResult(d_result)->
346 reset();
347 }
348 catch (SSqlException &e) {
349 throw PDNSException("GSQLBackend unable to retrieve list of slave domains: "+e.txtReason());
350 }
351
352 vector<DomainInfo> allSlaves;
353 int numanswers=d_result.size();
354 for(int n=0;n<numanswers;++n) { // id,name,master,last_check
355 DomainInfo sd;
356 sd.id=atol(d_result[n][0].c_str());
357 sd.zone=d_result[n][1];
358 stringtok(sd.masters, d_result[n][2], ", \t");
359 sd.last_check=atol(d_result[n][3].c_str());
360 sd.backend=this;
361 sd.kind=DomainInfo::Slave;
362 allSlaves.push_back(sd);
363 }
364
365 for(vector<DomainInfo>::iterator i=allSlaves.begin();i!=allSlaves.end();++i) {
366 SOAData sdata;
367 sdata.serial=0;
368 sdata.refresh=0;
369 getSOA(i->zone,sdata);
370 if((time_t)(i->last_check+sdata.refresh) < time(0)) {
371 i->serial=sdata.serial;
372 unfreshDomains->push_back(*i);
373 }
374 }
375 }
376
377 void GSQLBackend::getUpdatedMasters(vector<DomainInfo> *updatedDomains)
378 {
379 /* list all domains that need notifications for which we are master, and insert into updatedDomains
380 id,name,master IP,serial */
381 try {
382 d_InfoOfAllMasterDomainsQuery_stmt->
383 execute()->
384 getResult(d_result)->
385 reset();
386 }
387 catch(SSqlException &e) {
388 throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason());
389 }
390
391 vector<DomainInfo> allMasters;
392 int numanswers=d_result.size();
393 for(int n=0;n<numanswers;++n) { // id,name,master,last_check
394 DomainInfo sd;
395 sd.id=atol(d_result[n][0].c_str());
396 sd.zone=d_result[n][1];
397 sd.last_check=atol(d_result[n][3].c_str());
398 sd.notified_serial=atoi(d_result[n][4].c_str());
399 sd.backend=this;
400 sd.kind=DomainInfo::Master;
401 allMasters.push_back(sd);
402 }
403
404 for(vector<DomainInfo>::iterator i=allMasters.begin();i!=allMasters.end();++i) {
405 SOAData sdata;
406 sdata.serial=0;
407 sdata.refresh=0;
408 getSOA(i->zone,sdata);
409 if(i->notified_serial!=sdata.serial) {
410 i->serial=sdata.serial;
411 updatedDomains->push_back(*i);
412 }
413 }
414 }
415
416 bool GSQLBackend::updateDNSSECOrderAndAuth(uint32_t domain_id, const std::string& zonename, const std::string& qname, bool auth)
417 {
418 if(!d_dnssecQueries)
419 return false;
420 string ins=toLower(labelReverse(makeRelative(qname, zonename)));
421 return this->updateDNSSECOrderAndAuthAbsolute(domain_id, qname, ins, auth);
422 }
423
424 bool GSQLBackend::updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const std::string& qname, const std::string& ordername, bool auth)
425 {
426 if(!d_dnssecQueries)
427 return false;
428
429 try {
430 d_setOrderAuthQuery_stmt->
431 bind("ordername", ordername)->
432 bind("auth", auth)->
433 bind("qname", qname)->
434 bind("domain_id", domain_id)->
435 execute()->
436 reset();
437 }
438 catch(SSqlException &e) {
439 throw PDNSException("GSQLBackend unable to update ordername/auth for domain_id "+itoa(domain_id)+": "+e.txtReason());
440 }
441 return true;
442 }
443
444 bool GSQLBackend::nullifyDNSSECOrderNameAndUpdateAuth(uint32_t domain_id, const std::string& qname, bool auth)
445 {
446 if(!d_dnssecQueries)
447 return false;
448
449 try {
450 d_nullifyOrderNameAndUpdateAuthQuery_stmt->
451 bind("auth", auth)->
452 bind("domain_id", domain_id)->
453 bind("qname", qname)->
454 execute()->
455 reset();
456 }
457 catch(SSqlException &e) {
458 throw PDNSException("GSQLBackend unable to nullify ordername and update auth for domain_id "+itoa(domain_id)+": "+e.txtReason());
459 }
460 return true;
461 }
462
463 bool GSQLBackend::nullifyDNSSECOrderNameAndAuth(uint32_t domain_id, const std::string& qname, const std::string& type)
464 {
465 if(!d_dnssecQueries)
466 return false;
467
468 try {
469 d_nullifyOrderNameAndAuthQuery_stmt->
470 bind("qname", qname)->
471 bind("qtype", type)->
472 bind("domain_id", domain_id)->
473 execute()->
474 reset();
475 }
476 catch(SSqlException &e) {
477 throw PDNSException("GSQLBackend unable to nullify ordername/auth for domain_id "+itoa(domain_id)+": "+e.txtReason());
478 }
479 return true;
480 }
481
482 bool GSQLBackend::setDNSSECAuthOnDsRecord(uint32_t domain_id, const std::string& qname)
483 {
484 if(!d_dnssecQueries)
485 return false;
486
487 try {
488 d_setAuthOnDsRecordQuery_stmt->
489 bind("domain_id", domain_id)->
490 bind("qname", qname)->
491 execute()->
492 reset();
493 }
494 catch(SSqlException &e) {
495 throw PDNSException("GSQLBackend unable to set auth on DS record "+qname+" for domain_id "+itoa(domain_id)+": "+e.txtReason());
496 }
497 return true;
498 }
499
500 bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, const std::string& zonename, set<string>& insert, set<string>& erase, bool remove)
501 {
502 if(remove) {
503 try {
504 d_removeEmptyNonTerminalsFromZoneQuery_stmt->
505 bind("domain_id", domain_id)->
506 execute()->
507 reset();
508 }
509 catch (SSqlException &e) {
510 throw PDNSException("GSQLBackend unable to delete empty non-terminal records from domain_id "+itoa(domain_id)+": "+e.txtReason());
511 return false;
512 }
513 }
514 else
515 {
516 BOOST_FOREACH(const string qname, erase) {
517 try {
518 d_deleteEmptyNonTerminalQuery_stmt->
519 bind("domain_id", domain_id)->
520 bind("qname", qname)->
521 execute()->
522 reset();
523 }
524 catch (SSqlException &e) {
525 throw PDNSException("GSQLBackend unable to delete empty non-terminal rr "+qname+" from domain_id "+itoa(domain_id)+": "+e.txtReason());
526 return false;
527 }
528 }
529 }
530
531 BOOST_FOREACH(const string qname, insert) {
532 try {
533 d_insertEmptyNonTerminalQuery_stmt->
534 bind("domain_id", domain_id)->
535 bind("qname", qname)->
536 execute()->
537 reset();
538 }
539 catch (SSqlException &e) {
540 throw PDNSException("GSQLBackend unable to insert empty non-terminal rr "+qname+" in domain_id "+itoa(domain_id)+": "+e.txtReason());
541 return false;
542 }
543 }
544
545 return true;
546 }
547
548 bool GSQLBackend::doesDNSSEC()
549 {
550 return d_dnssecQueries;
551 }
552
553 bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after)
554 {
555 if(!d_dnssecQueries)
556 return false;
557 // cerr<<"gsql before/after called for id="<<id<<", qname='"<<qname<<"'"<<endl;
558 after.clear();
559 string lcqname=toLower(qname);
560
561 SSqlStatement::row_t row;
562 try {
563 d_afterOrderQuery_stmt->
564 bind("ordername", lcqname)->
565 bind("domain_id", id)->
566 execute();
567 while(d_afterOrderQuery_stmt->hasNextRow()) {
568 d_afterOrderQuery_stmt->nextRow(row);
569 after=row[0];
570 }
571 d_afterOrderQuery_stmt->reset();
572 }
573 catch(SSqlException &e) {
574 throw PDNSException("GSQLBackend unable to find before/after (after) for domain_id "+itoa(id)+": "+e.txtReason());
575 }
576
577 if(after.empty() && !lcqname.empty()) {
578 try {
579 d_firstOrderQuery_stmt->
580 bind("domain_id", id)->
581 execute();
582 while(d_firstOrderQuery_stmt->hasNextRow()) {
583 d_firstOrderQuery_stmt->nextRow(row);
584 after=row[0];
585 }
586 d_firstOrderQuery_stmt->reset();
587 }
588 catch(SSqlException &e) {
589 throw PDNSException("GSQLBackend unable to find before/after (first) for domain_id "+itoa(id)+": "+e.txtReason());
590 }
591 }
592
593 if (before.empty()) {
594 unhashed.clear();
595
596 try {
597 d_beforeOrderQuery_stmt->
598 bind("ordername", lcqname)->
599 bind("domain_id", id)->
600 execute();
601 while(d_beforeOrderQuery_stmt->hasNextRow()) {
602 d_beforeOrderQuery_stmt->nextRow(row);
603 before=row[0];
604 unhashed=row[1];
605 }
606 d_beforeOrderQuery_stmt->reset();
607 }
608 catch(SSqlException &e) {
609 throw PDNSException("GSQLBackend unable to find before/after (before) for domain_id "+itoa(id)+": "+e.txtReason());
610 }
611
612 if(! unhashed.empty())
613 {
614 // cerr<<"unhashed="<<unhashed<<",before="<<before<<", after="<<after<<endl;
615 return true;
616 }
617
618 try {
619 d_lastOrderQuery_stmt->
620 bind("domain_id", id)->
621 execute();
622 while(d_lastOrderQuery_stmt->hasNextRow()) {
623 d_lastOrderQuery_stmt->nextRow(row);
624 before=row[0];
625 unhashed=row[1];
626 }
627 d_lastOrderQuery_stmt->reset();
628 }
629 catch(SSqlException &e) {
630 throw PDNSException("GSQLBackend unable to find before/after (last) for domain_id "+itoa(id)+": "+e.txtReason());
631 }
632 } else {
633 before=lcqname;
634 }
635
636 return true;
637 }
638
639 int GSQLBackend::addDomainKey(const string& name, const KeyData& key)
640 {
641 if(!d_dnssecQueries)
642 return -1;
643
644 try {
645 d_AddDomainKeyQuery_stmt->
646 bind("flags", key.flags)->
647 bind("active", key.active)->
648 bind("content", key.content)->
649 bind("domain", toLower(name))->
650 execute()->
651 reset();
652 }
653 catch (SSqlException &e) {
654 throw PDNSException("GSQLBackend unable to store key: "+e.txtReason());
655 }
656 return 1; // XXX FIXME, no idea how to get the id
657 }
658
659 bool GSQLBackend::activateDomainKey(const string& name, unsigned int id)
660 {
661 if(!d_dnssecQueries)
662 return false;
663
664 try {
665 d_ActivateDomainKeyQuery_stmt->
666 bind("domain", toLower(name))->
667 bind("key_id", id)->
668 execute()->
669 reset();
670 }
671 catch (SSqlException &e) {
672 throw PDNSException("GSQLBackend unable to activate key: "+e.txtReason());
673 }
674 return true;
675 }
676
677 bool GSQLBackend::deactivateDomainKey(const string& name, unsigned int id)
678 {
679 if(!d_dnssecQueries)
680 return false;
681
682 try {
683 d_DeactivateDomainKeyQuery_stmt->
684 bind("domain", toLower(name))->
685 bind("key_id", id)->
686 execute()->
687 reset();
688 }
689 catch (SSqlException &e) {
690 throw PDNSException("GSQLBackend unable to deactivate key: "+e.txtReason());
691 }
692 return true;
693 }
694
695 bool GSQLBackend::removeDomainKey(const string& name, unsigned int id)
696 {
697 if(!d_dnssecQueries)
698 return false;
699
700 try {
701 d_RemoveDomainKeyQuery_stmt->
702 bind("domain", toLower(name))->
703 bind("key_id", id)->
704 execute()->
705 reset();
706 }
707 catch (SSqlException &e) {
708 throw PDNSException("GSQLBackend unable to remove key: "+e.txtReason());
709 }
710 return true;
711 }
712
713 bool GSQLBackend::getTSIGKey(const string& name, string* algorithm, string* content)
714 {
715 try {
716 d_getTSIGKeyQuery_stmt->
717 bind("key_name", toLower(name))->
718 execute();
719
720 SSqlStatement::row_t row;
721
722 content->clear();
723 while(d_getTSIGKeyQuery_stmt->hasNextRow()) {
724 d_getTSIGKeyQuery_stmt->nextRow(row);
725 if(row.size() >= 2 && (algorithm->empty() || pdns_iequals(*algorithm, row[0]))) {
726 *algorithm = row[0];
727 *content = row[1];
728 }
729 }
730
731 d_getTSIGKeyQuery_stmt->reset();
732 }
733 catch (SSqlException &e) {
734 throw PDNSException("GSQLBackend unable to retrieve named TSIG key: "+e.txtReason());
735 }
736
737 return !content->empty();
738 }
739
740 bool GSQLBackend::setTSIGKey(const string& name, const string& algorithm, const string& content)
741 {
742 try {
743 d_setTSIGKeyQuery_stmt->
744 bind("key_name", toLower(name))->
745 bind("algorithm", toLower(algorithm))->
746 bind("content", content)->
747 execute()->
748 reset();
749 }
750 catch (SSqlException &e) {
751 throw PDNSException("GSQLBackend unable to store named TSIG key: "+e.txtReason());
752 }
753 return true;
754 }
755
756 bool GSQLBackend::deleteTSIGKey(const string& name)
757 {
758 try {
759 d_deleteTSIGKeyQuery_stmt->
760 bind("key_name", toLower(name))->
761 execute()->
762 reset();
763 }
764 catch (SSqlException &e) {
765 throw PDNSException("GSQLBackend unable to store named TSIG key: "+e.txtReason());
766 }
767 return true;
768 }
769
770 bool GSQLBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
771 {
772 try {
773 d_getTSIGKeysQuery_stmt->
774 execute();
775
776 SSqlStatement::row_t row;
777
778 while(d_getTSIGKeysQuery_stmt->hasNextRow()) {
779 d_getTSIGKeysQuery_stmt->nextRow(row);
780 struct TSIGKey key;
781 key.name = row[0];
782 key.algorithm = row[1];
783 key.key = row[2];
784 keys.push_back(key);
785 }
786
787 d_getTSIGKeysQuery_stmt->reset();
788 }
789 catch (SSqlException &e) {
790 throw PDNSException("GSQLBackend unable to retrieve TSIG keys: "+e.txtReason());
791 }
792
793 return keys.empty();
794 }
795
796 bool GSQLBackend::getDomainKeys(const string& name, unsigned int kind, std::vector<KeyData>& keys)
797 {
798 if(!d_dnssecQueries)
799 return false;
800
801 try {
802 d_ListDomainKeysQuery_stmt->
803 bind("domain", toLower(name))->
804 execute();
805
806 SSqlStatement::row_t row;
807 // "select id, kind, active, content from domains, cryptokeys where domain_id=domains.id and name='%s'";
808 KeyData kd;
809 while(d_ListDomainKeysQuery_stmt->hasNextRow()) {
810 d_ListDomainKeysQuery_stmt->nextRow(row);
811 //~ BOOST_FOREACH(const std::string& val, row) {
812 //~ cerr<<"'"<<val<<"'"<<endl;
813 //~ }
814 kd.id = atoi(row[0].c_str());
815 kd.flags = atoi(row[1].c_str());
816 kd.active = atoi(row[2].c_str());
817 kd.content = row[3];
818 keys.push_back(kd);
819 }
820
821 d_ListDomainKeysQuery_stmt->reset();
822 }
823 catch (SSqlException &e) {
824 throw PDNSException("GSQLBackend unable to list keys: "+e.txtReason());
825 }
826
827 return true;
828 }
829
830 void GSQLBackend::alsoNotifies(const string &domain, set<string> *ips)
831 {
832 vector<string> meta;
833 getDomainMetadata(domain, "ALSO-NOTIFY", meta);
834 BOOST_FOREACH(string& str, meta) {
835 ips->insert(str);
836 }
837 }
838
839 bool GSQLBackend::getAllDomainMetadata(const string& name, std::map<std::string, std::vector<std::string> >& meta)
840 {
841 try {
842 d_GetAllDomainMetadataQuery_stmt->
843 bind("domain", toLower(name))->
844 execute();
845
846 SSqlStatement::row_t row;
847
848 while(d_GetAllDomainMetadataQuery_stmt->hasNextRow()) {
849 d_GetAllDomainMetadataQuery_stmt->nextRow(row);
850 if (!isDnssecDomainMetadata(row[0]))
851 meta[row[0]].push_back(row[1]);
852 }
853
854 d_GetAllDomainMetadataQuery_stmt->reset();
855 }
856 catch (SSqlException &e) {
857 throw PDNSException("GSQLBackend unable to list metadata: "+e.txtReason());
858 }
859
860 return true;
861 }
862
863
864 bool GSQLBackend::getDomainMetadata(const string& name, const std::string& kind, std::vector<std::string>& meta)
865 {
866 if(!d_dnssecQueries && isDnssecDomainMetadata(kind))
867 return false;
868
869 try {
870 d_GetDomainMetadataQuery_stmt->
871 bind("domain", toLower(name))->
872 bind("kind", kind)->
873 execute();
874
875 SSqlStatement::row_t row;
876
877 while(d_GetDomainMetadataQuery_stmt->hasNextRow()) {
878 d_GetDomainMetadataQuery_stmt->nextRow(row);
879 meta.push_back(row[0]);
880 }
881
882 d_GetDomainMetadataQuery_stmt->reset();
883 }
884 catch (SSqlException &e) {
885 throw PDNSException("GSQLBackend unable to list metadata: "+e.txtReason());
886 }
887
888 return true;
889 }
890
891 bool GSQLBackend::setDomainMetadata(const string& name, const std::string& kind, const std::vector<std::string>& meta)
892 {
893 if(!d_dnssecQueries && isDnssecDomainMetadata(kind))
894 return false;
895
896 try {
897 d_ClearDomainMetadataQuery_stmt->
898 bind("domain", toLower(name))->
899 bind("kind", kind)->
900 execute()->
901 reset();
902 if(!meta.empty()) {
903 BOOST_FOREACH(const std::string & value, meta) {
904 d_SetDomainMetadataQuery_stmt->
905 bind("kind", kind)->
906 bind("content", value)->
907 bind("domain", toLower(name))->
908 execute()->
909 reset();
910 }
911 }
912 }
913 catch (SSqlException &e) {
914 throw PDNSException("GSQLBackend unable to store metadata key: "+e.txtReason());
915 }
916
917 return true;
918 }
919
920 void GSQLBackend::lookup(const QType &qtype,const string &qname, DNSPacket *pkt_p, int domain_id)
921 {
922 string lcqname=toLower(qname);
923
924 try {
925 if(qtype.getCode()!=QType::ANY) {
926 if(domain_id < 0) {
927 d_query_stmt = d_NoIdQuery_stmt;
928 d_query_stmt->
929 bind("qtype", qtype.getName())->
930 bind("qname", lcqname);
931 } else {
932 d_query_stmt = d_IdQuery_stmt;
933 d_query_stmt->
934 bind("qtype", qtype.getName())->
935 bind("qname", lcqname)->
936 bind("domain_id", domain_id);
937 }
938 } else {
939 // qtype==ANY
940 if(domain_id < 0) {
941 d_query_stmt = d_ANYNoIdQuery_stmt;
942 d_query_stmt->
943 bind("qname", lcqname);
944 } else {
945 d_query_stmt = d_ANYIdQuery_stmt;
946 d_query_stmt->
947 bind("qname", lcqname)->
948 bind("domain_id", domain_id);
949 }
950 }
951
952 d_query_stmt->
953 execute();
954 }
955 catch(SSqlException &e) {
956 throw PDNSException("GSQLBackend lookup query:"+e.txtReason());
957 }
958
959 d_qname=qname;
960 }
961
962 bool GSQLBackend::list(const string &target, int domain_id, bool include_disabled)
963 {
964 DLOG(L<<"GSQLBackend constructing handle for list of domain id '"<<domain_id<<"'"<<endl);
965
966 try {
967 d_query_stmt = d_listQuery_stmt;
968 d_query_stmt->
969 bind("include_disabled", (int)include_disabled)->
970 bind("domain_id", domain_id)->
971 execute();
972 }
973 catch(SSqlException &e) {
974 throw PDNSException("GSQLBackend list query: "+e.txtReason());
975 }
976
977 d_qname="";
978 return true;
979 }
980
981 bool GSQLBackend::listSubZone(const string &zone, int domain_id) {
982 string wildzone = "%." + zone;
983
984 try {
985 d_query_stmt = d_listSubZoneQuery_stmt;
986 d_query_stmt->
987 bind("zone", zone)->
988 bind("wildzone", wildzone)->
989 bind("domain_id", domain_id)->
990 execute();
991 }
992 catch(SSqlException &e) {
993 throw PDNSException("GSQLBackend listSubZone query: "+e.txtReason());
994 }
995 d_qname="";
996 return true;
997 }
998
999 bool GSQLBackend::get(DNSResourceRecord &r)
1000 {
1001 // L << "GSQLBackend get() was called for "<<qtype.getName() << " record: ";
1002 SSqlStatement::row_t row;
1003 if(d_query_stmt->hasNextRow()) {
1004 try {
1005 d_query_stmt->nextRow(row);
1006 } catch (SSqlException &e) {
1007 throw PDNSException("GSQLBackend get: "+e.txtReason());
1008 }
1009 if (row[1].empty())
1010 r.ttl = ::arg().asNum( "default-ttl" );
1011 else
1012 r.ttl=atol(row[1].c_str());
1013 if(!d_qname.empty())
1014 r.qname=d_qname;
1015 else
1016 r.qname=row[6];
1017 r.qtype=row[3];
1018
1019 if (r.qtype==QType::MX || r.qtype==QType::SRV)
1020 r.content=row[2]+" "+row[0];
1021 else
1022 r.content=row[0];
1023
1024 r.last_modified=0;
1025
1026 if(d_dnssecQueries)
1027 r.auth = !row[7].empty() && row[7][0]=='1';
1028 else
1029 r.auth = 1;
1030
1031 r.disabled = !row[5].empty() && row[5][0]=='1';
1032
1033 r.domain_id=atoi(row[4].c_str());
1034 return true;
1035 }
1036
1037 try {
1038 d_query_stmt->reset();
1039 } catch (SSqlException &e) {
1040 throw PDNSException("GSQLBackend get: "+e.txtReason());
1041 }
1042 d_query_stmt = NULL;
1043 return false;
1044 }
1045
1046 bool GSQLBackend::superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **ddb)
1047 {
1048 // check if we know the ip/ns couple in the database
1049 for(vector<DNSResourceRecord>::const_iterator i=nsset.begin();i!=nsset.end();++i) {
1050 try {
1051 d_SuperMasterInfoQuery_stmt->
1052 bind("ip", ip)->
1053 bind("nameserver", i->content)->
1054 execute()->
1055 getResult(d_result)->
1056 reset();
1057 }
1058 catch (SSqlException &e) {
1059 throw PDNSException("GSQLBackend unable to search for a domain: "+e.txtReason());
1060 }
1061
1062 if(!d_result.empty()) {
1063 *nameserver=i->content;
1064 *account=d_result[0][0];
1065 *ddb=this;
1066 return true;
1067 }
1068 }
1069 return false;
1070 }
1071
1072 bool GSQLBackend::createDomain(const string &domain)
1073 {
1074 try {
1075 d_InsertZoneQuery_stmt->
1076 bind("domain", toLower(domain))->
1077 execute()->
1078 reset();
1079 }
1080 catch(SSqlException &e) {
1081 throw PDNSException("Database error trying to insert new domain '"+domain+"': "+ e.txtReason());
1082 }
1083 return true;
1084 }
1085
1086 bool GSQLBackend::createSlaveDomain(const string &ip, const string &domain, const string &nameserver, const string &account)
1087 {
1088 string name;
1089 string masters(ip);
1090 try {
1091 if (!nameserver.empty()) {
1092 // figure out all IP addresses for the master
1093 d_GetSuperMasterIPs_stmt->
1094 bind("nameserver", nameserver)->
1095 bind("account", account)->
1096 execute()->
1097 getResult(d_result)->
1098 reset();
1099 if (!d_result.empty()) {
1100 // collect all IP addresses
1101 vector<string> tmp;
1102 BOOST_FOREACH(SSqlStatement::row_t& row, d_result) {
1103 if (account == row[1])
1104 tmp.push_back(row[0]);
1105 }
1106 // set them as domain's masters, comma separated
1107 masters = boost::join(tmp, ", ");
1108 }
1109 }
1110 d_InsertSlaveZoneQuery_stmt->
1111 bind("domain", toLower(domain))->
1112 bind("masters", masters)->
1113 bind("account", account)->
1114 execute()->
1115 reset();
1116 }
1117 catch(SSqlException &e) {
1118 throw PDNSException("Database error trying to insert new slave domain '"+domain+"': "+ e.txtReason());
1119 }
1120 return true;
1121 }
1122
1123 bool GSQLBackend::deleteDomain(const string &domain)
1124 {
1125 DomainInfo di;
1126 if (!getDomainInfo(domain, di)) {
1127 return false;
1128 }
1129
1130 try {
1131 d_DeleteZoneQuery_stmt->
1132 bind("domain_id", di.id)->
1133 execute()->
1134 reset();
1135 d_ClearDomainAllMetadataQuery_stmt->
1136 bind("domain", toLower(domain))->
1137 execute()->
1138 reset();
1139 d_ClearDomainAllKeysQuery_stmt->
1140 bind("domain", toLower(domain))->
1141 execute()->
1142 reset();
1143 d_DeleteCommentsQuery_stmt->
1144 bind("domain_id", di.id)->
1145 execute()->
1146 reset();
1147 d_DeleteDomainQuery_stmt->
1148 bind("domain", toLower(domain))->
1149 execute()->
1150 reset();
1151 }
1152 catch(SSqlException &e) {
1153 throw PDNSException("Database error trying to delete domain '"+domain+"': "+ e.txtReason());
1154 }
1155 return true;
1156 }
1157
1158 void GSQLBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled)
1159 {
1160 DLOG(L<<"GSQLBackend retrieving all domains."<<endl);
1161
1162 try {
1163 d_getAllDomainsQuery_stmt->
1164 bind("include_disabled", (int)include_disabled)->
1165 execute();
1166
1167 SSqlStatement::row_t row;
1168 while (d_getAllDomainsQuery_stmt->hasNextRow()) {
1169 d_getAllDomainsQuery_stmt->nextRow(row);
1170 DomainInfo di;
1171 di.id = atol(row[0].c_str());
1172 di.zone = row[1];
1173
1174 if (!row[4].empty()) {
1175 stringtok(di.masters, row[4], " ,\t");
1176 }
1177
1178 SOAData sd;
1179 fillSOAData(row[2], sd);
1180 di.serial = sd.serial;
1181 di.notified_serial = atol(row[5].c_str());
1182 di.last_check = atol(row[6].c_str());
1183 di.account = row[7];
1184
1185 if (pdns_iequals(row[3], "MASTER"))
1186 di.kind = DomainInfo::Master;
1187 else if (pdns_iequals(row[3], "SLAVE"))
1188 di.kind = DomainInfo::Slave;
1189 else
1190 di.kind = DomainInfo::Native;
1191
1192 di.backend = this;
1193
1194 domains->push_back(di);
1195 }
1196 d_getAllDomainsQuery_stmt->reset();
1197 }
1198 catch (SSqlException &e) {
1199 throw PDNSException("Database error trying to retrieve all domains:" + e.txtReason());
1200 }
1201 }
1202
1203 bool GSQLBackend::replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
1204 {
1205 try {
1206 if (qt != QType::ANY) {
1207 d_DeleteRRSetQuery_stmt->
1208 bind("domain_id", domain_id)->
1209 bind("qname", qname)->
1210 bind("qtype", qt.getName())->
1211 execute()->
1212 reset();
1213 } else {
1214 d_DeleteNamesQuery_stmt->
1215 bind("domain_id", domain_id)->
1216 bind("qname", qname)->
1217 execute()->
1218 reset();
1219 }
1220 }
1221 catch (SSqlException &e) {
1222 throw PDNSException("GSQLBackend unable to delete RRSet: "+e.txtReason());
1223 }
1224
1225 if (rrset.empty()) {
1226 try {
1227 d_DeleteCommentRRsetQuery_stmt->
1228 bind("domain_id", domain_id)->
1229 bind("qname", qname)->
1230 bind("qtype", qt.getName())->
1231 execute()->
1232 reset();
1233 }
1234 catch (SSqlException &e) {
1235 throw PDNSException("GSQLBackend unable to delete comment: "+e.txtReason());
1236 }
1237 }
1238 BOOST_FOREACH(const DNSResourceRecord& rr, rrset) {
1239 feedRecord(rr);
1240 }
1241
1242 return true;
1243 }
1244
1245 bool GSQLBackend::feedRecord(const DNSResourceRecord &r, string *ordername)
1246 {
1247 int prio=0;
1248 string content(r.content);
1249 if (r.qtype == QType::MX || r.qtype == QType::SRV) {
1250 prio=atoi(content.c_str());
1251 string::size_type pos = content.find_first_not_of("0123456789");
1252 if(pos != string::npos)
1253 boost::erase_head(content, pos);
1254 trim_left(content);
1255 }
1256
1257 try {
1258 if(d_dnssecQueries && ordername)
1259 {
1260 d_InsertRecordOrderQuery_stmt->
1261 bind("content",content)->
1262 bind("ttl",r.ttl)->
1263 bind("priority",prio)->
1264 bind("qtype",r.qtype.getName())->
1265 bind("domain_id",r.domain_id)->
1266 bind("disabled",r.disabled)->
1267 bind("qname",toLower(r.qname));
1268 if (ordername == NULL)
1269 d_InsertRecordOrderQuery_stmt->bindNull("ordername");
1270 else
1271 d_InsertRecordOrderQuery_stmt->bind("ordername",*ordername);
1272 d_InsertRecordOrderQuery_stmt->
1273 bind("auth",r.auth)->
1274 execute()->
1275 reset();
1276 }
1277 else
1278 {
1279 d_InsertRecordQuery_stmt->
1280 bind("content",content)->
1281 bind("ttl",r.ttl)->
1282 bind("priority",prio)->
1283 bind("qtype",r.qtype.getName())->
1284 bind("domain_id",r.domain_id)->
1285 bind("disabled",r.disabled)->
1286 bind("qname",toLower(r.qname))->
1287 bind("auth", (r.auth || !d_dnssecQueries))->
1288 execute()->
1289 reset();
1290 }
1291 }
1292 catch (SSqlException &e) {
1293 throw PDNSException("GSQLBackend unable to feed record: "+e.txtReason());
1294 }
1295 return true; // XXX FIXME this API should not return 'true' I think -ahu
1296 }
1297
1298 bool GSQLBackend::feedEnts(int domain_id, map<string,bool>& nonterm)
1299 {
1300 string query;
1301 pair<string,bool> nt;
1302
1303 BOOST_FOREACH(nt, nonterm) {
1304 try {
1305 d_InsertEntQuery_stmt->
1306 bind("domain_id",domain_id)->
1307 bind("qname",toLower(nt.first))->
1308 bind("auth",(nt.second || !d_dnssecQueries))->
1309 execute()->
1310 reset();
1311 }
1312 catch (SSqlException &e) {
1313 throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e.txtReason());
1314 }
1315 }
1316 return true;
1317 }
1318
1319 bool GSQLBackend::feedEnts3(int domain_id, const string &domain, map<string,bool> &nonterm, unsigned int times, const string &salt, bool narrow)
1320 {
1321 if(!d_dnssecQueries)
1322 return false;
1323
1324 string ordername;
1325 pair<string,bool> nt;
1326
1327 BOOST_FOREACH(nt, nonterm) {
1328 try {
1329 if(narrow || !nt.second) {
1330 d_InsertEntQuery_stmt->
1331 bind("domain_id",domain_id)->
1332 bind("qname",toLower(nt.first))->
1333 bind("auth", nt.second)->
1334 execute()->
1335 reset();
1336 } else {
1337 ordername=toBase32Hex(hashQNameWithSalt(times, salt, nt.first));
1338 d_InsertEntOrderQuery_stmt->
1339 bind("domain_id",domain_id)->
1340 bind("qname",toLower(nt.first))->
1341 bind("ordername",toLower(ordername))->
1342 bind("auth",nt.second)->
1343 execute()->
1344 reset();
1345 }
1346 }
1347 catch (SSqlException &e) {
1348 throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e.txtReason());
1349 }
1350 }
1351 return true;
1352 }
1353
1354 bool GSQLBackend::startTransaction(const string &domain, int domain_id)
1355 {
1356 try {
1357 d_db->startTransaction();
1358 if(domain_id >= 0) {
1359 d_DeleteZoneQuery_stmt->
1360 bind("domain_id", domain_id)->
1361 execute()->
1362 reset();
1363 }
1364 }
1365 catch (SSqlException &e) {
1366 throw PDNSException("Database failed to start transaction: "+e.txtReason());
1367 }
1368
1369 return true;
1370 }
1371
1372 bool GSQLBackend::commitTransaction()
1373 {
1374 try {
1375 d_db->commit();
1376 }
1377 catch (SSqlException &e) {
1378 throw PDNSException("Database failed to commit transaction: "+e.txtReason());
1379 }
1380 return true;
1381 }
1382
1383 bool GSQLBackend::abortTransaction()
1384 {
1385 try {
1386 d_db->rollback();
1387 }
1388 catch(SSqlException &e) {
1389 throw PDNSException("Database failed to abort transaction: "+string(e.txtReason()));
1390 }
1391 return true;
1392 }
1393
1394 bool GSQLBackend::calculateSOASerial(const string& domain, const SOAData& sd, time_t& serial)
1395 {
1396 if (d_ZoneLastChangeQuery.empty()) {
1397 // query not set => fall back to default impl
1398 return DNSBackend::calculateSOASerial(domain, sd, serial);
1399 }
1400
1401 try {
1402 d_ZoneLastChangeQuery_stmt->
1403 bind("domain_id", sd.domain_id)->
1404 execute()->
1405 getResult(d_result)->
1406 reset();
1407 }
1408 catch (const SSqlException& e) {
1409 //DLOG(L<<"GSQLBackend unable to calculate SOA serial: " << e.txtReason()<<endl);
1410 return false;
1411 }
1412
1413 if (!d_result.empty()) {
1414 serial = atol(d_result[0][0].c_str());
1415 return true;
1416 }
1417
1418 return false;
1419 }
1420
1421 bool GSQLBackend::listComments(const uint32_t domain_id)
1422 {
1423 try {
1424 d_query_stmt = d_ListCommentsQuery_stmt;
1425 d_query_stmt->
1426 bind("domain_id", domain_id)->
1427 execute();
1428 }
1429 catch(SSqlException &e) {
1430 throw PDNSException("GSQLBackend list comments query: "+e.txtReason());
1431 }
1432
1433 return true;
1434 }
1435
1436 bool GSQLBackend::getComment(Comment& comment)
1437 {
1438 SSqlStatement::row_t row;
1439
1440 if (!d_query_stmt->hasNextRow()) {
1441 try {
1442 d_query_stmt->reset();
1443 } catch(SSqlException &e) {
1444 throw PDNSException("GSQLBackend comment get: "+e.txtReason());
1445 }
1446 d_query_stmt = NULL;
1447 return false;
1448 }
1449
1450 try {
1451 d_query_stmt->nextRow(row);
1452 } catch(SSqlException &e) {
1453 throw PDNSException("GSQLBackend comment get: "+e.txtReason());
1454 }
1455 // domain_id,name,type,modified_at,account,comment
1456 comment.domain_id = atol(row[0].c_str());
1457 comment.qname = row[1];
1458 comment.qtype = row[2];
1459 comment.modified_at = atol(row[3].c_str());
1460 comment.account = row[4];
1461 comment.content = row[5];
1462
1463 return true;
1464 }
1465
1466 void GSQLBackend::feedComment(const Comment& comment)
1467 {
1468 try {
1469 d_InsertCommentQuery_stmt->
1470 bind("domain_id",comment.domain_id)->
1471 bind("qname",toLower(comment.qname))->
1472 bind("qtype",comment.qtype.getName())->
1473 bind("modified_at",comment.modified_at)->
1474 bind("account",comment.account)->
1475 bind("content",comment.content)->
1476 execute()->
1477 reset();
1478 }
1479 catch (SSqlException &e) {
1480 throw PDNSException("GSQLBackend unable to feed comment: "+e.txtReason());
1481 }
1482 }
1483
1484 bool GSQLBackend::replaceComments(const uint32_t domain_id, const string& qname, const QType& qt, const vector<Comment>& comments)
1485 {
1486 try {
1487 d_DeleteCommentRRsetQuery_stmt->
1488 bind("domain_id",domain_id)->
1489 bind("qname",toLower(qname))->
1490 bind("qtype",qt.getName())->
1491 execute()->
1492 reset();
1493 }
1494 catch (SSqlException &e) {
1495 throw PDNSException("GSQLBackend unable to delete comment: "+e.txtReason());
1496 }
1497
1498 BOOST_FOREACH(const Comment& comment, comments) {
1499 feedComment(comment);
1500 }
1501
1502 return true;
1503 }
1504
1505 SSqlStatement::~SSqlStatement() {
1506 // make sure vtable won't break
1507 }