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
;
342 for(const auto& row
: d_result
) { // id,name,master,last_check
344 ASSERT_ROW_COLUMNS("info-all-slaves-query", row
, 4);
346 sd
.id
=pdns_stou(row
[0]);
347 sd
.zone
= DNSName(row
[1]);
349 vector
<string
> masters
;
350 stringtok(masters
, row
[2], ", \t");
351 for(const auto& m
: masters
)
352 sd
.masters
.emplace_back(m
, 53);
354 sd
.last_check
=pdns_stou(row
[3]);
356 sd
.kind
=DomainInfo::Slave
;
357 allSlaves
.push_back(sd
);
363 for (auto& slave
: allSlaves
) {
368 getSOA(slave
.zone
, sdata
);
369 if(static_cast<time_t>(slave
.last_check
+ sdata
.refresh
) < time(nullptr)) {
370 slave
.serial
=sdata
.serial
;
371 unfreshDomains
->push_back(slave
);
374 catch(const std::exception
& exp
) {
375 g_log
<<Logger::Warning
<<"Error while parsing SOA data for slave zone '"<<slave
.zone
.toLogString()<<"': "<<exp
.what()<<endl
;
379 g_log
<<Logger::Warning
<<"Error while parsing SOA data for slave zone '"<<slave
.zone
.toLogString()<<"', skipping"<<endl
;
385 void GSQLBackend::getUpdatedMasters(vector
<DomainInfo
> *updatedDomains
)
387 /* list all domains that need notifications for which we are master, and insert into updatedDomains
388 id,name,master IP,serial */
392 d_InfoOfAllMasterDomainsQuery_stmt
->
394 getResult(d_result
)->
397 catch(SSqlException
&e
) {
398 throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e
.txtReason());
401 vector
<DomainInfo
> allMasters
;
402 size_t numanswers
=d_result
.size();
403 for(size_t n
=0;n
<numanswers
;++n
) { // id,name,master,last_check,notified_serial
405 ASSERT_ROW_COLUMNS("info-all-master-query", d_result
[n
], 6);
406 sd
.id
=pdns_stou(d_result
[n
][0]);
408 sd
.zone
= DNSName(d_result
[n
][1]);
412 sd
.last_check
=pdns_stou(d_result
[n
][3]);
413 sd
.notified_serial
=pdns_stou(d_result
[n
][4]);
415 sd
.kind
=DomainInfo::Master
;
416 allMasters
.push_back(sd
);
419 for(vector
<DomainInfo
>::iterator i
=allMasters
.begin();i
!=allMasters
.end();++i
) {
423 getSOA(i
->zone
,sdata
);
424 if(i
->notified_serial
!=sdata
.serial
) {
425 i
->serial
=sdata
.serial
;
426 updatedDomains
->push_back(*i
);
431 bool GSQLBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id
, const DNSName
& qname
, const DNSName
& ordername
, bool auth
, const uint16_t qtype
)
436 if (!ordername
.empty()) {
437 if (qtype
== QType::ANY
) {
441 d_updateOrderNameAndAuthQuery_stmt
->
442 bind("ordername", ordername
.labelReverse().toString(" ", false))->
444 bind("domain_id", domain_id
)->
445 bind("qname", qname
)->
449 catch(SSqlException
&e
) {
450 throw PDNSException("GSQLBackend unable to update ordername and auth for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
456 d_updateOrderNameAndAuthTypeQuery_stmt
->
457 bind("ordername", ordername
.labelReverse().toString(" ", false))->
459 bind("domain_id", domain_id
)->
460 bind("qname", qname
)->
461 bind("qtype", QType(qtype
).getName())->
465 catch(SSqlException
&e
) {
466 throw PDNSException("GSQLBackend unable to update ordername and auth per type for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
470 if (qtype
== QType::ANY
) {
474 d_nullifyOrderNameAndUpdateAuthQuery_stmt
->
476 bind("domain_id", domain_id
)->
477 bind("qname", qname
)->
481 catch(SSqlException
&e
) {
482 throw PDNSException("GSQLBackend unable to nullify ordername and update auth for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
488 d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt
->
490 bind("domain_id", domain_id
)->
491 bind("qname", qname
)->
492 bind("qtype", QType(qtype
).getName())->
496 catch(SSqlException
&e
) {
497 throw PDNSException("GSQLBackend unable to nullify ordername and update auth per type for domain_id "+itoa(domain_id
)+": "+e
.txtReason());
504 bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id
, set
<DNSName
>& insert
, set
<DNSName
>& erase
, bool remove
)
510 d_RemoveEmptyNonTerminalsFromZoneQuery_stmt
->
511 bind("domain_id", domain_id
)->
515 catch (SSqlException
&e
) {
516 throw PDNSException("GSQLBackend unable to delete empty non-terminal records from domain_id "+itoa(domain_id
)+": "+e
.txtReason());
522 for(const auto& qname
: erase
) {
526 d_DeleteEmptyNonTerminalQuery_stmt
->
527 bind("domain_id", domain_id
)->
528 bind("qname", qname
)->
532 catch (SSqlException
&e
) {
533 throw PDNSException("GSQLBackend unable to delete empty non-terminal rr '"+qname
.toLogString()+"' from domain_id "+itoa(domain_id
)+": "+e
.txtReason());
539 for(const auto& qname
: insert
) {
543 d_InsertEmptyNonTerminalOrderQuery_stmt
->
544 bind("domain_id", domain_id
)->
545 bind("qname", qname
)->
546 bindNull("ordername")->
551 catch (SSqlException
&e
) {
552 throw PDNSException("GSQLBackend unable to insert empty non-terminal rr '"+qname
.toLogString()+"' in domain_id "+itoa(domain_id
)+": "+e
.txtReason());
560 bool GSQLBackend::doesDNSSEC()
562 return d_dnssecQueries
;
565 bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id
, const DNSName
& qname
, DNSName
& unhashed
, DNSName
& before
, DNSName
& after
)
571 SSqlStatement::row_t row
;
575 d_afterOrderQuery_stmt
->
576 bind("ordername", qname
.labelReverse().toString(" ", false))->
577 bind("domain_id", id
)->
579 while(d_afterOrderQuery_stmt
->hasNextRow()) {
580 d_afterOrderQuery_stmt
->nextRow(row
);
581 ASSERT_ROW_COLUMNS("get-order-after-query", row
, 1);
582 if(! row
[0].empty()) { // Hack because NULL values are passed on as empty strings
583 after
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
586 d_afterOrderQuery_stmt
->reset();
588 catch(SSqlException
&e
) {
589 throw PDNSException("GSQLBackend unable to find before/after (after) for domain_id "+itoa(id
)+" and qname '"+ qname
.toLogString() +"': "+e
.txtReason());
596 d_firstOrderQuery_stmt
->
597 bind("domain_id", id
)->
599 while(d_firstOrderQuery_stmt
->hasNextRow()) {
600 d_firstOrderQuery_stmt
->nextRow(row
);
601 ASSERT_ROW_COLUMNS("get-order-first-query", row
, 1);
602 after
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
604 d_firstOrderQuery_stmt
->reset();
606 catch(SSqlException
&e
) {
607 throw PDNSException("GSQLBackend unable to find before/after (first) for domain_id "+itoa(id
)+" and qname '"+ qname
.toLogString() + "': "+e
.txtReason());
611 if (before
.empty()) {
617 d_beforeOrderQuery_stmt
->
618 bind("ordername", qname
.labelReverse().toString(" ", false))->
619 bind("domain_id", id
)->
621 while(d_beforeOrderQuery_stmt
->hasNextRow()) {
622 d_beforeOrderQuery_stmt
->nextRow(row
);
623 ASSERT_ROW_COLUMNS("get-order-before-query", row
, 2);
624 before
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
626 unhashed
=DNSName(row
[1]);
631 d_beforeOrderQuery_stmt
->reset();
633 catch(SSqlException
&e
) {
634 throw PDNSException("GSQLBackend unable to find before/after (before) for domain_id "+itoa(id
)+" and qname '"+ qname
.toLogString() + ": "+e
.txtReason());
637 if(! unhashed
.empty())
639 // cerr<<"unhashed="<<unhashed<<",before="<<before<<", after="<<after<<endl;
646 d_lastOrderQuery_stmt
->
647 bind("domain_id", id
)->
649 while(d_lastOrderQuery_stmt
->hasNextRow()) {
650 d_lastOrderQuery_stmt
->nextRow(row
);
651 ASSERT_ROW_COLUMNS("get-order-last-query", row
, 2);
652 before
=DNSName(boost::replace_all_copy(row
[0]," ",".")).labelReverse();
654 unhashed
=DNSName(row
[1]);
659 d_lastOrderQuery_stmt
->reset();
661 catch(SSqlException
&e
) {
662 throw PDNSException("GSQLBackend unable to find before/after (last) for domain_id "+itoa(id
)+" and qname '"+ qname
.toLogString() + ": "+e
.txtReason());
671 bool GSQLBackend::addDomainKey(const DNSName
& name
, const KeyData
& key
, int64_t& id
)
679 d_AddDomainKeyQuery_stmt
->
680 bind("flags", key
.flags
)->
681 bind("active", key
.active
)->
682 bind("content", key
.content
)->
683 bind("domain", name
)->
687 catch (SSqlException
&e
) {
688 throw PDNSException("GSQLBackend unable to store key for domain '"+ name
.toLogString() + "': "+e
.txtReason());
694 d_GetLastInsertedKeyIdQuery_stmt
->execute();
695 if (!d_GetLastInsertedKeyIdQuery_stmt
->hasNextRow()) {
699 SSqlStatement::row_t row
;
700 d_GetLastInsertedKeyIdQuery_stmt
->nextRow(row
);
701 ASSERT_ROW_COLUMNS("get-last-inserted-key-id-query", row
, 1);
702 id
= std::stoi(row
[0]);
703 d_GetLastInsertedKeyIdQuery_stmt
->reset();
706 catch (SSqlException
&e
) {
714 bool GSQLBackend::activateDomainKey(const DNSName
& name
, unsigned int id
)
722 d_ActivateDomainKeyQuery_stmt
->
723 bind("domain", name
)->
728 catch (SSqlException
&e
) {
729 throw PDNSException("GSQLBackend unable to activate key with id "+ std::to_string(id
) + " for domain '" + name
.toLogString() + "': "+e
.txtReason());
734 bool GSQLBackend::deactivateDomainKey(const DNSName
& name
, unsigned int id
)
742 d_DeactivateDomainKeyQuery_stmt
->
743 bind("domain", name
)->
748 catch (SSqlException
&e
) {
749 throw PDNSException("GSQLBackend unable to deactivate key with id "+ std::to_string(id
) + " for domain '" + name
.toLogString() + "': "+e
.txtReason());
754 bool GSQLBackend::removeDomainKey(const DNSName
& name
, unsigned int id
)
762 d_RemoveDomainKeyQuery_stmt
->
763 bind("domain", name
)->
768 catch (SSqlException
&e
) {
769 throw PDNSException("GSQLBackend unable to remove key with id "+ std::to_string(id
) + " for domain '" + name
.toLogString() + "': "+e
.txtReason());
774 bool GSQLBackend::getTSIGKey(const DNSName
& name
, DNSName
* algorithm
, string
* content
)
779 d_getTSIGKeyQuery_stmt
->
780 bind("key_name", name
)->
783 SSqlStatement::row_t row
;
786 while(d_getTSIGKeyQuery_stmt
->hasNextRow()) {
787 d_getTSIGKeyQuery_stmt
->nextRow(row
);
788 ASSERT_ROW_COLUMNS("get-tsig-key-query", row
, 2);
790 if(algorithm
->empty() || *algorithm
==DNSName(row
[0])) {
791 *algorithm
= DNSName(row
[0]);
797 d_getTSIGKeyQuery_stmt
->reset();
799 catch (SSqlException
&e
) {
800 throw PDNSException("GSQLBackend unable to retrieve named TSIG key: "+e
.txtReason());
803 return !content
->empty();
806 bool GSQLBackend::setTSIGKey(const DNSName
& name
, const DNSName
& algorithm
, const string
& content
)
811 d_setTSIGKeyQuery_stmt
->
812 bind("key_name", name
)->
813 bind("algorithm", algorithm
)->
814 bind("content", content
)->
818 catch (SSqlException
&e
) {
819 throw PDNSException("GSQLBackend unable to store named TSIG key: "+e
.txtReason());
824 bool GSQLBackend::deleteTSIGKey(const DNSName
& name
)
829 d_deleteTSIGKeyQuery_stmt
->
830 bind("key_name", name
)->
834 catch (SSqlException
&e
) {
835 throw PDNSException("GSQLBackend unable to store named TSIG key: "+e
.txtReason());
840 bool GSQLBackend::getTSIGKeys(std::vector
< struct TSIGKey
> &keys
)
845 d_getTSIGKeysQuery_stmt
->
848 SSqlStatement::row_t row
;
850 while(d_getTSIGKeysQuery_stmt
->hasNextRow()) {
851 d_getTSIGKeysQuery_stmt
->nextRow(row
);
852 ASSERT_ROW_COLUMNS("get-tsig-keys-query", row
, 3);
855 key
.name
= DNSName(row
[0]);
856 key
.algorithm
= DNSName(row
[1]);
864 d_getTSIGKeysQuery_stmt
->reset();
866 catch (SSqlException
&e
) {
867 throw PDNSException("GSQLBackend unable to retrieve TSIG keys: "+e
.txtReason());
873 bool GSQLBackend::getDomainKeys(const DNSName
& name
, std::vector
<KeyData
>& keys
)
881 d_ListDomainKeysQuery_stmt
->
882 bind("domain", name
)->
885 SSqlStatement::row_t row
;
887 while(d_ListDomainKeysQuery_stmt
->hasNextRow()) {
888 d_ListDomainKeysQuery_stmt
->nextRow(row
);
889 ASSERT_ROW_COLUMNS("list-domain-keys-query", row
, 4);
890 //~ for(const auto& val: row) {
891 //~ cerr<<"'"<<val<<"'"<<endl;
893 kd
.id
= pdns_stou(row
[0]);
894 kd
.flags
= pdns_stou(row
[1]);
895 kd
.active
= row
[2] == "1";
900 d_ListDomainKeysQuery_stmt
->reset();
902 catch (SSqlException
&e
) {
903 throw PDNSException("GSQLBackend unable to list keys: "+e
.txtReason());
909 void GSQLBackend::alsoNotifies(const DNSName
&domain
, set
<string
> *ips
)
912 getDomainMetadata(domain
, "ALSO-NOTIFY", meta
);
913 for(const auto& str
: meta
) {
918 bool GSQLBackend::getAllDomainMetadata(const DNSName
& name
, std::map
<std::string
, std::vector
<std::string
> >& meta
)
923 d_GetAllDomainMetadataQuery_stmt
->
924 bind("domain", name
)->
927 SSqlStatement::row_t row
;
929 while(d_GetAllDomainMetadataQuery_stmt
->hasNextRow()) {
930 d_GetAllDomainMetadataQuery_stmt
->nextRow(row
);
931 ASSERT_ROW_COLUMNS("get-all-domain-metadata-query", row
, 2);
933 if (!isDnssecDomainMetadata(row
[0]))
934 meta
[row
[0]].push_back(row
[1]);
937 d_GetAllDomainMetadataQuery_stmt
->reset();
939 catch (SSqlException
&e
) {
940 throw PDNSException("GSQLBackend unable to list metadata: "+e
.txtReason());
947 bool GSQLBackend::getDomainMetadata(const DNSName
& name
, const std::string
& kind
, std::vector
<std::string
>& meta
)
949 if(!d_dnssecQueries
&& isDnssecDomainMetadata(kind
))
955 d_GetDomainMetadataQuery_stmt
->
956 bind("domain", name
)->
960 SSqlStatement::row_t row
;
962 while(d_GetDomainMetadataQuery_stmt
->hasNextRow()) {
963 d_GetDomainMetadataQuery_stmt
->nextRow(row
);
964 ASSERT_ROW_COLUMNS("get-domain-metadata-query", row
, 1);
965 meta
.push_back(row
[0]);
968 d_GetDomainMetadataQuery_stmt
->reset();
970 catch (SSqlException
&e
) {
971 throw PDNSException("GSQLBackend unable to list metadata: "+e
.txtReason());
977 bool GSQLBackend::setDomainMetadata(const DNSName
& name
, const std::string
& kind
, const std::vector
<std::string
>& meta
)
979 if(!d_dnssecQueries
&& isDnssecDomainMetadata(kind
))
985 d_ClearDomainMetadataQuery_stmt
->
986 bind("domain", name
)->
991 for(const auto& value
: meta
) {
992 d_SetDomainMetadataQuery_stmt
->
994 bind("content", value
)->
995 bind("domain", name
)->
1001 catch (SSqlException
&e
) {
1002 throw PDNSException("GSQLBackend unable to store metadata key: "+e
.txtReason());
1008 void GSQLBackend::lookup(const QType
&qtype
,const DNSName
&qname
, DNSPacket
*pkt_p
, int domain_id
)
1011 reconnectIfNeeded();
1013 if(qtype
.getCode()!=QType::ANY
) {
1015 d_query_name
= "basic-query";
1016 d_query_stmt
= &d_NoIdQuery_stmt
;
1018 bind("qtype", qtype
.getName())->
1019 bind("qname", qname
);
1021 d_query_name
= "id-query";
1022 d_query_stmt
= &d_IdQuery_stmt
;
1024 bind("qtype", qtype
.getName())->
1025 bind("qname", qname
)->
1026 bind("domain_id", domain_id
);
1031 d_query_name
= "any-query";
1032 d_query_stmt
= &d_ANYNoIdQuery_stmt
;
1034 bind("qname", qname
);
1036 d_query_name
= "any-id-query";
1037 d_query_stmt
= &d_ANYIdQuery_stmt
;
1039 bind("qname", qname
)->
1040 bind("domain_id", domain_id
);
1047 catch(SSqlException
&e
) {
1048 throw PDNSException("GSQLBackend lookup query:"+e
.txtReason());
1054 bool GSQLBackend::list(const DNSName
&target
, int domain_id
, bool include_disabled
)
1056 DLOG(g_log
<<"GSQLBackend constructing handle for list of domain id '"<<domain_id
<<"'"<<endl
);
1059 reconnectIfNeeded();
1061 d_query_name
= "list-query";
1062 d_query_stmt
= &d_listQuery_stmt
;
1064 bind("include_disabled", (int)include_disabled
)->
1065 bind("domain_id", domain_id
)->
1068 catch(SSqlException
&e
) {
1069 throw PDNSException("GSQLBackend list query: "+e
.txtReason());
1076 bool GSQLBackend::listSubZone(const DNSName
&zone
, int domain_id
) {
1078 string wildzone
= "%." + zone
.makeLowerCase().toStringNoDot();
1081 reconnectIfNeeded();
1083 d_query_name
= "list-subzone-query";
1084 d_query_stmt
= &d_listSubZoneQuery_stmt
;
1086 bind("zone", zone
)->
1087 bind("wildzone", wildzone
)->
1088 bind("domain_id", domain_id
)->
1091 catch(SSqlException
&e
) {
1092 throw PDNSException("GSQLBackend listSubZone query: "+e
.txtReason());
1098 bool GSQLBackend::get(DNSResourceRecord
&r
)
1100 // g_log << "GSQLBackend get() was called for "<<qtype.getName() << " record: ";
1101 SSqlStatement::row_t row
;
1104 if((*d_query_stmt
)->hasNextRow()) {
1106 (*d_query_stmt
)->nextRow(row
);
1107 ASSERT_ROW_COLUMNS(d_query_name
, row
, 8);
1108 } catch (SSqlException
&e
) {
1109 throw PDNSException("GSQLBackend get: "+e
.txtReason());
1112 extractRecord(row
, r
);
1120 (*d_query_stmt
)->reset();
1121 } catch (SSqlException
&e
) {
1122 throw PDNSException("GSQLBackend get: "+e
.txtReason());
1124 d_query_stmt
= NULL
;
1128 bool GSQLBackend::superMasterBackend(const string
&ip
, const DNSName
&domain
, const vector
<DNSResourceRecord
>&nsset
, string
*nameserver
, string
*account
, DNSBackend
**ddb
)
1130 // check if we know the ip/ns couple in the database
1131 for(vector
<DNSResourceRecord
>::const_iterator i
=nsset
.begin();i
!=nsset
.end();++i
) {
1133 reconnectIfNeeded();
1135 d_SuperMasterInfoQuery_stmt
->
1137 bind("nameserver", i
->content
)->
1139 getResult(d_result
)->
1142 catch (SSqlException
&e
) {
1143 throw PDNSException("GSQLBackend unable to search for a domain: "+e
.txtReason());
1145 if(!d_result
.empty()) {
1146 ASSERT_ROW_COLUMNS("supermaster-query", d_result
[0], 1);
1147 *nameserver
=i
->content
;
1148 *account
=d_result
[0][0];
1156 bool GSQLBackend::createDomain(const DNSName
&domain
, const string
&type
, const string
&masters
, const string
&account
)
1159 reconnectIfNeeded();
1161 d_InsertZoneQuery_stmt
->
1162 bind("type", type
)->
1163 bind("domain", domain
)->
1164 bind("masters", masters
)->
1165 bind("account", account
)->
1169 catch(SSqlException
&e
) {
1170 throw PDNSException("Database error trying to insert new domain '"+domain
.toLogString()+"': "+ e
.txtReason());
1175 bool GSQLBackend::createSlaveDomain(const string
&ip
, const DNSName
&domain
, const string
&nameserver
, const string
&account
)
1180 if (!nameserver
.empty()) {
1181 // figure out all IP addresses for the master
1182 reconnectIfNeeded();
1184 d_GetSuperMasterIPs_stmt
->
1185 bind("nameserver", nameserver
)->
1186 bind("account", account
)->
1188 getResult(d_result
)->
1190 if (!d_result
.empty()) {
1191 // collect all IP addresses
1193 for(const auto& row
: d_result
) {
1194 if (account
== row
[1])
1195 tmp
.push_back(row
[0]);
1197 // set them as domain's masters, comma separated
1198 masters
= boost::join(tmp
, ", ");
1201 createDomain(domain
, "SLAVE", masters
, account
);
1203 catch(SSqlException
&e
) {
1204 throw PDNSException("Database error trying to insert new slave domain '"+domain
.toLogString()+"': "+ e
.txtReason());
1209 bool GSQLBackend::deleteDomain(const DNSName
&domain
)
1212 if (!getDomainInfo(domain
, di
)) {
1217 reconnectIfNeeded();
1219 d_DeleteZoneQuery_stmt
->
1220 bind("domain_id", di
.id
)->
1223 d_ClearDomainAllMetadataQuery_stmt
->
1224 bind("domain", domain
)->
1227 d_ClearDomainAllKeysQuery_stmt
->
1228 bind("domain", domain
)->
1231 d_DeleteCommentsQuery_stmt
->
1232 bind("domain_id", di
.id
)->
1235 d_DeleteDomainQuery_stmt
->
1236 bind("domain", domain
)->
1240 catch(SSqlException
&e
) {
1241 throw PDNSException("Database error trying to delete domain '"+domain
.toLogString()+"': "+ e
.txtReason());
1246 void GSQLBackend::getAllDomains(vector
<DomainInfo
> *domains
, bool include_disabled
)
1248 DLOG(g_log
<<"GSQLBackend retrieving all domains."<<endl
);
1251 reconnectIfNeeded();
1253 d_getAllDomainsQuery_stmt
->
1254 bind("include_disabled", (int)include_disabled
)->
1257 SSqlStatement::row_t row
;
1258 while (d_getAllDomainsQuery_stmt
->hasNextRow()) {
1259 d_getAllDomainsQuery_stmt
->nextRow(row
);
1260 ASSERT_ROW_COLUMNS("get-all-domains-query", row
, 8);
1262 di
.id
= pdns_stou(row
[0]);
1264 di
.zone
= DNSName(row
[1]);
1269 if (!row
[4].empty()) {
1270 vector
<string
> masters
;
1271 stringtok(masters
, row
[4], " ,\t");
1272 for(const auto& m
: masters
)
1273 di
.masters
.emplace_back(m
, 53);
1277 fillSOAData(row
[2], sd
);
1278 di
.serial
= sd
.serial
;
1279 di
.notified_serial
= pdns_stou(row
[5]);
1280 di
.last_check
= pdns_stou(row
[6]);
1281 di
.account
= row
[7];
1283 if (pdns_iequals(row
[3], "MASTER"))
1284 di
.kind
= DomainInfo::Master
;
1285 else if (pdns_iequals(row
[3], "SLAVE"))
1286 di
.kind
= DomainInfo::Slave
;
1288 di
.kind
= DomainInfo::Native
;
1292 domains
->push_back(di
);
1294 d_getAllDomainsQuery_stmt
->reset();
1296 catch (SSqlException
&e
) {
1297 throw PDNSException("Database error trying to retrieve all domains:" + e
.txtReason());
1301 bool GSQLBackend::replaceRRSet(uint32_t domain_id
, const DNSName
& qname
, const QType
& qt
, const vector
<DNSResourceRecord
>& rrset
)
1304 reconnectIfNeeded();
1306 if (qt
!= QType::ANY
) {
1307 d_DeleteRRSetQuery_stmt
->
1308 bind("domain_id", domain_id
)->
1309 bind("qname", qname
)->
1310 bind("qtype", qt
.getName())->
1314 d_DeleteNamesQuery_stmt
->
1315 bind("domain_id", domain_id
)->
1316 bind("qname", qname
)->
1321 catch (SSqlException
&e
) {
1322 throw PDNSException("GSQLBackend unable to delete RRSet: "+e
.txtReason());
1325 if (rrset
.empty()) {
1327 reconnectIfNeeded();
1329 d_DeleteCommentRRsetQuery_stmt
->
1330 bind("domain_id", domain_id
)->
1331 bind("qname", qname
)->
1332 bind("qtype", qt
.getName())->
1336 catch (SSqlException
&e
) {
1337 throw PDNSException("GSQLBackend unable to delete comment: "+e
.txtReason());
1340 for(const auto& rr
: rrset
) {
1341 feedRecord(rr
, DNSName());
1347 bool GSQLBackend::feedRecord(const DNSResourceRecord
&r
, const DNSName
&ordername
, bool ordernameIsNSEC3
)
1350 string
content(r
.content
);
1351 if (r
.qtype
== QType::MX
|| r
.qtype
== QType::SRV
) {
1352 string::size_type pos
= content
.find_first_not_of("0123456789");
1353 if (pos
!= string::npos
) {
1354 prio
=pdns_stou(content
.substr(0,pos
));
1355 boost::erase_head(content
, pos
);
1361 reconnectIfNeeded();
1363 d_InsertRecordQuery_stmt
->
1364 bind("content",content
)->
1366 bind("priority",prio
)->
1367 bind("qtype",r
.qtype
.getName())->
1368 bind("domain_id",r
.domain_id
)->
1369 bind("disabled",r
.disabled
)->
1370 bind("qname",r
.qname
);
1372 if (!ordername
.empty())
1373 d_InsertRecordQuery_stmt
->bind("ordername", ordername
.labelReverse().makeLowerCase().toString(" ", false));
1375 d_InsertRecordQuery_stmt
->bindNull("ordername");
1377 if (d_dnssecQueries
)
1378 d_InsertRecordQuery_stmt
->bind("auth", r
.auth
);
1380 d_InsertRecordQuery_stmt
->bind("auth", true);
1382 d_InsertRecordQuery_stmt
->
1386 catch (SSqlException
&e
) {
1387 throw PDNSException("GSQLBackend unable to feed record: "+e
.txtReason());
1389 return true; // XXX FIXME this API should not return 'true' I think -ahu
1392 bool GSQLBackend::feedEnts(int domain_id
, map
<DNSName
,bool>& nonterm
)
1394 for(const auto& nt
: nonterm
) {
1396 reconnectIfNeeded();
1398 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1399 bind("domain_id",domain_id
)->
1400 bind("qname", nt
.first
)->
1401 bindNull("ordername")->
1402 bind("auth",(nt
.second
|| !d_dnssecQueries
))->
1406 catch (SSqlException
&e
) {
1407 throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e
.txtReason());
1413 bool GSQLBackend::feedEnts3(int domain_id
, const DNSName
&domain
, map
<DNSName
,bool> &nonterm
, const NSEC3PARAMRecordContent
& ns3prc
, bool narrow
)
1415 if(!d_dnssecQueries
)
1420 for(const auto& nt
: nonterm
) {
1422 reconnectIfNeeded();
1424 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1425 bind("domain_id",domain_id
)->
1426 bind("qname", nt
.first
);
1427 if (narrow
|| !nt
.second
) {
1428 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1429 bindNull("ordername");
1431 ordername
=toBase32Hex(hashQNameWithSalt(ns3prc
, nt
.first
));
1432 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1433 bind("ordername", ordername
);
1435 d_InsertEmptyNonTerminalOrderQuery_stmt
->
1436 bind("auth",nt
.second
)->
1440 catch (SSqlException
&e
) {
1441 throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e
.txtReason());
1447 bool GSQLBackend::startTransaction(const DNSName
&domain
, int domain_id
)
1450 reconnectIfNeeded();
1452 d_db
->startTransaction();
1453 d_inTransaction
= true;
1454 if(domain_id
>= 0) {
1455 d_DeleteZoneQuery_stmt
->
1456 bind("domain_id", domain_id
)->
1461 catch (SSqlException
&e
) {
1462 d_inTransaction
= false;
1463 throw PDNSException("Database failed to start transaction: "+e
.txtReason());
1469 bool GSQLBackend::commitTransaction()
1473 d_inTransaction
= false;
1475 catch (SSqlException
&e
) {
1476 d_inTransaction
= false;
1477 throw PDNSException("Database failed to commit transaction: "+e
.txtReason());
1482 bool GSQLBackend::abortTransaction()
1486 d_inTransaction
= false;
1488 catch(SSqlException
&e
) {
1489 d_inTransaction
= false;
1490 throw PDNSException("Database failed to abort transaction: "+string(e
.txtReason()));
1495 bool GSQLBackend::listComments(const uint32_t domain_id
)
1498 reconnectIfNeeded();
1500 d_query_name
= "list-comments-query";
1501 d_query_stmt
= &d_ListCommentsQuery_stmt
;
1503 bind("domain_id", domain_id
)->
1506 catch(SSqlException
&e
) {
1507 throw PDNSException("GSQLBackend list comments query: "+e
.txtReason());
1513 bool GSQLBackend::getComment(Comment
& comment
)
1515 SSqlStatement::row_t row
;
1518 if (!(*d_query_stmt
)->hasNextRow()) {
1520 (*d_query_stmt
)->reset();
1521 } catch(SSqlException
&e
) {
1522 throw PDNSException("GSQLBackend comment get: "+e
.txtReason());
1524 d_query_stmt
= NULL
;
1529 (*d_query_stmt
)->nextRow(row
);
1530 ASSERT_ROW_COLUMNS(d_query_name
, row
, 6);
1531 } catch(SSqlException
&e
) {
1532 throw PDNSException("GSQLBackend comment get: "+e
.txtReason());
1535 extractComment(row
, comment
);
1543 void GSQLBackend::feedComment(const Comment
& comment
)
1546 reconnectIfNeeded();
1548 d_InsertCommentQuery_stmt
->
1549 bind("domain_id",comment
.domain_id
)->
1550 bind("qname",comment
.qname
)->
1551 bind("qtype",comment
.qtype
.getName())->
1552 bind("modified_at",comment
.modified_at
)->
1553 bind("account",comment
.account
)->
1554 bind("content",comment
.content
)->
1558 catch (SSqlException
&e
) {
1559 throw PDNSException("GSQLBackend unable to feed comment: "+e
.txtReason());
1563 bool GSQLBackend::replaceComments(const uint32_t domain_id
, const DNSName
& qname
, const QType
& qt
, const vector
<Comment
>& comments
)
1566 reconnectIfNeeded();
1568 d_DeleteCommentRRsetQuery_stmt
->
1569 bind("domain_id",domain_id
)->
1570 bind("qname", qname
)->
1571 bind("qtype",qt
.getName())->
1575 catch (SSqlException
&e
) {
1576 throw PDNSException("GSQLBackend unable to delete comment: "+e
.txtReason());
1579 for(const auto& comment
: comments
) {
1580 feedComment(comment
);
1586 string
GSQLBackend::directBackendCmd(const string
&query
)
1591 auto stmt
= d_db
->prepare(query
,0);
1593 reconnectIfNeeded();
1597 SSqlStatement::row_t row
;
1599 while(stmt
->hasNextRow()) {
1601 for(const auto& col
: row
)
1602 out
<<"\'"<<col
<<"\'\t";
1608 catch (SSqlException
&e
) {
1609 throw PDNSException("GSQLBackend unable to execute query: "+e
.txtReason());
1613 string
GSQLBackend::pattern2SQLPattern(const string
&pattern
)
1615 string escaped_pattern
= boost::replace_all_copy(pattern
,"\\","\\\\");
1616 boost::replace_all(escaped_pattern
,"_","\\_");
1617 boost::replace_all(escaped_pattern
,"%","\\%");
1618 boost::replace_all(escaped_pattern
,"*","%");
1619 boost::replace_all(escaped_pattern
,"?","_");
1620 return escaped_pattern
;
1623 bool GSQLBackend::searchRecords(const string
&pattern
, int maxResults
, vector
<DNSResourceRecord
>& result
)
1627 string escaped_pattern
= pattern2SQLPattern(pattern
);
1629 reconnectIfNeeded();
1631 d_SearchRecordsQuery_stmt
->
1632 bind("value", escaped_pattern
)->
1633 bind("value2", escaped_pattern
)->
1634 bind("limit", maxResults
)->
1637 while(d_SearchRecordsQuery_stmt
->hasNextRow())
1639 SSqlStatement::row_t row
;
1640 DNSResourceRecord r
;
1641 d_SearchRecordsQuery_stmt
->nextRow(row
);
1642 ASSERT_ROW_COLUMNS("search-records-query", row
, 8);
1644 extractRecord(row
, r
);
1648 result
.push_back(r
);
1651 d_SearchRecordsQuery_stmt
->reset();
1655 catch (SSqlException
&e
) {
1656 throw PDNSException("GSQLBackend unable to execute query: "+e
.txtReason());
1662 bool GSQLBackend::searchComments(const string
&pattern
, int maxResults
, vector
<Comment
>& result
)
1666 string escaped_pattern
= pattern2SQLPattern(pattern
);
1668 reconnectIfNeeded();
1670 d_SearchCommentsQuery_stmt
->
1671 bind("value", escaped_pattern
)->
1672 bind("value2", escaped_pattern
)->
1673 bind("limit", maxResults
)->
1676 while(d_SearchCommentsQuery_stmt
->hasNextRow()) {
1677 SSqlStatement::row_t row
;
1678 d_SearchCommentsQuery_stmt
->nextRow(row
);
1679 ASSERT_ROW_COLUMNS("search-comments-query", row
, 6);
1681 extractComment(row
, comment
);
1682 result
.push_back(comment
);
1685 d_SearchCommentsQuery_stmt
->reset();
1689 catch (SSqlException
&e
) {
1690 throw PDNSException("GSQLBackend unable to execute query: "+e
.txtReason());
1696 void GSQLBackend::extractRecord(const SSqlStatement::row_t
& row
, DNSResourceRecord
& r
)
1699 r
.ttl
= ::arg().asNum( "default-ttl" );
1701 r
.ttl
=pdns_stou(row
[1]);
1702 if(!d_qname
.empty())
1705 r
.qname
=DNSName(row
[6]);
1709 if (r
.qtype
==QType::MX
|| r
.qtype
==QType::SRV
)
1710 r
.content
=row
[2]+" "+row
[0];
1717 r
.auth
= !row
[7].empty() && row
[7][0]=='1';
1721 r
.disabled
= !row
[5].empty() && row
[5][0]=='1';
1723 r
.domain_id
=pdns_stou(row
[4]);
1726 void GSQLBackend::extractComment(const SSqlStatement::row_t
& row
, Comment
& comment
)
1728 comment
.domain_id
= pdns_stou(row
[0]);
1729 comment
.qname
= DNSName(row
[1]);
1730 comment
.qtype
= row
[2];
1731 comment
.modified_at
= pdns_stou(row
[3]);
1732 comment
.account
= row
[4];
1733 comment
.content
= row
[5];
1736 SSqlStatement::~SSqlStatement() {
1737 // make sure vtable won't break