Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Alternative to SELECT 1 to check MariaDB Server online status ( using DO 1 generates an error )

dylim

Programmer
Dec 12, 2001
146
PH
Hi Guys,

With MySQL, I use "DO 1" to check for the server's online status. Works like a charm. But MySQL 8.x has caused me so much pain by way of unknown errors I cannot seem to understand and correct.

So, I tried MariaDb, installed the latest GA todate, 11.7.2 and used the latest ODBC 3.2.5 32 bit.

None of the horrific problems came out! What a joy! And so far so good. It's even way way faster!

I have since been testing MariaDb, hoping to use this as my new go to database server.

So far, my only issue now is that MariaDb returns an error when I use "DO 1" in checking for online status. I have to use "SELECT 1" in lieu of this. What I don't like about this is it returns a cursor which I need to erase each and everytime I check for online status.

Any other commands like DO 1 that do not return a cursor?

Thanks in advance! Long live the Fox!
 
First of all, thanks for pointing out, that way I don't have to come up with that topic to state that for I'd generally now recommend MariaDB over MySQL.

DO is still a MariaDB command (https://mariadb.com/kb/en/do/) so the detail question just becomes why you can't execute DO 1, specifically with 1. I guess it's an expression Maria DB doesn't consider as valid. Which poses the question why it still can be done by MariaDB, when connecting with a MySQL driver. I actually don't really care and am pragmatic about this and suggest you DO something else, like a variable assignment:

Code:
SQLEXEC(h,'Do @dummy=0')

I would also say you could also stick to DO 1, as it doesn't stop the connection working when an error occurs within MariaDB server, nor does it harm MariaDB server, nor does it actually trigger a VFP error and it also proves the command did arrive and was executed, it just triggers an error.

You already have the confirmation the connection is established by SQLCONNECT or SQLSTRINGCONNECT returning a handle number>0. And to actually see, whether the connection works fine is mainly checking whether the driver works fine with VFP. You'll need to create a test suite that covers receiving all data types you need to handle to cover the aspect of possible problems in data type conversions, which is the most common detail problem of ODBC driver mismatch. Something that goes one step in that direction is what I already suggested in your lengthy thread, even though it requires one work area, temporarily:

Code:
SQLEXEC(h,'Select Now() as servertime','crsServertime'))

With the benefit of enabling to check whether clients cheat with local time setting.

Besides that, you would only need to establish once, whether it works. You seem to be after verifying whether the returned handle number actually works for this session. Well, if it doesn't that will be apparent with any other first query, when this is a permanent recurring issue, it would point out something is quirky with the driver or the network, but it wouldn't also necessarily proof the driver is working nor that it is the culprit, as the reasons and sources of problems in a complex system like a client/server with driver, network and server involvement can mean any component can temporarily fail.
 
Atlopes, our posts crossed. I checked executing nothing or a comment. Most variations of that return -1, just one version works: SQLEXEC(h,'/* */') While, accoring to https://mariadb.com/kb/en/comment-syntax/ comments could also be --, as you suggest, and #.

Besides SELECT Now(), which may not be your cup of tea, dylim, you could make the first thing a verification of database consistency of some level, like checking whether all expected databases and tables exist with execution of SQLEXEC(h,'Show Databases','crsDBs'), SQLTABLES(), and SQLCOLUMNS(). I just would warn to go into the level of all columns, as you'd need to maintain the test with every DB change and you gain more control about data consistency by defining referential integrity and other constraints that the db server maintains and checks, anyway. You could also establish your own version table and verify to be connected to the right database version with a query like SELECT * from dbversion.
 
Last edited:
You're right, Chriss, MariaDB is a bit more restrictive regarding comment syntax and minimal SQL statements, and I should have tested before.

Your proposal

SQL:
/* */

or a more precise -- based comment

SQL:
--

(hard to see, but equivalent to "-- " + 0h0d0a) will check ODBC connectivity with the server without generating a cursor at the client side.
 
