3

I have a need to connect to a data source on an old unix box via ODBC, but I don't seem to be getting far and I can't find any examples to help me.

I have started with https://docs.joomla.org/Connecting_to_an_external_database and set up the following details:

$option['driver'] = 'pdo';            // Database driver name
$option['host'] = 'nnn.nnn.nnn.nnn:nnnn';    // Database host name
$options['dsn'] = 'Fred';
$option['user'] = 'Barney';       // User for database authentication
$option['password'] = 'Wilma';   // Password for database authentication
$option['database'] = 'dbname';      // Database name
$option['prefix'] = '';             // Database prefix (may be empty)

$dbx = JDatabaseDriver::getInstance($option);

With that configuration, I get an error message of:

Cannot instantiate abstract class JDatabaseDriverPdo
E:\www\bedrock\libraries\joomla\database\driver.php:313

This happens because driver.php takes the value 'pdo' from $option['driver'] = 'pdo'; and appends it to a class of JDatabaseDriver to be found in \libraries\database\driver\pdo.php which is an abstract class the extends JDatabaseDriver hence the message. It is the only abstract class in /driver. If I replace 'pdo' with 'odbc', I get a message to say it can't load the database driver which will be because the class JDatabaseDriverOdbc is not found.

When I look at \libraries\database\driver\pdo.php, I can see that 'odbc' is the default if no other driver is specified and further down I can see the connection string set up for 'odbc' so it looks like it is supported.

public function __construct($options)
{
    // Get some basic values from the options.
    $options['driver'] = (isset($options['driver'])) ? $options['driver'] : 'odbc';
    $options['dsn'] = (isset($options['dsn'])) ? $options['dsn'] : '';
    $options['host'] = (isset($options['host'])) ? $options['host'] : 'localhost';
    ...
    // Find the correct PDO DSN Format to use:
    switch ($this->options['driver'])
    {
    ..
    case 'odbc':
    $format = 'odbc:DSN=#DSN#;UID:#USER#;PWD=#PASSWORD#';
    $replace = array('#DSN#', '#USER#', '#PASSWORD#');
    $with = array($this->options['dsn'], $this->options['user'], $this->options['password']);

It seems to me that $option['driver'] = has two different uses depending on where it is used, as either a suffix to build a class name or as a switch to set the connection string.

I have also tried to use the class directly with

`$option['driver'] = 'odbc';
...
$dbx = JDatabaseDriverPdo::getInstance($option);

however that still tries to find a class of JDatabaseDriverOdbc from driver.php

I really could use some pointers in the right direction or an example of ODBC in use.

Some hours later...

Looking at the code in driver.php and some of the data base formats in \libraries\database\driver\ it would appear I need to create a new class that extends JDatabaseDriverPdo, eg. class JDatabaseDriverOdbc extends JDatabaseDriverPdo and make that available to my code. So I think the Joomla answer is yes you can do it if you write your own connector.

6
  • This is straying away from my scope of knowledge, but can you confirm that your Unix box has this driver installed? Test ODBC entry on Unix and How to set up and test the ODBC driver on Unix? Jul 2, 2020 at 4:18
  • 2
    @mickmackusa I spend most of my day outside my scope of knowledge.:) I can make a connection through a window based client so no problems there. For this issue I am not even getting to the stage of making a connection, I am still stuck in the way Joomla is trying to set up the code for the drivers so purely a Joomla code issue as far as I can determine. There is a lack of documentation or at least examples on how a PDO connection is supposed to work
    – Irata
    Jul 2, 2020 at 4:53
  • Here is a throw away comment that I'll likely delete... instead of $option['driver'] = 'odbc' can you try $option['driver'] = null;? This will fail all isset() checks that the core will run. I am at work at the moment and cannot go digging through the core code now. Jul 2, 2020 at 4:56
  • 1
    @mickmackusa came back with this Cannot instantiate abstract class JDatabaseDriver in \libraries\joomla\database\driver.php:313
    – Irata
    Jul 2, 2020 at 6:25
  • If anyone is curious about what a good, upvoteworthy JSE question looks like -- this is one. It is unique to the site, it is clear about the expected result, the issue is boiled down / reasonably isolated, it shows toil/research, and it includes relevant disgnostic details. This question is pretty near perfect. Jul 2, 2020 at 6:47

1 Answer 1

1

Although I have had to put this work aside for the time being I wanted to provide some closure to this question.

The last part of my original post is approximately what was required, I had to create a /joomla/database/odbc.php which I created from copying from one of the existing drivers and change the relevant references to 'odbc', and that extended the JDatabaseDriverPdo class.

That got me past the error message in the original Question but then I hit a problem with the next line, $query = $dbx->getQuery(true);due to either an error in the core code or my lack of understanding but it is worth mentioning here if anyone else finds this post.

The getQuery command calls this piece of code in /joomla/database/driver.php

public function getQuery($new = false)
    {
        if ($new)
        {
            // Derive the class name from the driver.
            $class = 'JDatabaseQuery' . ucfirst($this->name);

            // Make sure we have a query class for this driver.
            if (!class_exists($class))
            {
                // If it doesn't exist we are at an impasse so throw an exception.
                throw new JDatabaseExceptionUnsupported('Database Query Class not found.');
            }

            return new $class($this);
        }
        else
        {
            return $this->sql;
        }
    }

However $this->name which creates the $class is not picking up the value set in the JDatabaseDriverXxxx for $this-name therefore it always falls out the bottom returning a value of mysqli.

My resolution was to copy this function into my joomla/database/odbc.php so that it would receive the correct value of $this->name, odbc.

The lack of being able to find a suitable linux ODBC driver to work with the target has put this stage of the project on hold for the time being.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.