2023-02-04: build 2732 *) Handle line breaks and tabs in cells when copying and pasting TSV. Cells containing any of \r \n \t " are enclosed in double quotes, and any double quotes are doubled. This way of escaping is compatible with Microsoft Office and LibreOffice, and hopefully with other spreadsheets as well. 2023-01-19: build 2731 *) Fixed Reload for PartialTables created by FK chasing. *) Prevent PartialTable in query with functions. *) Added Select All option to QueryResultFrame. *) Added logic to identify 'identity' columns for MS SQL *) Fixed conflict between exit confirmation dialog and About box, that would cause the app to get stuck if the former appeared while the latter happened to be visible. 2022-12-10: build 2730 *) Added shortcuts: Ctrl-L for Reload and Ctrl-Shift-R for Reconnect. *) Foreign key following: now offers choice between showing the full referenced table with the referenced rows highlighted (the already existing behavior) and showing a partial table with only the referenced rows loaded. The new option helps when the referenced table is very large. *) Support for generated columns: editing them is now prevented, and on insert and update, they are now skipped. *) When editing cells with rearranged columns, the cell editor would be initialized with the column type corresponding to the un-rearranged column, leading to editing and commit failures. Fixed. 2022-11-03: build 2727 *) FK option selector would not populate if the PK column names contained reserved words. Fixed. *) No longer closing table and query result windows when Reload fails. Treating this as a fatal error is no longer appropriate now that the browser frames can reconnect, making that failure mode non-fatal. 2022-10-26: build 2726 *) Date & time handling fixes for MS SQL. 2022-10-24: build 2724 *) Added support for Microsoft SQL Server (MS SQL). This is very new; please report any issues you may run into. I'm using this at work so it is at least somewhat usable. *) Fixed some bugs in selection handling in table views, related to earlier changes to support copying rectangular selections of cells. *) Added Reconnect option, so you can continue working with a database browser window after the JDBC connection to the server has timed out. 2019-05-06: build 2717 *) When getting table metadata, changed the order in which the column metadata is fetched to match the order in which the elements are listed in the JDBC spec. Apparently, fetching them in a different order can make certain JDBC drivers unhappy -- specifically, Oracle doesn't like fetching COLUMN_DEF after IS_NULLABLE, at least if COLUMN_DEF is not null. 2019-02-23: build 2716 *) Changed the window cycling shortcut key from 'W' to 'R' to fix collision with Ctrl-W for Close. *) Fixed Yes/No, Yes/No/Cancel, and OK/Cancel dialogs, so that closing the dialogs by typing Esc performs the safe action (No or Cancel) instead of the unsafe one (Yes or OK). 2017-11-25: build 2714 *) Fixed the menu shortcuts so that on MacOS, they work with the Command key rather than Ctrl. Also, wherever alternative shortcuts are needed, standardized on Command-Shift / Ctrl-Shift instead of Alt or Alt-Shift. *) Implemented spreadsheet-compatible cell copying (tab-separated values) in QueryResultFrame. 2017-04-16: build 2713 *) Updated email address in About box. 2017-04-09: build 2711 *) Added default values to Table Details. 2014-08-24: build 2709 *) Apparently, some obscure JDBC driver doesn't support DriverManager. getConnection(String url, Properties props). Modified the connection code so that it only uses that API when connecting to Oracle (that's the only case when we specifically need it), and use getConnection(url, user, pass) for all others. 2014-05-17: build 2708 *) Fixed more connection config deletion breakage. 2014-05-17: build 2707 *) Bug workaround for SQLite: DatabaseMetaData.getPrimaryKeys() returns an element with KEY_SEQ = 0, which should never happen accoring to the JDBC API documentation; KEY_SEQ is a 1-based index. Simply ignoring this element fixes the problem. Note, however, that the SQLite JDBC driver has other bugs in its metadata handling as well (as of May 17, 2014) -- specifically, it throws exceptions from DBMD.getIndexInfo() in many cases -- so use JDBC Navigator with SQLite at your own risk. *) Deleting a connection configuration was broken: it would be removed from the menu, but not from the stored configs, so it would reappear the next time the Open JDBC Connection dialog was presented. 2012-12-02: build 2706 *) Generating escaped HTML strings would choke on character codes greater than 255. This could cause saving File databases and presenting table details windows to fail. Fixed. *) When importing CSV files into tables, empty strings would be treated as nulls. Fixed. *) Upgraded Rhino to 1.7R4, and added generics wherever the new Rhino and the latest Java APIs support them (e.g. JList). 2012-11-30: build 2705 *) With Java 1.7, the Preferences, MessageBox, and Binary Editor windows would throw a ClassCastException in their constructors. Fixed. 2011-11-23: build 2703 *) The JDBCDatabase constructor was protected, which caused opening unrecognized database types to fail. Changed it to public, fixing the problem. *) Improved JDBCDatabase.makeTypeSpec(): it now recognizes basic string, numeric, and date/time types, so that some basic table editing is now possible even with unsupported databases. 2010-06-14: build 2700 *) In JDBCDatabase.getJavaTypes(), added a "where 1 = 2" clause to the statement used to find a table's column types. This prevents stupid JDBC drivers (specifically, MySQL) from actually loading the whole table when all we want is the metadata. 2009-07-10: build 2697 *) Changed the homepage URL to http://thomasokken.com/jdbcnav/. 2009-07-02: build 2696 *) Sorting on byte[] columns works now. *) When moving columns, the column formatting would not move. Fixed. 2008-02-16: build 2688 *) Running a query that selects columns from only one table, including all of that table's PK columns, now returns an updatable query result *even* if the JDBC driver does not provide catalog/schema/table information in ResultSet. Formerly, with such drivers you would only get an updatable query result if you performed a "select *". 2007-12-16: build 2684 *) The initial Database.getRootNode() call, which loads all the table metadata when a JDBC connection is opened, is now performed in the background, so it does not freeze the UI. 2007-12-04: build 2681 *) The MySQL driver did not recognize varchar columns, making it impossible to edit them. Fixed. 2007-08-13: build 2680 *) Saving the .jdbcnav file did not work unless one already existed. When JDBC Navigator exits, it actually writes a file called .jdbcnavrc-new, and once that is done, it deletes the old .jdbcnavrc file, and renames .jdbcnavrc-new to .jdbcnavrc. All well and good so far, except that it considered it an error if it couldn't delete the old .jdbcnavrc. Note to self: getting an error while trying to delete a file is not *really* an error if that file did not exist in the first place! 2007-04-07: build 2679 *) Now showing a "Please Wait" dialog while the tree in the BrowserFrame is initially populated upon opening a JDBC connection. It's a totally lame dialog so far; it does not yet have a progress indicator nor a Cancel button, but at least now there is *some* feedback -- you can now tell the difference between waiting for the Connection to be established, and waiting for the table information to load. 2007-04-06: build 2672 *) Now showing an hourglass cursor while opening a JDBC connection, opening a table editing window, opening a table details window, and while running a query. 2007-03-14: build 2657 *) Now recognizes MySQL unsigned types, so they can be edited. They are still not handled correctly when generating scripts, though. 2007-03-04: build 2654 *) The previous release still didn't fix all of the problems with loading large tables; it turned out that there were still a couple of places where background threads were making Swing calls. I fixed those, and so far, it looks like it's working properly now. (Loading tables that won't fit in memory is still a problem, but that's a separate issue, and has much different symptoms. This type of problem can be identified by running jdbcnav from the command line and looking for OutOfMemoryError messages.) 2007-03-03: build 2651 *) Added a new option for Import CSV, called "Replace conflicting rows". What it does is completely replace rows whose PK matches that of imported rows, as opposed to the "Overwrite conflicting rows" option, which only replaces those columns that are actually present in the CSV. *) When importing a CSV file into a table that has no primary key, or when importing a CSV file that does not contain the full set of columns matching the table's primary key, none of the imported rows are considered to conflict with (i.e., match) any of the table's rows, so they are all imported and all of the table's existing rows are retained. Previously, jdbcnav would refuse to import CSV files that did not specify the full PK, and it would attempt to match rows even in tables with no PK. I think this new behavior is a bit more useful, and hopefully also a bit more intuitive. *) Pasting rows from the Clipboard now uses the same logic as Import CSV in "Overwrite/Replace conflicting rows" mode. *) Writing the .jdbcnavrc file is now done in two stages: first, write a new file called .jdbcnavrc-new, and only when that is successful, delete the old .jdbcnavrc and rename .jdbcnavrc-new to .jdbcnavrc. This prevents the .jdbcnavrc file from becoming corrupted if jdbcnav crashes on exit. (Not that that ever happens, of course. ;-) ) *) Sometimes, modifying a table using JavaScript would cause the application to freeze. Also, loading large tables sometimes failed in weird ways. I believe both of these types of problems were caused by ResultSetTableModel firing table events from background threads -- some of the event handlers that get invoked perform Swing calls that should only be made from the AWT event thread. I modified ResultSetTableModel so that it will now always check if it is on the AWT event thread before firing events; if it is not, it queues them up using SwingUtilities.invokeLater() instead. 2007-03-02: build 2638 *) In the Preferences dialog, clicking OK just after editing the Class Path would cause the most recent edits to be lost (if one of the Class Path items still had a blinking cursor in it). Fixed. 2007-02-27: build 2637 *) SELECT * queries from more than one table would fail, because jdbcnav would treat them like SELECT * from one table, and then choke when trying to match the columns from the ResultSet to the smaller number of columns from the first table from the FROM clause. The end result was that no result window would appear, and the Exception would just kill the background table loading thread and never be reported to the user. Fixed now. 2007-02-26: build 2636 *) Copy Cell could copy the wrong cell if the columns in the table view had been rearranged. 2007-02-10: build 2635 *) Updatable query results (that is, windows resulting from a "select * from foo" type query) now support the same foreign-key chasing as regular table windows. 2006-12-25: build 2628 *) With Oracle 10g (and possibly earlier versions), DBMD.getTables() can return a lot of useless junk along with the actual table/view/synonym info. This is confusing, annoying, and it slows things down. I changed the jdbcnav's Oracle driver so that it now queries SYS.ALL_TABLES, SYS.ALL_VIEWS, and SYS.ALL_SYNONYMS instead. 2006-11-11: build 2626 *) In some situations, JDBC Navigator would get an "ORA-01866: the datetime class is invalid" while running the initial DBMD.getTables() right after opening a connection to an Oracle database. The problem appears to be caused by an earlier (unreported!) error while trying to set the session time zone ("ORA-01882: timezone region not found"). The Exception thrown by setSessionTimeZone() is now reported to the user, and jdbcnav now recognizes a System property named jdbcnav.tz which can be used to override the default time zone ID. The default, which is used if jdbcnav.tz is not set, is whatever is returned by java.util.TimeZone.getDefault().getID(). 2006-09-19: build 2625 *) Removed a couple of JDK 1.5 dependencies that I had inadvertently introduced in earlier builds. The offending code used the Boolean.parseBoolean(String) method and the IllegalArgumentException(Throwable) constructor. 2006-08-26: build 2619 *) Added support for Oracle SYNONYMs. *) When pasting illegal values into a column, the table editing window now catches the exceptions thrown by the object-to-string conversion, and displays the word "illegal" instead. Before, it used to just let the exceptions fall through to the AWT repaint thread, killing it and messing up the UI! Oops. 2006-08-25: build 2610 *) Using MyTextArea/MyTextField instead of JTextArea/JTextField again; these take care of automatically refreshing the Clipboard window when a cut or copy operation is performed. I had removed this functionality in the previous release, as part of the changes for eliminating the JDBC Navigator private clipboard, but I later realized that the clipboard window auto-refresh can still be supported. It's still not perfect, but that is impossible as long as the java Clipboard class does not support content change notifications. So, meanwhile, whenever the clipboard is changed by a plain JTextArea/JTextField, or anything else outside of jdbcnav, the clipboard window will not refresh automatically. 2006-08-24: build 2609 *) Copying rows in QueryResultFrame has been broken since build 2239; it didn't handle the TypeSpec column class introduced in that build. As a result, the copy operation itself would still succeed, but displaying the Clipboard would not. Fixed now. *) All copy and paste operations now use the system clipboard. The JDBC Navigator clipboard is gone completely, as is the messy and broken code to synchronize it with the system clipboard, that I introduced in build 2531. Copy and paste of table rows should work properly again. *) Copying n table rows would always copy the top n rows from the table, instead of the n rows that were actually selected. Oops! Fixed now. 2006-07-22: build 2600 *) When using the 'Select FK Value' command on a column that allows nulls, the ForeignKeySelector window did not show the last of the available PK values. This was caused by an error in the code that adds 'null' to the list of options for this case. Fixed. 2006-07-16: build 2596 *) The DateTime and Interval classes now implement the Comparable interface, so that DATE, TIMESTAMP, and INTERVAL columns can now be used for sorting. 2006-05-09: build 2593 *) In addition to oracle.jdbc.driver.OracleDriver, JDBC Navigator now also recognizes oracle.jdbc.OracleDriver as being an Oracle driver class. Previously, if you opened a connection using the oracle.jdbc.OracleDriver class name, the generic internal driver would get used, and that leads to problems. *) MyTable.getDefaultRenderer() and MyTable.getDefaultEditor() did not handle interfaces properly. Fortunately, Table Editing windows rely exclusively on the TypeSpec class and its associated DatabaseObjectRenderer and DatabaseObject- Editor, so they were unaffected, but it did cause the wrong renderer to be picked for the "#", "Size", and "Scale" columns in Table Details windows. 2006-02-05: build 2590 *) Fixed a serious bug that broke table cell editing (!). *) Added support for SmallSQL 0.10. Note, however, that creating a new database from JDBC Navigator does not work at the moment, since JDBC Navigator calls DBMD.getTables() on all newly openend Connections, and the SmallSQL 0.10 driver throws a NullPointerException when this call is performed on an uninitialized database. If the DB is initialized outside jdbcnav, you *can* work with it. This problem is fixed in SmallSQL 0.11. 2006-02-02: build 2586 *) Oracle BFILEs can now be viewed using the Edit Cell command. *) The PostgreSQL driver now looks at the 'scale' reported by DBMD and RSMD for time, timetz, timestamp, timestamptz, and interval types. Note that you need a recent PostgreSQL driver with the relevant DBMD and RSMD patches, or you'll still get bogus precision/scale values for those types. *) When generating Drop/Create scripts from a Derby DB, with a set of related tables, a script containing ALTER TABLE commands would be generated, instead of the DROP and CREATE statements being ordered properly so as to avoid ALTER TABLE statements as much as possible. Fixed. 2006-02-01: build 2576 *) Some code cleanup to get rid of warnings in Eclipse. 2006-01-17: build 2567 *) Derby driver: fixed TypeSpec generation for NUMERIC columns. 2006-01-16: build 2565 *) Added Derby support. 2006-01-16: build 2561 *) Pushed LOB loading into JDBCDatabase class; added support for DBs where Blob and Clob objects become invalid when the ResultSet that produced them is closed. Currently, this support is only activated in the Derby driver. (Note: this does not mean that Derby is fully supported yet; that will happen in another release in the near future.) 2005-12-21: build 2549 *) More logging: now logs all system properties on startup, and jdbcnav's version string. Also, now logs all messages displayed by MessageBox.show(). 2005-12-20: build 2545 *) Added option in Preferences to disable the "splash" screen that is usually displayed when the application starts up. *) Added logging support. Should usually be disabled because it can slow things down quite a bit (particularly with Oracle), but can be useful in generating the kind of information Yours Truly needs when trying to debug problems he can't reproduce. 2005-12-12: build 2531 *) QueryResultFrame: Cut, Copy, and Paste now use the usual accelerators (Ctrl-X, Ctrl-C, Ctrl-V) instread of Alt-X etc.; jdbcnav now attempts to keep its own clipboard and the system's clipboard in sync, and as far as the user is concerned, there is only one clipboard now. *) Added code to work around the bug that affects ResultSetMetaData.getPrecision() in some recent versions of Oracle; this bug can cause a NumberFormatException to be thrown. This seems to happen when the precision of a BLOB or CLOB is reported to be 4294967295 (0xFFFFFFFF), which is too large for a Java "int". *) Fixed the code that calls setSessionTimeZone() on an OracleConnection; this now works using the reflection API (again) so that it is once again not necessary to have the Oracle JDBC driver in the CLASSPATH when compiling the JDBC Navigator source code. *) FileDatabase fixes: now loads the "native_representation" TypeSpec property when opening a File Data Source, so generating a SQL script with matching source and destination DB types now generates the proper column type -- and not "null". Also, fixed a bug where for some database types binary columns were written to the XML file as a hex string, instead of being Base64 encoded, which would cause an exception when trying to read the file back in. 2005-12-07: build 2450 *) Added DB2 support. 2005-12-06: build 2428 *) Added Transbase support. Not complete yet: inserting/updating BITS and TIMESPAN does not work yet. I probably need to contact the Transbase developers since I can't find any documentation on the TBBits and TBTimespan classes; also, there seem to be some nasty bugs in Transbase itself (e.g. setting a TIMESPAN to null using a plain "set ts=null where..." causes the entire app to freeze). *) MySQL: BINARY and VARBINARY now recognized correctly. *) Released the source code under the GNU General Public License. 2005-12-05: build 2395 *) Added MySQL support. *) Improved the code for handling INTERVAL types in SQL script generation. If the target DB does not support INTERVAL, it now generates DECIMAL columns and populates them using the interval's number of months or nanoseconds. For PostgreSQL's INTERVAL, which has incompatible "YEAR TO SECOND" type semantics, the months value is multiplied by 2,629,746,000,000,000 and added to the nanoseconds value; the resulting INTERVAL_DS-compatible value is then used whenever the target DB is not PostgreSQL. *) In tables with a primary key, the wrong columns were highlighted if the primary key's columns were not the first columns in the table. Fixed. *) SQL script generation would quote number literals. Fixed. 2005-12-02: build 2357 *) Oracle TIMESTAMP, TIMESTAMP WITH TIME ZONE, and TIMESTAMP WITH LOCAL TIME ZONE support completed. *) Completed DATE, TIME, and TIMESTAMP support in CSV import/export, snapshots, and SQL script generation. PostgreSQL and SmallSQL time support added. *) Oracle and PostgreSQL INTERVAL support. *) Fixed the limitLineLength() function in the SQL script generator; it will now not only wrap long string literals properly, but also wrap SQL code, by inserting line feeds when needed but never inside a word, double-quoted word, or number literal. *) Fixed behavior of "select * from <table>" in SQL Window. 2005-11-13: build 2254 *) SQL script generation: the code that checks if a column is part of a key or index is back, and this means that when the Script Generator generates CREATE TABLE statements for Oracle, it will not use BLOB or CLOB types for such columns, but fall back on RAW(4000) or VARCHAR2(4000) instead. *) SQL script generation: Oracle DATE and TIMESTAMP values now handled. Note that TIMESTAMP WITH LOCAL TIME ZONE probably does not work correctly; it is misbehaving in the table editor too (the timestampValue() method and the Timestamp-consuming constructor appear not to be each other's inverses; I must be missing something there). *) SQL script generation: now handles Oracle LOB, LONG, and RAW types -- but note that due to string length restrictions in SQL*Plus, you may still not be able to use jdbcnav-generated SQL scripts for backing up tables containing large objects. A big rotten tomato for Oracle for having a script processor with such silly restrictions! *) SQL script generation: now handles Oracle BFILE. *) SQL script generation: the "Same As Source" driver was removed; its special behavior, which is to use the source database's native data type representation in CREATE TABLE statements, is now the standard behavior whenever the source and destination databases have the same internal driver name. It made no sense to re-encode the type representations in this situation anyway, and the Same As Source driver also had the problem that it had no specialized knowledge of how to render data *values*, which made it pretty much useless for generating Populate and Update scripts. *) Table editing windows now prevent the user from editing cells containing Blob, Clob, and byte[] objects inside the JTable; they must use the Edit Cell command to bring up a separate Binary/Text editor frame. This is to avoid the confusion over what happens when you start editing a string like "Clob (size = 10000)" or the hex representation of a byte array. 2005-11-12: build 2239 *) Fixed a few bugs having to do with moving columns in table editing windows. *) Clob and Blob handling changed: table editing windows now load them lazily, and they are written back to the database when the table is committed, and no longer immediately. *) Snapshots and CSV files now convert objects using the same database- dependent object->string conversions that are used in the table editing window. Snapshots and CSV files now support LOB and RAW types properly. *) Oracle BINARY_FLOAT and BINARY_DOUBLE can now be written back to the DB, rather than merely being displayed in table editing windows. *) Added 'clipboard' property to the global scope in JavaScript; this can be used to get and set the JDBC Navigator clipboard. 2005-11-10: build 2203 *) Oracle DATE columns are once again treated as java.sql.Timestamp values; I added code to enable the Oracle 8i compatibility mode in the Oracle >= 9 drivers. *) Column widths are once again set properly; this got broken in build 2187 because the custom column renderers did not get set until after the table was starting to be populated. 2005-11-09: build 2193 *) The latest Oracle JDBC drivers apparently finally implement java.sql.Blob.setBytes(long, byte[]), but it does not work. So, I had to disable the code that uses this method, and keep using the old Oracle work-around code, which fortunately is still OK. The whole thing is rather weird, because according to Oracle's own Javadocs, oracle.sql.BLOB does not implement setBytes(long, byte[]) at all. 2005-11-09: build 2189 *) Fixed a few bugs (related to BLOB and RAW types, and Oracle 8 & 9) that I introduced with the code changes for the previous two releases. Sorry about that, folks -- I hope that kind of thing will become rarer in the future as I clean up the code further. 2005-11-09: build 2187 *) Abstacted conversion of database datatypes to/from user-editable strings; this is now done through methods in the Database object. Note, however, that at the moment this new conversion code is only used in table editing windows and query result windows; it is not yet used for creating snapshots nor for generating scripts. This will be added in the near future. 2005-11-08: build 2172 *) Fixed handling of Oracle NCHAR and NVARCHAR2 types. *) Added support for Oracle BINARY_FLOAT, BINARY_DOUBLE, TIMESTAMP, and INTERVAL types. *) Improved type conversion algorithm for SQL script generation, so that generating a script for a different RDBMS product than the originating database now generates CREATE TABLE statements with more accurate column types. The new code is also easier to maintain, so that adding support for additional products is now much easier than before. 2005-10-25: build 2134 *) Added Transbase driver; this is needed because the Transbase JDBC driver does not support ResultSetMetaData.getCatalogName() etc. (no surprises there, I guess -- I have not seen *any* JDBC drivers yet that support this). The new driver fixes the situation that simple queries in the SQL window do not work. 2005-09-08: build 2130 *) Fixed handling of NULL values in CLOB, BLOB, LONG, and LONG RAW columns. *) Fixed NullPointerException that occurred in CLOB columns when the Java type returned by ResultSetMetaData.getColumnClassName() was an interface rather than a class (affects DB2). 2005-06-13: build 2108 *) Added custom layout manager to the Windows menu, so it stays usable even when very many windows are open. *) Added code to window placement code to ensure that new windows are placed entirely on-screen, if possible. This means that opening a large table returns a window that you don't have to manually reposition before you can use it. 2005-06-06: build 2103 *) In the column-jumping menu, columns with "not null" constraints are now highlighted by showing their names in boldface. *) Executing "Reload Tree", after a table had been added to a node that had not been expanded previously (so that the 'kids' array in the MyTreeNode object was still null), would throw an IndexOutOfBoundsException, and subsequent attempts to view that node would all fail. Fixed. *) Fixed a couple of orphanage-related bugs: "Reload Tree" would throw a ConcurrentModificationException when the orphanage was first created; also, makeOrphan() generated names that findTableNode() couldn't resolve in some cases, having to do with quoting. 2005-06-04: build 2075 *) MyFrame.dispose(): added work-around for JInternalFrame bug, where the behavior of doDefaultCloseAction() (the method invoked when the user clicks the close box) does extra work that dispose() does not; the upshot is that without this work-around, the DesktopManager does not highlight the next lower window when the topmost window is disposed. This is bad, especially if the Windows L&F is used, because it relies on window activation to handle maximized internal frames properly. 2005-05-30: build 2066 *) TableFrame now highlights PK and FK columns using special background colors. *) TableFrame now supports populating FK columns by selecting available values from the referenced table's corresponding PK columns. *) Added window cycling (Alt-W, Alt-Shift-W). *) Added website URL to splash screen. *) ResultSetTableModel and ArrayTableModel now sort String values using case- insensitive comparisons, instead of case-sensitive. *) In BrowserFrame, added a multi-table rollback command. 2005-05-22: build 1977 *) Added SmallSQL support (JDBCDatabase and ScriptGenerator subclasses). 2005-05-02: *) Changed the REMARKS getting code so that it first tries REMARKS, then TABLE_REMARKS. Simply picking TABLE_REMARKS whenever we're talking to Oracle does not work any more; apparently, Oracle have fixed this JDBC incompatibility in 9.x. 2004-09-08: *) Added showAbout() method to Main.AboutGlassPane. Showing the "about" box on setVisible(true) turned out not to be such a great idea, since some part of Swing (JDesktop, I suppose) shows the glass pane when you resize an internal frame (but not when you drag one -- go figure). So, I had to add a state variable to AboutGlassPane to decide whether to paint the "about" box or not; setVisible(true) does not set this flag, and showAbout() does. 2004-09-05: *) Added classpath configuration area to preferences dialog. It only shows up if the jdbcnavboot.Boot class exists. In addition to directories and jar/zip files, you can use the word "CLASSPATH" in the dialog to indicate that the value of the CLASSPATH environment variable should be used at that point in the search order (but this only works with JDK 1.5 or later, since it needs System.getenv() to get that variable, and older JDKs don't actually implement that method). *) Changed JButton.requestFocus() call in MessageBox to requestFocusInWindow(). This was necessary because the former caused the top-level window to be raised when running under Windows 98SE. In fact, the javadoc for requestFocus() warns about just such potentially undesired behavior. *) Removed hard-coded references to oracle.sql.BFILE class from MyTable (this had to do with the BfileRenderer). Using reflection now, so MyTable will load properly even if the Oracle driver is not in the classpath. *) Fixed handling of missing <classpath> element; this is detected in the Preferences() constructor now, after the call to read(), so that the fall-back version of the classpath gets set even if there is no .jdbcnavrc file at all. *) Changed the "system properties" area in PreferencesFrame from JTextArea to NonTabJTextArea so that tabbing behavior is a bit nicer (though you still need Ctrl-Tab to escape from the JTable). *) Fixed the classpath searching code in SneakyClassLoader, and fixed the URL generation so that valid URLs are generated when running under Windows. This turns out to be pretty simple: use File.getAbsolutePath() to get an absolute path; translate all file separators to slashes; if the path does not start with a slash, prepend one (this is needed for Windows paths that start with a drive letter); for directory URLs, prepend "file:"; for Jar URLs, prepend "jar:file:" and append "!". Finally, when generating the final URL, take the resource name and tack it onto what we just generated (note that resource names start with slashes and have their components separated by slashes; SneakyClassLoader.findResource() and findResources() enforce the former, and Class.getResourceAsStream() takes care of the latter). This works like a charm on both Windows 98SE and Linux. Of course, I do wonder if this works on MacOS, too... 2004-09-04: *) I found a reasonably elegant way to create a runnable jar file after all (see yesterday's item 3). It uses a two-stage startup process, stage 1 being a new class named jdbcnavboot.Boot; this class creates a class loader that looks for classes and resources in two places: in the default class loader, with "/foo" prepended to the class or resource name, and in a list of jar files and directories, which can be configured using the method jdbcnavboot.Boot.addClassPathItem(). The build process moves the entire jdbcnav package to a directory called "foo", which has the effect of throwing the default class loader off the scent; the class loader installed by jdbcnavboot.Boot looks for names starting with "jdbcnav", prepends "foo", and looks them up in the default class loader. Voila, all the application code is now loaded through my custom class loader, and I'm still only using one jar file. Hee hee hee. And of course when it comes to loading additional stuff, say, a JDBC driver, I can make my own custom class loader look wherever I want. Mission accomplished. (Except for the part of adding a classpath configuration panel to PreferencesFrame; that's next on the list. Meanwhile you can add stuff like <classpath> <item>/home/thomas/.jars/classes12.zip</item> <item>/home/thomas/.jars/pgdev.305.jdbc3.jar</item> </classpath> to the .jdbcnavrc file.) *) Some code changes to support builds both with and without the Boot class. Also added code to allow the use of $CLASSPATH by SneakyClassLoader if running under JDK 1.5 or later -- with this functionality, a user who already had his JDBC drivers listed on the CLASSPATH won't have to perform *any* configuration when using the stand-alone version. 2004-09-03: *) Added a splash screen. This is also displayed when the "About JDBC Navigator" command is selected, unless the splash.gif image is missing, in which case the old plain message box is used. *) Cleaned up the build.xml file a little bit. *) A wasted afternoon: tried to add a custom class loader, so I could load JDBC drivers without them being in the classpath, so I would be able to wrap the application in a self-contained double-clickable jar file (the contortions would be needed because when you run a jar file with "java -jar", CLASSPATH is ignored). Alas, 'twas all in vain; java.sql.DriverManager refuses to use drivers that were loaded by a different class loader than the application itself. Loading the app itself through a custom class loader would require a two-stage startup process that can't be done with a single jar file. Ergo, double-clickable jar files can't use JDBC drivers, so JDBC Navigator can't be a double-clickable jar file. :-( 2004-09-02: *) Added option to encrypt JDBC connection configuration settings when saving them to the .jdbcnavrc file. It is possible to run JDBC Navigator if you don't know the password for the encrypted .jdbcnavrc stuff; the non-encrypted parts of that file are processed normally, and the encrypted stuff is kept in memory in encrypted state, until such time as you enter the right password. It is allowed to enter a different password at that time; any new configs will be written to .jdbcnavrc encrypted with the new password, while the old stuff is written unchanged (that is, still encrypted with the old password). In this manner, it is possible to accumulate any number of encrypted chunks in .jdbcnavrc, all encrypted with different passwords. Nothing is lost; whenever you enter a password that matches one of the chunks, that chunk is decrypted; enter all the passwords one by one and everything is available once more. Neat, huh? :-) *) Added code to track a brief history of observed 'window drift' (that's when you call setLocation() on a JFrame, then show it, then call getLocationOnScreen(), and find that the location that's returned is not the location you just set). Race conditions involving the window manager make my drift detection approach a bit unreliable (no way to do it better without having access to X11 APIs, though), but the occasions where I get it wrong seem to be few and far between. So, I maintain a list of the 5 most recent drift values, and go with the majority. The downside is that you may get drift a few times when you switch window managers or reconfigure your window decorations; the upside is that you won't get drift on any other occasion. *) Clicking "connect" in the JDBC login dialog now automatically saves the connection configuration parameters; if the "name" field is blank, a name of the form "Unnamed #n" is automagically provided. Saving now always moves a config to the top of the list (even if you only do "save" without "connect"). *) Strengthened config encryption: switched from using plain DESede (that is, DESede in the default mode, which is (gasp) ECB) to DESede/CBC; to make things even more cryptic, I start the encryption with 8 bytes of randomness. Of course the Achilles heel of JDBC Navigator's security is that I keep all kinds of stuff in plaintext in memory... Here's hoping that security-conscious admins manage to keep prying eyes away from /dev/mem and such, and that they and jdbcnav users know about the the perils of core files. It's hard to do a better job, although I *could* do it by using a third-party DES implementation (e.g. a Java port, in source form, of libdes) where I can ensure that keys are *never* stored in Strings, and that all byte or char arrays used to store keys are scrubbed after use, and (this is the really unpleasant part) by making the user re-enter the password whenever we need it, so we never have to keep it around. Yeah, I know, that doesn't appeal to me either. 2004-09-01: *) In QueryResultFrame.nuke(), handle updatable query results specially: don't tell the user that "No" is a safe option, as it is for plain Tables, but warn them that "No" means their edits will be lost. (This is still not really satisfactory; updatable query results should be accessible from JavaScript, but since I don't feel like dealing with that can of worms right now, I just want to make sure that at least the user isn't lied to.) *) The configuration name combobox in JDBCDatabase now displays config names in the order they were read from the .jdbcnavrc file; when the user tries to open a connection, that config is moved to the front of the list. The .jdbcnavrc file no longer has a line with the most recently used config name at the beginning; it is no longer needed since the first config is guaranteed to be the most recently used one. (There is no need for special code to deal with old .jdbcnavrc files; the most-recently-selected line is just another line with no pipe character, and as such is silently ignored by the config reading code.) Cleaned up the config list code -- created a ConfigList class that encapsulates all the ugliness and which implements ComboBoxModel to keep things simple. *) Changed .jdbcnavrc to a new XML-based format; in addition to JDBC connection configurations, it is now also used to store the Swing Look-and-Feel name, the size and location of the top-level window, and an arbitrary set of system properties (name/value pairs that are fed to System.setProperty() on startup; I needed this so I could set swing.metalTheme=steel (in case I never get used to that new "Ocean" theme in Metal)). 2004-08-31: *) CHANGELOG file created. What a concept, 3 1/2 years and at least 1790 builds after I started work on JDBC Navigator. :-) *) Fixed PartialTable so that reloading it (i.e., calling getData()) causes the query to be re-run. Also added a distinguishing " (query)" to the title of QueryResultFrame and TableDetailsFrame when they're displaying an updatable query result; rigged PartialTable.remarks so it returns the query that was used to create the instance; added code to TableDetailsFrame to display the Table.remarks property.
Go back.