[logback-dev] svn commit: r598 - in logback/trunk/logback-classic/src: main/java/ch/qos/logback/classic/db main/java/ch/qos/logback/classic/db/dialect test/input/db test/java/ch/qos/logback/classic/db

noreply.seb at qos.ch noreply.seb at qos.ch
Fri Sep 22 17:12:36 CEST 2006


Author: seb
Date: Fri Sep 22 17:12:36 2006
New Revision: 598

Added:
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/ConnectionSource.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/ConnectionSourceBase.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBHelper.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DataSourceConnectionSource.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DriverManagerConnectionSource.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/JNDIConnectionSource.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/DBUtil.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/HSQLDBDialect.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/MsSQLDialect.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/MySQLDialect.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/OracleDialect.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/PostgreSQLDialect.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/SQLDialect.java
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2l.sql
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql
   logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql
   logback/trunk/logback-classic/src/test/input/db/
   logback/trunk/logback-classic/src/test/input/db/dbAppenderUsingConnectionSource.xml
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/db/
   logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/db/DBAppenderTest.java

Log:
Work in progress:
- added DBAppender and related classes.
- added a configuration example
- added a empty-for-now test case.
A simple logback to mysql test worked with this first version

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/ConnectionSource.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/ConnectionSource.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,66 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.qos.logback.classic.db;
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import ch.qos.logback.core.spi.LifeCycle;
+
+
+/**
+ *  The <id>ConnectionSource</id> interface provides a pluggable means of
+ *  transparently obtaining JDBC {@link java.sql.Connection}s for log4j classes
+ *  that require the use of a {@link java.sql.Connection}.
+ *
+ *  @author <a href="mailto:rdecampo at twcny.rr.com">Ray DeCampo</a>
+ */
+public interface ConnectionSource extends LifeCycle {
+
+  final int UNKNOWN_DIALECT = 0;
+  final int POSTGRES_DIALECT = 1;
+  final int MYSQL_DIALECT = 2;
+  final int ORACLE_DIALECT = 3;
+  final int MSSQL_DIALECT = 4;
+  final int HSQL_DIALECT = 5;  
+  /**
+   *  Obtain a {@link java.sql.Connection} for use.  The client is
+   *  responsible for closing the {@link java.sql.Connection} when it is no
+   *  longer required.
+   *
+   *  @throws SQLException  if a {@link java.sql.Connection} could not be
+   *                        obtained
+   */
+  Connection getConnection() throws SQLException;
+
+  /**
+   * Get the SQL dialect that should be used for this connection. Note that the
+   * dialect is not needed if the JDBC driver supports the getGeneratedKeys 
+   * method.
+   */
+  int getSQLDialectCode();
+  
+  /**
+   * If the connection supports the JDBC 3.0 getGeneratedKeys method, then
+   * we do not need any specific dialect support.
+   */
+  boolean supportsGetGeneratedKeys();
+  
+  /**
+   * If the connection does not support batch updates, we will avoid using them.
+   */  
+  public boolean supportsBatchUpdates();
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/ConnectionSourceBase.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/ConnectionSourceBase.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.qos.logback.classic.db;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+import ch.qos.logback.classic.db.dialect.DBUtil;
+import ch.qos.logback.core.spi.ContextAwareBase;
+
+
+/**
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public abstract class ConnectionSourceBase extends ContextAwareBase implements ConnectionSource {
+  
+  private boolean started;
+  
+  private String user = null;
+  private String password = null;
+
+  // initially we have an unkonw dialect
+  private int dialectCode = UNKNOWN_DIALECT;
+  private boolean supportsGetGeneratedKeys = false;
+  private boolean supportsBatchUpdates = false;
+
+
+  /**
+   * Learn relevant information about this connection source.
+   *
+   */
+  public void discoverConnnectionProperties() {
+    try {
+      Connection connection = getConnection();
+      if (connection == null) {
+        addWarn("Could not get a conneciton");
+        return;
+      }
+      DatabaseMetaData meta = connection.getMetaData();
+      DBUtil util = new DBUtil();
+      util.setContext(getContext());
+      supportsGetGeneratedKeys = util.supportsGetGeneratedKeys(meta);
+      supportsBatchUpdates = util.supportsBatchUpdates(meta);
+      dialectCode = DBUtil.discoverSQLDialect(meta);
+    } catch (SQLException se) {
+      addWarn("Could not discover the dialect to use.", se);
+    }
+  }
+
+  /**
+   * Does this connection support the JDBC Connection.getGeneratedKeys method?
+   */
+  public final boolean supportsGetGeneratedKeys() {
+    return supportsGetGeneratedKeys;
+  }
+
+  public final int getSQLDialectCode() {
+    return dialectCode;
+  }
+
+  /**
+   * Get the password for this connection source.
+   */
+  public final String getPassword() {
+    return password;
+  }
+
+  /**
+   * Sets the password.
+   * @param password The password to set
+   */
+  public final void setPassword(final String password) {
+    this.password = password;
+  }
+
+  /**
+   * Get the user for this connection source.
+   */
+  public final String getUser() {
+    return user;
+  }
+
+  /**
+   * Sets the username.
+   * @param username The username to set
+   */
+  public final void setUser(final String username) {
+    this.user = username;
+  }
+
+  /**
+   * Does this connection support batch updates?
+   */
+  public final boolean supportsBatchUpdates() {
+    return supportsBatchUpdates;
+  }
+
+  public boolean isStarted() {
+    return started;
+  }
+
+  public void start() {
+    started = true;
+  }
+
+  public void stop() {
+    started = false;
+  }
+  
+  
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBAppender.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,394 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import ch.qos.logback.classic.db.dialect.DBUtil;
+import ch.qos.logback.classic.db.dialect.SQLDialect;
+import ch.qos.logback.classic.spi.CallerData;
+import ch.qos.logback.classic.spi.LoggingEvent;
+import ch.qos.logback.classic.spi.ThrowableInformation;
+import ch.qos.logback.core.AppenderBase;
+import ch.qos.logback.core.Layout;
+
+/**
+ * The DBAppender inserts loggin events into three database tables in a format
+ * independent of the Java programming language. The three tables that
+ * DBAppender inserts to must exists before DBAppender can be used. These tables
+ * may be created with the help of SQL scripts found in the
+ * <em>src/main/java/ch/qos/logback/classic/db/dialect</em> directory. There
+ * is a specific script for each of the most popular database systems. If the
+ * script for your particular type of database system is missing, it should be
+ * quite easy to write one, taking example on the already existing scripts. If
+ * you send them to us, we will gladly include missing scripts in future
+ * releases.
+ * 
+ * <p>
+ * If the JDBC driver you are using supports the
+ * {@link java.sql.Statement#getGeneratedKeys}method introduced in JDBC 3.0
+ * specification, then you are all set. Otherwise, there must be an
+ * {@link SQLDialect}appropriate for your database system. Currently, we have
+ * dialects for PostgreSQL, MySQL, Oracle and MsSQL. As mentioed previously, an
+ * SQLDialect is required only if the JDBC driver for your database system does
+ * not support the {@link java.sql.Statement#getGeneratedKeys getGeneratedKeys}
+ * method.
+ * </p>
+ * 
+ * <table border="1" cellpadding="4">
+ * <tr>
+ * <th>RDBMS</th>
+ * <th>supports <br/><code>getGeneratedKeys()</code> method</th>
+ * <th>specific <br/>SQLDialect support</th>
+ * <tr>
+ * <tr>
+ * <td>PostgreSQL</td>
+ * <td align="center">NO</td>
+ * <td>present and used</td>
+ * <tr>
+ * <tr>
+ * <td>MySQL</td>
+ * <td align="center">YES</td>
+ * <td>present, but not actually needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>Oracle</td>
+ * <td align="center">YES</td>
+ * <td>present, but not actually needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>DB2</td>
+ * <td align="center">YES</td>
+ * <td>not present, and not needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>MsSQL</td>
+ * <td align="center">YES</td>
+ * <td>not present, and not needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>HSQL</td>
+ * <td align="center">NO</td>
+ * <td>present and used</td>
+ * <tr>
+ * 
+ * </table>
+ * <p>
+ * <b>Performance: </b> Experiments show that writing a single event into the
+ * database takes approximately 50 milliseconds, on a "standard" PC. If pooled
+ * connections are used, this figure drops to under 10 milliseconds. Note that
+ * most JDBC drivers already ship with connection pooling support.
+ * </p>
+ * 
+ * 
+ * 
+ * <p>
+ * <b>Configuration </b> DBAppender can be configured programmatically, or using
+ * {@link ch.qos.logback.classic.joran.JoranConfigurator JoranConfigurator}.
+ * Example scripts can be found in the <em>tests/input/db</em> directory.
+ * 
+ * @author Ceki G&uuml;lc&uuml;
+ * @author Ray DeCampo
+ * @author S&eacute;bastien Pennec
+ */
+public class DBAppender extends AppenderBase {
+  static final String insertPropertiesSQL = "INSERT INTO  logging_event_property (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)";
+  static final String insertExceptionSQL = "INSERT INTO  logging_event_exception (event_id, i, trace_line) VALUES (?, ?, ?)";
+  static final String insertSQL;
+  private static final Method GET_GENERATED_KEYS_METHOD;
+
+  static {
+    StringBuffer sql = new StringBuffer();
+    sql.append("INSERT INTO logging_event (");
+    sql.append("timestmp, ");
+    sql.append("formatted_message, ");
+    sql.append("logger_name, ");
+    sql.append("level_string, ");
+    sql.append("thread_name, ");
+    sql.append("reference_flag, ");
+    sql.append("caller_filename, ");
+    sql.append("caller_class, ");
+    sql.append("caller_method, ");
+    sql.append("caller_line) ");
+    sql.append(" VALUES (?, ?, ? ,?, ?, ?, ?, ?, ?,?)");
+    insertSQL = sql.toString();
+    //
+    // PreparedStatement.getGeneratedKeys added in JDK 1.4
+    //
+    Method getGeneratedKeysMethod;
+    try {
+      getGeneratedKeysMethod = PreparedStatement.class.getMethod(
+          "getGeneratedKeys", (Class[]) null);
+    } catch (Exception ex) {
+      getGeneratedKeysMethod = null;
+    }
+    GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
+  }
+
+  ConnectionSource connectionSource;
+  boolean cnxSupportsGetGeneratedKeys = false;
+  boolean cnxSupportsBatchUpdates = false;
+  SQLDialect sqlDialect;
+  boolean locationInfo = false;
+
+  public DBAppender() {
+  }
+
+  @Override
+  public void start() {
+
+    if (connectionSource == null) {
+      throw new IllegalStateException(
+          "DBAppender cannot function without a connection source");
+    }
+
+    sqlDialect = DBUtil
+        .getDialectFromCode(connectionSource.getSQLDialectCode());
+    if (GET_GENERATED_KEYS_METHOD != null) {
+      cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
+    } else {
+      cnxSupportsGetGeneratedKeys = false;
+    }
+    cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
+    if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
+      throw new IllegalStateException(
+          "DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
+    }
+
+    // all nice and dandy on the eastern front
+    super.start();
+  }
+
+  /**
+   * @return Returns the connectionSource.
+   */
+  public ConnectionSource getConnectionSource() {
+    return connectionSource;
+  }
+
+  /**
+   * @param connectionSource
+   *          The connectionSource to set.
+   */
+  public void setConnectionSource(ConnectionSource connectionSource) {
+    this.connectionSource = connectionSource;
+  }
+
+  @Override
+  protected void append(Object eventObject) {
+    LoggingEvent event = (LoggingEvent) eventObject;
+    Connection connection = null;
+    try {
+      connection = connectionSource.getConnection();
+      connection.setAutoCommit(false);
+
+      PreparedStatement insertStatement = connection
+          .prepareStatement(insertSQL);
+
+      addLoggingEvent(insertStatement, event);
+      // This is very expensive... should we do it every time?
+      addCallerData(insertStatement, event.getCallerData());
+
+      int updateCount = insertStatement.executeUpdate();
+      if (updateCount != 1) {
+        addWarn("Failed to insert loggingEvent");
+      }
+
+      int eventId = getEventId(insertStatement, connection);
+
+      // we no longer need the insertStatement
+      if (insertStatement != null) {
+        insertStatement.close();
+        insertStatement = null;
+      }
+
+      Map<String, String> mergedMap = mergePropertyMaps(event);
+      insertProperties(mergedMap, connection, eventId);
+
+      insertThrowable(event.getThrowableInformation(), connection, eventId);
+
+      connection.commit();
+    } catch (Throwable sqle) {
+      addError("problem appending event", sqle);
+    } finally {
+      DBHelper.closeConnection(connection);
+    }
+  }
+
+  void addLoggingEvent(PreparedStatement stmt, LoggingEvent event)
+      throws SQLException {
+    stmt.setLong(1, event.getTimeStamp());
+    stmt.setString(2, event.getFormattedMessage());
+    stmt.setString(3, event.getLoggerRemoteView().getName());
+    stmt.setString(4, event.getLevel().toString());
+    stmt.setString(5, event.getThreadName());
+    stmt.setShort(6, DBHelper.computeReferenceMask(event));
+  }
+
+  void addCallerData(PreparedStatement stmt, CallerData[] callerDataArray)
+      throws SQLException {
+    CallerData callerData = callerDataArray[0];
+    if (callerData != null) {
+      stmt.setString(7, callerData.getFileName());
+      stmt.setString(8, callerData.getClassName());
+      stmt.setString(9, callerData.getMethodName());
+      stmt.setString(10, Integer.toString(callerData.getLineNumber()));
+    }
+  }
+
+  int getEventId(PreparedStatement insertStatement, Connection connection)
+      throws SQLException, InvocationTargetException {
+    ResultSet rs = null;
+    Statement idStatement = null;
+    boolean gotGeneratedKeys = false;
+    if (cnxSupportsGetGeneratedKeys) {
+      try {
+        rs = (ResultSet) GET_GENERATED_KEYS_METHOD.invoke(insertStatement,
+            (Object[]) null);
+        gotGeneratedKeys = true;
+      } catch (InvocationTargetException ex) {
+        Throwable target = ex.getTargetException();
+        if (target instanceof SQLException) {
+          throw (SQLException) target;
+        }
+        throw ex;
+      } catch (IllegalAccessException ex) {
+        addWarn(
+            "IllegalAccessException invoking PreparedStatement.getGeneratedKeys",
+            ex);
+      }
+    }
+
+    if (!gotGeneratedKeys) {
+      insertStatement.close();
+      insertStatement = null;
+
+      idStatement = connection.createStatement();
+      idStatement.setMaxRows(1);
+      rs = idStatement.executeQuery(sqlDialect.getSelectInsertId());
+    }
+
+    // A ResultSet cursor is initially positioned before the first row;
+    // the
+    // first call to the method next makes the first row the current row
+    rs.next();
+    int eventId = rs.getInt(1);
+
+    rs.close();
+
+    if (idStatement != null) {
+      idStatement.close();
+      idStatement = null;
+    }
+
+    return eventId;
+  }
+
+  Map<String, String> mergePropertyMaps(LoggingEvent event) {
+    Map<String, String> mergedMap = new HashMap<String, String>();
+    // we add the context properties first, then the event properties, since
+    // we consider that event-specific properties should have priority over
+    // context-wide
+    // properties.
+    Map<String, String> loggerContextMap = event.getLoggerRemoteView()
+        .getLoggerContextView().getPropertyMap();
+    Map<String, String> mdcMap = event.getMDCPropertyMap();
+    if (loggerContextMap != null) {
+      mergedMap.putAll(loggerContextMap);
+    }
+    if (mdcMap != null) {
+      mergedMap.putAll(mdcMap);
+    }
+
+    return mergedMap;
+  }
+
+  void insertProperties(Map<String, String> mergedMap, Connection connection,
+      int eventId) throws SQLException {
+    Set propertiesKeys = mergedMap.keySet();
+    if (propertiesKeys.size() > 0) {
+      PreparedStatement insertPropertiesStatement = connection
+          .prepareStatement(insertPropertiesSQL);
+
+      for (Iterator i = propertiesKeys.iterator(); i.hasNext();) {
+        String key = (String) i.next();
+        String value = (String) mergedMap.get(key);
+
+        insertPropertiesStatement.setInt(1, eventId);
+        insertPropertiesStatement.setString(2, key);
+        insertPropertiesStatement.setString(3, value);
+
+        if (cnxSupportsBatchUpdates) {
+          insertPropertiesStatement.addBatch();
+        } else {
+          insertPropertiesStatement.execute();
+        }
+      }
+
+      if (cnxSupportsBatchUpdates) {
+        insertPropertiesStatement.executeBatch();
+      }
+
+      insertPropertiesStatement.close();
+      insertPropertiesStatement = null;
+    }
+  }
+
+  void insertThrowable(ThrowableInformation ti, Connection connection,
+      int eventId) throws SQLException {
+    String[] strRep = null;
+    if (ti != null) {
+      strRep = ti.getThrowableStrRep();
+
+      PreparedStatement insertExceptionStatement = connection
+          .prepareStatement(insertExceptionSQL);
+
+      for (short i = 0; i < strRep.length; i++) {
+        insertExceptionStatement.setInt(1, eventId);
+        insertExceptionStatement.setShort(2, i);
+        insertExceptionStatement.setString(3, strRep[i]);
+        if (cnxSupportsBatchUpdates) {
+          insertExceptionStatement.addBatch();
+        } else {
+          insertExceptionStatement.execute();
+        }
+      }
+      if (cnxSupportsBatchUpdates) {
+        insertExceptionStatement.executeBatch();
+      }
+      insertExceptionStatement.close();
+      insertExceptionStatement = null;
+    }
+  }
+
+  @Override
+  public void stop() {
+    super.stop();
+  }
+
+  public Layout getLayout() {
+    return null;
+  }
+
+  public void setLayout(Layout layout) {
+  }
+
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBHelper.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DBHelper.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,72 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import ch.qos.logback.classic.spi.LoggingEvent;
+
+/**
+ * @author Ceki G&uuml;lc&uuml;
+ * 
+ */
+public class DBHelper {
+
+  public static short PROPERTIES_EXIST = 0x01;
+  public static short EXCEPTION_EXISTS = 0x02;
+
+  public static short computeReferenceMask(LoggingEvent event) {
+    short mask = 0;
+
+    int mdcPropSize = 0;
+    if (event.getMDCPropertyMap() != null) {
+      mdcPropSize = event.getMDCPropertyMap().keySet().size();
+    }
+    int contextPropSize = 0;
+    if (event.getLoggerRemoteView().getLoggerContextView().getPropertyMap() != null) {
+      contextPropSize = event.getLoggerRemoteView().getLoggerContextView()
+          .getPropertyMap().size();
+    }
+
+    if (mdcPropSize > 0 || contextPropSize > 0) {
+      mask = PROPERTIES_EXIST;
+    }
+    if (event.getThrowableInformation() != null) {
+      String[] strRep = event.getThrowableInformation().getThrowableStrRep();
+      if (strRep != null) {
+        mask |= EXCEPTION_EXISTS;
+      }
+    }
+    return mask;
+  }
+
+  static public void closeConnection(Connection connection) {
+    if (connection != null) {
+      try {
+        connection.close();
+      } catch (SQLException sqle) {
+        // static utility classes should not log without an explicit repository
+        // reference
+      }
+    }
+  }
+
+  public static void closeStatement(Statement statement) {
+    if (statement != null) {
+      try {
+        statement.close();
+      } catch (SQLException sqle) {
+      }
+    }
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DataSourceConnectionSource.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DataSourceConnectionSource.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,78 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db;
+
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.DataSource;
+
+
+/**
+ *  The DataSourceConnectionSource is an implementation of {@link ConnectionSource}
+ *  that obtains the Connection in the recommended JDBC manner based on
+ *  a {@link javax.sql.DataSource DataSource}.
+ *  <p>
+ *
+ *  @author Ray DeCampo
+ *  @author Ceki G&uuml;lc&uuml;
+ */
+public class DataSourceConnectionSource extends ConnectionSourceBase {
+
+  private DataSource dataSource;
+
+  @Override
+  public void start() {
+    //LogLog.debug("**********DataSourceConnectionSource.activateOptions called");
+    if (dataSource == null) {
+      addWarn("WARNING: No data source specified");
+    } else {
+      Connection connection = null;
+      try {
+        connection = getConnection();
+      } catch(SQLException se) {
+        addWarn("Could not get a connection to discover the dialect to use.", se);
+      }
+      if(connection != null) {
+        discoverConnnectionProperties();
+      } 
+      if(!supportsGetGeneratedKeys() && getSQLDialectCode() == ConnectionSource.UNKNOWN_DIALECT) {
+        addWarn("Connection does not support GetGeneratedKey method and could not discover the dialect.");
+      }
+    }
+    super.start();
+  }
+
+  /**
+   * @see org.apache.log4j.db.ConnectionSource#getConnection()
+   */
+  public Connection getConnection() throws SQLException {
+    if (dataSource == null) {
+      addError("WARNING: No data source specified");
+      return null;
+    }
+
+    if (getUser() == null) {
+      return dataSource.getConnection();
+    } else {
+      return dataSource.getConnection(getUser(), getPassword());
+    }
+  }
+
+  public DataSource getDataSource() {
+    return dataSource;
+  }
+
+  public void setDataSource(DataSource dataSource) {
+    this.dataSource = dataSource;
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DriverManagerConnectionSource.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/DriverManagerConnectionSource.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,129 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * The DriverManagerConnectionSource is an implementation of
+ * {@link ConnectionSource} that obtains the Connection in the traditional JDBC
+ * manner based on the connection URL.
+ * <p>
+ * Note that this class will establish a new Connection for each call to
+ * {@link #getConnection()}. It is recommended that you either use a JDBC
+ * driver that natively supported Connection pooling or that you create your own
+ * implementation of {@link ConnectionSource} that taps into whatever pooling
+ * mechanism you are already using. (If you have access to a JNDI implementation
+ * that supports {@link javax.sql.DataSource}s, e.g. within a J2EE application
+ * server, see {@link JNDIConnectionSource}). See <a href="#dbcp">below</a>
+ * for a configuration example that uses the <a
+ * href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
+ * package from Apache.
+ * <p>
+ * Sample configuration:<br>
+ * 
+ * <pre>
+ *      &lt;connectionSource class=&quot;org.apache.log4j.jdbc.DriverManagerConnectionSource&quot;&gt;
+ *         &lt;param name=&quot;driver&quot; value=&quot;com.mysql.jdbc.Driver&quot; /&gt;
+ *         &lt;param name=&quot;url&quot; value=&quot;jdbc:mysql://localhost:3306/mydb&quot; /&gt;
+ *         &lt;param name=&quot;username&quot; value=&quot;myUser&quot; /&gt;
+ *         &lt;param name=&quot;password&quot; value=&quot;myPassword&quot; /&gt;
+ *      &lt;/connectionSource&gt;
+ * </pre>
+ * 
+ * <p>
+ * <a name="dbcp">If</a> you do not have another connection pooling mechanism
+ * built into your application, you can use the <a
+ * href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
+ * package from Apache:<br>
+ * 
+ * <pre>
+ *      &lt;connectionSource class=&quot;org.apache.log4j.jdbc.DriverManagerConnectionSource&quot;&gt;
+ *         &lt;param name=&quot;driver&quot; value=&quot;org.apache.commons.dbcp.PoolingDriver&quot; /&gt;
+ *         &lt;param name=&quot;url&quot; value=&quot;jdbc:apache:commons:dbcp:/myPoolingDriver&quot; /&gt;
+ *      &lt;/connectionSource&gt;
+ * </pre>
+ * 
+ * Then the configuration information for the commons-dbcp package goes into the
+ * file myPoolingDriver.jocl and is placed in the classpath. See the <a
+ * href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
+ * documentation for details.
+ * 
+ * @author <a href="mailto:rdecampo at twcny.rr.com">Ray DeCampo</a>
+ */
+public class DriverManagerConnectionSource extends ConnectionSourceBase {
+  private String driverClass = null;
+  private String url = null;
+
+  public void start() {
+    try {
+      if (driverClass != null) {
+        Class.forName(driverClass);
+        discoverConnnectionProperties();
+      } else {
+        addError("WARNING: No JDBC driver specified for log4j DriverManagerConnectionSource.");
+      }
+    } catch (final ClassNotFoundException cnfe) {
+      addError("Could not load JDBC driver class: " + driverClass, cnfe);
+    }
+  }
+
+  /**
+   * @see org.apache.log4j.db.ConnectionSource#getConnection()
+   */
+  public Connection getConnection() throws SQLException {
+    if (getUser() == null) {
+      return DriverManager.getConnection(url);
+    } else {
+      return DriverManager.getConnection(url, getUser(), getPassword());
+    }
+  }
+
+  /**
+   * Returns the url.
+   * 
+   * @return String
+   */
+  public String getUrl() {
+    return url;
+  }
+
+  /**
+   * Sets the url.
+   * 
+   * @param url
+   *          The url to set
+   */
+  public void setUrl(String url) {
+    this.url = url;
+  }
+
+  /**
+   * Returns the name of the driver class.
+   * 
+   * @return String
+   */
+  public String getDriverClass() {
+    return driverClass;
+  }
+
+  /**
+   * Sets the driver class.
+   * 
+   * @param driverClass
+   *          The driver class to set
+   */
+  public void setDriverClass(String driverClass) {
+    this.driverClass = driverClass;
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/JNDIConnectionSource.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/JNDIConnectionSource.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,140 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.db;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+// PortableRemoteObject was introduced in JDK 1.3. We won't use it.
+// import javax.rmi.PortableRemoteObject;
+import javax.sql.DataSource;
+
+/**
+ * The <id>JNDIConnectionSource</id> is an implementation of
+ * {@link ConnectionSource} that obtains a {@link javax.sql.DataSource} from a
+ * JNDI provider and uses it to obtain a {@link java.sql.Connection}. It is
+ * primarily designed to be used inside of J2EE application servers or
+ * application server clients, assuming the application server supports remote
+ * access of {@link javax.sql.DataSource}s. In this way one can take advantage
+ * of connection pooling and whatever other goodies the application server
+ * provides.
+ * <p>
+ * Sample configuration:<br>
+ * 
+ * <pre>
+ *     &lt;connectionSource class=&quot;org.apache.log4j.jdbc.JNDIConnectionSource&quot;&gt;
+ *         &lt;param name=&quot;jndiLocation&quot; value=&quot;jdbc/MySQLDS&quot; /&gt;
+ *     &lt;/connectionSource&gt;
+ * </pre>
+ * 
+ * <p>
+ * Sample configuration (with username and password):<br>
+ * 
+ * <pre>
+ *     &lt;connectionSource class=&quot;org.apache.log4j.jdbc.JNDIConnectionSource&quot;&gt;
+ *         &lt;param name=&quot;jndiLocation&quot; value=&quot;jdbc/MySQLDS&quot; /&gt;
+ *         &lt;param name=&quot;username&quot; value=&quot;myUser&quot; /&gt;
+ *         &lt;param name=&quot;password&quot; value=&quot;myPassword&quot; /&gt;
+ *     &lt;/connectionSource&gt;
+ * </pre>
+ * 
+ * <p>
+ * Note that this class will obtain an {@link javax.naming.InitialContext} using
+ * the no-argument constructor. This will usually work when executing within a
+ * J2EE environment. When outside the J2EE environment, make sure that you
+ * provide a jndi.properties file as described by your JNDI provider's
+ * documentation.
+ * 
+ * @author <a href="mailto:rdecampo at twcny.rr.com">Ray DeCampo</a>
+ */
+public class JNDIConnectionSource extends ConnectionSourceBase {
+  private String jndiLocation = null;
+  private DataSource dataSource = null;
+
+  /**
+   * @see org.apache.log4j.spi.OptionHandler#activateOptions()
+   */
+  public void start() {
+    if (jndiLocation == null) {
+      addError("No JNDI location specified for JNDIConnectionSource.");
+    }
+
+    discoverConnnectionProperties();
+
+  }
+
+  /**
+   * @see org.apache.log4j.db.ConnectionSource#getConnection()
+   */
+  public Connection getConnection() throws SQLException {
+    Connection conn = null;
+    try {
+
+      if (dataSource == null) {
+        dataSource = lookupDataSource();
+      }
+      if (getUser() == null) {
+        conn = dataSource.getConnection();
+      } else {
+        conn = dataSource.getConnection(getUser(), getPassword());
+      }
+    } catch (final NamingException ne) {
+      addError("Error while getting data source", ne);
+      throw new SQLException("NamingException while looking up DataSource: "
+          + ne.getMessage());
+    } catch (final ClassCastException cce) {
+      addError("ClassCastException while looking up DataSource.", cce);
+      throw new SQLException("ClassCastException while looking up DataSource: "
+          + cce.getMessage());
+    }
+
+    return conn;
+  }
+
+  /**
+   * Returns the jndiLocation.
+   * 
+   * @return String
+   */
+  public String getJndiLocation() {
+    return jndiLocation;
+  }
+
+  /**
+   * Sets the jndiLocation.
+   * 
+   * @param jndiLocation
+   *          The jndiLocation to set
+   */
+  public void setJndiLocation(String jndiLocation) {
+    this.jndiLocation = jndiLocation;
+  }
+
+  private DataSource lookupDataSource() throws NamingException, SQLException {
+    DataSource ds;
+    Context ctx = new InitialContext();
+    Object obj = ctx.lookup(jndiLocation);
+
+    // PortableRemoteObject was introduced in JDK 1.3. We won't use it.
+    // ds = (DataSource)PortableRemoteObject.narrow(obj, DataSource.class);
+    ds = (DataSource) obj;
+
+    if (ds == null) {
+      throw new SQLException("Failed to obtain data source from JNDI location "
+          + jndiLocation);
+    } else {
+      return ds;
+    }
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/DBUtil.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/DBUtil.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,125 @@
+/*
+ * Copyright 1999,2006 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ch.qos.logback.classic.db.dialect;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+import ch.qos.logback.classic.db.ConnectionSource;
+import ch.qos.logback.core.spi.ContextAwareBase;
+
+/**
+ * 
+ * @author Ceki Gulcu
+ * 
+ */
+public class DBUtil extends ContextAwareBase {
+  private static final String POSTGRES_PART = "postgresql";
+  private static final String MYSQL_PART = "mysql";
+  private static final String ORACLE_PART = "oracle";
+  // private static final String MSSQL_PART = "mssqlserver4";
+  private static final String MSSQL_PART = "microsoft";
+  private static final String HSQL_PART = "hsql";
+
+  public static int discoverSQLDialect(DatabaseMetaData meta) {
+    int dialectCode = 0;
+
+    try {
+
+      String dbName = meta.getDatabaseProductName().toLowerCase();
+
+      if (dbName.indexOf(POSTGRES_PART) != -1) {
+        return ConnectionSource.POSTGRES_DIALECT;
+      } else if (dbName.indexOf(MYSQL_PART) != -1) {
+        return ConnectionSource.MYSQL_DIALECT;
+      } else if (dbName.indexOf(ORACLE_PART) != -1) {
+        return ConnectionSource.ORACLE_DIALECT;
+      } else if (dbName.indexOf(MSSQL_PART) != -1) {
+        return ConnectionSource.MSSQL_DIALECT;
+      } else if (dbName.indexOf(HSQL_PART) != -1) {
+        return ConnectionSource.HSQL_DIALECT;
+      } else {
+        return ConnectionSource.UNKNOWN_DIALECT;
+      }
+    } catch (SQLException sqle) {
+      // we can't do much here
+    }
+
+    return dialectCode;
+  }
+
+  public static SQLDialect getDialectFromCode(int dialectCode) {
+    SQLDialect sqlDialect = null;
+
+    switch (dialectCode) {
+    case ConnectionSource.POSTGRES_DIALECT:
+      sqlDialect = new PostgreSQLDialect();
+
+      break;
+    case ConnectionSource.MYSQL_DIALECT:
+      sqlDialect = new MySQLDialect();
+
+      break;
+    case ConnectionSource.ORACLE_DIALECT:
+      sqlDialect = new OracleDialect();
+
+      break;
+    case ConnectionSource.MSSQL_DIALECT:
+      sqlDialect = new MsSQLDialect();
+
+      break;
+    case ConnectionSource.HSQL_DIALECT:
+      sqlDialect = new HSQLDBDialect();
+
+      break;
+    }
+    return sqlDialect;
+  }
+
+  /**
+   * This method handles cases where the
+   * {@link DatabaseMetaData#supportsGetGeneratedKeys} method is missing in the
+   * JDBC driver implementation.
+   */
+  public boolean supportsGetGeneratedKeys(DatabaseMetaData meta) {
+    try {
+      //
+      // invoking JDK 1.4 method by reflection
+      //
+      return ((Boolean) DatabaseMetaData.class.getMethod(
+          "supportsGetGeneratedKeys", (Class[]) null).invoke(meta,
+          (Object[]) null)).booleanValue();
+    } catch (Throwable e) {
+      addInfo("Could not call supportsGetGeneratedKeys method. This may be recoverable");
+      return false;
+    }
+  }
+
+  /**
+   * This method handles cases where the
+   * {@link DatabaseMetaData#supportsBatchUpdates} method is missing in the JDBC
+   * driver implementation.
+   */
+  public boolean supportsBatchUpdates(DatabaseMetaData meta) {
+    try {
+      return meta.supportsBatchUpdates();
+    } catch (Throwable e) {
+      addInfo("Missing DatabaseMetaData.supportsBatchUpdates method.");
+      return false;
+    }
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/HSQLDBDialect.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/HSQLDBDialect.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,23 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.db.dialect; 
+
+/** 
+ * The HSQLDB dialect. 
+ * 
+ * @author <a href="http://www.qos.ch/log4j/">Ceki G&uuml;lc&uuml;</a>
+*/ 
+public class HSQLDBDialect implements SQLDialect { 
+ public static final String SELECT_CURRVAL = "CALL IDENTITY()"; 
+
+ public String getSelectInsertId() { 
+   return SELECT_CURRVAL; 
+ } 
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/MsSQLDialect.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/MsSQLDialect.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,27 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db.dialect; 
+
+/** 
+* The MS SQL Server dialect is untested. 
+* 
+* Note that the dialect is not needed if your JDBC driver supports 
+* the getGeneratedKeys method introduced in JDBC 3.0 specification.
+* 
+* @author James Stauffer 
+*/ 
+public class MsSQLDialect implements SQLDialect { 
+ public static final String SELECT_CURRVAL = "SELECT @@identity id"; 
+
+ public String getSelectInsertId() { 
+   return SELECT_CURRVAL; 
+ } 
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/MySQLDialect.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/MySQLDialect.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,24 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.db.dialect;
+
+/**
+ * 
+ * 
+ * @author Ceki
+ *
+ */
+public class MySQLDialect implements SQLDialect {
+  public static final String SELECT_LAST_INSERT_ID = "SELECT LAST_INSERT_ID()";
+  
+  public String getSelectInsertId() {
+    return SELECT_LAST_INSERT_ID;
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/OracleDialect.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/OracleDialect.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,26 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db.dialect;
+
+/**
+ * The Oracle dialect. Tested successfully on Oracle9i Release 9.2.0.3.0 by 
+ * James Stauffer.
+ * 
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public class OracleDialect implements SQLDialect {
+  public static final String SELECT_CURRVAL = "SELECT logging_event_id_seq.currval from dual";
+
+  public String getSelectInsertId() {
+    return SELECT_CURRVAL;
+  }
+
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/PostgreSQLDialect.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/PostgreSQLDialect.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,28 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+
+package ch.qos.logback.classic.db.dialect;
+
+
+/**
+ * 
+ * @author ceki
+ *
+ * To change the template for this generated type comment go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public class PostgreSQLDialect
+       implements SQLDialect {
+  public static final String SELECT_CURRVAL = "SELECT currval('logging_event_id_seq')";
+
+  public String getSelectInsertId() {
+    return SELECT_CURRVAL;
+  }
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/SQLDialect.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/SQLDialect.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,20 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * 
+ * Copyright (C) 1999-2006, QOS.ch
+ * 
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.classic.db.dialect;
+
+/**
+ * @author ceki
+ *
+ */
+public interface SQLDialect {
+  
+  public String getSelectInsertId();
+  
+}

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,49 @@
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for IBM DB2 databases.
+#
+# WARNING  WARNING WARNING  WARNING 
+# =================================
+# This SQL script has not been tested on an actual DB2
+# instance. It may contain errors or even invalid SQL
+# statements.
+
+DROP TABLE  logging_event_property;
+DROP TABLE  logging_event_exception;
+DROP TABLE  logging_event;
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  VARCHAR(4000) NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               VARCHAR(4000),
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1)
+  );
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INTEGER NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      VARCHAR(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INTEGER NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2l.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/db2l.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,47 @@
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for PostgreSQL databases.
+
+DROP TABLE    logging_event_property;
+DROP TABLE    logging_event_exception;
+DROP TABLE    logging_event;
+
+
+CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1;
+
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  TEXT NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               TEXT,
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT IDENTITY GENERATED ALWAYS PRIMARY KEY
+  );
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      VARCHAR(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/hsqldb.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,46 @@
+// This SQL script creates the required tables by
+// org.apache.log4j.db.DBAppender and org.apache.log4j.db.DBReceiver.
+//
+// It is intended for HSQLDB. 
+//
+
+DROP TABLE logging_event_exception IF EXISTS;
+DROP TABLE logging_event_property IF EXISTS;
+DROP TABLE logging_event IF EXISTS;
+
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  LONGVARCHAR NOT NULL,
+    logger_name       VARCHAR NOT NULL,
+    level_string      VARCHAR NOT NULL,
+    ndc               LONGVARCHAR,
+    thread_name       VARCHAR,
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR, 
+    caller_class      VARCHAR, 
+    caller_method     VARCHAR, 
+    caller_line       CHAR(4), 
+    event_id          INT NOT NULL IDENTITY
+  );
+
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      LONGVARCHAR,
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mssql.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,45 @@
+-- This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+-- org.apache.log4j.db.DBReceiver. 
+-- 
+-- It is intended for MS SQL Server databases.  This has been tested with version 7.0. 
+
+DROP TABLE logging_event_property 
+DROP TABLE logging_event_exception 
+DROP TABLE logging_event 
+
+CREATE TABLE logging_event 
+  ( 
+    sequence_number   DECIMAL(20) NOT NULL, 
+    timestamp         DECIMAL(20) NOT NULL, 
+    rendered_message  VARCHAR(4000) NOT NULL, 
+    logger_name       VARCHAR(254) NOT NULL, 
+    level_string      VARCHAR(254) NOT NULL, 
+    ndc               VARCHAR(4000), 
+    thread_name       VARCHAR(254), 
+    reference_flag    SMALLINT, 
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT NOT NULL identity, 
+    PRIMARY KEY(event_id) 
+  ) 
+
+CREATE TABLE logging_event_property 
+  ( 
+    event_id          INT NOT NULL, 
+    mapped_key        VARCHAR(254) NOT NULL, 
+    mapped_value      VARCHAR(1024), 
+    PRIMARY KEY(event_id, mapped_key), 
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id) 
+  ) 
+
+CREATE TABLE logging_event_exception 
+  ( 
+    event_id         INT NOT NULL, 
+    i                SMALLINT NOT NULL, 
+    trace_line       VARCHAR(254) NOT NULL, 
+    PRIMARY KEY(event_id, i), 
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id) 
+  ) 
+

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/mysql.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,54 @@
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for MySQL databases. It has been tested on MySQL 4.1.1 with 
+# INNODB tables.
+
+
+BEGIN;
+DROP TABLE IF EXISTS logging_event_property;
+DROP TABLE IF EXISTS logging_event_exception;
+DROP TABLE IF EXISTS logging_event;
+COMMIT;
+
+
+BEGIN;
+CREATE TABLE logging_event 
+  (
+    sequence_number BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  TEXT NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               TEXT,
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT NOT NULL AUTO_INCREMENT PRIMARY KEY
+  );
+COMMIT;
+
+BEGIN;
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      TEXT,
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+COMMIT;
+
+BEGIN;
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+COMMIT;
\ No newline at end of file

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/oracle.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,67 @@
+-- This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+-- org.apache.log4j.db.DBReceiver.
+--
+-- It is intended for Oracle databases.
+
+-- Tested successfully on Oracle9i Release 9.2.0.3.0 by James Stauffer
+
+-- The following lines are useful in cleaning any previous tables 
+
+--drop TRIGGER logging_event_id_seq_trig; 
+--drop SEQUENCE logging_event_id_seq; 
+--drop table logging_event_property; 
+--drop table logging_event_exception; 
+--drop table logging_event; 
+
+
+CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START WITH 1;
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   NUMBER(20) NOT NULL,
+    timestamp         NUMBER(20) NOT NULL,
+    rendered_message  VARCHAR2(4000) NOT NULL,
+    logger_name       VARCHAR2(254) NOT NULL,
+    level_string      VARCHAR2(254) NOT NULL,
+    ndc               VARCHAR2(4000),
+    thread_name       VARCHAR2(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR2(254) NOT NULL,
+    caller_class      VARCHAR2(254) NOT NULL,
+    caller_method     VARCHAR2(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          NUMBER(10) PRIMARY KEY
+  );
+
+
+CREATE TRIGGER logging_event_id_seq_trig
+  BEFORE INSERT ON logging_event
+  FOR EACH ROW  
+  BEGIN  
+    SELECT logging_event_id_seq.NEXTVAL 
+    INTO   :NEW.event_id 
+    FROM   DUAL;  
+  END logging_event_id_seq_trig;
+
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      NUMBER(10) NOT NULL,
+    mapped_key        VARCHAR2(254) NOT NULL,
+    mapped_value      VARCHAR2(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+  
+CREATE TABLE logging_event_exception
+  (
+    event_id         NUMBER(10) NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR2(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+  
+
+
+

Added: logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/main/java/ch/qos/logback/classic/db/dialect/postgresql.sql	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,48 @@
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for PostgreSQL databases.
+
+DROP TABLE    logging_event_property;
+DROP TABLE    logging_event_exception;
+DROP SEQUENCE logging_event_id_seq;
+DROP TABLE    logging_event;
+
+
+CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1;
+
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  TEXT NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               TEXT,
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT DEFAULT nextval('logging_event_id_seq') PRIMARY KEY
+  );
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      VARCHAR(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

Added: logback/trunk/logback-classic/src/test/input/db/dbAppenderUsingConnectionSource.xml
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/input/db/dbAppenderUsingConnectionSource.xml	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,23 @@
+<configuration>
+
+  <appender name="DB" class="ch.qos.logback.classic.db.DBAppender">
+     <connectionSource class="ch.qos.logback.classic.db.DriverManagerConnectionSource">
+       <param name="driverClass" value="com.mysql.jdbc.Driver"/>
+       <param name="url" value="jdbc:mysql://host_name:3306/datebase_name"/>
+       <param name="user" value="logback"/>
+       <param name="password" value="logback"/>
+     </connectionSource>
+  </appender>
+
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <layout class="ch.qos.logback.classic.PatternLayout">
+      <param name="pattern" value="%p %t %c - %m%n"/>
+    </layout>
+  </appender>
+  <root>
+    <level value="debug"/>
+    <appender-ref ref="STDOUT"/>
+    <appender-ref ref="DB"/>
+  </root>
+</configuration>

Added: logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/db/DBAppenderTest.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-classic/src/test/java/ch/qos/logback/classic/db/DBAppenderTest.java	Fri Sep 22 17:12:36 2006
@@ -0,0 +1,7 @@
+package ch.qos.logback.classic.db;
+
+import junit.framework.TestCase;
+
+public class DBAppenderTest extends TestCase {
+
+}



More information about the logback-dev mailing list