Using the Dummy Temp file tf

(a tip for Clarion programmers using MSSQL).

I define my dummy files with the name  tf (indicating a TempFile and quick to type and easy to find) in my local data in any procedure/function where I need it.

I set each data column as a CSTRING of at least the max size I might need for any data coming back from the SQL-Server. The number of columns I define varies as needed and can easily be changed when more are needed.

There is NO actual table needed in the Server Server database to match this dummy table, so long as I use the '/TURBOSQL = TRUE'  MSSQL driver switch. It is just a local table buffer (within the procedure).

I take care of opening and closing the file (well, it's really only a file buffer that gets created and instantiated with the OPEN() command).

Here is a typical  declaration:-

tf     file,driver('mssql', '/TURBOSQL = TRUE'), PRE(tf),owner( TblOwner )
record      record
f1    cstring(201)  
f2    cstring(201)  
                     end
         end

I also put my sql command into the local cstring-

SQLstr      CSTRING(801)

Whilst this is not absolutely necessary, it makes things neater. If I wanted to retrieve a couple of fields, say using

SELECT lname, fname from Client where sysid = 1234

So, I could do

clear(tf)
tf{prop:sql}= 'SELECT lname, fname from Client where sysid = 1234'

but I like to use the SQLstr variable....

clear(tf)
SQLstr =  'SELECT lname, fname from Client where sysid = 1234'
tf{prop:sql}= SQLstr

Now, the above shows a simplified version of what is actually used in the source code. Reason being, to prevent any SQL injection or user nastiness. That is the subject of a whole other  future  article.

Remote MS-SQL2005 Connection Problem

I have a program I am trying to get ready for potential users to download and test. This is a program developed in Clarion For Windows (6.3). The testing database is a MS-SQL2005 system which is hosted on a shared server at discountasp.net and the server is located in Los Angeles. My users will most likely be located in Australia.

The problem I saw was the initial time it takes to make a connection to the remote database, and then a further delay with each Table I was opening. These turned out to be two separate issues.

Initial Connection:

The time taken to establish the initial connection was in the order of 20+ seconds. The connection was being attempted before the main APPFrame screen was being displayed. So expecting someone to start a program and wait 20+ seconds before the first screen response was not going to work. This lead me to build a separate “Starter” program with just one screen that received staged updates from the main program, and then once the AppFrame opened, the “Starter” program simply closed, or displayed any error applicable. The Starter program also had a Seconds Elapsed display and a notice that they may need to wait 20 seconds to connect to the database.

But why was this initial connection taking so long? I could fire up MS-Studio Express and connect in about 4 seconds. It was only the Clarion program that was very slow to connect. This I would research further and eventually solve. See below.

Slow File Opening:

The time taken to open a Browse/List screen was also slow. It was taking about 5 seconds per table to open. Again, this is just too slow. I solved this by adding the Driver switches /FASTCOLUMNFETCH = TRUE to most tables. That has helped. I also set the program to Keep Files Open and I opened a few of the larger tables (those with more columns, not rows).

Testing:

After spending several days fiddling with the various Driver switches, I was resigned to the fact that it would take 20+ seconds to connect. I started looking for another closed SQL server that would be hosted in Australia. Then, along came Christmas and I took some time off from the development computer. I was relaxing out-doors and just for kicks, decided to try running the program from a 10″ netbook with an Atom processor and on a local wireless network. I started up the program, which worked just fine, and got connected to my Los Angeles database server in about 4 seconds. Could not believe my eyes! Looked at the data and yes, this was indeed coming from the LA database. This little netbook had no database stuff loaded, no MS-SQL and had very few programs installed. Basically it had IE and Firefox for travelling.

So, back to the development PC which could not be 20 seconds slower than the netbook.

I tried several things… Stop all running MS-Servers, Stop a bunch of system services that were running (pretty much anything that looked like a network service). Still I could not get any faster connection from the PC.

Next I remembered someone on the Clarion Database forum had mentioned SQL Native Client. This certainly was not installed on the netbook. But it was on my PC. I had another notebook PC laying around that did have some SQL stuff installed. It was running MSSQL2005 database. I tried running my program on that notebook and it also would connect in 4 seconds. The laptop also had MS SQL Native Client installed, albeit an older version of SQLNCLI.dll. OK, after backing up my newer SQLNCLI.dll I copied the older one from the Laptop to my Development PC. Testing the program again I was still taking 20+ seconds to connect. Then I renamed the file SQLNCLI.dll (located in \windows\system32 ) and tried again. This time I finally managed to connect in about 4 seconds. I put the original SQLNCLI.dll back and connection time again went out to 20+ seconds.

So there was a problem with the SQLNCLI DLL that was causing the problem. I researched this in several places on the internet and found one other report of this problem. But there was no resolution there.

Next I went to Control Panel, and un-installed SQL Native Client. Now I was back to 4 second connect times. OK, Let’s put the Native Client back in. So I downloaded the latest MSSQL2005 version( which turned out to contain the exact same DLL that I was having problems with, and now I was able to connect in about 4 seconds each time the test program started.

MS SQL Native Client (or a related setting) had been the problem all along. By removing and re-installing I had solved the major connection problem. But I had wasted about 4 days getting to that stage! Oh well, that’s computing.

John Griffiths

 

Executing SQL directly; no cursor

I was doing some extensive software testing in a program that talks to a MS-SQL2005 database. I detected that a table INSERT/UPDATE Trigger was seemingly not firing.

I scrutinised the trigger code and could see nothing wrong, and know that it has been functioning well for several years in other applications, using both MSSQL2000 and MSSQL2005.

So what was different in this program? I searched the web and did not find an answer.

I added some code to a test program to work around the issue. That is when I started catching this error message:

No Cursor Error

Here I was trying to CALL a stored procedure to update some balances. Again, the stored procedure has been working great for many years with no change. So, what was this message all about? Back to the web again and still no resolution.

That is when I dug deeper and added some more tests into a couple of other test programs I wrote, each of which tried different approaches to see what was really happening.

Strangely, some tested OK with no errors, and others threw the same error! So, what was the difference?

The Answer

The original error it seems is caught by the SQL Native Client ( or perhaps Microsoft Data Access Components (MDAC) ) and translated for the ODBC file drivers I was using. A translation (or miss-translation) is performed and a meaningless message is captured by the ODBC based drivers and passed back to my program as “Executing SQL directly; no cursor”.

Comparing the test programs I was working with pointed me to the answer. It was all to do with permissions! Nothing about “Executing SQL directly; no cursor”.

I found in some programs where I was using Application Role permissions to access the backend SQL, that the Application Role I was using did not have EXECUTE permission on the stored procedure.

Back into MS SQL Server Management Studio I went, and ran this command:

GRANT EXECUTE ON [dbo].[jg_AllBalances11] TO [LMGaus]

Now all my test programs began behaving as expected.

Also, my TRIGGER began working. The trigger was calling the stored procedure to do some of its work, and so now it too performed as expected.

Next time you see the

Executing SQL directly; no cursor

error, check all your permissions!

Hope this helps someone.

John Griffiths

The Dreaded “Record Was Changed By Another Station”

The subject error message shows up sometimes when working with Clarion and SQL based data.

When working on a recent conversion project I received the message when testing. I had moved a database from .TPS files to a MS-SQL Server database.

I had seen this message many time before, when getting started with SQL and dealing with DateTime data fields. So, I knew exactly where to look this time. Looking through the table in question, I noticed that I had no DateTime fields in the table. So something else was causing the warning “Record Was Changed By Another Station”. But, as there were no other “Stations” active, I was now in search of the source of the message.

First thing I checked was the order of the fields in my Dictionary, and the order of the fields in the database. This should not cause the error, but who knows… This all checked out OK.

Next I checked the data types were aligned and this too was all OK.

That is when I noticed that I had a STRING field in my dictionary as STRING(12) and in the database it was declared as CHAR(16). Yep, I had deliberately made it wider when I designed the new table but I had forgotten to adjust my Dictionary. Once I adjusted my dictionary to match the database, and re-compiled. all worked as it should.

But why would it report the “Record Changed By Another Station” warning, and not some more relevant message? Probably because the Clarion SQL file driver was doing its job correctly, and comparing my initially saved file buffer (with the 12 bytes I hade in my string in my dictionary). Then, just as I go to save my changed to the database, the SQL File Driver re-reads the data from the database, this time not using my data declarations, but the data as defined in the SQL table. It then does a byte-by-byte compare with the saved buffer. They do no match, so the warning message is displayed.

Bottom line: Make sure your Clarion dictionary declarations match the database fields.

John.

SQL Programming in Clarion

I have posted several hints for working with MS-SQL2005 and get many requests for more.

If you are working with SQL-2005 Express or Standard, and have a hint you would like published, then please let me know and I will add it to the site.

The site I post to is www.sqlkey.com/

John Griffiths