]> granicus.if.org Git - pdns/commitdiff
wuh
authorBert Hubert <bert.hubert@netherlabs.nl>
Mon, 10 Feb 2003 12:08:06 +0000 (12:08 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Mon, 10 Feb 2003 12:08:06 +0000 (12:08 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@150 d19b8d6e-7fed-0310-83ef-9ca221ded41b

modules/godbcbackend/godbcbackend.cc [new file with mode: 0644]
modules/godbcbackend/godbcbackend.hh [new file with mode: 0644]
modules/godbcbackend/sodbc.cc [new file with mode: 0644]
modules/godbcbackend/sodbc.hh [new file with mode: 0644]
modules/pdnsbackend/pdnsbackend.cc

diff --git a/modules/godbcbackend/godbcbackend.cc b/modules/godbcbackend/godbcbackend.cc
new file mode 100644 (file)
index 0000000..694f3e5
--- /dev/null
@@ -0,0 +1,103 @@
+// 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
diff --git a/modules/godbcbackend/godbcbackend.hh b/modules/godbcbackend/godbcbackend.hh
new file mode 100644 (file)
index 0000000..c7fcf2b
--- /dev/null
@@ -0,0 +1,15 @@
+// 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
diff --git a/modules/godbcbackend/sodbc.cc b/modules/godbcbackend/sodbc.cc
new file mode 100644 (file)
index 0000000..738113e
--- /dev/null
@@ -0,0 +1,283 @@
+// 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
diff --git a/modules/godbcbackend/sodbc.hh b/modules/godbcbackend/sodbc.hh
new file mode 100644 (file)
index 0000000..caf1252
--- /dev/null
@@ -0,0 +1,87 @@
+// 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
index 349b77d6fdb04f23e28a34e202813b19e9a2c851..15b95609cfe0319f4df6d8720c4e0b4580cced38 100644 (file)
@@ -1,4 +1,4 @@
-// $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>
@@ -166,6 +166,7 @@ bool PdnsBackend::getSOA(const string& inZoneName, SOAData& outSoaData)
       outSoaData.retry = 3600;
       outSoaData.expire = 604800;
       outSoaData.default_ttl = 40000;
+      outSoaData.db = this;
       
       theResult = true;
    }