Interestingly, an empty comment /**/ also does not work. To get # to work it can't be the first character, you have to precede it with a space, and like -- it only works with a CR LF.

However, I stick to what I said earlier, such empty non queries working doesn't prove the connection is actually allowing to query a database, that you want to prevent a workarea to be used has to come from legacy VFP only providing a few workareas. Whatever, I would personally only consider having a result of any type to be verifying the connection to work. If you'd like to verify the conection without actually returning something, that proves nothing. If you do this to verify you got the connection with the features asked for, like option flag 2^26=67108864 - allows to send multiple statements in one query, you'd even need to allow at least two wokareas to be populated.

I understand you want to verify the connection only, find out whether it's still alive on the server. Look at AUTO_RECONNECT to not worry about that. Specifically right after the SQLSTRINGCONNNECT a check like executing a comment won't tell you anything you don't know already. When you do this as a kind of ping, to assure to the server you're still there and prevent the connection to become idle, look into https://mariadb.com/kb/en/transaction-timeouts/.

idle_transaction_timeout​


 
Last edited:
Dylim,

A simple SQL comment, even an empty string, will do. Both do not return any cursor:

SQL:
--
Hi,

Pardon my ignorance, but how do you execute a comment sir? I tried this first in Workbench, but no response or feedback.

Thanks.
 
Interestingly, an empty comment /**/ also does not work. To get # to work it can't be the first character, you have to precede it with a space, and like -- it only works with a CR LF.

However, I stick to what I said earlier, such empty non queries working doesn't prove the connection is actually allowing to query a database, that you want to prevent a workarea to be used has to come from legacy VFP only providing a few workareas. Whatever, I would personally only consider having a result of any type to be verifying the connection to work. If you'd like to verify the conection without actually returning something, that proves nothing. If you do this to verify you got the connection with the features asked for, like option flag 2^26=67108864 - allows to send multiple statements in one query, you'd even need to allow at least two wokareas to be populated.

I understand you want to verify the connection only, find out whether it's still alive on the server. Look at AUTO_RECONNECT to not worry about that. Specifically right after the SQLSTRINGCONNNECT a check like executing a comment won't tell you anything you don't know already. When you do this as a kind of ping, to assure to the server you're still there and prevent the connection to become idle, look into https://mariadb.com/kb/en/transaction-timeouts/.

Chriss,

For now, I will use your suggestion:

Code:
SQLEXEC(h,'Do @dummy=0')

I get your point regarding having empty non-queries. I just hate the idea of having to programmatically erase/delete the resulting returning cursor each and every time my system queries this.

I use this in a timer event. Although we have AUTO_RECONNECT settings, lots of times the client LAN has faulty physical wired connections.

Thanks!
 
I just hate the idea of having to programmatically erase/delete the resulting returning cursor each and every time my system queries this.
You could have saved a lot of key presses, if you just put USE after the SQLEXEC of SELECT 1. a) SQLEXEC creates a cursor in a new empty workarea and selects it, b) USE closes that.

You assume you check the network connection that way, but when you get no error returned, how do you know the connection is still working correctly? If at all you check the connection unidirectionally only. There will also be no error if that didn't even arrive in MariaDB. So the only way to know the connection is alive is do a full roundtrip, that is getting a result, no matter how simple.
 
Last edited:
Hi,

Pardon my ignorance, but how do you execute a comment sir? I tried this first in Workbench, but no response or feedback.

Thanks.

Dylim,

Just SQLEXEC() it. If there is an active connection with the server, the function will return 1 without generating a cursor. If it returns -1, you'll know the connection is broken and your application must reconnect.

Code:
m.ActiveConnection = SQLEXEC(m.ConnectionHandle, "-- " + 0h0d0a) == 1

IF ! m.ActiveConnection
    * do whatever is needed to reconnect, or die trying
ENDIF

* carry on...
 
but no response or feedback.
Besides atlopes answer on this: Look at my post #4, there I told SQLEXEC(h,'/* */') works.
Also, what feedback do you expect from a comment in Workbench? It is like DO 1 not having any feedback.

