Column mappings are required to insert messages (#213)
* Column mappings are required to insert messages
* Remove references to PatterLayout supported queries from documentation. Remove unused code.
---------
Co-authored-by: Stephen Webb <swebb2066@gmail.com>
diff --git a/src/main/cpp/odbcappender.cpp b/src/main/cpp/odbcappender.cpp
index f6f9315..2e757b0 100644
--- a/src/main/cpp/odbcappender.cpp
+++ b/src/main/cpp/odbcappender.cpp
@@ -192,7 +192,7 @@
bool ODBCAppender::requiresLayout() const
{
- return false;
+ return false;
}
void ODBCAppender::activateOptions(log4cxx::helpers::Pool&)
@@ -200,6 +200,10 @@
#if !LOG4CXX_HAVE_ODBC
LogLog::error(LOG4CXX_STR("Can not activate ODBCAppender unless compiled with ODBC support."));
#else
+ if (_priv->mappedName.empty())
+ {
+ LogLog::error(LOG4CXX_STR("ODBCAppender column mappings not defined, logging events will not be inserted"));
+ }
auto specs = getFormatSpecifiers();
for (auto& name : _priv->mappedName)
{
@@ -248,56 +252,11 @@
LogString ODBCAppender::getLogStatement(const spi::LoggingEventPtr& event, log4cxx::helpers::Pool& p) const
{
- return event->getMessage();
+ return LogString();
}
void ODBCAppender::execute(const LogString& sql, log4cxx::helpers::Pool& p)
{
-#if LOG4CXX_HAVE_ODBC
- SQLRETURN ret;
- SQLHDBC con = SQL_NULL_HDBC;
- SQLHSTMT stmt = SQL_NULL_HSTMT;
-
- try
- {
- con = getConnection(p);
-
- ret = SQLAllocHandle( SQL_HANDLE_STMT, con, &stmt);
-
- if (ret < 0)
- {
- throw SQLException( SQL_HANDLE_DBC, con, "Failed to allocate sql handle", p);
- }
-
-#if LOG4CXX_LOGCHAR_IS_WCHAR
- ret = SQLExecDirectW(stmt, (SQLWCHAR*)sql.c_str(), SQL_NTS);
-#elif LOG4CXX_LOGCHAR_IS_UTF8
- ret = SQLExecDirectA(stmt, (SQLCHAR*)sql.c_str(), SQL_NTS);
-#else
- SQLWCHAR* wsql;
- encode(&wsql, sql, p);
- ret = SQLExecDirectW(stmt, wsql, SQL_NTS);
-#endif
- if (ret < 0)
- {
- throw SQLException(SQL_HANDLE_STMT, stmt, "Failed to execute sql statement", p);
- }
- }
- catch (SQLException&)
- {
- if (stmt != SQL_NULL_HSTMT)
- {
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- }
-
- throw;
- }
-
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- closeConnection(con);
-#else
- throw SQLException("log4cxx build without ODBC support");
-#endif
}
/* The default behavior holds a single connection open until the appender
@@ -609,25 +568,18 @@
{
for (auto& logEvent : _priv->buffer)
{
- try
- {
- if (!_priv->parameterValue.empty())
- {
+ if (_priv->parameterValue.empty())
+ _priv->errorHandler->error(LOG4CXX_STR("ODBCAppender column mappings not defined"));
#if LOG4CXX_HAVE_ODBC
- if (0 == _priv->preparedStatement)
- _priv->setPreparedStatement(getConnection(p), p);
- _priv->setParameterValues(logEvent, p);
- auto ret = SQLExecute(_priv->preparedStatement);
- if (ret < 0)
- {
- throw SQLException(SQL_HANDLE_STMT, _priv->preparedStatement, "Failed to execute prepared statement", p);
- }
-#endif
- }
- else
+ else try
+ {
+ if (0 == _priv->preparedStatement)
+ _priv->setPreparedStatement(getConnection(p), p);
+ _priv->setParameterValues(logEvent, p);
+ auto ret = SQLExecute(_priv->preparedStatement);
+ if (ret < 0)
{
- auto sql = getLogStatement(logEvent, p);
- execute(sql, p);
+ throw SQLException(SQL_HANDLE_STMT, _priv->preparedStatement, "Failed to execute prepared statement", p);
}
}
catch (SQLException& e)
@@ -635,6 +587,7 @@
_priv->errorHandler->error(LOG4CXX_STR("Failed to execute sql"), e,
ErrorCode::FLUSH_FAILURE);
}
+#endif
}
// clear the buffer of reported events
diff --git a/src/main/include/log4cxx/db/odbcappender.h b/src/main/include/log4cxx/db/odbcappender.h
index 6c65ad4..3b308ad 100644
--- a/src/main/include/log4cxx/db/odbcappender.h
+++ b/src/main/include/log4cxx/db/odbcappender.h
@@ -56,16 +56,6 @@
using the <b>sql</b> parameter element
or programatically by calling the <code>setSql(String sql)</code> method.
-If no <b>ColumnMapping</b> element is provided in the configuration file
-the sql statement is assumed to be a PatternLayout layout.
-In this case all the conversion patterns in PatternLayout
-can be used inside of the statement. (see the test cases for examples)
-
-If the <b>sql</b> element is not provided
-and no <b>ColumnMapping</b> element is provided
-the attached a PatternLayout layout element
-is assumed to contain the sql statement.
-
The following <b>param</b> elements are optional:
- one of <b>DSN</b>, <b>URL</b>, <b>ConnectionString</b> -
The <b>serverName</b> parameter value in the <a href="https://learn.microsoft.com/en-us/sql/odbc/reference/syntax/sqlconnect-function">SQLConnect</a> call.
@@ -138,10 +128,6 @@
<priority value ="INFO" />
<appender-ref ref="ASYNC" />
</root>
-<appender name="PatternAppender" class="ODBCAppender">
- <param name="DSN" value="LoggingDSN"/>
- <param name="sql" value="INSERT INTO [ApplicationLogs].[dbo].[UnitTestLog] ([Thread],[LogName],[LogTime],[LogLevel],[FileName],[FileLine],[Message],[MappedContext]) VALUES ('%t', '%c','%d{yyyy-MM-dd HH:mm:ss.SSSSSS}','%p','%f','%L','%m{'}','%J{'}')" />
-</appender>
</log4j:configuration>
~~~
@@ -182,20 +168,14 @@
protected:
/**
- * Sends the event to the attached PatternLayout object.
- * The layout will format the given pattern into a workable SQL string.
- *
+ * To be removed.
*/
LogString getLogStatement(const spi::LoggingEventPtr& event,
helpers::Pool& p) const;
/**
*
- * Override this to provide an alternate method of getting
- * connections (such as caching). One method to fix this is to open
- * connections at the start of flushBuffer() and close them at the
- * end. I use a connection pool outside of ODBCAppender which is
- * accessed in an override of this method.
+ * To be removed.
* */
virtual void execute(const LogString& sql,
log4cxx::helpers::Pool& p) /*throw(SQLException)*/;
diff --git a/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml b/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml
index c82c63b..04e278d 100644
--- a/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml
+++ b/src/test/resources/input/xml/odbcAppenderDSN-Log4cxxTest.xml
@@ -25,15 +25,10 @@
<param name="ConversionPattern" value="%d %-5p %c{2} - %m%n"/>
</layout>
</appender>
-<appender name="PatternAppender" class="ODBCAppender">
- <param name="DSN" value="Log4cxxTest"/>
- <param name="sql" value="INSERT INTO UnitTestLog (Thread,LogName,LogTime,LogLevel,FileName,FileLine,Message) VALUES ('%t','%c','%d{yyyy-MM-dd HH:mm:ss.SSSSSS}','%p','%f','%L','%m{'}')" />
- <!--param name="sql" value="INSERT INTO ApplicationLogs.dbo.UnitTestLog (Thread,LogName,LogTime,LogLevel,FileName,FileLine,Message) VALUES ('%t','%c','%d{yyyy-MM-dd HH:mm:ss.SSSSSS}','%p','%f','%L','%m{'}')" /-->
-</appender>
<appender name="PreparedAppender" class="ODBCAppender">
<param name="DSN" value="Log4cxxTest"/>
- <param name="sql" value="INSERT INTO UnitTestLog (Thread,LogName,LogTime,LogLevel,FileName,FileLine,Message) VALUES (?,?,?,?,?,?,?)" />
- <!--param name="sql" value="INSERT INTO ApplicationLogs.dbo.UnitTestLog (Thread,LogName,LogTime,LogLevel,FileName,FileLine,Message) VALUES (?,?,?,?,?,?,?)" /-->
+ <!--param name="sql" value="INSERT INTO UnitTestLog (Thread,LogName,LogTime,LogLevel,FileName,FileLine,Message) VALUES (?,?,?,?,?,?,?)" /-->
+ <param name="sql" value="INSERT INTO ApplicationLogs.dbo.UnitTestLog (Thread,LogName,LogTime,LogLevel,FileName,FileLine,Message) VALUES (?,?,?,?,?,?,?)" />
<param name="ColumnMapping" value="thread"/>
<param name="ColumnMapping" value="logger"/>
<param name="ColumnMapping" value="time"/>