It’s a big pain having to manually format source code. Usually i write all my code without indenting. There are basically two ways to automatically format your code: using your IDE or using a build script. I prefer the latter. Source formatting in the IDE has two problems. First, you need to manually invoke the formatter. Second, developers can change the formatting preferences, which leads to formatting differences between developers.
Using a build script, in my case an Ant build script, guarantees that my files are formatted, even if i forget to invoke the format action in the IDE. In my opinion, source files need to be formatted almost after every change, to avoid having unformatted source files in CVS. Comparing different versions of a file is a lot easier when the files are formatted. The build script also solves the second problem. All developers use the same build script, which means that formatting is consistent.
For java source code it’s easy to define an Ant task which will format the source code. There are quite a number of formatting tools you can run from Ant: jalopy, jindent, and some others. But for sql source code i haven’t found any useable tools. That is, until Oracle released Project Raptor.
Project Raptor doesn’t contain an Ant task for sql formatting, but it does contain some java code which formats sql source. So it’s not difficult to create an Ant task to format sql source code.
Here’s an example of how i would like to use this formatter:
<taskdef name="format-sql" classname="..." classpathref="lib.path" />
<format-sql>
<fileset dir="sql">
<include name="**/*.sql"/>
</fileset>
</format-sql>
The first step is to create a class which extends Task. In the execute method we’ll loop through all the sql source files as specified using the nested fileset task.
public void execute() throws BuildException {
Iterator fileSetListIterator = fileSetList.iterator();
while (fileSetListIterator.hasNext()) {
FileSet fileSet = (FileSet)fileSetListIterator.next();
DirectoryScanner ds = fileSet.getDirectoryScanner(getProject());
String[] files = ds.getIncludedFiles();
for (int i = 0; i < files.length; i++) {
try {
format(new File(ds.getBasedir(), files[i]));
} catch (Exception e) {
throw new BuildException(e.getMessage());
}
}
}
}
For every file the format method is called. This is where we need to call Raptors sql formatter. The jar file which contains the sql formatter is oracle.dbtools.sqlformatter.10.1.3.jar. You can find this file in %RAPTOR_HOME%\jdev\extensions. You need to place this jar in your classpath. Doing the formatting is actually pretty straight forward. You create a file reader and writer for the source and destination files, and instantiate PrettyPLSQL to do the formatting:
private void format(File file) throws FileNotFoundException, IOException,
TokenStreamException {
System.out.println("Formattings: " + file);
boolean status = false;
File backupFile = new File(file.getAbsolutePath() + ".bck");
File outputFile = new File(file.getAbsolutePath());
// delete existing backup file
status = backupFile.delete();
// rename file to backup file
status = file.renameTo(backupFile);
if (!status) {
throw new BuildException("Failed to create backup file " +
backupFile.getAbsolutePath());
}
// create reader and writer
FileReader reader = new FileReader(backupFile);
FileWriter writer = new FileWriter(outputFile);
// format sql file
System.setProperty("ANTLR_USE_DIRECT_CLASS_LOADING", "true");
PrettyPLSQL prettyPlsql = new PrettyPLSQL();
PLSQLLexer lexer = new PLSQLLexer(reader);
writer.write(prettyPlsql.format(lexer, getFormatOptions()));
// close reader and writer
writer.close();
reader.close();
}
The getFormatOptions method returns a FormatOptions object. You can use this object, for example, to specify if identifiers need to be uppercase or lowercase.
During testing i got some ClassNotFound exceptions. Turns out that you can specify how certain classes need to be loaded using the ANTLR_USE_DIRECT_CLASS_LOADING property. Jad is a big help to discover these things.
More info:

January 2nd, 2006 at 09:58:56
Cool. Very well explained, useful too. I like it. En een gelukkig nieuwjaar!
regards,
Lucas
January 2nd, 2006 at 10:25:49
Thx, gelukkig nieuwjaar to you too!
Andrej
January 2nd, 2006 at 16:57:33
That’s exactly what I was hoping for once I saw that Raport had a SQL formatter. Since it is based on tje JDev framework it had to be some Java class that’s performing the formatting. One of the first things that came into my mind is to try and use it in an Ant task to format our SQL and PL/SQL files.
Thank you very much for this code. From the Raptor forum I understand that there are still a number of annoying issues with the code formatter, but let’s hope they fix that for the final release.
January 16th, 2006 at 18:34:30
Hi, did you already have a look at the online SQL formatter at http://www.sqlinform.com? It is a java applet.
Regards
Guido
January 16th, 2006 at 20:56:38
An applet is pretty useless, i want to reformat my code automatically as part of an ant build file. It’s too much work to copy and paste my sql code into an applet after every change.
June 6th, 2006 at 21:39:04
Great blog. Still having trouble linking up the fileSetList. Is there some sample code on how to use this particular object…I have Ant 1.6.5 and there is no iterator() associated with the FileSet object ?!?
Does anyone have a working version of this that they could publish? The only Ant Task I’ve ever extended is an Oracle PL/SQL compile task…think from Andrej if I remember correctly.
tia,
adym
October 6th, 2006 at 16:52:01
the new sqldeveloper pretty printer doesn’t really do anything.
May 28th, 2008 at 14:49:35
I just came across this blog post when looking for a way to format SQL from within java. I downloaded SQL Developer (which Raptor has become), but I couldn’t find any of the classes mentioned above.
Has anyone gotten this working with SQL Developer?