Usually, it is symbolic of an omitted profanity when you see several special characters together in print, as, for example, $#@_. IBM i developers, however, probably recognize those characters as allowable characters in DDS and RPG field names. Because the IBM i has so readily accommodated the use of those special characters in both its data description language and its programming languages, there has generally been little thought given to the advisability of using or not using those characters.
A recent email caught me off-guard:
I cannot create an SQL statement where the field name has a $. I get the following message:Error in SELECT clause: expression near '$'.
Missing FROM clause.
Error in SELECT clause: expression near ','.
Unable to parse query text.
A number of simple resolutions immediately came to mind, none of which worked. I'll describe those attempts a bit later in this article. For now, I'll show you the test environment that I created and the results of working with those $#@_ characters.
To get started, I created a test file using the DDS shown in Figure 1. This is a simple physical file, there is nothing tricky about it. I created FIELD1 as a "control" field, it has no special characters. FIELD2 - FIELD7 are variations of field names that begin with one of the allowable special characters ($, @, #) or have one of those characters embedded. FIELD8 shows the use of the other allowable special character (_), which can be embedded within a field name but not used as a starting character. The conventional Create Physical File (CRTPF) command was used to create the file.
To see how the file would work with SQL, I used the OS/400 Start SQL (STRSQL) command in a 5250 session. I then used the INSERT statement shown in Figure 2 to put some test values into each of the fields. This worked without error. A subsequent SELECT statement, also in the STRSQL environment, is shown in Figure 3. This worked as expected, displaying the contents of the fields.
At this point, I have a valid IBM i physical file that contains data. It can apparently be accessed using SQL Statements.
I now went over to Visual Studio 2008. For my first test, I created a new Data Connection using the IBM DB2 Provider for .NET (the V6R1 version; I have no reason to suspect that the V5Rx version would work any differently, in regards to the tests I show in this article). Using the Visual Studio Server Explorer, I started a new query. In the query SQL statement panel, I entered the SELECT * SQL statement shown in Figure 4. When I executed the query, all of the data was retrieved from all of the fields.
One of the first things you learn when working with SQL is that it is generally inadvisable to use SELECT * queries. Instead, it is better to list the columns that are needed by your application, the idea being that you usually need fewer columns for your application than are available in the table. So my next SELECT statement included all of the column names. When I tried to execute the query, the Query Definitions Differ message shown in Figure 5 was displayed, followed by the SQL Execution Error message shown in Figure 6.
At first glance, this seems to not make any sense: why could I successfully run the same SELECT statement in STRSQL, but I cannot run it against the same database file in Visual Studio?
The answer is, the parser used in STRSQL is not the same as that used in the .NET provider.
Now it turns out that the Query Definitions Differ message shown in Figure 5, although alarming, is innocuous. The real issue is identified in the SQL Execution Error message, in Figure 6. The SQL0418 error in Figure 6 states that the "use of [the] parameter marker [is] not valid". The IBM .NET provider treats names that begin with the @ (at-sign) character as being parameter markers, that is, substitution values within an SQL statement. The problem is, parameter markers are only valid in the WHERE clause. As much as we might like to create parameter-driven lists of columns, or tables to query, or ORDER BY clauses, we can't. So when the .NET provider sees the @FIELD3 column name in the SELECT column list, it simply gives up.
Usually, when you come upon something that can't be done in a programming environment, there is some easy work-around. So the first thing I tried, since it always worked before, was renaming the column: SELECT @FIELD3 as asFIELD3...
With the exact same parameter marker error message. The .NET provider is not willing to "read ahead", if it sees that you are trying to sneak a parameter marker into the SELECT list, it bails out on you.
Another technique that works with SQL Server queries is to surround the column name with square bracket characters:
SELECT [@FIELD3]...
This time, a different SQL error message, informing me that the [ character is not a valid delimiter (according to the IBM .NET provider).
At this point, I was starting to get a little concerned, as the obvious work-arounds were not working. Digging into the MSDN Help file for information about parameter markers, Help suggested that Visual Studio provides a way to specify the character to use for a parameter marker and an escape character. Figure 7 shows the Database Tools, Query and View Designers options (you access the Options dialog by using the Visual Studio Tools, Options menu item). The parameter prefix and parameter escape character looked promising. I first tried setting the parameter prefix to the ~ (tilde) character, thinking that I could tell the provider to use that as the parameter marker character. The .NET provider simply ignored my attempt to mislead it, and stubbornly told me I couldn't use a parameter marker in a SELECT list.
I then tried to use the escape character, like this:
SELECT \@FIELD3...
And got the invalid delimiter message.
No way, no how.
I wanted to see what this looked like when I ran my own code. So I created the test programs (Module1.vb, Test1.cs) to work with the SQL statement using the .NET provider, controlled by my own code. (You can access these test programs in SQLFieldNameTesterVB.zip and SQLFieldNameTesterCS.zip).
Figure 8 shows that I get the same result (SQL0418 error) when running my code. I also tried the variations here (@FIELD3 as asFIELD3, [@FIELD3]), with the same ill results.
Finally, in desperation, I abandoned the .NET provider and created Module2.vb and Test2.cs, working with the IBM OLE DB provider (in this case, the IBMDASQL provider). Success at last, as Figure 9 shows! Using the OLE DB provider, I can simply use my column names as they are defined in my IBM i physical file.
The reason why this works is not difficult to understand. The OLE DB provider uses the ? (question mark) as a parameter marker. That character is not allowed in an IBM i file field name, so there is no danger that it will ever be encountered in an SQL statement except as a parameter marker.
As you can imagine, it is more convenient when developing an application to use "named" parameter markers, rather than single-character ? parameter markers. It is especially nicer when you are working with several parameter markers in a statement; rather than just see a list of ? parameters, you see the field name, albeit the names start with the dreaded @ character.
So you now have some examples of what does not work and some examples of what does work. In a nutshell, here are some of the options you have for developing SQL statements in .NET applications, when working with those $@#_ characters (in order from least preferred to most preferred as a solution):
However, my preferred solution would be to use the system's long name support, to provide a long name, that doesn't contain special characters, for use by SQL based interfaces.
You can assign a long name to all the fields without changing the files Record Format Level Identifier, thus you won't even need to recompile existing RPG program to prevent a level check. It doesn't matter if you use SQL DDL and the "SYSTEM NAME" clause or DDS and the ALIAS keyword.
HTH,
Charles Wilt