Written by

Question JASON PARKER · Oct 14, 2023

Delphi 11 Front end to Cache Database

Hi,

Any examples please of connection a Delphi 11 Front end to a Cache database?

I can get it to connect but then when I try and view data it fails

 

4 fields in front end

SERVER = 127.0.0.1

PORT = 1972

NAMESPACE = DROP DOWN LIST (I SELECT "DEVELOP" FROM THE LIST

EDIT_CLASSNAME = Default value is Test (with maybe 3 fields just of random stuff)

 

 

procedure TFMAIN.BtnConnectClick(Sender: TObject);
 var
 ConnectString: string;
 Success: Boolean;
 Col,Row:Integer;
 FieldName:array[0..10] of string;
begin

    IF NAMESPACE.TEXT<='' THEN
     BEGIN
      SHOWMESSAGE('Please select a Namespace from the drop down list');
      NAMESPACE.SETFOCUS;
      EXIT;
     END;
    //Create instance of the TFactory object
    Factory :=  TFactory.Create(nil);
    //Establish connection with the server if there is no connection
    if not Factory.IsConnected then
     BEGIN
      {
       You can explicitly specify the connection string:
       cn_iptcp - connection protocol
       127.0.0.1 - Ip or sever name(Local Server)
       [1972]      - Port number
       DEVELOP     - Namespace
      }

      //ConnectString := 'cn_iptcp:127.0.0.1[1972]:DEVELOP';
      //ConnectString := 'cn_iptcp:127.0.0.1[1972]:DEVELOP:User:Pass';
      ConnectString := 'cn_iptcp:'+SERVER.TEXT+'['+PORT.TEXT+']:'+NAMESPACE.TEXT;
      Success := Factory.Connect1(ConnectString);
     END;

    if not Success then
     begin
      ShowMessage('Could not connect!');
      //Close the application if the connection fail.
      //Application.Terminate;
      BtnOpenObject.Enabled:=FALSE;
      EXIT;
     end;

    outputMemo.Text := 'Connected to '+ConnectString;
    BtnOpenObject.Enabled:=TRUE;
end;

 

;-------------------------------------------------------------------------------------------------------------

 

procedure TFMAIN.BtnOpenObjectClick(Sender: TObject);
var
 sql:String;
begin
 tmp:=EDIT_CLASSNAME.TEXT;  //Angio.Episode1
 IF tmp<='' THEN
  BEGIN
   SHOWMESSAGE('Enter an Object name');
   EDIT_CLASSNAME.SETFOCUS;
   EXIT;
  END;

 sql:='SELECT * FROM '+tmp;

TRY
 //SQLQuery1.DatabaseName:='CacheDelphi';
 //SQLCONNECTION1.ConnectionName:='CacheDelphi';

 //-------------------------------------------------
 //driver names can be found here
 //C:\Windows\System32\odbcad32.exe
    //InterSystems IRIS ODBC35
    //InterSystems ODBC
    //InterSystems ODBS35
    //MySQL ODBC 8.0 ANSI Driver
    //MySQL ODBC 8.0 Unicode Driver
    //ODBS Driver 17for SQL Server
    //SQL Server
    //SQL Server Native Client 11.0
 //-------------------------------------------------

 SQLCONNECTION1.DriverName:='InterSystems ODBS35';   //DEVELOP

 //SQLConnection1.Params.Values['Database'] := 'CacheDelphi';
 //SQLConnection1.Params.Values['HostName'] := NAMESPACE.TEXT;   //DEVELOP
 SQLConnection1.Params.Values['User_Name'] := '_SYSTEM';
 //SQLConnection1.Params.Values['Password'] := '';

 SQLQuery1.CLOSE;
 SQLQuery1.SQL.CLEAR;
 SQLQuery1.SQL.ADD(sql);
 SQLQuery1.OPEN;
  except
    on E: Exception do
      outputMemo.Text := 'ERROR: ' + E.Message;
  end;
  // Show the results of the query in a TMemo control.
  ShowSelectResults();

end;

 

;-------------------------------------------------------------------------------------------------------------

 

//show results in memo
procedure TFMAIN.ShowSelectResults();
var
  names: TStringList;
  i: Integer;
  currentField: TField;
  currentLine: string;
begin
  if not SQLQuery1.IsEmpty then
  begin
    SQLQuery1.First;
    names := TStringList.Create;
    try
      SQLQuery1.GetFieldNames(names);
      while not SQLQuery1.Eof do
      begin
        currentLine := '';
        for i := 0 to names.Count - 1 do
        begin
          currentField := SQLQuery1.FieldByName(names[i]);
          currentLine := currentLine + ' ' + currentField.AsString;
        end;
        outputMemo.Lines.Add(currentLine);
        SQLQuery1.Next;
      end;
    finally
      names.Free;
    end;
  end;
end;
 

 

 

 

 

 

 

Jason

Comments

DC AI Bot · May 26 Bot

You appear to be mixing two different access methods in the same Delphi form:

  • TFactory.Connect1() is one connection mechanism using a connection string like cn_iptcp:127.0.0.1:DEVELOP. [2]
  • SQLConnection1 / SQLQuery1 is a separate ODBC-based mechanism, where the driver must be configured and used correctly. [2]

Because your code connects with Factory.Connect1() but then runs SQLQuery1.OPEN through SQLConnection1, the successful Factory connection does not by itself make the SQL query work. [2]

A few points from your code stand out:

  1. Your query is built as:

    sql := 'SELECT * FROM ' + tmp;
    

    so EDIT_CLASSNAME must contain something SQL can query as a table/class name. In your own example you mention values like Test or Angio.Episode1; the code is expecting that string to be directly usable in SELECT * FROM .... [2]

  2. For the SQL part, you set only:

    SQLConnection1.DriverName := 'InterSystems ODBS35';
    SQLConnection1.Params.Values['User_Name'] := '_SYSTEM';
    

    but the shown code does not show the rest of the ODBC connection details being set before SQLQuery1.OPEN. The commented lines also suggest uncertainty about DatabaseName, ConnectionName, and HostName. [2]

  3. Your own driver list comment shows possible driver names including:

    • InterSystems IRIS ODBC35
    • InterSystems ODBC
    • InterSystems ODBS35 [2]

So the likely issue in the code shown is not the initial socket-style connection, but the incomplete or incorrect ODBC setup used by SQLConnection1 when you actually fetch data. [2]

Also, there is a related example from another discussion that suggests using SQL directly for external language access, for example:

insert into JASON.BikeDB (Make, Model) values (:make, :model)

and, if calling a class method instead, marking it with SqlProc and calling it as a stored procedure. [3]

This supports the idea that for a Delphi front end, SQL/stored procedure access is the simpler path than trying to mix object access and ODBC access in one flow. [3]

If you continue with ODBC-based access, there is an example showing the standard sequence for SQL access: open a connection, prepare a query, execute it, then fetch the result set. [4][5][6]

Important:

This article is intended only for developers who need to maintain existing legacy code.  When developing new code to access the ODBC SQL Gateway programmatically, InterSystems strongly recommends use of the XDBC Gateway, which provides a much simpler and more maintainable way to accomplish the same tasks. [4][5][6]

Note:

This article assumes that you have significant experience using ODBC API calls — it is not intended to provide details on how to use ODBC functions. If you encounter any problems, you can monitor the SQL Gateway by enabling logging for both InterSystems IRIS and ODBC (see the "Logging and Environment Variables" chapter in Using the InterSystems ODBC Driver). [4][5][6]

Based on the code you posted, the safest conclusion is:

  • your Factory.Connect1() success only proves that one connection path works; [2]
  • your data retrieval is failing in the separate ODBC path; [2]
  • you should use one access method consistently, and if using SQLConnection1 then fully configure that ODBC connection before SQLQuery1.OPEN. [2]

If you want, post the exact exception text from:

outputMemo.Text := 'ERROR: ' + E.Message;

because that message is what will identify whether the failure is driver selection, login, namespace/database selection, or invalid SQL/class name. [2]


Sources:

Tell us more:
Don't like the style
Not factually correct
Didn't fully follow instructions
Refused when it shouldn't have
Being lazy
More...
Submit
0 0