Click here for RAC Consulting sponsor message | |||||
ODBC
Gotchas
Now that it's
becoming a popular tool to connect to 3000 databases,
Since weve been working with all of the driver products out there, weve been compiling lists and statistics on these products. Part of the collection are what we call the gotchas those items which tend to make you tear your hair out. There are a number of issues surrounding the collection of drivers available today: all are not immune to problems. Most problems fall into two categories: perception and education. Because TurboIMAGE is not a relational database management system, SQL is not its native language. The DB calls weve grown to use and the intrinsic library which support them are the native language. HP has placed an SQL layer on TurboIMAGE, via Allbase, so that access to the data contained in these databases can be accessed via SQL. With the advent of client-server applications and Web development, there came a need to open the interface up even more. HP first developed PCAPI, then replaced it with ODBCLink/SE. In addition to this product, there are the commercial products, some of which have been out since 1994. Linkway from CSL and ODBCLink from M. B. Foster are two of the most notable drivers which have been available for some time. ODBC32 from MiniSoft has been available for some time now as well. All of these drivers have their good and bad points. Most notable, however, is that these drivers are not interchangable. A bold statement to make, and
this leads to our first gotcha. Just slap it in and go. Well, nothing can be further from the truth. Yes, they may be interchangable in terms of SQL support; however, performance is a completely different story. Drivers such as Linkway and ODBCLink primarily utilize the IMAGE/SQL interface to the TurboIMAGE database. ODBC32 and ODBCLink/with DataExpress Option have the ability to access TurboIMAGE databases directly, without using the Allbase interface. The perception is that direct access is faster and better than access via IMAGE/SQL. Direct access may be advantageous, and again, it may not. A lot depends on the access itself, the datasets being accessed, how they are being accessed, how they are being joined, and which operations are being performed on them. For example, a simple hashread (DBGET, Mode 7) against a Master dataset: All drivers will return this row, if the driver is configured correctly, within milliseconds of each other. The same holds true for short chain reads (DBGET, Mode 5) on a Detail dataset. Where they start to differ are in areas of either unconventional accesses or when wildcard access are being utilized. For example, using the LIKE predicate in a SELECT clause to locate a match is performed consistently faster under IMAGE/SQL because of the Allbase optimizer and B-Trees. Direct access is dependent on B-trees only, and the optimizers incorporated into these drivers do not necessarily produce the most efficient access paths. On the other hand, processor utilization is lower in quite a few cases where a direct interface is employed. This is because the layer of IMAGE/SQL and Allbase/Turbo-Connect are not present. So which driver should you employ in your project? Pilot projects and small production projects may get away nicely with using ODBCLink/SE. Its free, but also requires the use of IMAGE/SQL and the obligatory attachment of databases. Larger projects, however, should be using a commercial driver. The reasons are simple ODBCLink/SE is the slowest of all of the available drivers in most cases and consumes more connections to the HP 3000 than its commercial counterparts, all of which contribute to response time issues and performance problems. Gotcha #2: Locking Strategies With DBLOCK, we have a variety of ways of locking data for write, update or delete. We can lock at the database, dataset or data item levels, we can lock conditionally or unconditionally. Fred White, Jon Bale and their IMAGE team were thinking of how to keep this database available concurrently while other users needed data. We were spoiled rotten, thanks to these two gentlemen. And we do appreciate their efforts. Now youre using ODBC, and guess what? Youre stuck with two types of locks, and guess at what level they lock? The dataset. Note that this does not apply to direct-to-TurboIMAGE drivers, only those utilizing IMAGE/SQL. Out of the four Isolation Levels mentioned in the Allbase and IMAGE/SQL manuals for locking, IMAGE/SQL recognizes two of them. These are RR (Repeatable Read) and RU (Read Uncommitted). These isolation levels correspond well to a relational database, but to TurboIMAGE, improper use can be catastrophic for application and system performance. The rule of thumb to follow is this: If you need the dataset exclusively, and dont mind locking everyone else out, then use Repeatable Read. If concurrency is what you need (and who doesnt), then use Read Uncommitted. For those who are not familiar
with SQL Isolation Levels, Repeatable Read is basically a
pessimistic locking mechanism. It will place a lock on the data
after it has been read and queue all other processes accessing the database
behind the locking process until the transaction is committed. Read
Uncommitted is optimistic locking, which basically places a
lock around the update, insert or delete. It exists only for the time of
the update. Do you have fields in your datasets defined as Zoned or Packed, and defined in COBOL programs as Unsigned? In other words, is there something like this lurking in one of your programs:
If so, you need to know how to get around this little gem. These fields are commonly used for counters and other such data which does not require a field. A recent project of ours used this type of field for a serial number. Well, with SQL, every numeric has a sign, whether you want one there or not. The problem is simple: Update FIELD-A, or insert a row with FIELD-A filled in, and it will be signed. When the COBOL program reads the value, depending on how the systems COBRUNTIME variable is set, the program will abort or will show an ILLEGAL ASCII DIGIT warning. How can this be? Well, when IMAGE was written, the idea of datatypes was foreign. IMAGE, and TurboIMAGE, do not really enforce datatypes. Your program enforces data types, QUERY enforces datatypes, but TurboIMAGE does not. It is entirely possible to place ABCDEF into a field that is defined in the databases schema as Z6! Just define the item in a COBOL program as PIC X(6), and DBPUT away. When a field is defined as Z6 in the schema and root file, and a COBOL program has a definition of PIC 9(6), a value of 123456 is shown in the database, in Hexadecimal, as 31 32 33 34 35 36. This is the expected behavior, right? Change the PICture clause in the COBOL program to PIC S9(6), and this same value is now 12345F. The F is the sign overpunch that weve all grown to know and love. Going back to our PIC 9(6) field, if we use an INSERT or UPDATE statement from any SQL source (not just ODBC) to update this field, the numeric will be signed. IMAGE/SQL makes no distinction between signed and unsigned for two reasons. First, Zoned or Packed can be signed or unsigned and SQL cannot tell the difference, except by possibly reading the data in advance. Secondly, the ANSI standard for SQL for numerics is signed, and Allbase/SQL, which lies behind IMAGE/SQL, follows these standards rather closely in this regard. So how do we get around this when dealing with an ODBC driver? The solution is called casting a way of changing the datatype of the data being written and overriding what SQL thinks the datatype might actually be. In our case here, we need to cast the value as a string (or in COBOL-speak, a PIC X(6)). Lets take our serial number as an example. This field is a Zoned decimal field of 10 positions. Its defined in COBOL programs as PIC 9(10). It contains no sign and its a counter, which is read from the dataset. The number read is incremented by one, then updated. This field is treated in a Visual Basic program as a long integer. Arithmetic is performed on this variable, but the Update is treated as a string (see Figure 1 below). Figure 1:
Visual Basic Code Fragment to update the Serial Number Note that we read the value from the database (a recordset in Visual Basic, which can also be referred to as a cursor). We then add one to this value and attempt an update. During the update sequence, note the use of CStr this is a Visual Basic version of a Cast. We are converting the value to a String, from Long Integer. This strips off the sign, as the value is positive. The use of Format in the same statement will ensure that the value is zero filled prior to conversion. The final result is an unsigned zoned decimal number instead of a signed zoned decimal number. The rest of the code (If Err > 0 Then ...) just shows that if the update is not successful, we roll everything back as if nothing had happened (which is the beauty of SQL, by the way). Gotcha #4: Dates Now that you know about unsigned numerics, youre ready for the next gotcha covering dates. There are two issues here. The first is that there is no date datatype in TurboIMAGE or IMAGE/SQL. The second is simple if dates are stored in a Zoned decimal field, then re-read Gotcha #3 before continuing, because more than likely, they are stored as unsigned numerics, right? How do we use the date functions within our PC-based languages, such as Visual Studio and other Interactive Development Environments (IDEs)? These IDEs require dates to be in a Date Format or datatype. If data is read from an SQL table and the value has a datatype of DATE or DATETIME, then youre covered. This datatype exists in Allbase and other SQL databases, but alas, does not exist in IMAGE/SQL. These IDEs have functions: permitting the programmer to find the difference between two dates, to add a number of days, months, and years to come up with a new date, to handle leap years automatically. These functions are real time- and code-savers. So how do you get these CCYYMMDD and YYMMDD dates into a format so they can be used in these functions? Again, the use of a cast (changing the datatype) is used, but the function will probably require the format of the date be in a different format from which it is stored (See Figure 2 below). Figure 2: Casting a CCYYMMDD date field in Visual Basic
In this example, we read a date field from an IMAGE/SQL recordset in Visual Basic. This value is a CCYYMMDD date. We then use the string manipulation function Mid to extract the components into individual variables. After this is complete, concatenate the date into a standard date format of Month, Day and Year, separated with slashed or hyphens. Once this concatenated string is passed through the Cdate cast, the value is converted to a date format, and may be used in all date functions within Visual Basic (in this case). To get a date back into string format (for update or insert, for example), use the Format and Now functions. For example, to assemble the current date:
The value of SimageDate$ (as of today, that is), is 19980910. The Year function will return the year of the date field. The Month and Day functions return the month and day respectively. Use of the Now() function returns the current date, but any date-format field can be used. For example, the date field SnewDate which we used in our previous figure can be substituted for Now() as follows:
This will work if the datatype in the dataset is type X. Again, if the datatype is Zoned decimal, you have a little more work to do add the CStr cast to the above, to convert the number to a string. A question that commonly comes up is: Can TurboIMAGE store an SQL Date? Yes, it can. The problem with doing this is that the value cannot be used with any other code except SQL. Even QUERY will have a problem with the field. If you really want to do this, heres how: 1. Define a field in a dataset as a K8. 2. Using IMAGESQL.PUB.SYS, override the type with an UPDATE TYPE command, and change the datatype to DATETIME 3. Use INSERT or UPDATE to place a Date-Format value in the field. We demonstrated this on an HP-TV broadcast on Cure2000 when showing how Adager handles Y2K issues. We also showed how QUERY absolutely could not handle the field, but it will yield a DATETIME datatype each and every time from SQL. Gotcha #5: Unique Keys This gets off the bits and bytes and onto a topic which infuriates quite a few people the requirement of unique keys in a table. Why should this be a necessity anyway? Well, ODBC in most cases is handled by Microsoft Jet, which is the engine which drives Microsoft Access. If youve ever tried to use Microsoft Access Linked Tables and you tried to link in Detail Datasets, then you have been prompted for a unique key. Master datasets already have a unique key and will be reported as such. Detail datasets are never guaranteed to have a unique key, and are reported as such. Microsoft Access will prompt users to specify one or more fields which comprise a unique key for all detail datasets. The reason is simple, really so that there is a unique identifier for a row in the event an Update or Delete query is performed on the dataset. Without a unique identifier, it is possible to delete or update rows that were never intended to be deleted or updated. As stated earlier, Microsoft Jet requires this, which means that Microsoft Access also requires this. There is however, another mode of ODBC called ODBCDirect which was introduced with ODBC 3.0. The passthrough mode of ODBCDirect, which most of the drivers for the HP3000 support, does not require the unique key. This means that linked tables cannot be used with Microsoft Access, but can be directly accessed from within the application. ODBCDirect should be used whenever possible, especially if Remote Data Objects (RDO) and Active Data Objects (ADO) are being contemplated for use. (See the sidebar on how to find out more about these objects.) In Visual Basic (Visual C++ and Visual Interdev are similar), when using the OpenDatabase method, specify vbUseODBC constant instead of vbUseJet constant, to utilize ODBCDirect. Again, note that not all drivers can use this mode of access but that will change shortly. If the driver is fully, ODBC 3.0 compliant, then it should work with ODBCDirect. If youre using Visual Basic 4.0 or earlier, ODBCDirect is not supported. It is supported only on Visual Studio 5.0, and now on Visual Studio 6.0. (The suite of languages of Visual Basic, C++, InterDev, FoxPro and J++ are now known as Visual Studio). Joe Geiser is principal partner in CSI Business Solutions, an integrator and supplier of HP 3000-related client-server and Internet software and services. |
|||||
Copyright 1998, The 3000 NewsWire. All rights reserved. |