1. Jostein Ullestad
  2. PowerBuilder
  3. Tuesday, 10 December 2024 14:51 PM UTC

Hi

We face an issue related to ADO database connection and are seeking help resolving it.

PowerBuilder: 2022 R3 Build 3391

Visual Studio: 2022

DBMS: Microsoft Azure

 

In short, the issue is that any SQL command fails with SQLCode -1 and no SQL error text.

A datastore retrieve terminates the application.

  1. We tried OLE and SQL connections, with the same result.
  2. We also tried using the PowerBuilder "MSOLEDBSQL SQL Server" connection to the same database, which works.
  3. We tried the DLL from a C# console application, which works.
  4. We ran the SQL commands below to check the connection and get the last SQL that was executed.
    1. We can see that all the database connections are alive.
    2. We can only see the SQL performed using the PowerBuilder connection.
    3. Any SQL command performed by PowerBuilder using ADO is not listed.

 

select max (spid) from sys.sysprocesses
WHERE DB_NAME(dbid) = '****'
AND loginame <> 'sa'
AND Trim (hostname) = '******'
AND Trim (program_name) <> 'azdata';

SELECT deqs.last_execution_time AS [Time], dest.text AS [Query]
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest
ORDER BY deqs.last_execution_time DESC;

 


Here is the PowerBuilder code. Based upon the “template application” with MDI.

On the main window, we have:

Instance Variables

CONSTANT long TEST_TYPE_OLE = 1
CONSTANT long TEST_TYPE_SQL = 2
CONSTANT long TEST_TYPE_PB  = 3
CONSTANT String PATH = "C:\Temp\PowerBuilder.ADO.NET\net8.0\publish\"

// **** to be replaced with real values
CONSTANT String is_Password = "*****"
CONSTANT String is_ServerName = "******.database.windows.net,1433"
CONSTANT String is_Database = "Database='****'"
CONSTANT String is_LogId = "*****"

 

A command button with this clicked event code:

wf_testado (TEST_TYPE_OLE)
wf_testado (TEST_TYPE_SQL)
wf_testado (TEST_TYPE_PB)

 

Windows function: integer wf_testado (long al_testtype)

DotNetAssembly lcs_ass
DotNetObject   lcs_obj
long           ll_return
boolean        lb_return
Long           ll_version
String         ls_Name
Transaction    lu_Trans
datastore      lds

ChangeDirectory (PATH)

lu_Trans = CREATE Transaction

IF al_TestType <> TEST_TYPE_PB THEN
   lcs_ass = Create DotNetAssembly
   lcs_obj = Create DotNetObject

   //Load the .NET assembly
   ll_return = lcs_ass.LoadWithDotNet(PATH + "SafranAdoDatabaseConnection.dll")
   if ll_return < 0 then
       messagebox("The DLL Load Failed " + String (ll_return), lcs_ass.errortext)
       return -1
   end if

   ll_return = lcs_ass.createinstance ("SafranAdoDatabaseConnection.AdoConnection", lcs_obj)
   if ll_return < 0 then
       messagebox("The Create Instance failed " + string (ll_return),lcs_ass.errortext)
       return -1;
   end if
END IF

CHOOSE CASE al_TestType
CASE TEST_TYPE_SQL
   // --------------------------------------------------------------------------------
   // ADO Connection, SQL connection
   // --------------------------------------------------------------------------------
   lu_Trans.DBMS = "ADO.NET"
   lu_Trans.LogPass = is_Password
   lu_Trans.LogId = is_LogId
   lu_Trans.AutoCommit = False
   lu_Trans.ServerName = "tcp:" + is_ServerName
   lu_Trans.Database = is_Database
   lu_Trans.DBParm = "Provider='MSOLEDBSQL19';DataSource=tcp:" + is_ServerName +";"+is_Database+";Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"

   DISCONNECT USING lu_Trans;

   //Get the C# database connection information
   lb_return = lu_Trans.SetAdoConnection(lcs_obj.AdoConnectionProxySQL)

CASE TEST_TYPE_OLE
   // --------------------------------------------------------------------------------
   // ADO Connection, OLE connection
   // --------------------------------------------------------------------------------
   lu_Trans.DBMS = "ADO.NET"
   lu_Trans.LogPass = is_Password
   lu_Trans.LogId = is_LogId
   lu_Trans.AutoCommit = False
   lu_Trans.ServerName = "tcp:" + is_ServerName
   lu_Trans.Database = is_Database
   lu_Trans.DBParm = "Provider='MSOLEDBSQL19',DataSource='"+is_ServerName+"',"+is_Database+";"

   DISCONNECT USING lu_Trans;

   //Get the C# database connection information
   lb_return = lu_Trans.SetAdoConnection(lcs_obj.AdoConnectionProxyOLE)