I stick to not relying on the returnvalue of a mariadb command that doesn't return a resultset. Sure, if SQLEXEC returns -1 it's proof of a broken connection, but I go as far as claiming a return value of 1 of a call without a result coming back does not confirm the connection, what clearly confirms it working is getting a result from a roundtrip use of the connection. You're completely on the safe side with that, only. I guess the argument for a return value of 1 sufficiently proving a working connection is that there still is some communication between VFP and ODBC driver confirming the command arrived at the server and was executed. But there's absolutely no doubt the connection works, if you have a result coming back, too. The devil always is in the detail, by Murphys's law you might have a situation the server is dead and the ODBC driver still confirms towards VFP an sqlexec worked. You don't have to have any inside knowlegde to see that a roundtrip with a cursor result is proving the connection undoubtedly.
 
Although we have AUTO_RECONNECT settings, lots of times the client LAN has faulty physical wired connections.
Well, and then auto_reconnect chimes in, when necessary and you would only recognize this in a longer than usual SQLEXEC time. If you still have situaions where your timer finds out a broken connection, then the conclusion is you're not using AUTO_RECONNECT correctly.
 
To not argue about AUTO_RECONNECT, lets focus on the no-sideeffect of a general application timer for such things as watching a connection:

Create a form with private datasession, put you timer on it. You're ready to go without side effects on the always existing session id 1 or any other datasession but that private datasession of the form you use for the timer. That form does not need to get shown to hold the timer separate from any influence on any other datasession.

You ma need to adapt code that closes all forms so that timer doesn't get destroyed prematurely, unless that routine is used when closing the application. Otherwise this will not influence the rest of your application code nor their datasessions, workareas, record pointers, index sort orders etc. You could even not care to close the workarea that's used by SQLEXEC within the timer.

Problem solved.
 
By the way, notice every object you create is bound to the current datasession at it's creation. The only and obvious exceptions are a form with private datasession creating a new datasession it itself also lives in and a session class when set to create a priavte datasession (which is the default, as thats the intent of that class).

So let's demonstrate: That also means an object you create without a parent, i.e. you create it with CREATEOBJECT or NEWOBJECT instead of ADDOBJECT, will be in the datasession of whatever code makes these CREATEOBJECT or NEWOBJECT calls. It doesn't set Parent object property nor do objects need to have a datasessionid prpoerty to be part of a datasession, that's standard behavior, nothing you need to program. There's no compliaction in needing to care about this with code that switches to the correct session, the session is an automatic separation from the rest regarding anything about workareas.

So here's a demo of that concept. What you should notice is that Set("Datasession") - which reports the current datasesion id - only depends on what was the session id when the object was created, not what is the current session at time of calling it.

Code:
Clear
? "General code is in session id", Set("Datasession")

oDemoform = CreateObject("privatesessionform") && shows its datasession id and the custom objects (same) session id.
oDemoform.ShowSessionId() && still shows its datasession id, not 1, the session id of the code calling the method.
? "General code still is in session id", Set("Datasession") && to show the general code session still is 1 and has not switched session
goCustom.ShowSessionId() && showing the custom obnject session calling from genral code instead of calling from inside the form, session is still the same as the form
oCustom = CreateObject("mycustom","custom2") && creating a second object from the genreal session 1
oCustom.ShowSessionId()  && will show to be part of session 1
oDemoform.ShowSessionOf(oCustom) && ...also when the form makes that call

Define Class PrivateSessionForm as form
   Datasession = 2 && private datasession
 
   Procedure Init()
      ? this.Name + " is in session id", This.DataSessionId && not every class has that property, though. But every object lives in a datasession
      Public goCustom && for sake of simple demonstration of an object without parent you can access here and in general code.
      goCustom = CreateObject("mycustom","custom1")
      goCustom.ShowSessionId()
   EndProc

   Procedure ShowSessionOf(oObject)
      oObject.ShowSessionId()
   Endproc
    
   Procedure ShowSessionId()
       ? This.Name + " is in session id", Set("Datasession")
   EndProc
