SQLite2 Object Based Driver baby steps

I figured I would start very simple. One file, set up with a primary key. Imported into the dictionary, then changed the driver to SQLite2. Wizard-generated app.

Browse works fine. Opening the form works fine, but try to change any value in the form and you get: Unable to log transaction (48) attempting to frame the transaction on Test2.

I figured adding some logging would maybe help, but test2{PROP:Profile} = ‘fn’ or {PROP:LogFile} does not produce a logfile.

LoggingOn(test2,‘whateverfile’) results in “Unknown procedure label”.

I used my text editor to look for LoggingOn in the driver directory and what it finds is CLALIT2L.LIB(223): LOGGINGONview for each of the drivers.

Not sure what my next step should be.

A few details … what Driver Kit version?
Is it from GitHub or purchased from Capesoft?
If from GitHub did you download the Zip or get it via a Git Client?

Always helpful to see the Code e.g. at least your FILE declaration source.
A picture of the file in the DCT would show if there are Related files.

1 Like

Is this app or handcode?

If an app, check the RI settings for the file.

https://www.capesoft.com/docs/Driverkit/ClarionObjectBasedDrivers.htm#encloseri

1 Like

Jon,
As Carl mentions it’s useful to understand your context, and specifically the version of the code you are using.

Regarding the “Unknown Procedure Label” - my guess is that you’ve either
a) not added theGlobal Extension to your app (commercial versions) Clarion Object Based Database Drivers Documentation or
b) Not added the necessary INCLUDE to the Global Includes Embed point.
Include('cwdriver.inc'),Once

Regarding the Relational Update error. There was a bug in that space, but I think it has been fixed (or in the process of being fixed). In the meantime to further your testing you can turn off Relational Updates (as Jane mentions) on the Global Setting, File Control tab.

Hi all,

Github version downloaded last week, SQLite Driver says it is 1.01. Came in as a zip, already had to deal with the line endings problem.

Baby steps, so this is a one-table ABC app. No relationships between tables because there is only one. Will possibly try Jane’s suggestion, but seems like it is the logout by itself is the problem.

Bruce pointing me to the “hand code” section is what I think I needed. I hadn’t really understood that was the code I needed to include if I didn’t have the template (not having the Capesoft version), but now I’ve looked at it it seems obvious.

Thanks, will let you know where I get to.

Jon

I just committed build 1.10, so grab that.

My little baby steps program now works, at least on my home computer. Main problem I had, which has nothing to do with the new driver is that in importing the table with a text column into the Clarion dictionary, the mapping in the Clarion dictionary will be to a STRING, not a CSTRING, column. This will then cause problems with the optimistic concurrency checking, since the value in the database is 'value' and the value that Clarion has stored is 'value ', which will give you a record changed by another station error.

Wy people use string and not cstring as datatype? I mean, what are string vs cstring advantages?

Strings allow binary, Cstring sort of do.. as long as there no 00F in there.
There are also a few places where, talking to external functions where one works and the other does not.
Other than that they both work. I tend to use Strings, because I always have. I don’t think there’s a compelling reason to use one over the other as a general case.

For everyday use, I simply do not like empty spaces in the database, for each string. On the other hand, I also don’t like using clip-in for each variable in the code and that’s why I’m using cstring’s since forever. Also, cstring uses less memory, am I right?

No. Actually they use more. The max amount of memory must still be allocated to store the string, plus a 00F to terminate it.

Yeah the clip can be annoying, but that about all.

Strings go back to the clarion for DOS days. So I think most people use them simply because that’s what they’ve used in the past. While there are reasons to choose one over the other, ultimately consistency is a good thing, so having a “preferred” one is ideal.

As to advantages; there are primarily two. Firstly they can contain binary values, which a cstring cannot. That makes them more useful in lots of coding situations, (although not necessarily in data storage.) They’re also able to do string slicing (slicing CStrings requires a lot more care.)

I don’t think CStrings use less memory. They have a declared length (same as Strings). Indeed it could be argued they use 1 byte more memory since they have a terminator byte.

From a database point of view, STRING and CSTRING are mostly interchangeable (at least in my drivers.) Either can be paired to CHAR or VARCHAR on the backend. So it’s not necessarily a database question. (Traditionally there was a school of thought that CSTRING in the dict mapped to a VARCHAR in the dict, so that was preferred.)

I’m not aware of any situation where this would be an actual issue - Clarion clips trailing spaces when doing string comparisons - but I’d be happy to see a test program that shows the problem.

Cheers
Bruce

Probably depends on the database. In Oracle it works like this:

A varchar2 datatype (cstring), when stored in a database table, uses only the space allocated to it. If you have a varchar2(1999) and put 50 bytes in the table, we will use 52 bytes (leading length byte).

