2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
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.
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "pdns/dns.hh"
26 #include "pdns/dnsbackend.hh"
27 #include "gsqlbackend.hh"
28 #include "pdns/dnspacket.hh"
29 #include "pdns/pdnsexception.hh"
30 #include "pdns/logger.hh"
31 #include "pdns/arguments.hh"
32 #include "pdns/base32.hh"
33 #include "pdns/dnssecinfra.hh"
34 #include <boost/algorithm/string.hpp>
36 #include <boost/format.hpp>
37 #include <boost/scoped_ptr.hpp>
39 #define ASSERT_ROW_COLUMNS(query, row, num) { if (row.size() != num) { throw PDNSException(std::string(query) + " returned wrong number of columns, expected " #num ", got " + std::to_string(row.size())); } }
41 GSQLBackend::GSQLBackend(const string
&mode
, const string
&suffix
)
43 setArgPrefix(mode
+suffix
);
45 d_logprefix
="["+mode
+"Backend"+suffix
+"] ";
49 d_dnssecQueries
= mustDo("dnssec");
51 catch (const ArgException
&)
53 d_dnssecQueries
= false;
56 d_NoIdQuery
=getArg("basic-query");
57 d_IdQuery
=getArg("id-query");
58 d_ANYNoIdQuery
=getArg("any-query");
59 d_ANYIdQuery
=getArg("any-id-query");
61 d_listQuery
=getArg("list-query");
62 d_listSubZoneQuery
=getArg("list-subzone-query");
64 d_InfoOfDomainsZoneQuery
=getArg("info-zone-query");
65 d_InfoOfAllSlaveDomainsQuery
=getArg("info-all-slaves-query");
66 d_SuperMasterInfoQuery
=getArg("supermaster-query");
67 d_GetSuperMasterIPs
=getArg("supermaster-name-to-ips");
68 d_InsertZoneQuery
=getArg("insert-zone-query");
69 d_InsertRecordQuery
=getArg("insert-record-query");
70 d_UpdateMasterOfZoneQuery
=getArg("update-master-query");
71 d_UpdateKindOfZoneQuery
=getArg("update-kind-query");
72 d_UpdateSerialOfZoneQuery
=getArg("update-serial-query");
73 d_UpdateLastCheckofZoneQuery
=getArg("update-lastcheck-query");
74 d_UpdateAccountOfZoneQuery
=getArg("update-account-query");
75 d_InfoOfAllMasterDomainsQuery
=getArg("info-all-master-query");
76 d_DeleteDomainQuery
=getArg("delete-domain-query");
77 d_DeleteZoneQuery
=getArg("delete-zone-query");
78 d_DeleteRRSetQuery
=getArg("delete-rrset-query");
79 d_DeleteNamesQuery
=getArg("delete-names-query");
80 d_getAllDomainsQuery
=getArg("get-all-domains-query");
82 d_InsertEmptyNonTerminalOrderQuery
=getArg("insert-empty-non-terminal-order-query");
83 d_DeleteEmptyNonTerminalQuery
= getArg("delete-empty-non-terminal-query");
84 d_RemoveEmptyNonTerminalsFromZoneQuery
= getArg("remove-empty-non-terminals-from-zone-query");
86 d_ListCommentsQuery
= getArg("list-comments-query");
87 d_InsertCommentQuery
= getArg("insert-comment-query");
88 d_DeleteCommentRRsetQuery
= getArg("delete-comment-rrset-query");
89 d_DeleteCommentsQuery
= getArg("delete-comments-query");
91 d_firstOrderQuery
= getArg("get-order-first-query");
92 d_beforeOrderQuery
= getArg("get-order-before-query");
93 d_afterOrderQuery
= getArg("get-order-after-query");
94 d_lastOrderQuery
= getArg("get-order-last-query");
96 d_updateOrderNameAndAuthQuery
= getArg("update-ordername-and-auth-query");
97 d_updateOrderNameAndAuthTypeQuery
= getArg("update-ordername-and-auth-type-query");
98 d_nullifyOrderNameAndUpdateAuthQuery
= getArg("nullify-ordername-and-update-auth-query");
99 d_nullifyOrderNameAndUpdateAuthTypeQuery
= getArg("nullify-ordername-and-update-auth-type-query");
101 d_AddDomainKeyQuery
= getArg("add-domain-key-query");
102 d_GetLastInsertedKeyIdQuery
= getArg("get-last-inserted-key-id-query");
103 d_ListDomainKeysQuery
= getArg("list-domain-keys-query");
105 d_GetAllDomainMetadataQuery
= getArg("get-all-domain-metadata-query");
106 d_GetDomainMetadataQuery
= getArg("get-domain-metadata-query");
107 d_ClearDomainMetadataQuery
= getArg("clear-domain-metadata-query");
108 d_ClearDomainAllMetadataQuery
= getArg("clear-domain-all-metadata-query");
109 d_SetDomainMetadataQuery
= getArg("set-domain-metadata-query");
111 d_ActivateDomainKeyQuery
= getArg("activate-domain-key-query");
112 d_DeactivateDomainKeyQuery
= getArg("deactivate-domain-key-query");
113 d_RemoveDomainKeyQuery
= getArg("remove-domain-key-query");
114 d_ClearDomainAllKeysQuery
= getArg("clear-domain-all-keys-query");
116 d_getTSIGKeyQuery
= getArg("get-tsig-key-query");
117 d_setTSIGKeyQuery
= getArg("set-tsig-key-query");
118 d_deleteTSIGKeyQuery
= getArg("delete-tsig-key-query");
119 d_getTSIGKeysQuery
= getArg("get-tsig-keys-query");
121 d_SearchRecordsQuery
= getArg("search-records-query");
122 d_SearchCommentsQuery
= getArg("search-comments-query");
125 d_NoIdQuery_stmt
= NULL
;
126 d_IdQuery_stmt
= NULL
;
127 d_ANYNoIdQuery_stmt
= NULL
;
128 d_ANYIdQuery_stmt
= NULL
;
129 d_listQuery_stmt
= NULL
;
130 d_listSubZoneQuery_stmt
= NULL
;
131 d_InfoOfDomainsZoneQuery_stmt
= NULL
;
132 d_InfoOfAllSlaveDomainsQuery_stmt
= NULL
;
133 d_SuperMasterInfoQuery_stmt
= NULL
;
134 d_GetSuperMasterIPs_stmt
= NULL
;
135 d_InsertZoneQuery_stmt
= NULL
;
136 d_InsertRecordQuery_stmt
= NULL
;
137 d_InsertEmptyNonTerminalOrderQuery_stmt
= NULL
;
138 d_UpdateMasterOfZoneQuery_stmt
= NULL
;
139 d_UpdateKindOfZoneQuery_stmt
= NULL
;
140 d_UpdateSerialOfZoneQuery_stmt
= NULL
;
141 d_UpdateLastCheckofZoneQuery_stmt
= NULL
;
142 d_UpdateAccountOfZoneQuery_stmt
= NULL
;
143 d_InfoOfAllMasterDomainsQuery_stmt
= NULL
;
144 d_DeleteDomainQuery_stmt
= NULL
;
145 d_DeleteZoneQuery_stmt
= NULL
;
146 d_DeleteRRSetQuery_stmt
= NULL
;
147 d_DeleteNamesQuery_stmt
= NULL
;
148 d_firstOrderQuery_stmt
= NULL
;
149 d_beforeOrderQuery_stmt
= NULL
;
150 d_afterOrderQuery_stmt
= NULL
;
151 d_lastOrderQuery_stmt
= NULL
;
152 d_updateOrderNameAndAuthQuery_stmt
= NULL
;
153 d_updateOrderNameAndAuthTypeQuery_stmt
= NULL
;
154 d_nullifyOrderNameAndUpdateAuthQuery_stmt
= NULL
;
155 d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt
= NULL
;
156 d_RemoveEmptyNonTerminalsFromZoneQuery_stmt
= NULL
;
157 d_DeleteEmptyNonTerminalQuery_stmt
= NULL
;
158 d_AddDomainKeyQuery_stmt
= NULL
;
159 d_GetLastInsertedKeyIdQuery_stmt
= NULL
;
160 d_ListDomainKeysQuery_stmt
= NULL
;
161 d_GetAllDomainMetadataQuery_stmt
= NULL
;
162 d_GetDomainMetadataQuery_stmt
= NULL
;
163 d_ClearDomainMetadataQuery_stmt
= NULL
;
164 d_ClearDomainAllMetadataQuery_stmt
= NULL
;
165 d_SetDomainMetadataQuery_stmt
= NULL
;
166 d_RemoveDomainKeyQuery_stmt
= NULL
;
167 d_ActivateDomainKeyQuery_stmt
= NULL
;
168 d_DeactivateDomainKeyQuery_stmt
= NULL
;
169 d_ClearDomainAllKeysQuery_stmt
= NULL
;
170 d_getTSIGKeyQuery_stmt
= NULL
;
171 d_setTSIGKeyQuery_stmt
= NULL
;
172 d_deleteTSIGKeyQuery_stmt
= NULL
;
173 d_getTSIGKeysQuery_stmt
= NULL
;
174 d_getAllDomainsQuery_stmt
= NULL
;
175 d_ListCommentsQuery_stmt
= NULL
;
176 d_InsertCommentQuery_stmt
= NULL
;
177 d_DeleteCommentRRsetQuery_stmt
= NULL
;
178 d_DeleteCommentsQuery_stmt
= NULL
;
179 d_SearchRecordsQuery_stmt
= NULL
;
180 d_SearchCommentsQuery_stmt
= NULL
;
183 void GSQLBackend::setNotified(uint32_t domain_id
, uint32_t serial
)
188 d_UpdateSerialOfZoneQuery_stmt
->
189 bind("serial", serial
)->
190 bind("domain_id", domain_id
)->
194 catch(SSqlException
&e
) {
195 throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id
)+": "+e
.txtReason());
199 void GSQLBackend::setFresh(uint32_t domain_id
)
204 d_UpdateLastCheckofZoneQuery_stmt
->
205 bind("last_check", time(0))->
206 bind("domain_id", domain_id
)->
210 catch (SSqlException
&e
) {
211 throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id
)+": "+e
.txtReason());
215 bool GSQLBackend::setMaster(const DNSName
&domain
, const string
&ip
)
220 d_UpdateMasterOfZoneQuery_stmt
->
222 bind("domain", domain
)->
226 catch (SSqlException
&e
) {
227 throw PDNSException("GSQLBackend unable to set master of domain '"+domain
.toLogString()+"': "+e
.txtReason());
232 bool GSQLBackend::setKind(const DNSName
&domain
, const DomainInfo::DomainKind kind
)
237 d_UpdateKindOfZoneQuery_stmt
->
238 bind("kind", toUpper(DomainInfo::getKindString(kind
)))->
239 bind("domain", domain
)->
243 catch (SSqlException
&e
) {
244 throw PDNSException("GSQLBackend unable to set kind of domain '"+domain
.toLogString()+"': "+e
.txtReason());
249 bool GSQLBackend::setAccount(const DNSName
&domain
, const string
&account
)
254 d_UpdateAccountOfZoneQuery_stmt
->
255 bind("account", account
)->
256 bind("domain", domain
)->
260 catch (SSqlException
&e
) {
261 throw PDNSException("GSQLBackend unable to set account of domain '"+domain
.toLogString()+"': "+e
.txtReason());
266 bool GSQLBackend::getDomainInfo(const DNSName
&domain
, DomainInfo
&di
, bool getSerial
)
268 /* fill DomainInfo from database info:
269 id,name,master IP(s),last_check,notified_serial,type,account */
273 d_InfoOfDomainsZoneQuery_stmt
->
274 bind("domain", domain
)->
276 getResult(d_result
)->
279 catch(SSqlException
&e
) {
280 throw PDNSException("GSQLBackend unable to retrieve information about a domain: "+e
.txtReason());
283 int numanswers
=d_result
.size();
287 ASSERT_ROW_COLUMNS("info-zone-query", d_result
[0], 7);
289 di
.id
=pdns_stou(d_result
[0][0]);
291 di
.zone
=DNSName(d_result
[0][1]);
295 vector
<string
> masters
;
296 stringtok(masters
, d_result
[0][2], " ,\t");
297 for(const auto& m
: masters
)
298 di
.masters
.emplace_back(m
, 53);
299 di
.last_check
=pdns_stou(d_result
[0][3]);
300 di
.notified_serial
= pdns_stou(d_result
[0][4]);
301 string type
=d_result
[0][5];
302 di
.account
=d_result
[0][6];
309 if(!getSOA(domain
, sd
))
310 g_log
<<Logger::Notice
<<"No serial for '"<<domain
<<"' found - zone is missing?"<<endl
;
312 di
.serial
= sd
.serial
;
314 catch(PDNSException
&ae
){
315 g_log
<<Logger::Error
<<"Error retrieving serial for '"<<domain
<<"': "<<ae
.reason
<<endl
;
319 di
.kind
= DomainInfo::stringToKind(type
);
324 void GSQLBackend::getUnfreshSlaveInfos(vector
<DomainInfo
> *unfreshDomains
)
326 /* list all domains that need refreshing for which we are slave, and insert into SlaveDomain:
327 id,name,master IP,serial */
331 d_InfoOfAllSlaveDomainsQuery_stmt
->
333 getResult(d_result
)->
336 catch (SSqlException
&e
) {
337 throw PDNSException("GSQLBackend unable to retrieve list of slave domains: "+e
.txtReason());
340 vector
<DomainInfo
> allSlaves
;
341 int numanswers
=d_result
.size();
342 for(int n
=0;n
<numanswers
;++n
) { // id,name,master,last_check
344 ASSERT_ROW_COLUMNS("info-all-slaves-query", d_result
[n
], 4);
345 sd
.id
=pdns_stou(d_result
[n
][0]);
347 sd
.zone
= DNSName(d_result
[n
][1]);
352 vector
<string
> masters
;
353 stringtok(masters
, d_result
[n
][2], ", \t");
354 for(const auto& m
: masters
)
355 sd
.masters
.emplace_back(m
, 53);
357 sd
.last_check
=pdns_stou(d_result
[n
][3]);
359 sd
.kind
=DomainInfo::Slave
;
360 allSlaves
.push_back(sd
);
363 for(vector
<DomainInfo
>::iterator i
=allSlaves
.begin();i
!=allSlaves
.end();++i
) {
367 getSOA(i
->zone
,sdata
);
368 if((time_t)(i
->last_check
+sdata
.refresh
) < time(0)) {
369 i
->serial
=sdata
.serial
;
370 unfreshDomains
->push_back(*i
);
375 void GSQLBackend::getUpdatedMasters(vector
<DomainInfo
> *updatedDomains
)
377 /* list all domains that need notifications for which we are master, and insert into updatedDomains
378 id,name,master IP,serial */
382 d_InfoOfAllMasterDomainsQuery_stmt
->
384 getResult(d_result
)->
387 catch(SSqlException
&e
) {
388 throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e
.txtReason());
391 vector
<DomainInfo
> allMasters
;
392 size_t numanswers
=d_result
.size();
393 for(size_t n
=0;n
<numanswers
;++n
) { // id,name,master,last_check,notified_serial
395 ASSERT_ROW_COLUMNS("info-all-master-query", d_result
[n
], 6);
396 sd
.id
=pdns_stou(d_result
[n
][0]);
398 sd
.zone
= DNSName(d_result
[n
][1]);
402 sd
.last_check
=pdns_stou(d_result
[n
][3]);
403 sd
.notified_serial
=pdns_stou(d_result
[n
][4]);
405 sd
.kind
=DomainInfo::Master
;
406 allMasters
.push_back(sd
);
409 for(vector
<DomainInfo
>::iterator i
=allMasters
.begin();i
!=allMasters
.end();++i
) {
413 getSOA(i
->zone
,sdata
);
414 if(i
->notified_serial
!=sdata
.serial
) {
415 i
->serial
=sdata
.serial
;
416 updatedDomains
->push_back(*i
);
421 bool GSQLBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id
, const DNSName
& qname
, const DNSName
& ordername
, bool auth
, const uint16_t qtype
)
426 if (!ordername
.empty()) {
427 if (qtype
== QType::ANY
) {
431 d_updateOrderNameAndAuthQuery_stmt
->
432 bind("ordername", ordername
.labelReverse().toString(" ", false))->
434 bind("domain_id", domain_id
)->
435 bind("qname", qname
)->
439 catch(SSqlException
&e
) {
440 throw PDNSException("GSQLBackend unable to update ordername and auth for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
446 d_updateOrderNameAndAuthTypeQuery_stmt
->
447 bind("ordername", ordername
.labelReverse().toString(" ", false))->
449 bind("domain_id", domain_id
)->
450 bind("qname", qname
)->
451 bind("qtype", QType(qtype
).getName())->
455 catch(SSqlException
&e
) {
456 throw PDNSException("GSQLBackend unable to update ordername and auth per type for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
460 if (qtype
== QType::ANY
) {
464 d_nullifyOrderNameAndUpdateAuthQuery_stmt
->
466 bind("domain_id", domain_id
)->
467 bind("qname", qname
)->
471 catch(SSqlException
&e
) {
472 throw PDNSException("GSQLBackend unable to nullify ordername and update auth for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
478 d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt
->
480 bind("domain_id", domain_id
)->
481 bind("qname", qname
)->
482 bind("qtype", QType(qtype
).getName())->
486 catch(SSqlException
&e
) {
487 throw PDNSException("GSQLBackend unable to nullify ordername and update auth per type for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
494 bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id
, set
<DNSName
>& insert
, set
<DNSName
>& erase
, bool remove
)
500 d_RemoveEmptyNonTerminalsFromZoneQuery_stmt
->
501 bind("domain_id", domain_id
)->
505 catch (SSqlException
&e
) {
506 throw PDNSException("GSQLBackend unable to delete empty non-terminal records from domain_id "+itoa(domain_id
)+": "+e
.txtReason());
512 for(const auto& qname
: erase
) {
516 d_DeleteEmptyNonTerminalQuery_stmt
->
517 bind("domain_id", domain_id
)->
518 bind("qname", qname
)->
522 catch (SSqlException
&e
) {
523 throw PDNSException("GSQLBackend unable to delete empty non-terminal rr '"+qname
.toLogString()+"' from domain_id "+itoa(domain_id
)+": "+e
.txtReason());
529 for(const auto& qname
: insert
) {
533 d_InsertEmptyNonTerminalOrderQuery_stmt
->
534 bind("domain_id", domain_id
)->
535 bind("qname", qname
)->
536 bindNull("ordername")->
541 catch (SSqlException
&e
) {
542 throw PDNSException("GSQLBackend unable to insert empty non-terminal rr '"+qname
.toLogString()+"' in domain_id "+itoa(domain_id
)+": "+e
.txtReason());
550 bool GSQLBackend::doesDNSSEC()
552 return d_dnssecQueries
;
555 bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id
, const DNSName
& qname
, DNSName
& unhashed
, DNSName
& before
, DNSName
& after
)
561 SSqlStatement::row_t row
;
565 d_afterOrderQuery_stmt
->
566 bind("ordername", qname
.labelReverse().toString(" ", false))->
567 bind("domain_id", id
)->
569 while(d_afterOrderQuery_stmt
->hasNextRow()) {
570 d_afterOrderQuery_stmt
->nextRow(row
);
571 ASSERT_ROW_COLUMNS("get-order-after-query", row
, 1);
572 if(! row
[0].empty()) { // Hack because NULL values are passed on as empty strings
573 after
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
576 d_afterOrderQuery_stmt
->reset();
578 catch(SSqlException
&e
) {
579 throw PDNSException("GSQLBackend unable to find before/after (after) for domain_id "+itoa(id
)+": "+e
.txtReason());
586 d_firstOrderQuery_stmt
->
587 bind("domain_id", id
)->
589 while(d_firstOrderQuery_stmt
->hasNextRow()) {
590 d_firstOrderQuery_stmt
->nextRow(row
);
591 ASSERT_ROW_COLUMNS("get-order-first-query", row
, 1);
592 after
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
594 d_firstOrderQuery_stmt
->reset();
596 catch(SSqlException
&e
) {
597 throw PDNSException("GSQLBackend unable to find before/after (first) for domain_id "+itoa(id
)+": "+e
.txtReason());
601 if (before
.empty()) {
607 d_beforeOrderQuery_stmt
->
608 bind("ordername", qname
.labelReverse().toString(" ", false))->
609 bind("domain_id", id
)->
611 while(d_beforeOrderQuery_stmt
->hasNextRow()) {
612 d_beforeOrderQuery_stmt
->nextRow(row
);
613 ASSERT_ROW_COLUMNS("get-order-before-query", row
, 2);
614 before
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
616 unhashed
=DNSName(row
[1]);
621 d_beforeOrderQuery_stmt
->reset();
623 catch(SSqlException
&e
) {
624 throw PDNSException("GSQLBackend unable to find before/after (before) for domain_id "+itoa(id
)+": "+e
.txtReason());
627 if(! unhashed
.empty())
629 // cerr<<"unhashed="<<unhashed<<",before="<<before<<", after="<<after<<endl;
636 d_lastOrderQuery_stmt
->
637 bind("domain_id", id
)->
639 while(d_lastOrderQuery_stmt
->hasNextRow()) {
640 d_lastOrderQuery_stmt
->nextRow(row
);
641 ASSERT_ROW_COLUMNS("get-order-last-query", row
, 2);
642 before
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
644 unhashed
=DNSName(row
[1]);
649 d_lastOrderQuery_stmt
->reset();
651 catch(SSqlException
&e
) {
652 throw PDNSException("GSQLBackend unable to find before/after (last) for domain_id "+itoa(id
)+": "+e
.txtReason());
661 bool GSQLBackend::addDomainKey(const DNSName
& name
, const KeyData
& key
, int64_t& id
)
669 d_AddDomainKeyQuery_stmt
->
670 bind("flags", key
.flags
)->
671 bind("active", key
.active
)->
672 bind("content", key
.content
)->
673 bind("domain", name
)->
677 catch (SSqlException
&e
) {
678 throw PDNSException("GSQLBackend unable to store key: "+e
.txtReason());
684 d_GetLastInsertedKeyIdQuery_stmt
->execute();
685 if (!d_GetLastInsertedKeyIdQuery_stmt
->hasNextRow()) {
689 SSqlStatement::row_t row
;
690 d_GetLastInsertedKeyIdQuery_stmt
->nextRow(row
);
691 ASSERT_ROW_COLUMNS("get-last-inserted-key-id-query", row
, 1);
692 id
= std::stoi(row
[0]);
693 d_GetLastInsertedKeyIdQuery_stmt
->reset();
696 catch (SSqlException
&e
) {
704 bool GSQLBackend::activateDomainKey(const DNSName
& name
, unsigned int id
)
712 d_ActivateDomainKeyQuery_stmt
->
713 bind("domain", name
)->
718 catch (SSqlException
&e
) {
719 throw PDNSException("GSQLBackend unable to activate key: "+e
.txtReason());
724 bool GSQLBackend::deactivateDomainKey(const DNSName
& name
, unsigned int id
)
732 d_DeactivateDomainKeyQuery_stmt
->
733 bind("domain", name
)->
738 catch (SSqlException
&e
) {
739 throw PDNSException("GSQLBackend unable to deactivate key: "+e
.txtReason());
744 bool GSQLBackend::removeDomainKey(const DNSName
& name
, unsigned int id
)
752 d_RemoveDomainKeyQuery_stmt
->
753 bind("domain", name
)->
758 catch (SSqlException
&e
) {
759 throw PDNSException("GSQLBackend unable to remove key: "+e
.txtReason());
764 bool GSQLBackend::getTSIGKey(const DNSName
& name
, DNSName
* algorithm
, string
* content
)
769 d_getTSIGKeyQuery_stmt
->
770 bind("key_name", name
)->
773 SSqlStatement::row_t row
;
776 while(d_getTSIGKeyQuery_stmt
->hasNextRow()) {
777 d_getTSIGKeyQuery_stmt
->nextRow(row
);
778 ASSERT_ROW_COLUMNS("get-tsig-key-query", row
, 2);
780 if(algorithm
->empty() || *algorithm
==DNSName(row
[0])) {
781 *algorithm
= DNSName(row
[0]);
787 d_getTSIGKeyQuery_stmt
->reset();
789 catch (SSqlException
&e
) {
790 throw PDNSException("GSQLBackend unable to retrieve named TSIG key: "+e
.txtReason());
793 return !content
->empty();
796 bool GSQLBackend::setTSIGKey(const DNSName
& name
, const DNSName
& algorithm
, const string
& content
)
801 d_setTSIGKeyQuery_stmt
->
802 bind("key_name", name
)->
803 bind("algorithm", algorithm
)->
804 bind("content", content
)->
808 catch (SSqlException
&e
) {
809 throw PDNSException("GSQLBackend unable to store named TSIG key: "+e
.txtReason());
814 bool GSQLBackend::deleteTSIGKey(const DNSName
& name
)
819 d_deleteTSIGKeyQuery_stmt
->
820 bind("key_name", name
)->
824 catch (SSqlException
&e
) {
825 throw PDNSException("GSQLBackend unable to store named TSIG key: "+e
.txtReason());
830 bool GSQLBackend::getTSIGKeys(std::vector
< struct TSIGKey
> &keys
)
835 d_getTSIGKeysQuery_stmt
->
838 SSqlStatement::row_t row
;
840 while(d_getTSIGKeysQuery_stmt
->hasNextRow()) {
841 d_getTSIGKeysQuery_stmt
->nextRow(row
);
842 ASSERT_ROW_COLUMNS("get-tsig-keys-query", row
, 3);
845 key
.name
= DNSName(row
[0]);
846 key
.algorithm
= DNSName(row
[1]);
854 d_getTSIGKeysQuery_stmt
->reset();
856 catch (SSqlException
&e
) {
857 throw PDNSException("GSQLBackend unable to retrieve TSIG keys: "+e
.txtReason());
863 bool GSQLBackend::getDomainKeys(const DNSName
& name
, std::vector
<KeyData
>& keys
)
871 d_ListDomainKeysQuery_stmt
->
872 bind("domain", name
)->
875 SSqlStatement::row_t row
;
877 while(d_ListDomainKeysQuery_stmt
->hasNextRow()) {
878 d_ListDomainKeysQuery_stmt
->nextRow(row
);
879 ASSERT_ROW_COLUMNS("list-domain-keys-query", row
, 4);
880 //~ for(const auto& val: row) {
881 //~ cerr<<"'"<<val<<"'"<<endl;
883 kd
.id
= pdns_stou(row
[0]);
884 kd
.flags
= pdns_stou(row
[1]);
885 kd
.active
= row
[2] == "1";
890 d_ListDomainKeysQuery_stmt
->reset();
892 catch (SSqlException
&e
) {
893 throw PDNSException("GSQLBackend unable to list keys: "+e
.txtReason());
899 void GSQLBackend::alsoNotifies(const DNSName
&domain
, set
<string
> *ips
)
902 getDomainMetadata(domain
, "ALSO-NOTIFY", meta
);
903 for(const auto& str
: meta
) {
908 bool GSQLBackend::getAllDomainMetadata(const DNSName
& name
, std::map
<std::string
, std::vector
<std::string
> >& meta
)
913 d_GetAllDomainMetadataQuery_stmt
->
914 bind("domain", name
)->
917 SSqlStatement::row_t row
;
919 while(d_GetAllDomainMetadataQuery_stmt
->hasNextRow()) {
920 d_GetAllDomainMetadataQuery_stmt
->nextRow(row
);
921 ASSERT_ROW_COLUMNS("get-all-domain-metadata-query", row
, 2);
923 if (!isDnssecDomainMetadata(row
[0]))
924 meta
[row
[0]].push_back(row
[1]);
927 d_GetAllDomainMetadataQuery_stmt
->reset();
929 catch (SSqlException
&e
) {
930 throw PDNSException("GSQLBackend unable to list metadata: "+e
.txtReason());
937 bool GSQLBackend::getDomainMetadata(const DNSName
& name
, const std::string
& kind
, std::vector
<std::string
>& meta
)
939 if(!d_dnssecQueries
&& isDnssecDomainMetadata(kind
))
945 d_GetDomainMetadataQuery_stmt
->
946 bind("domain", name
)->
950 SSqlStatement::row_t row
;
952 while(d_GetDomainMetadataQuery_stmt
->hasNextRow()) {
953 d_GetDomainMetadataQuery_stmt
->nextRow(row
);
954 ASSERT_ROW_COLUMNS("get-domain-metadata-query", row
, 1);
955 meta
.push_back(row
[0]);
958 d_GetDomainMetadataQuery_stmt
->reset();
960 catch (SSqlException
&e
) {
961 throw PDNSException("GSQLBackend unable to list metadata: "+e
.txtReason());
967 bool GSQLBackend::setDomainMetadata(const DNSName
& name
, const std::string
& kind
, const std::vector
<std::string
>& meta
)
969 if(!d_dnssecQueries
&& isDnssecDomainMetadata(kind
))
975 d_ClearDomainMetadataQuery_stmt
->
976 bind("domain", name
)->
981 for(const auto& value
: meta
) {
982 d_SetDomainMetadataQuery_stmt
->
984 bind("content", value
)->
985 bind("domain", name
)->
991 catch (SSqlException
&e
) {
992 throw PDNSException("GSQLBackend unable to store metadata key: "+e
.txtReason());
998 void GSQLBackend::lookup(const QType
&qtype
,const DNSName
&qname
, DNSPacket
*pkt_p
, int domain_id
)
1001 reconnectIfNeeded();
1003 if(qtype
.getCode()!=QType::ANY
) {
1005 d_query_name
= "basic-query";
1006 d_query_stmt
= &d_NoIdQuery_stmt
;
1008 bind("qtype", qtype
.getName())->
1009 bind("qname", qname
);
1011 d_query_name
= "id-query";
1012 d_query_stmt
= &d_IdQuery_stmt
;
1014 bind("qtype", qtype
.getName())->
1015 bind("qname", qname
)->
1016 bind("domain_id", domain_id
);
1021 d_query_name
= "any-query";
1022 d_query_stmt
= &d_ANYNoIdQuery_stmt
;
1024 bind("qname", qname
);
1026 d_query_name
= "any-id-query";
1027 d_query_stmt
= &d_ANYIdQuery_stmt
;
1029 bind("qname", qname
)->
1030 bind("domain_id", domain_id
);
1037 catch(SSqlException
&e
) {
1038 throw PDNSException("GSQLBackend lookup query:"+e
.txtReason());
1044 bool GSQLBackend::list(const DNSName
&target
, int domain_id
, bool include_disabled
)
1046 DLOG(g_log
<<"GSQLBackend constructing handle for list of domain id '"<<domain_id
<<"'"<<endl
);
1049 reconnectIfNeeded();
1051 d_query_name
= "list-query";
1052 d_query_stmt
= &d_listQuery_stmt
;
1054 bind("include_disabled", (int)include_disabled
)->
1055 bind("domain_id", domain_id
)->
1058 catch(SSqlException
&e
) {
1059 throw PDNSException("GSQLBackend list query: "+e
.txtReason());
1066 bool GSQLBackend::listSubZone(const DNSName
&zone
, int domain_id
) {
1068 string wildzone
= "%." + zone
.makeLowerCase().toStringNoDot();
1071 reconnectIfNeeded();
1073 d_query_name
= "list-subzone-query";
1074 d_query_stmt
= &d_listSubZoneQuery_stmt
;
1076 bind("zone", zone
)->
1077 bind("wildzone", wildzone
)->
1078 bind("domain_id", domain_id
)->
1081 catch(SSqlException
&e
) {
1082 throw PDNSException("GSQLBackend listSubZone query: "+e
.txtReason());
1088 bool GSQLBackend::get(DNSResourceRecord
&r
)
1090 // g_log << "GSQLBackend get() was called for "<<qtype.getName() << " record: ";
1091 SSqlStatement::row_t row
;
1094 if((*d_query_stmt
)->hasNextRow()) {
1096 (*d_query_stmt
)->nextRow(row
);
1097 ASSERT_ROW_COLUMNS(d_query_name
, row
, 8);
1098 } catch (SSqlException
&e
) {
1099 throw PDNSException("GSQLBackend get: "+e
.txtReason());
1102 extractRecord(row
, r
);
1110 (*d_query_stmt
)->reset();
1111 } catch (SSqlException
&e
) {
1112 throw PDNSException("GSQLBackend get: "+e
.txtReason());
1114 d_query_stmt
= NULL
;
1118 bool GSQLBackend::superMasterBackend(const string
&ip
, const DNSName
&domain
, const vector
<DNSResourceRecord
>&nsset
, string
*nameserver
, string
*account
, DNSBackend
**ddb
)
1120 // check if we know the ip/ns couple in the database
1121 for(vector
<DNSResourceRecord
>::const_iterator i
=nsset
.begin();i
!=nsset
.end();++i
) {
1123 reconnectIfNeeded();
1125 d_SuperMasterInfoQuery_stmt
->
1127 bind("nameserver", i
->content
)->
1129 getResult(d_result
)->
1132 catch (SSqlException
&e
) {
1133 throw PDNSException("GSQLBackend unable to search for a domain: "+e
.txtReason());
1135 if(!d_result
.empty()) {
1136 ASSERT_ROW_COLUMNS("supermaster-query", d_result
[0], 1);
1137 *nameserver
=i
->content
;
1138 *account
=d_result
[0][0];
1146 bool GSQLBackend::createDomain(const DNSName
&domain
, const string
&type
, const string
&masters
, const string
&account
)
1149 reconnectIfNeeded();
1151 d_InsertZoneQuery_stmt
->
1152 bind("type", type
)->
1153 bind("domain", domain
)->
1154 bind("masters", masters
)->
1155 bind("account", account
)->
1159 catch(SSqlException
&e
) {
1160 throw PDNSException("Database error trying to insert new domain '"+domain
.toLogString()+"': "+ e
.txtReason());
1165 bool GSQLBackend::createSlaveDomain(const string
&ip
, const DNSName
&domain
, const string
&nameserver
, const string
&account
)
1170 if (!nameserver
.empty()) {
1171 // figure out all IP addresses for the master
1172 reconnectIfNeeded();
1174 d_GetSuperMasterIPs_stmt
->
1175 bind("nameserver", nameserver
)->
1176 bind("account", account
)->
1178 getResult(d_result
)->
1180 if (!d_result
.empty()) {
1181 // collect all IP addresses
1183 for(const auto& row
: d_result
) {
1184 if (account
== row
[1])
1185 tmp
.push_back(row
[0]);
1187 // set them as domain's masters, comma separated
1188 masters
= boost::join(tmp
, ", ");
1191 createDomain(domain
, "SLAVE", masters
, account
);
1193 catch(SSqlException
&e
) {
1194 throw PDNSException("Database error trying to insert new slave domain '"+domain
.toLogString()+"': "+ e
.txtReason());
1199 bool GSQLBackend::deleteDomain(const DNSName
&domain
)
1202 if (!getDomainInfo(domain
, di
)) {
1207 reconnectIfNeeded();
1209 d_DeleteZoneQuery_stmt
->
1210 bind("domain_id", di
.id
)->
1213 d_ClearDomainAllMetadataQuery_stmt
->
1214 bind("domain", domain
)->
1217 d_ClearDomainAllKeysQuery_stmt
->
1218 bind("domain", domain
)->
1221 d_DeleteCommentsQuery_stmt
->
1222 bind("domain_id", di
.id
)->
1225 d_DeleteDomainQuery_stmt
->
1226 bind("domain", domain
)->
1230 catch(SSqlException
&e
) {
1231 throw PDNSException("Database error trying to delete domain '"+domain
.toLogString()+"': "+ e
.txtReason());
1236 void GSQLBackend::getAllDomains(vector
<DomainInfo
> *domains
, bool include_disabled
)
1238 DLOG(g_log
<<"GSQLBackend retrieving all domains."<<endl
);
1241 reconnectIfNeeded();
1243 d_getAllDomainsQuery_stmt
->
1244 bind("include_disabled", (int)include_disabled
)->
1247 SSqlStatement::row_t row
;
1248 while (d_getAllDomainsQuery_stmt
->hasNextRow()) {
1249 d_getAllDomainsQuery_stmt
->nextRow(row
);
1250 ASSERT_ROW_COLUMNS("get-all-domains-query", row
, 8);
1252 di
.id
= pdns_stou(row
[0]);
1254 di
.zone
= DNSName(row
[1]);
1259 if (!row
[4].empty()) {
1260 vector
<string
> masters
;
1261 stringtok(masters
, row
[4], " ,\t");
1262 for(const auto& m
: masters
)
1263 di
.masters
.emplace_back(m
, 53);
1267 fillSOAData(row
[2], sd
);
1268 di
.serial
= sd
.serial
;
1269 di
.notified_serial
= pdns_stou(row
[5]);
1270 di
.last_check
= pdns_stou(row
[6]);
1271 di
.account
= row
[7];
1273 if (pdns_iequals(row
[3], "MASTER"))
1274 di
.kind
= DomainInfo::Master
;
1275 else if (pdns_iequals(row
[3], "SLAVE"))
1276 di
.kind
= DomainInfo::Slave
;
1278 di
.kind
= DomainInfo::Native
;
1282 domains
->push_back(di
);
1284 d_getAllDomainsQuery_stmt
->reset();
1286 catch (SSqlException
&e
) {
1287 throw PDNSException("Database error trying to retrieve all domains:" + e
.txtReason());
1291 bool GSQLBackend::replaceRRSet(uint32_t domain_id
, const DNSName
& qname
, const QType
& qt
, const vector
<DNSResourceRecord
>& rrset
)
1294 reconnectIfNeeded();
1296 if (qt
!= QType::ANY
) {
1297 d_DeleteRRSetQuery_stmt
->
1298 bind("domain_id", domain_id
)->
1299 bind("qname", qname
)->
1300 bind("qtype", qt
.getName())->
1304 d_DeleteNamesQuery_stmt
->
1305 bind("domain_id", domain_id
)->
1306 bind("qname", qname
)->
1311 catch (SSqlException
&e
) {
1312 throw PDNSException("GSQLBackend unable to delete RRSet: "+e
.txtReason());
1315 if (rrset
.empty()) {
1317 reconnectIfNeeded();
1319 d_DeleteCommentRRsetQuery_stmt
->
1320 bind("domain_id", domain_id
)->
1321 bind("qname", qname
)->
1322 bind("qtype", qt
.getName())->
1326 catch (SSqlException
&e
) {
1327 throw PDNSException("GSQLBackend unable to delete comment: "+e
.txtReason());
1330 for(const auto& rr
: rrset
) {
1331 feedRecord(rr
, DNSName());
1337 bool GSQLBackend::feedRecord(const DNSResourceRecord
&r
, const DNSName
&ordername
)
1340 string
content(r
.content
);
1341 if (r
.qtype
== QType::MX
|| r
.qtype
== QType::SRV
) {
1342 string::size_type pos
= content
.find_first_not_of("0123456789");
1343 if (pos
!= string::npos
) {
1344 prio
=pdns_stou(content
.substr(0,pos
));
1345 boost::erase_head(content
, pos
);
1351 reconnectIfNeeded();
1353 d_InsertRecordQuery_stmt
->
1354 bind("content",content
)->
1356 bind("priority",prio
)->
1357 bind("qtype",r
.qtype
.getName())->
1358 bind("domain_id",r
.domain_id
)->
1359 bind("disabled",r
.disabled
)->
1360 bind("qname",r
.qname
);
1362 if (!ordername
.empty())
1363 d_InsertRecordQuery_stmt
->bind("ordername", ordername
.labelReverse().makeLowerCase().toString(" ", false));
1365 d_InsertRecordQuery_stmt
->bindNull("ordername");
1367 if (d_dnssecQueries
)
1368 d_InsertRecordQuery_stmt
->bind("auth", r
.auth
);
1370 d_InsertRecordQuery_stmt
->bind("auth", true);
1372 d_InsertRecordQuery_stmt
->
1376 catch (SSqlException
&e
) {
1377 throw PDNSException("GSQLBackend unable to feed record: "+e
.txtReason());
1379 return true; // XXX FIXME this API should not return 'true' I think -ahu
1382 bool GSQLBackend::feedEnts(int domain_id
, map
<DNSName
,bool>& nonterm
)
1384 for(const auto& nt
: nonterm
) {
1386 reconnectIfNeeded();
1388 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1389 bind("domain_id",domain_id
)->
1390 bind("qname", nt
.first
)->
1391 bindNull("ordername")->
1392 bind("auth",(nt
.second
|| !d_dnssecQueries
))->
1396 catch (SSqlException
&e
) {
1397 throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e
.txtReason());
1403 bool GSQLBackend::feedEnts3(int domain_id
, const DNSName
&domain
, map
<DNSName
,bool> &nonterm
, const NSEC3PARAMRecordContent
& ns3prc
, bool narrow
)
1405 if(!d_dnssecQueries
)
1410 for(const auto& nt
: nonterm
) {
1412 reconnectIfNeeded();
1414 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1415 bind("domain_id",domain_id
)->
1416 bind("qname", nt
.first
);
1417 if (narrow
|| !nt
.second
) {
1418 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1419 bindNull("ordername");
1421 ordername
=toBase32Hex(hashQNameWithSalt(ns3prc
, nt
.first
));
1422 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1423 bind("ordername", ordername
);
1425 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1426 bind("auth",nt
.second
)->
1430 catch (SSqlException
&e
) {
1431 throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e
.txtReason());
1437 bool GSQLBackend::startTransaction(const DNSName
&domain
, int domain_id
)
1440 reconnectIfNeeded();
1442 d_db
->startTransaction();
1443 d_inTransaction
= true;
1444 if(domain_id
>= 0) {
1445 d_DeleteZoneQuery_stmt
->
1446 bind("domain_id", domain_id
)->
1451 catch (SSqlException
&e
) {
1452 d_inTransaction
= false;
1453 throw PDNSException("Database failed to start transaction: "+e
.txtReason());
1459 bool GSQLBackend::commitTransaction()
1463 d_inTransaction
= false;
1465 catch (SSqlException
&e
) {
1466 d_inTransaction
= false;
1467 throw PDNSException("Database failed to commit transaction: "+e
.txtReason());
1472 bool GSQLBackend::abortTransaction()
1476 d_inTransaction
= false;
1478 catch(SSqlException
&e
) {
1479 d_inTransaction
= false;
1480 throw PDNSException("Database failed to abort transaction: "+string(e
.txtReason()));
1485 bool GSQLBackend::listComments(const uint32_t domain_id
)
1488 reconnectIfNeeded();
1490 d_query_name
= "list-comments-query";
1491 d_query_stmt
= &d_ListCommentsQuery_stmt
;
1493 bind("domain_id", domain_id
)->
1496 catch(SSqlException
&e
) {
1497 throw PDNSException("GSQLBackend list comments query: "+e
.txtReason());
1503 bool GSQLBackend::getComment(Comment
& comment
)
1505 SSqlStatement::row_t row
;
1508 if (!(*d_query_stmt
)->hasNextRow()) {
1510 (*d_query_stmt
)->reset();
1511 } catch(SSqlException
&e
) {
1512 throw PDNSException("GSQLBackend comment get: "+e
.txtReason());
1514 d_query_stmt
= NULL
;
1519 (*d_query_stmt
)->nextRow(row
);
1520 ASSERT_ROW_COLUMNS(d_query_name
, row
, 6);
1521 } catch(SSqlException
&e
) {
1522 throw PDNSException("GSQLBackend comment get: "+e
.txtReason());
1525 extractComment(row
, comment
);
1533 void GSQLBackend::feedComment(const Comment
& comment
)
1536 reconnectIfNeeded();
1538 d_InsertCommentQuery_stmt
->
1539 bind("domain_id",comment
.domain_id
)->
1540 bind("qname",comment
.qname
)->
1541 bind("qtype",comment
.qtype
.getName())->
1542 bind("modified_at",comment
.modified_at
)->
1543 bind("account",comment
.account
)->
1544 bind("content",comment
.content
)->
1548 catch (SSqlException
&e
) {
1549 throw PDNSException("GSQLBackend unable to feed comment: "+e
.txtReason());
1553 bool GSQLBackend::replaceComments(const uint32_t domain_id
, const DNSName
& qname
, const QType
& qt
, const vector
<Comment
>& comments
)
1556 reconnectIfNeeded();
1558 d_DeleteCommentRRsetQuery_stmt
->
1559 bind("domain_id",domain_id
)->
1560 bind("qname", qname
)->
1561 bind("qtype",qt
.getName())->
1565 catch (SSqlException
&e
) {
1566 throw PDNSException("GSQLBackend unable to delete comment: "+e
.txtReason());
1569 for(const auto& comment
: comments
) {
1570 feedComment(comment
);
1576 string
GSQLBackend::directBackendCmd(const string
&query
)
1581 auto stmt
= d_db
->prepare(query
,0);
1583 reconnectIfNeeded();
1587 SSqlStatement::row_t row
;
1589 while(stmt
->hasNextRow()) {
1591 for(const auto& col
: row
)
1592 out
<<"\'"<<col
<<"\'\t";
1598 catch (SSqlException
&e
) {
1599 throw PDNSException("GSQLBackend unable to execute query: "+e
.txtReason());
1603 string
GSQLBackend::pattern2SQLPattern(const string
&pattern
)
1605 string escaped_pattern
= boost::replace_all_copy(pattern
,"\\","\\\\");
1606 boost::replace_all(escaped_pattern
,"_","\\_");
1607 boost::replace_all(escaped_pattern
,"%","\\%");
1608 boost::replace_all(escaped_pattern
,"*","%");
1609 boost::replace_all(escaped_pattern
,"?","_");
1610 return escaped_pattern
;
1613 bool GSQLBackend::searchRecords(const string
&pattern
, int maxResults
, vector
<DNSResourceRecord
>& result
)
1617 string escaped_pattern
= pattern2SQLPattern(pattern
);
1619 reconnectIfNeeded();
1621 d_SearchRecordsQuery_stmt
->
1622 bind("value", escaped_pattern
)->
1623 bind("value2", escaped_pattern
)->
1624 bind("limit", maxResults
)->
1627 while(d_SearchRecordsQuery_stmt
->hasNextRow())
1629 SSqlStatement::row_t row
;
1630 DNSResourceRecord r
;
1631 d_SearchRecordsQuery_stmt
->nextRow(row
);
1632 ASSERT_ROW_COLUMNS("search-records-query", row
, 8);
1634 extractRecord(row
, r
);
1638 result
.push_back(r
);
1641 d_SearchRecordsQuery_stmt
->reset();
1645 catch (SSqlException
&e
) {
1646 throw PDNSException("GSQLBackend unable to execute query: "+e
.txtReason());
1652 bool GSQLBackend::searchComments(const string
&pattern
, int maxResults
, vector
<Comment
>& result
)
1656 string escaped_pattern
= pattern2SQLPattern(pattern
);
1658 reconnectIfNeeded();
1660 d_SearchCommentsQuery_stmt
->
1661 bind("value", escaped_pattern
)->
1662 bind("value2", escaped_pattern
)->
1663 bind("limit", maxResults
)->
1666 while(d_SearchCommentsQuery_stmt
->hasNextRow()) {
1667 SSqlStatement::row_t row
;
1668 d_SearchCommentsQuery_stmt
->nextRow(row
);
1669 ASSERT_ROW_COLUMNS("search-comments-query", row
, 6);
1671 extractComment(row
, comment
);
1672 result
.push_back(comment
);
1675 d_SearchRecordsQuery_stmt
->reset();
1679 catch (SSqlException
&e
) {
1680 throw PDNSException("GSQLBackend unable to execute query: "+e
.txtReason());
1686 void GSQLBackend::extractRecord(const SSqlStatement::row_t
& row
, DNSResourceRecord
& r
)
1689 r
.ttl
= ::arg().asNum( "default-ttl" );
1691 r
.ttl
=pdns_stou(row
[1]);
1692 if(!d_qname
.empty())
1695 r
.qname
=DNSName(row
[6]);
1699 if (r
.qtype
==QType::MX
|| r
.qtype
==QType::SRV
)
1700 r
.content
=row
[2]+" "+row
[0];
1707 r
.auth
= !row
[7].empty() && row
[7][0]=='1';
1711 r
.disabled
= !row
[5].empty() && row
[5][0]=='1';
1713 r
.domain_id
=pdns_stou(row
[4]);
1716 void GSQLBackend::extractComment(const SSqlStatement::row_t
& row
, Comment
& comment
)
1718 comment
.domain_id
= pdns_stou(row
[0]);
1719 comment
.qname
= DNSName(row
[1]);
1720 comment
.qtype
= row
[2];
1721 comment
.modified_at
= pdns_stou(row
[3]);
1722 comment
.account
= row
[4];
1723 comment
.content
= row
[5];
1726 SSqlStatement::~SSqlStatement() {
1727 // make sure vtable won't break