> >> Problems: >> addBatch is an optional method in Statement. It is not guarenteed >> to be implemented by all drivers (in fact it is not implemented in >> the mySQL driver I use). >> Your logEvents table definition is not valid on all databases. And >> in fact it's not valid on -most- databases. And any table we come up >> with will lack something a user may want, until we have some much >> that it's overly bloated for 95% of the users. Then we would likely >> need to write several different versions of the table creation to >> support the different databases. > > > addBatch is an optional method? Version 2.0 of the JDBC spec. clearly > mentions Batch statements in Chapter 6. Can you please point me to the > where in the JDBC spec. Batch Statements are declared as optional?
JDBC2.1 spec (I couldn't find 2.0 on the sun site): "6.2 What's Required Support for batch updates is optional. If a JDBC driver supports batch updates, the the DatabaseMetaData.supportsBatchUpdates() method must return true, else it must return false. In addition, to preserve backward compatibility, JDBC drivers that do not continue processing after a failure are not required to return a value of -2 as described in Section 6.1, however, this is encouraged. JDBC drivers that continue processing are required to support both of the negative return values. Note: In the future, the JDBC API shall define symbolic constatns for the negative array entry values described in Section 6.1. These values have been added as an addendum to the original JDBC2.0 API specification." Also note JDBC 3.0 final release Chapter 6: "Any features not identified here [add Batch is not listed] are optional. In general, a driver is not required to implement any feature that its underlying data source does not support." And of course the JavaDoc (where I first found the optional note): http://java.sun.com/j2se/1.4/docs/api/java/sql/Statement.html#addBatch(java.lang.String) Now fortunately the DatabaseMetaData will tell us whether it is supported or not and we can cover both cases intelligently. > > Yes, table creation syntax admits variation between the different DNMS > vendors. However, table creation is not under the responsibility of > JDBCAppender. However, if we confine the JDBCAppender to a single pre-determined definition, then it is our/log4j's responsibility to provide that syntax. > > First, what any log4j appender does is tp utput an > o.a.log4j.spi.LoggingEvent object to some output device. A > JDBCAppender does the same. It outputs a LoggingEvent to a DBMS. > > Second the number of databases in the world is limited. If we could > reliably write to say DB2, MySQL, Oracle, PostgreSQL (note the > alphabetical order) we'd be in good shape. I would add MS-SQL Server and Sybase to that list. Still, as you point out, a fairly managable number, all with reasonable adherence to SQL92. > > Third, although there are variations in the SQL syntax, the bulk of > the work of the JDBCAppender consists of sending an INSERT statement > to the database. Unless the user wants to speed things up with stored procedures, or do something fancy. > > And as far as I know, in most databases, in particualr as DB2, MySql, > PostgreSQL (could not check Oracle yet), the syntax of the INSERT > command is > > INSERT INTO tablename (col1, col2, ...) VALUES (val1, val2, ...) > > Looks simple enough to me. Unless someone does it first, I'll write an > appender that can reliably insert complete logging events to a table > on MySQL and PostgresQL. When that is done, I am sure someone else > will continue on DB2, Oracle and what have you. > >> Note that your prepared statements were in fact slower than simple >> statements and not all databases truely support prepared statements >> (mySQL is the only slacker that I know of but there may be others). > > > The difference is minimal and the winner changes between runs. > Sometimes simple statements are win and sometimes prepared statements > do, although batch statements are always way ahead. > >> Suggestions/Solutions/Previous design considerations: >> >> When I first wrote the JDBCAppender I knew that it would be used on >> a variety of databases in different circumstances for users with >> different logging needs. The base level JDBCAppender needs to >> support that level of generality. The only way to support that >> variety is to leave the sql and the table definition to the user. >> The current JDBCAppender supports this in an easy and straight >> forward way. In particular, if users want prepared statements they >> can set the sql to call a stored procedure of their choice (in >> essence what the prepared statement does). The advantage here is >> that the users' table can be matched to their particular needs -- for >> example, storing Thread but not NDC, or Class & line number, or an >> Event extension... It also allows them to log to an existing table >> in a legacy installation. >> Due to the problems above and the design goals in the previous >> paragraph I am strong opposed to tieing the basic JDBCAppender to a >> particular table definition. > > > There are obviously advantages to being totally flexible. On the other > hand, total flexibility by the way of delegation to the user does not > give you any foundation to build upon. The current JDBCAppender does provide a foundation while delegating flexibility to the user. ~300 lines of code for logging to a database becomes 4 lines of configuration. I call that a nice foundation. As is under discussion, however, it does not provide a foundation for other log4j components. > > As for the argument about optional NDC, class/line number/method name > fields, we can expect the table to contain *all* fields but choose not > to insert the information if that is what the user desires. This is > similar to what is done with SocketAppender where location info is > optional but the LoggingEvent contains the field, even when it is > null. I suspect Ceki won't like this suggestion, but I'll make it anyway: Have a two-layer solution. First a totally flexible JDBCAppender, such as the current implementation, for the sql savvy user. Second, build a defined-table implementation on top of that -- as a subclass or whatever. This way the savvy user gets some core functionality, the basic user gets a well verified implementation, and other components have a table definition they can write to. -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>