CASE TEST_TYPE_PB
   // --------------------------------------------------------------------------------
   // Direct none ADO connection
   // --------------------------------------------------------------------------------
   lu_Trans.DBMS = "MSOLEDBSQL SQL Server"
   lu_Trans.LogPass = is_Password
   lu_Trans.LogId = is_LogId
   lu_Trans.AutoCommit = False
   lu_Trans.ServerName = "tcp:" + is_ServerName
   lu_Trans.DBParm = ""+is_Database+",Provider='MSOLEDBSQL19'"

   DISCONNECT USING lu_Trans;

   lb_return = TRUE
END CHOOSE

IF lb_return THEN
    CONNECT USING lu_Trans;
    IF lu_Trans.sqlcode <> 0 THEN
      messagebox("Error",lu_Trans.sqlerrtext)
    END IF

   //Use the C# connection to execute ESQL in
   SELECT TOP 1 1 into :ll_version FROM sys.objects USING lu_trans;
   ls_name = String (ll_version)

   IF lu_Trans.SQLCode = 0 THEN
      MessageBox("name", ls_name)
   ELSE
      MessageBox("Error, Test type " + String (al_TestType), lu_Trans.SQLErrText + "~r~nSQLDBCode:" + String (lu_Trans.SQLDBCode) + "~r~nSQLCode:" + String (lu_Trans.SQLCode))
   END IF

   DISCONNECT USING lu_Trans;
ELSE
   MessageBox ("Error, Test type " + String (al_TestType), "Could not SetAdoConnection")
END IF

DISCONNECT USING lu_Trans;
DESTROY lu_Trans

Return 1

Our C# code, compiled using .NET 8.0

Configuration = Release | x64

Target framework = net8.0-windows7.0

Deployment mode = Self-contained

Target runtime = Win.x64

 

using Appeon.DB.Sharing;
using Microsoft.Identity.Client;
using System.Data.OleDb;
using System.Data.SqlClient;

namespace SafranAdoDatabaseConnection
{
    public class AdoConnection
    {
        public IAdoConnectionProxy AdoConnectionProxySQL { get; set; }
        public IAdoConnectionProxy AdoConnectionProxyOLE { get; set; }

        private readonly string ClientId = "*********";
        private readonly string ClientSecret = "*******";
        private readonly string TenantId = "******";
        private readonly string[] Scopes = new[] { "https://database.windows.net/.default" };
        private readonly string ConnectionStringOLE = "Provider=MSOLEDBSQL19;Data Source=tcp:******.database.windows.net,1433;Initial Catalog=*****;";
        private readonly string ConnectionStringSQL = "Server=tcp:*****.database.windows.net,1433;Initial Catalog=****;Persist Security Info=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";

        public AdoConnection ()
        {
            var task = GetAccessToken ();
            string accesstoken = task.GetAwaiter ().GetResult ();

            SetupSQL (accesstoken);
            SetupOLE (accesstoken);
        }

        // called from a console application, to test the connection
        public void TestSQL ()
        {
            SqlConnection connection = (SqlConnection)AdoConnectionProxySQL.Connection;
            string query = "SELECT TOP 1 * FROM networks"; // Just to test if we can get some data
            using (SqlCommand command = new SqlCommand (query, connection))
            {
                using (SqlDataReader reader = command.ExecuteReader ())
                {
                    while (reader.Read ())
                    {
                        // Replace with actual column index or column name
                        Console.WriteLine ("Project name: " + reader["name"].ToString ());
                    }
                }
            }
        }

        // called from a console application, to test the connection
        public void TestOLE ()
        {
            OleDbConnection connection = (OleDbConnection)AdoConnectionProxyOLE.Connection;
            string query = "SELECT TOP 1 * FROM networks"; // Just to test if we can get some data
            using (OleDbCommand command = new OleDbCommand (query, connection))
            {
                using (OleDbDataReader reader = command.ExecuteReader ())
                {
                    while (reader.Read ())
                    {
                        // Replace with actual column index or column name
                        Console.WriteLine ("Project name: " + reader["name"].ToString ());
                    }
                }
            }
        }

        private void SetupOLE (string accessToken)
        {
            // First get the access token
            string oleConnectionString = ConnectionStringOLE;
            oleConnectionString += $"Access Token={accessToken};";
            OleDbConnection connection = new (oleConnectionString);
            connection.Open ();
            AdoConnectionProxyOLE = new AdoConnectionProxy
            {
                Connection = connection
            };
        }

        private void SetupSQL (string accessToken)
        {
            string connectionString = ConnectionStringSQL;
            SqlConnection connection = new (connectionString);
            connection.AccessToken = accessToken;
            connection.Open ();
            AdoConnectionProxySQL = new AdoConnectionProxy
            {
                Connection = connection
            };
        }

        ///
        /// Gets the access token
        ///
        ///
        private async Task GetAccessToken ()
        {
            var app = ConfidentialClientApplicationBuilder.Create(ClientId)
                .WithClientSecret(ClientSecret)
                .WithAuthority(new Uri($"https://login.microsoftonline.com/{TenantId}"))
                .Build();
            var result = await app.AcquireTokenForClient(Scopes).ExecuteAsync();
            var accessToken = result.AccessToken;
            return accessToken;
        }
    }
}

 