EndDefine

Define class MyCustom as Custom
   Procedure Init(cName)
      This.Name = cName
   EndProc
 
   Procedure ShowSessionId()
       ? This.Name + " is in session id", Set("Datasession")
   EndProc
Enddefine

Expected outcome:
1746174753793.png
Notice no matter from where and in which session the call to a ShowSession method is done, the session is always the one that was the session when creating the object. General code is always in session 1, custom1 in the same session as the form (2 or higher, depends on whether you have further private session forms running before running this demo code), custom2 is in session 1, as general code created custom2, that's also the case when the ShowSessionOf(oObject) method of the form calls custom2s ShowSessionId method. So the session is not the session of the caller, but of the creator or that of creation time. What happens, if the form is destroyed and custom1 still is kept existing? Experiment to find out.

What can be concluded from this is that you could even let a private datasession form create a timer as child object of screen or in a goTimer public variable or however you create your timer now, just put that timer creation into the private form code. In init, for example, to keep it simple. The timer does not need to be a child object of the form and any code which addresses the timer object can stay as is, of you have a goTimer variable, that can be kept. If you add it to the _screen, that can stay as is, even if the private form init calls _screen.addobject() and makes the timer an object of the screen It will still be created in the private datasession of the form and not the session of the screen, as the form create the timer object and does that in the form datasession.

And after you change that, the timer can't affect anything in any session. You can even now use a dbf or cursor as a permanent timer workarea that you also can be sure won't be affected by application code unless it closes all workareas of all existing datasessions. But CLOSE DATA ALL, for example, is only acting in one session and will keep timer workareas untouched. So even such extreme code doesn't harm the timer. And so you can keep the SQLEXEC result and don't care about, you can use workareas to add logging of timer events or monitor anything you want in workareas of the timer without effecting any other code and without needing to maintain where which workarea is by what alias name in which session id, you will have your own private session "inherited" by the forms private session. Don't show the form, don't use it for anything so you don't introduce a possible side effect of the timer with what you show in that form, so don't make it part of the application main form, just use a separate private datasession form for creating the timer.

Also: You don't need a form class, you can also make it a scx form with private datasession and call it with DO FORM ... NOSHOW, perhaps LINKED to a variable not going out of scope, so that session is existing all the time and the timer therefore also lives in that separate "world".

In essence: Creating an general purpose application timer from within a private datasession is general advice for a sideeffect free timer. Even when it uses workareas and not only for your SQLEXEC scenario. The only way you may cause side effects from the timer to other datasessions or application code from other datasessions affecting the timer is when you switch sessions in code and are irresponsible with how you do that. So if you would act responsible with anything that intentionally switches data sessions to act on them, too, don't touch the session of the timer, and you're good with that, too.
 
Last edited:
Dylim,

Just SQLEXEC() it. If there is an active connection with the server, the function will return 1 without generating a cursor. If it returns -1, you'll know the connection is broken and your application must reconnect.

Code:
m.ActiveConnection = SQLEXEC(m.ConnectionHandle, "-- " + 0h0d0a) == 1

IF ! m.ActiveConnection
    * do whatever is needed to reconnect, or die trying
ENDIF

* carry on...

Hi Atlopes:

This did not work:

Code:
m.ActiveConnection = SQLEXEC(m.ConnectionHandle, "-- " + 0h0d0a) == 1

But this did: (I had to add a DO):