A char datatype (string), when stored in a database table, always uses the maximum length and is blank padded. If you have char(1999) and put 50 bytes into it, it will consume 2001 bytes (leading length field is present on char’s as well).

In the database – a CHAR is a VARCHAR that is blank padded to its maximum length.

Hi Bruce,

The trace file looks like this (trad version not the LoggingOn version, which wasn’t working on my home computer, but was working on work computer earlier):

01A88H(2) 10:19:31.823 POSITIONkey(test1:064D7D8H,TES:PRIMARYKEY[0])  Time Taken:0.00 secs
01A88H(2) 10:19:31.823 Preparing  : UPDATE test1 SET FIELD3 = ? WHERE ID = ? AND FIELD2 = ? AND FIELD3 = ? .  Returned statement id is 06748C0H Time Taken:0.00 secs
01A88H(2) 10:19:31.823 Binding 3.03 to ? 1 of Statement 06748C0H Time Taken:0.00 secs
01A88H(2) 10:19:31.823 Binding 3 to ? 2 of Statement 06748C0H Time Taken:0.00 secs
`01A88H(2) 10:19:31.823 Binding 'third               ' to ? 3 of Statement 06748C0H Time Taken:0.00 secs`
01A88H(2) 10:19:31.823 Binding 3 to ? 4 of Statement 06748C0H Time Taken:0.00 secs
01A88H(2) 10:19:31.823 Executing Statement 06748C0H Error Occurred: 101 sqlite3_step() has finished executing Time Taken:0.00 secs
01A88H(2) 10:19:31.823 PUT(test1:064D7D8H) Error: Record Changed By Another Station  Time Taken:0.00 secs
01A88H(2) 10:19:31.823  TES:ID      : 3
`01A88H(2) 10:19:31.823  TES:FIELD2  : 'third'`
01A88H(2) 10:19:31.823  TES:FIELD3  : 3.03

sqlite_test.zip (41.5 KB)

Hi Bruce,

I should have probably also pointed out that how Clarion does string comparisons is not relevant in this case. The driver is sending an update statement to the server, and the value that clarion sends when the file field is declared as a STRING is a right-padded string. The server compares that to the text/cstring it has stored, which doesn’t have any spaces after the actual text, and tells you it can’t update the row because it doesn’t exist.

Jon

With CString the CLIP() is still done, but it MUST be done at assignment; otherwise you may have the trailing spaces. If the User adds trailing spaces in an ENTRY those are in a USE CString.

I use STRING’s for most things as I see them as the native type for Clarion. In cases where I want to specifically manage trailing spaces I’ll use CString or PString.

PString can be the fastest because the length is stored in byte [0] so the RTL does not have to search for first CHR(0) or last CHR(32). I use it a lot for a Path variable that often gets concatenated with a file name. Max size is PSTRING(256) giving a 255 byte String.

Small example HX is a PString:

HexDigits PROCEDURE(ULONG Lng)!,STRING 
HX  PSTRING(9)
Dgt STRING('0123456789ABCDEF')
  CODE
  LOOP 
    HX = Dgt[1+BAND(Lng,0Fh)] & HX
    Lng = BSHIFT(Lng,-4)
  UNTIL ~Lng
  RETURN HX 
1 Like

Sorry Jon, I thought you were using the new driver, not the old one.

As an aside, when the new SQLITE2 driver creates a STRING field in the database, it creates it as

Something TEXT COLLATE RTRIM

which then means it is stored as a “Clipped” value. And if it’s used in filters it can still use the key because the key contains the “clipped” strings.

Obviously this is SQLite, other databases do it differently.

Hi Bruce,

I thought I was using the new driver, but it turned out I was wrong. I think what happened is when I transferred things over to my home computer (cos I cannot run the debugger on my work computer), I did not have the SQLite2 driver registered, and I unwittingly ended up with the SQLite driver. That also explains why I was having trouble with LoggingOn.

So… now I am back with the new driver, like I was supposed to be all along. If I turn off transaction framing, things work fine. If I leave it on I get the “unable to logout”. In the non-logout version I can see that there is no concurrency checking – the update is just:

update test1 set field3 = ?1 where id = ?2;

In the version with logout (=Yes or =Default) I get the (Unable to Log Transaction(48)) attempting to frame the transaction on test1… message. As you can see from the app/dct I posted there is just the single SQLite (now SQLite2) file, so it is not like there are different databases or types of databases involved. I traced in the debugger as far as RelationManager.LogoutPrime, the line
IF FileToLogout{PROP:LOGOUT} <1
but then the debugger wants to open a source file called WXEH: I think if I really wanted to see what was happening I’d have to compile the driver with full debug info?

Jon

Thanks for yhe update Jon. I’ll look into the transaction thing in the morning.