Armeen Mazda @Appeon Accepted Answer Pending Moderation
  1. Thursday, 12 December 2024 19:35 PM UTC
  2. PowerBuilder
  3. # 1

You mentioned the MSOLEDBSQL works correctly. Why not just use that?

Are you aware this is the recommended driver to migrate to for PB client/server apps?

Comment
  1. Jostein Ullestad
  2. Friday, 13 December 2024 06:55 AM UTC
Thank you, Mazda



That driver merely points out that the PowerBuilder code could access the server. This connection uses a user/password connection our client will not accept.



They are requesting an access token setup. I am aware that others have got this working and we are looking for samples and help, as I am unable to spot why our code is not working. Also, the ADO connection works from the C# code application. I have also tried creating a usr/pwd connection (in case the access token was the issue) in c# and providing that to PowerBuilder through ADO.NET, but it also fails. For me, the SQL command does not seem to reach the server.



I am starting to wonder if the C# code and DLL are not compiled correctly, but as the initial code and setup seem to work I am unsure where to look.



Please notice that I previously attempted to use an access token within the connection string, but limitations in PowerBuilder prevented this, so we were recommended the ADO approach.

https://community.appeon.com/index.php/qna/q-a/connecting-to-msoledbsql-using-access-token-issue-with-the-dbparm-length.



Rgs

Jostein

  1. Helpful
  1. Armeen Mazda @Appeon
  2. Friday, 13 December 2024 14:02 PM UTC
Oh, I missed that point. I'm not sure if the DB connection in PB supports using tokens instead of username/password to connect to database. I would suggest opening a support ticket so the product engineering team confirms whether this scenario supported or not. https://www.appeon.com/standardsupport/newbug
  1. Helpful
  1. Jostein Ullestad
  2. Friday, 13 December 2024 14:47 PM UTC
Thank you.



I do hope that is supported, as it was recommended. However, I have now also tried connecting to MS SQL server using usr/pwd. It also fails.

Will open a support ticket. also, we could try the "Premium Support Single Ticket", as we simply need to resolve it.



Rgs

Jostein

  1. Helpful
There are no comments made yet.
Jostein Ullestad Accepted Answer Pending Moderation
  1. Wednesday, 11 December 2024 09:58 AM UTC
  2. PowerBuilder
  3. # 2

Thank you Andreas

 

The code is, I removed the ' at the end only in the code above when I replaced the real string with *

In reality the code is correct.


CONSTANT String is_Database = "Database='****'"
Comment
There are no comments made yet.
Andreas Mykonios Accepted Answer Pending Moderation
  1. Wednesday, 11 December 2024 09:52 AM UTC
  2. PowerBuilder
  3. # 3

Hi.

Just to check. is_Database is defined as:

CONSTANT String is_Database = "Database='****"

// or

CONSTANT String is_Database = "Database='****'"

Andreas.

Comment
There are no comments made yet.
Jostein Ullestad Accepted Answer Pending Moderation
  1. Wednesday, 11 December 2024 06:49 AM UTC
  2. PowerBuilder
  3. # 4

Hi Chris

 

That was merely to point out that PowerBuilder code could access the server. This connection uses a user/password connection that our client will not accept.

They are requesting an access token setup. I am aware that others have got this working and we are looking for samples and help, as I am unable to spot why our code is not working. Also, the ADO connection works from the C# code application as well.

 

Rgs

Jostein

 

Comment
  1. Jostein Ullestad
  2. Thursday, 12 December 2024 08:45 AM UTC
Thank you Chris



It seems the SQL is not reaching the server, as I am using this SQL on the server to check for any SQL command:



SELECT deqs.last_execution_time AS [Time], dest.text AS [Query]

FROM sys.dm_exec_query_stats AS deqs

CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest

ORDER BY deqs.last_execution_time DESC;



I have since updated my test c# to avoid using the access token and simply usr/pwd, which also failed when used in PowerBuilder.



Rgs

Jostein

  1. Helpful
  1. Chris Pollach @Appeon
  2. Thursday, 12 December 2024 15:29 PM UTC
Hi Jostein;

Bummer!

If you have a simple PB Test Case App that replicates this OLEDB issue, please open a Support Ticket for this problem.

Regards .. Chris
  1. Helpful
  1. Jostein Ullestad
  2. Friday, 13 December 2024 14:47 PM UTC
Thank you Chris



I will open a support ticket, with the source code I have prepared.



Rgs

Jostein

  1. Helpful
There are no comments made yet.
Chris Pollach @Appeon Accepted Answer Pending Moderation
  1. Tuesday, 10 December 2024 16:06 PM UTC
  2. PowerBuilder
  3. # 5

Hi Jostein;

  =>  From your #2 .... "We also tried using the PowerBuilder "MSOLEDBSQL SQL Server" connection to the same database, which works".

Then, why not use that DB Client?

Regards .. Chris

 

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.