Code:
m.ActiveConnection = SQLEXEC(m.ConnectionHandle, [DO "--"] == 1

Thank you for being kind.
 
Besides atlopes answer on this: Look at my post #4, there I told SQLEXEC(h,'/* */') works.
Also, what feedback do you expect from a comment in Workbench? It is like DO 1 not having any feedback.

I stick to not relying on the returnvalue of a mariadb command that doesn't return a resultset. Sure, if SQLEXEC returns -1 it's proof of a broken connection, but I go as far as claiming a return value of 1 of a call without a result coming back does not confirm the connection, what clearly confirms it working is getting a result from a roundtrip use of the connection. You're completely on the safe side with that, only. I guess the argument for a return value of 1 sufficiently proving a working connection is that there still is some communication between VFP and ODBC driver confirming the command arrived at the server and was executed. But there's absolutely no doubt the connection works, if you have a result coming back, too. The devil always is in the detail, by Murphys's law you might have a situation the server is dead and the ODBC driver still confirms towards VFP an sqlexec worked. You don't have to have any inside knowlegde to see that a roundtrip with a cursor result is proving the connection undoubtedly.

Chriss,

Look at my post #4, there I told SQLEXEC(h,'/* */') works.

Just to share sir:

Code:
? SQLEXEC(h,'/* */' )    && this worked; there should be a space between the asterisks
? SQLEXEC(h,'/**/' )     && this did not work; if there is no space between the asterisks
? SQLEXEC(h, [DO '/**/'] )     && this worked; even if there is no space between the asterisks
? SQLEXEC(h, [DO '/* */'] )     && this worked; even if there is a space between the asterisks

Thank you for your kindness and generosity of time.
 
By the way, notice every object you create is bound to the current datasession at it's creation. The only and obvious exceptions are a form with private datasession creating a new datasession it itself also lives in and a session class when set to create a priavte datasession (which is the default, as thats the intent of that class).

So let's demonstrate: That also means an object you create without a parent, i.e. you create it with CREATEOBJECT or NEWOBJECT instead of ADDOBJECT, will be in the datasession of whatever code makes these CREATEOBJECT or NEWOBJECT calls. It doesn't set Parent object property nor do objects need to have a datasessionid prpoerty to be part of a datasession, that's standard behavior, nothing you need to program. There's no compliaction in needing to care about this with code that switches to the correct session, the session is an automatic separation from the rest regarding anything about workareas.

So here's a demo of that concept. What you should notice is that Set("Datasession") - which reports the current datasesion id - only depends on what was the session id when the object was created, not what is the current session at time of calling it.

Code:
Clear
? "General code is in session id", Set("Datasession")

oDemoform = CreateObject("privatesessionform") && shows its datasession id and the custom objects (same) session id.
oDemoform.ShowSessionId() && still shows its datasession id, not 1, the session id of the code calling the method.
? "General code still is in session id", Set("Datasession") && to show the general code session still is 1 and has not switched session
goCustom.ShowSessionId() && showing the custom obnject session calling from genral code instead of calling from inside the form, session is still the same as the form
oCustom = CreateObject("mycustom","custom2") && creating a second object from the genreal session 1
oCustom.ShowSessionId()  && will show to be part of session 1
oDemoform.ShowSessionOf(oCustom) && ...also when the form makes that call

Define Class PrivateSessionForm as form
   Datasession = 2 && private datasession
 
   Procedure Init()
      ? this.Name + " is in session id", This.DataSessionId && not every class has that property, though. But every object lives in a datasession
      Public goCustom && for sake of simple demonstration of an object without parent you can access here and in general code.
      goCustom = CreateObject("mycustom","custom1")
      goCustom.ShowSessionId()
   EndProc

   Procedure ShowSessionOf(oObject)
      oObject.ShowSessionId()
   Endproc
   
   Procedure ShowSessionId()
       ? This.Name + " is in session id", Set("Datasession")
   EndProc
EndDefine

Define class MyCustom as Custom
   Procedure Init(cName)
      This.Name = cName
   EndProc
 
   Procedure ShowSessionId()
       ? This.Name + " is in session id", Set("Datasession")
   EndProc
Enddefine

Expected outcome:
View attachment 2153
Notice no matter from where and in which session the call to a ShowSession method is done, the session is always the one that was the session when creating the object. General code is always in session 1, custom1 in the same session as the form (2 or higher, depends on whether you have further private session forms running before running this demo code), custom2 is in session 1, as general code created custom2, that's also the case when the ShowSessionOf(oObject) method of the form calls custom2s ShowSessionId method. So the session is not the session of the caller, but of the creator or that of creation time. What happens, if the form is destroyed and custom1 still is kept existing? Experiment to find out.

What can be concluded from this is that you could even let a private datasession form create a timer as child object of screen or in a goTimer public variable or however you create your timer now, just put that timer creation into the private form code. In init, for example, to keep it simple. The timer does not need to be a child object of the form and any code which addresses the timer object can stay as is, of you have a goTimer variable, that can be kept. If you add it to the _screen, that can stay as is, even if the private form init calls _screen.addobject() and makes the timer an object of the screen It will still be created in the private datasession of the form and not the session of the screen, as the form create the timer object and does that in the form datasession.

And after you change that, the timer can't affect anything in any session. You can even now use a dbf or cursor as a permanent timer workarea that you also can be sure won't be affected by application code unless it closes all workareas of all existing datasessions. But CLOSE DATA ALL, for example, is only acting in one session and will keep timer workareas untouched. So even such extreme code doesn't harm the timer. And so you can keep the SQLEXEC result and don't care about, you can use workareas to add logging of timer events or monitor anything you want in workareas of the timer without effecting any other code and without needing to maintain where which workarea is by what alias name in which session id, you will have your own private session "inherited" by the forms private session. Don't show the form, don't use it for anything so you don't introduce a possible side effect of the timer with what you show in that form, so don't make it part of the application main form, just use a separate private datasession form for creating the timer.

Also: You don't need a form class, you can also make it a scx form with private datasession and call it with DO FORM ... NOSHOW, perhaps LINKED to a variable not going out of scope, so that session is existing all the time and the timer therefore also lives in that separate "world".

In essence: Creating an general purpose application timer from within a private datasession is general advice for a sideeffect free timer. Even when it uses workareas and not only for your SQLEXEC scenario. The only way you may cause side effects from the timer to other datasessions or application code from other datasessions affecting the timer is when you switch sessions in code and are irresponsible with how you do that. So if you would act responsible with anything that intentionally switches data sessions to act on them, too, don't touch the session of the timer, and you're good with that, too.

Hi Chriss,

Thank you for your intricate example.

Would the following be "sound design"?

All my apps have a global variable oApplication, an object variable from my Application class, which has object references to my Security an Connection manager classes, among others.

My data entry form classes are obviously designated as Private Data Session. Upon firing, one of the things they check is if the "global connection" is still alive, housed in a timer control, like so:

oApplication.oConnectionMgr.Connected() which returns .T. or .F., and has the following code:

Code:
LOCAL llResult

llResult = ( oApplication.oConnectionMgr.DataSource > 0 ) AND ( SQLEXEC( oApplication.oConnectionMgr.DataSource, [DO "/**/"] ) > 0 )

RETURN llResult

If I disconnect the LAN cable, it will report that it is indeed disconnected. If I put it back, it will report that it is once again connected.

If I stop MariaDB service, it will report the disconnection. If I start it back again, it will still report it as disconnected. I need to call oApplication to connect again with the server.
 
? SQLEXEC(h, [DO '/**/'] ) && this worked; even if there is no space between the asterisks
Interesting, but unimportant.

The current recommendation that's on the table for negotiating about it is making your sql connection verification timer side effect free by putting it into a private datasession. Which would make even SELECT NOW() being no hassle and having a connection verification that's undoubtedly proving the connection works by bringing back data. I'd prefer this.

It's your decision, in the end, when you prefer executing a comment, now, then do so.

If you want to discuss better ways of verifying and repairing a connection to MariaDB with setting timouts to infinity and auto_reconnect, we should continue that discussion in a new thread, as that's only related to DO 1 in that you used DO 1 as a connection verification, but the question was about what can be done in MariaDB, which does not error and does not return a result. Both of which are unimportant, actually, as a command that errors does not break or harm the connection and you can isolate a timer to work in a private datasession.
 
Last edited:
Interesting, but unimportant.

The current recommendation that's on the table for negotiating about it is making your sql connection verification timer side effect freer by putting it into a private datasession. Which would make even SELECT NOW() being no hassle and having a connection verification that's undoubtedly proving the connection works by bringing back data. I'd prefer this.

It's your decision, in the end, when you prefer executing a comment, now, then do so.

If you want to discuss better ways of verifying and repairing a connection to MariaDB with setting timouts to infinity and aut_reconnect, we should continue that discussion in a new thread, as that's only related to DO 1 in that you used DO 1 as a connection verification, but the question was about what can be done in MariaDB, which does not error and does not return a result. Both of which are unimportant, actually, as a command that errors does not break or harm the connection and you can isolate a timer to work in a private datasession.

Will you be shifting to MariaDB as well? Or have you already for a long time?

As for me, I am trying out all features and functionalities on a project I am working on on a test laptop with Windows 11, MariaDB 11.7.2 and ODBC 3.2.5.

So far, so good. It is basically more seamless, hassle free and way faster.

Am so glad I ran into MariaDB.
 
Will you be shifting to MariaDB as well? Or have you already for a long time?
For my private usage, I have unknowingly for a long time. And didn't ever bump into these intricate differences in DO or comments, as that's not in my usage.
For commercial projects I did not maintain anything with MySQL for a long time. Latest customers with a backend server choose MSSQL over anything else. Old customer will likely not have upgrade MySQL Server. I remember one customer actually did use a rather old MySQL server version and I recommended upgrading, which they still didn't do. Maybe because they already found trouble working with the MySQL Workbench and MySQL 8 Server, I never heard back about that. But the problems with ODBC are not new.

I do consider using MariaDB. I am not so sure about it generally being faster in comparsion with current MySQL versions. Googling MySQL vs MariaDB differences you find that assertion. I can only guess Oracle won't care for this, as they would like their customers to move towards Oracle databases anyway. Problem for us is you can't compare without having a way to connect and use more modern MySQL Oracle versions with a new driver. According to version history information on https://dev.mysql.com/doc/connector-odbc/en/connector-odbc-support-version-history.html 8.0.35 is the last 32bit driver that added new features into the ODBC driver necessary to use new features in the server, further versions only contain bug fixes. That's still in progeress, the 8.0.42 version is from April 15th, this year 2025, but it's only bugfixes.

As VFP is having trouble with this driver series also up to version 35 as far as I remeber this series still being extended is still not getting you into anything MySQL would hae to offer in 64bitness. The most srtking thing is that I guess this means no usage of MySQL 9.

By the way, this doesn't mean you're only able to use 32bit servers, even if using a locally installed server for a single user MySQL driven application with VFP frontend a 32bit driver allows connecting to a 64bit server. And the same is true for MariaDB, you already will know this. Also, new features in a server, like new functions and commands of the SQL dialefct don't necessarily require an ODBC driver to know them, he's just a messenger between client and server, the server side database engine executes the SQL, so that's also not necessarily a reason to not use this, but what's still happening is that there's no upgrade, whenever necessary.

You could likely get further with MySQL usinag VFPA 64bit and overcoming that aspect of it, enabling to use 9.x drivers. Not sure VFPA has advanced it's runtime general ODBC capabilities. When it comes to SQLEXEC, it's not a direct step from VFP to the ODBC driver, the basis is still how VFP communicates with an ODBC driver and that can break with newer versions of ODBC itself, also within the 64bitness of VFPA.

So far MariaDB is more legacy friendly and I don't see anything that would change that. It doesn't cost to build for both 64bit and 32bit Windows. I don't know the reason Oracle cuts that off, my guess is they want to encourage developers to go fully into the 64bitness and not caring for the MariaDB competition regarding performance likely is because they care much more for their flagship Oracle database.
 

Part and Inventory Search

Sponsor

Back
Top