Wednesday, August 15, 2007

Oracle 11G first look

Oracle 11g is now available for download, but only for Linux. This blog posting covers practical issues we've seen since we started playing with it. If you are looking for marketing/new feature info you can find the PDF's here.





    Installation




      1. Download is a 1.8GB zip file.
      2. The Installer requires a minimum of 922MB of memory and large quantities of swap space. If you need more swap you can use 'swapadd'.
      3. Installer for X86 expects recent patches - don't think that your copy of RHEL4 will work without new rpm's.
      4. Oracle has changed the default location of the *dump and other configuration directories.
      5. Some minor Kernel tweaks required.




        DB Upgrade Process





          Process expects that your copy of 10.2.0 is patched to 10.2.0.3.0 to address a DST issue. If not you have to manually apply Oracle patches and jump through various other hoops. We encountered problems with the upgrade and eventually built an11g DB from scratch for our regression testing. This may a fundamental problem with the upgrade but is more likely to be because 'someone' unplugged our router during the upgrade process and left the DB in a mess.





            Security

              Passwords are now case sensitive. This will cause hours of fun.


                11g JDBC Driver



                  1. 1.4 and earlier versions of Java are not supported.
                  2. 9.0.1 and prior versions of Oracle are not supported.
                  3. 'oracle.jdbc.driver' is gone - but then it's been deprecated since 9i...
                  4. We were expecting OracleConnection to be extended to prrovide support for Asynchronous Commit, but that didn't happen. We'll be adding our own support to OrindaBuild.




                    JPublisher


                      The 11g version of JPublisher still creates .sqlj files but then deletes them after producing .java files. JPublisher still has all its other limitations.



                        OrindaBuild 11g Support



                          We have completed regression testing and the first build that supports 11g is available here. JDeveloper users can use this update center:

                            http://www.orindasoft.com/public/jdev103Center.xml

                              SQLDeveloper users can use this update center:

                                http://www.orindasoft.com/public/sqldevCenter.xml

                                  Labels: , , , , ,

                                  Sunday, July 15, 2007

                                  TOAD - Not all stories have happy endings...

                                  Over at forums.oracle.com there was a sort-of-interesting thread on TOAD and it's usefulness when compared to other products such a SQL Developer and PL/SQL Developer. The subject of TOAD's acquisition by Quest came up and someone asked what happened to Jim McDaniels, aka 'Toadman'. The answer they got was:
                                  I believe that he was hired on as a manager. I would assume that some decent stock options & a fair amount of money came along with that deal, but I don't envision him having enough to retire immediately. It is rarely the developer that gets rich in situations like this.
                                  Unfortunately while Jim appears to have done very well out of his deal with TOAD he then appears to have made some devastatingly bad personal choices afterwards. It's unlikely he'll be contributing to the future development of TOAD any time soon. If you really (and I mean really) want to know what he got involved in click here and here. O'Reilly might want to update their author bio for him.

                                  Labels: ,

                                  Thursday, July 12, 2007

                                  Oracle's DECODE funtion...

                                  Oracle's decode function can be used to create arbitrary ORDER BY clauses. This is useful if you are providing lists with the most frequently picked value at the top - e.g. a list of countries which starts with 'United States' and then turns into a conventional alphabetical listing. Your SELECT statement will have two things in the ORDER BY clause - first it sorts by a DECODE that turns your favoured value into '1' and all other values into '2' and then it sorts the rest of the list conventionally. The alternatives to using DECODE are to hard code the entire list (bad!) or add a numeric column to the underlying table that defines the sort order, which is a lot more work than a DECODE in an ORDER BY.


                                  SQL> r



                                  1 select country_name


                                  2 from iso_countries


                                  3* order by decode(country_name,'UNITED STATES',1,2)

                                    , country_name





                                  COUNTRY_NAME


                                  --------------------------------------------------


                                  UNITED STATES


                                  AFGHANISTAN


                                  ALBANIA


                                  ALGERIA


                                  AMERICAN SAMOA


                                  ANDORRA


                                  ANGOLA


                                  ANGUILLA


                                  ANTARCTICA


                                  ANTIGUA AND BARBUDA


                                  ARGENTINA


                                  ...





                                  This behavior is common for web sites where drop down lists have to be dynamic (the contents may change) but also require location or market specific default preferences.





                                  While we're on the subject of lists of countries one really should think twice before including Bouvet Island one's list...

                                  Labels:

                                  Wednesday, July 11, 2007

                                  BLOBs, CLOBs and BFILEs

                                  Summary




                                  Oracle users currently have 3 different Large OBject data types to choose from - BLOB, CLOB and BFILE. We'll look at the basic mechanics of how they work from a Java developers perspective and then explain why oracle.sql.BFILE poses serious challanges for web service developers.





                                  LOB's 101





                                  When you retrieve an oracle.sql.BLOB or oracle.sql.CLOB the single most important thing to understand is that you're dealing with a pointer, not a file. Not only that, but that the oracle.sql.CLOB you just retrieved from the database is totally independent of the SQL statement or PL/SQL procedure that was used to return it to you. What you've actually got is a pointer to a large object inside the database that will continue to exist until your commit, rollback or lose your connection. Once you understand this life will become bearable. There are significant API changes for Oracle's JDBC drivers as you move up through the different versions of Oracle. You will need to re-read the JavaDocs and check your LOB code line by line when you upgrade. Of course, if you used OrindaBuild you could just re-generate your code...



                                  BFILE



                                  oracle.sql.BFILE is different. A BFILE is a pointer to a file that resides outside the database. In fact a BFILE consists of two things:

                                  1. The name of an Oracle DIRECTORY (as found in the ALL_DIRECTORIES view)
                                  2. The name of the file within that directory


                                  oracle.sql.BFILE objects are small - often under 100 bytes. Oracle makes no attempt to verify that the file referred to by the oracle.sql.BFILE exists and is usable until you attempt to read from it. The only way to create an oracle.sql.BFILE is to call use the SQL function BFILENAME, which implies a database call. You can quite happily create BFILE objects for files which don't exist. This makes sense when you consider how much work checking every BFILE every time it was referred to would impose on the server, but obviously needs to be understood by the developer.



                                  LOBs and Web Services



                                  If you're going to write a Web Service app and are one of the surprising number of people who are still on 8i you should upgrade to at least 9i. Creating CLOBS and BLOBS is a lot easier because of the createTemporary() method that appears in 9.0.1.Using LOBS in a Web Service environment is not a problem, provided you think carefully about how big the LOBs will actually be and how much memory you'll need - Oracle can support huge CLOBS and BLOBS that simply wouldn't be practical in a Web Service scenario.Creating BFILES and Web Services. If you are writing a web service application that stores LOBs in Oracle you should avoid the use of the BFILE data type. It may well seem very tempting but the JVM which is running the service will need to be on the same filesystem as the Oracle database server, which will severly limit scalability. If, as is normal, your JVM is on a different machine you could in theory get round this by creating a BFILE that points to a non-existent directory/file on the database server and then trying to asynchronously move the file to where the BFILE pointer claims it is before anyone actually tries to read the BFILE. For obvious reasons we don't recommend this.



                                  [This post originally appeared on JRoller]

                                  Sunday, July 1, 2007

                                  Not All Jdbc Advice Is Good JDBC Advice...

                                  While wandering around the web I stumbled across a link to a sample chapter for 'Java Programming with Oracle JDBC', published in December 2001 by O'Reilly. Now 2001 is a bit dated but one would assume that if they are plugging it on their web site it must still be relevent. And that any glaring

                                  errors would have been corrected, right? Think again...

                                  The author spends the chapter conducting elaborate benchmarks which in his view demonstrate that there's nothing special about PreparedStatement
                                  and that you should really be using Statement most of the time. His reasoning is based on the premise that the additional set up costs of Prepareing a statement and sending all the bind variables etc cause applications to run more slowly than if you had simply said something like:

                                  code>


                                  Statement stmt = conn.createStatement();

                                  stmt.executeUpdate(

                                  "insert into oehr.testxxxperf ( id, code, descr,insert_user, insert_date ) "

                                  "values ( " + Integer.toString( i ) + ", '125678901234567890', "

                                  "'1234567890', " +




                                  "USER, to_date('" + sdf.format(new java.util.Date(System.currentTimeMillis()))
                                  + "', 'YYYYMMDDHH24MISS'))");

                                  instead of:

                                  PreparedStatement stmt = conn.prepareStatement(

                                  "insert into oehr.testxxxperf ( id, code, descr,insert_user,

                                  insert_date ) " +

                                  "values ( ?, ?, ?, ?, ? )");

                                  startTime = System.currentTimeMillis();

                                  int i=1;

                                  stmt.setInt(1,i);

                                  stmt.setString(2,"123456789012345678901234567890");

                                  stmt.setString(3,"123456789019012345678901234567890");

                                  stmt.setString(4,"ZXVI01");

                                  stmt.setDate(5,newjava.sql.Date(System.currentTimeMillis()));

                                  stmt.executeUpdate();




                                  The point made is that unless you plan on issuing hundreds of statements the first method is faster because it has fewer network round trips and therefore less elapsed time. All of which is true - provided there is only 1 copy of the client software being used. In practice what will happen is that using Statement in preference to PreparedStatement will cause the database server to devote significant resources to compiling execution plans for each and every version of the insert statement being called. Indeed, not using PreparedStatement and bind variables is listed as the second most common mistake in Oracle's '
                                  Top Ten Mistakes Found in Oracle Systems'.There's also a less obvious but equally serious problem with cobbling together your SQL statements instead of using bind variables and PreparedStatement - sooner or later someone with an apostrophe in their name will show up and cause a syntax error:



                                  Int empno = 42;

                                  String empname = "O'Reilly";

                                  String myStatement = "INSERT INTO EMP (empno, ename) VALUES ("

                                  + empno + ",'" + empname + "');";




                                  But wait... it gets worse! If you're working on a public facing web system and some bright spark realizes you are hacking together SQL statements you could have something like this happen:



                                  Int empno = 42;

                                  String ename = "'Smith', sal = 99999";

                                  String myStatement = "UPDATE EMP set ename = "

                                  + ename+ " WHERE empno = " + empno');";


                                  which means that your Statement would be:


                                  UPDATE EMP set ename = 'Smith', sal = 99999 WHERE empno = 42;

                                  [This post originally appeared on JRoller]

                                  Labels: , ,

                                  Wednesday, June 20, 2007

                                  Rowid Madness

                                  For years the first of my interview questions for Oracle developers has been one in which I ask them to explain why it's a bad idea to use the ROWID of table 'A' as a foreign key to table 'B'. This is not hard for a competant person to answer, as ROWID changes when you import the data into another database which will happen sooner or later. It never occured to me that someone could be crazy enough to actually do this, but someone has.


                                  [This post originally appeared on JRoller]

                                  Labels:

                                  Wednesday, June 6, 2007

                                  Why '43113f...0308' is bad news for Java users...

                                  While going through our web server logs recently we found out that we had our first single word google hit. Unfortunately the word in question is 43113f32554e54494d45110e4350500308,
                                  which we suspect isn't terribly memorable. It's thrown as an error id when the JVM crashes and is referred to in the support section of our web site.

                                  We've now had hundreds of people show up at our web site trying to find out about this. We suspect we may see many more, as the underlying problem appears to affect all applications that use the Java 1.3 or 1.4 JVMs.

                                  If you encounter this you will find the following information useful:

                                    • This is Sun bug 4820592.
                                    • The bug appears to be limited to x86 based systems.
                                    • The bug will appear as a JVM crash after the application has done a fair amount of work.
                                    • If you try and use the 'debug' mode of an IDE such as Eclipse the JVM crash will take place at odd and changing locations.
                                    • Using interpreted mode ('-Xint') is an effective workaround.
                                    • Changing other JVM parameters may postpone the crash but will not prevent it.
                                    • To prevent it you can:
                                      • Move to Java 1.5
                                      • Rewrite your code.
                                  In our case we were able to fix the problem by replacing an ArrayList of String[] with an ArrayList of File, with each File containing 0 or more String. We suspect that the presence of zero length 'String[]'s in the arraylist was the root cause of the problem.

                                  [This post originally appeared on JRoller]

                                  Labels: