--- /dev/null
+// The Generic ODBC Backend\r
+// By Michel Stol <michel@powerdns.com>\r
+\r
+#include "utility.hh"\r
+#include <map>\r
+#include <sstream>\r
+#include <string>\r
+\r
+#include "dns.hh"\r
+#include "dnsbackend.hh"\r
+#include "dnspacket.hh"\r
+#include "ueberbackend.hh"\r
+#include "ahuexception.hh"\r
+#include "logger.hh"\r
+#include "arguments.hh"\r
+#include "sodbc.hh"\r
+#include "godbcbackend.hh"\r
+\r
+\r
+// Connects to the database.\r
+gODBCBackend::gODBCBackend (const std::string & mode, const std::string & suffix) : GSQLBackend( mode, suffix )\r
+{\r
+ try \r
+ {\r
+ setDB( new SODBC( getArg( "datasource" ), getArg( "username" ), getArg( "password" ))); \r
+ } \r
+ catch( SSqlException & e ) \r
+ {\r
+ L<<Logger::Error<< mode << " Connection failed: " << e.txtReason() << std::endl;\r
+ throw AhuException( "Unable to launch " + mode + " connection: " + e.txtReason());\r
+ }\r
+\r
+ L << Logger::Warning << mode << " Connection succesful" << std::endl;\r
+}\r
+\r
+\r
+//! Constructs a gODBCBackend\r
+class gODBCFactory : public BackendFactory\r
+{\r
+public:\r
+ //! Constructor.\r
+ gODBCFactory( const std::string & mode ) : BackendFactory( mode ), d_mode( mode )\r
+ {\r
+ }\r
+ \r
+ //! Declares all needed arguments.\r
+ void declareArguments( const std::string & suffix = "" )\r
+ {\r
+ declare( suffix, "datasource", "Datasource (DSN) to use","PowerDNS");\r
+ declare( suffix, "username", "User to connect as","powerdns");\r
+ declare( suffix, "password", "Password to connect with","");\r
+\r
+ declare( suffix, "basic-query", "Basic query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name='%s'");\r
+ declare( suffix, "id-query", "Basic with ID query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name='%s' and domain_id=%d");\r
+ declare( suffix, "wildcard-query", "Wildcard query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name like '%s'");\r
+ declare( suffix, "wildcard-id-query", "Wildcard with ID query","select content,ttl,prio,type,domain_id,name from records where type='%s' and name like '%s' and domain_id='%d'");\r
+\r
+ declare( suffix, "any-query", "Any query","select content,ttl,prio,type,domain_id,name from records where name='%s'");\r
+ declare( suffix, "any-id-query", "Any with ID query","select content,ttl,prio,type,domain_id,name from records where name='%s' and domain_id=%d");\r
+ declare( suffix, "wildcard-any-query", "Wildcard ANY query","select content,ttl,prio,type,domain_id,name from records where name like '%s'");\r
+ declare( suffix, "wildcard-any-id-query", "Wildcard ANY with ID query","select content,ttl,prio,type,domain_id,name from records where like '%s' and domain_id='%d'");\r
+\r
+ declare( suffix, "list-query", "AXFR query", "select content,ttl,prio,type,domain_id,name from records where domain_id='%d'");\r
+ declare( suffix, "master-zone-query", "Data", "select master from domains where name='%s' and type='SLAVE'");\r
+\r
+ declare( suffix, "info-zone-query", "","select id,name,master,last_check,notified_serial,type from domains where name='%s'");\r
+\r
+ declare( suffix, "info-all-slaves-query", "","select id,name,master,last_check,type from domains where type='SLAVE'");\r
+ declare( suffix, "supermaster-query", "", "select account from supermasters where ip='%s' and nameserver='%s'");\r
+ declare( suffix, "insert-slave-query", "", "insert into domains (type,name,master,account) values('SLAVE','%s','%s','%s')");\r
+ declare( suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,name) values ('%s',%d,%d,'%s',%d,'%s')");\r
+ declare( suffix, "update-serial-query", "", "update domains set notified_serial=%d where id=%d");\r
+ declare( suffix, "update-lastcheck-query", "", "update domains set last_check=%d where id=%d");\r
+ declare( suffix, "info-all-master-query", "", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");\r
+ declare( suffix, "delete-zone-query", "", "delete from records where domain_id=%d");\r
+ }\r
+ \r
+ //! Constructs a new gODBCBackend object.\r
+ DNSBackend *make(const string & suffix = "" )\r
+ {\r
+ return new gODBCBackend( d_mode, suffix );\r
+ }\r
+\r
+private:\r
+ const string d_mode;\r
+};\r
+\r
+\r
+//! Magic class that is activated when the dynamic library is loaded\r
+class gODBCLoader\r
+{\r
+public:\r
+ //! This reports us to the main UeberBackend class\r
+ gODBCLoader()\r
+ {\r
+ BackendMakers().report( new gODBCFactory("godbc"));\r
+ L<<Logger::Warning << "This is module godbcbackend reporting" << std::endl;\r
+ }\r
+};\r
+\r
+\r
+//! Reports the backendloader to the UeberBackend.\r
+static gODBCLoader gmysqlloader;\r
--- /dev/null
+// The Generic ODBC Backend\r
+// By Michel Stol <michel@powerdns.com>\r
+\r
+#include <string>\r
+#include "backends/gsql/gsqlbackend.hh"\r
+\r
+class gODBCBackend : public GSQLBackend\r
+{\r
+private:\r
+public:\r
+ //! Constructor that connects to the database, throws an exception if something went wrong.\r
+ gODBCBackend( const std::string & mode, const std::string & suffix );\r
+\r
+};\r
+\r
--- /dev/null
+// The Generic ODBC Backend\r
+// By Michel Stol <michel@powerdns.com>\r
+\r
+#include "utility.hh"\r
+#include <sstream>\r
+#include "sodbc.hh"\r
+\r
+\r
+// Constructor.\r
+SODBC::SODBC( \r
+ const std::string & dsn,\r
+ const std::string & username,\r
+ const std::string & password \r
+ )\r
+{\r
+ SQLRETURN result;\r
+\r
+ // Allocate an environment handle.\r
+ result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_environment );\r
+ testResult( result, "Could not allocate an environment handle." );\r
+\r
+ // Set ODBC version. (IEUW!)\r
+ result = SQLSetEnvAttr( m_environment, SQL_ATTR_ODBC_VERSION, reinterpret_cast< void * >( SQL_OV_ODBC3 ), 0 );\r
+ testResult( result, "Could not set the ODBC version." );\r
+\r
+ // Allocate connection handle.\r
+ result = SQLAllocHandle( SQL_HANDLE_DBC, m_environment, &m_connection );\r
+ testResult( result, "Could not allocate a connection handle." );\r
+\r
+ // Connect to the database.\r
+ char *l_dsn = _strdup( dsn.c_str());\r
+ char *l_username = _strdup( username.c_str());\r
+ char *l_password = _strdup( password.c_str());\r
+\r
+ result = SQLConnect( m_connection,\r
+ reinterpret_cast< SQLTCHAR * >( l_dsn ), dsn.length(),\r
+ reinterpret_cast< SQLTCHAR * >( l_username ), username.length(),\r
+ reinterpret_cast< SQLTCHAR * >( l_password ), password.length());\r
+\r
+ free( l_dsn );\r
+ free( l_username );\r
+ free( l_password );\r
+\r
+ testResult( result, "Could not connect to ODBC datasource." );\r
+\r
+ // Allocate statement handle.\r
+ result = SQLAllocHandle( SQL_HANDLE_STMT, m_connection, &m_statement );\r
+ testResult( result, "Could not allocate a statement handle." );\r
+\r
+ m_busy = false;\r
+ m_log = false;\r
+}\r
+\r
+\r
+// Destructor.\r
+SODBC::~SODBC( void )\r
+{\r
+ // Disconnect from database and free all used resources.\r
+ SQLFreeHandle( SQL_HANDLE_STMT, m_statement );\r
+\r
+ SQLDisconnect( m_connection );\r
+\r
+ SQLFreeHandle( SQL_HANDLE_DBC, m_connection );\r
+ SQLFreeHandle( SQL_HANDLE_ENV, m_environment );\r
+\r
+ // Free all allocated column memory.\r
+ for ( int i = 0; i < m_columnInfo.size(); i++ )\r
+ {\r
+ if ( m_columnInfo[ i ].m_pData )\r
+ delete m_columnInfo[ i ].m_pData;\r
+ }\r
+}\r
+\r
+\r
+// Executes a query.\r
+int SODBC::doQuery( const std::string & query )\r
+{\r
+ SQLRETURN result;\r
+ char *tmp;\r
+ \r
+ if ( m_busy )\r
+ throw SSqlException( "Tried to execute another query while being busy." );\r
+\r
+ tmp = _strdup( query.c_str());\r
+\r
+ // Execute query.\r
+ result = SQLExecDirect( m_statement, reinterpret_cast< SQLTCHAR * >( tmp ), query.length());\r
+ free( tmp );\r
+\r
+ testResult( result, "Could not execute query." );\r
+\r
+ // We are now busy.\r
+ m_busy = true;\r
+\r
+ // Determine the number of columns.\r
+ SQLSMALLINT numColumns;\r
+ SQLNumResultCols( m_statement, &numColumns );\r
+\r
+ if ( numColumns == 0 )\r
+ throw SSqlException( "Could not determine the number of columns." );\r
+\r
+ // Fill m_columnInfo.\r
+ m_columnInfo.clear();\r
+\r
+ column_t column;\r
+ SQLSMALLINT nullable;\r
+ SQLSMALLINT type;\r
+\r
+ for ( SQLSMALLINT i = 1; i <= numColumns; i++ )\r
+ {\r
+ SQLDescribeCol( m_statement, i, NULL, 0, NULL, &type, &column.m_size, NULL, &nullable );\r
+\r
+ if ( nullable == SQL_NULLABLE )\r
+ column.m_canBeNull = true;\r
+ else\r
+ column.m_canBeNull = false;\r
+\r
+ // Allocate memory.\r
+ switch ( type )\r
+ {\r
+ case SQL_CHAR:\r
+ case SQL_VARCHAR:\r
+ case SQL_LONGVARCHAR:\r
+ column.m_type = SQL_C_CHAR;\r
+ column.m_pData = new SQLCHAR[ column.m_size ];\r
+ break;\r
+\r
+ case SQL_SMALLINT:\r
+ case SQL_INTEGER:\r
+ column.m_type = SQL_C_SLONG;\r
+ column.m_size = sizeof( long int );\r
+ column.m_pData = new long int;\r
+ break;\r
+\r
+ case SQL_REAL:\r
+ case SQL_FLOAT:\r
+ case SQL_DOUBLE:\r
+ column.m_type = SQL_C_DOUBLE;\r
+ column.m_size = sizeof( double );\r
+ column.m_pData = new double;\r
+ break;\r
+\r
+ default:\r
+ column.m_pData = NULL;\r
+\r
+ }\r
+\r
+ m_columnInfo.push_back( column );\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+// Executes a query.\r
+int SODBC::doQuery( const std::string & query, result_t & result )\r
+{\r
+ result.clear();\r
+\r
+ doQuery( query );\r
+\r
+ row_t row;\r
+ while ( getRow( row ))\r
+ result.push_back( row );\r
+\r
+ return result.size();\r
+}\r
+\r
+\r
+// Escapes a SQL string.\r
+std::string SODBC::escape( const std::string & name )\r
+{\r
+ std::string a;\r
+\r
+ for( std::string::const_iterator i = name.begin(); i != name.end(); ++i ) \r
+ {\r
+ if( *i == '\'' || *i == '\\' )\r
+ a += '\\';\r
+ a += *i;\r
+ }\r
+\r
+ return a;\r
+}\r
+\r
+\r
+// Returns the content of a row.\r
+bool SODBC::getRow( row_t & row )\r
+{\r
+ SQLRETURN result;\r
+\r
+ row.clear();\r
+\r
+ result = SQLFetch( m_statement );\r
+ if ( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO )\r
+ {\r
+ // We've got a data row, now lets get the results.\r
+ SQLINTEGER len;\r
+ for ( int i = 0; i < m_columnInfo.size(); i++ )\r
+ {\r
+ if ( m_columnInfo[ i ].m_pData == NULL )\r
+ continue;\r
+\r
+ // Clear buffer.\r
+ memset( m_columnInfo[ i ].m_pData, 0, m_columnInfo[ i ].m_size );\r
+\r
+ SQLGetData( m_statement, i + 1, m_columnInfo[ i ].m_type, m_columnInfo[ i ].m_pData, m_columnInfo[ i ].m_size, &len );\r
+\r
+ if ( len == SQL_NULL_DATA )\r
+ {\r
+ // Column is NULL, so we can skip the converting part.\r
+ row.push_back( "" );\r
+ continue;\r
+ }\r
+\r
+ // Convert the data into strings.\r
+ std::ostringstream str;\r
+\r
+ switch ( m_columnInfo[ i ].m_type )\r
+ {\r
+ case SQL_C_CHAR:\r
+ row.push_back( reinterpret_cast< char * >( m_columnInfo[ i ].m_pData ));\r
+ break;\r
+\r
+ case SQL_C_SSHORT:\r
+ case SQL_C_SLONG:\r
+ str << *( reinterpret_cast< long * >( m_columnInfo[ i ].m_pData ));\r
+ row.push_back( str.str());\r
+\r
+ break;\r
+\r
+ case SQL_C_DOUBLE:\r
+ str << *( reinterpret_cast< double * >( m_columnInfo[ i ].m_pData ));\r
+ row.push_back( str.str());\r
+\r
+ break;\r
+\r
+ default:\r
+ // Eh?\r
+ row.push_back( "" );\r
+\r
+ }\r
+ }\r
+\r
+ // Done!\r
+ return true;\r
+ }\r
+\r
+ // No further results, or error.\r
+ m_busy = false;\r
+\r
+ // Free all allocated column memory.\r
+ for ( int i = 0; i < m_columnInfo.size(); i++ )\r
+ {\r
+ if ( m_columnInfo[ i ].m_pData )\r
+ delete m_columnInfo[ i ].m_pData;\r
+ }\r
+\r
+ SQLFreeStmt( m_statement, SQL_CLOSE );\r
+\r
+ return false;\r
+}\r
+\r
+\r
+// Sets the log state.\r
+void SODBC::setLog( bool state )\r
+{\r
+ m_log = state;\r
+}\r
+\r
+\r
+// Returns an exception.\r
+SSqlException SODBC::sPerrorException( const std::string & reason )\r
+{\r
+ return SSqlException( reason );\r
+}\r
+\r
+\r
+// Tests the result.\r
+void SODBC::testResult( SQLRETURN result, const std::string & message )\r
+{\r
+ if ( result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO )\r
+ throw SSqlException( message );\r
+}\r
--- /dev/null
+// The Generic ODBC Backend\r
+// By Michel Stol <michel@powerdns.com>\r
+\r
+#ifndef SODBC_HH\r
+#define SODBC_HH\r
+\r
+#include <string>\r
+#include <vector>\r
+\r
+// The following line makes Bert puke everytime he sees it.\r
+#define WINDOWS_LEAN_AND_MEAN\r
+#include <windows.h>\r
+#include <sql.h>\r
+#include <sqlext.h>\r
+\r
+#include "backends/gsql/ssql.hh"\r
+\r
+\r
+//! ODBC SSql implementation for use with the Generic ODBC Backend.\r
+class SODBC : public SSql\r
+{\r
+private: \r
+ //! Column type.\r
+ struct column_t\r
+ {\r
+ SQLSMALLINT m_type; //!< Type of the column.\r
+ SQLUINTEGER m_size; //!< Column size.\r
+ SQLPOINTER m_pData; //!< Pointer to the memory where to store the data.\r
+ bool m_canBeNull; //!< Can this column be null?\r
+ };\r
+\r
+ bool m_log; //!< Should we log?\r
+ bool m_busy; //!< Are we busy executing a query?\r
+ \r
+ SQLHDBC m_connection; //!< Database connection handle. \r
+ SQLHENV m_environment; //!< Database environment handle \r
+ SQLHSTMT m_statement; //!< Database statement handle.\r
+\r
+ //! Column info.\r
+ std::vector< column_t > m_columnInfo;\r
+\r
+\r
+ //! Throws a SQLException if the result has an error value.\r
+ void testResult( SQLRETURN result, const std::string & message = "" );\r
+\r
+\r
+public:\r
+ //! Default constructor.\r
+ /*!\r
+ This constructor connects to an ODBC datasource and makes sure it's ready to use.\r
+\r
+ \param database The database where the data is located (not used).\r
+ \param dsn The ODBC DSN to use.\r
+ \param username Username to use.\r
+ \param password Password to use.\r
+ */\r
+ SODBC( \r
+ const std::string & dsn = "PowerDNS", \r
+ const std::string & username = "", \r
+ const std::string & password = "" \r
+ );\r
+\r
+ //! Destructor.\r
+ virtual ~SODBC( void );\r
+\r
+ //! Executes a query.\r
+ int doQuery( const std::string & query );\r
+\r
+ //! Executes a query and stores the result.\r
+ int doQuery( const std::string & query, result_t & result );\r
+\r
+ //! Escapes a SQL string.\r
+ std::string escape( const std::string & name );\r
+\r
+ //! Returns a row.\r
+ bool getRow( row_t & row );\r
+\r
+ //! Sets the logging state.\r
+ void setLog( bool state );\r
+\r
+ //! Returns an exception.\r
+ SSqlException sPerrorException( const std::string & reason );\r
+\r
+};\r
+\r
+\r
+#endif // SODBC_HH\r
-// $Id: pdnsbackend.cc,v 1.3 2002/12/09 16:24:17 ahu Exp $
+// $Id: pdnsbackend.cc,v 1.4 2003/02/10 12:08:06 ahu Exp $
#include <string>
#include <map>
outSoaData.retry = 3600;
outSoaData.expire = 604800;
outSoaData.default_ttl = 40000;
+ outSoaData.db = this;
theResult = true;
}