Parse a DSN string in Python

A simple hack to get the different parts of a DSN string (which are used in PDO in PHP):

def parse_dsn(dsn):
    m = re.search("([a-zA-Z0-9]+):(.*)", dsn)
    values = {}
    
    if (m and m.group(1) and m.group(2)):
        values['driver'] = m.group(1)
        m_options = re.findall("([a-zA-Z0-9]+)=([a-zA-Z0-9]+)", m.group(2))
        
        for pair in m_options:
            values[pair[0]] = pair[1]

    return values

The returned dictionary contains one entry for each of the entries in the DSN.

Update: helge also submitted a simplified version of the above:

driver, rest = dsn.split(':', 1)
values = dict(re.findall('(\w+)=(\w+)', rest), driver=driver)

Fatal error: Undefined class constant ‘ATTR_DEFAULT_FETCH_MODE’

This is one of the common error messages that seems to appear after installing PHP – in particular under Ubuntu or Debian (where I experienced it). The reason for this is that the PDO version you’ve just installed is too old for the constant to exist, usually because you where naive enough to install the extension from PECL instead of using the default supplied by ubuntu. If you did the same as me:

apt-get install 
pecl install pdo
pecl install pdo_mysql

/etc/init.d/apache2 restart

And everything seems to work, except for that missing constant. What the fsck?!

The reason is that the PECL version of PDO is no longer maintained (I’d suggest to automagically push the newest version to PECL too, just so pecl install and pecl upgrade works as expected). The fact is that when you did pecl install pdo, you destroyed the more recent version provided by the default php5-common package (under Ubuntu, at least).

To solve the problem (and if you also did pecl install pdo_mysql, you’ll have to replace that one too…)

apt-get install --reinstall php5-common php5-mysql php5-mysqli

Restart. Relive. Re.. eh .. yeah. Rerere.

If you’re building from source, you’ll need to add:

--enable-pdo --with-pdo-mysql --with-pdo-pgsql (and any other driver you need)

PDO and PDO::PARAM_INT

Hi there Mr. PDO!

We’ve come to know each other, and yes, while you have your troubles (.. which I don’t, of course), I’ve accepted your short comings. Today you threw another one of your fits, but I’ll be sure to document it for the world to see.

$statement = $pdo->prepare("
    ...
    LIMIT
        :offset, :hits
");

Yep. This will of course fail if you’re binding strings. ’10’, ’10’ is not very helpful now, is it. Good point. So let’s tell PDO that we’re really binding ints:

$statement->bindValue(':offset', $offset, PDO::PARAM_INT);
$statement->bindValue(':hits', $hits, PDO::PARAM_INT);

But wait. You’re still complaining?! I told you they were ints?! What’s the problem now?!?!

Well. Mr. PDO requires you to also convert the values for him. So first you have to convert the values of a loosely typed language to a strong type, then you have to tell the library that yes, this is in fact another type than what the library obviously assumes that it is. This works:

$statement->bindValue(':offset', (int) $offset, PDO::PARAM_INT);
$statement->bindValue(':hits', (int) $hits, PDO::PARAM_INT);

Which means the following:

If the type of your variable internally is a string, it’ll be escaped as a string, even if you tell PDO that it should be handled as an INT in your database layer.

If the type of your variable is an int, it’ll be handled as a string, unless you tell PDO it is an int.

Something is backwards here.

Fatal error: Exception thrown without a stack frame in Unknown on line 0

While Christer were updating his profile on one of our current projects, he suddenly got this rather cryptic message. We tossed a few ideas around, before just leaving it for the day. We came back to the issue earlier today, and I suddenly had the realization that it had to have something to do with the session handling. Changing our session handler from memcache to the regular file based cache did nothing, so then it had to be something in the code itself.

The only thing we have in our session is an object representing the currently logged in user, so it had to be something in regards to that. After a bit of debugging I found the culprit; a reference to an object which contained a reference to a PDO object. PDO objects cannot be serialized, and this exception was being thrown after the script had finished running. The session is committed to the session storage handler when the script terminates, and therefor is run out of the regular script context (and this is why you get “in Unknown on line 0”. It would be very helpful if the PHP engine had been able to provide at least the message from the exception, but that’s how it currently is.

Hopefully someone else will get an Eureka!-moment when reading this!

The solution we ended up with was to remove the references to the objects containing the unserializable structures. This was done by implementing the magic __sleep method, which returns a list of all the fields that should be kept when serializing the object (we miss the option of instead just unsetting the fields that needs to be unset and then let the object be serialized as it would have if the __sleep method wasn’t implemented). We solved this by implemeting the __sleep method and removing our references, before returning all the fields contained in the object:

public function __sleep()
{
    $this->manager = null;
 
    return array_keys(get_object_vars($this));
}

And there you have it, one solved problem!

Getting a Look Behind the Scenes of PDO

Ulf Wendel is presenting several good articles about the process about implementing the mysqlnd library for PDO as PDO_MYSQLND. I wrote about PDO_MYSQLND when it first was announced, but Ulf has posted two good articles about the implementation of PDO_MYSQLND since then. These articles provide a unique insight into how PDO is built and what challenges lies ahead for PDO2 (.. in addition to the license and NDA debate..)

Remember that you can always follow the latest developments over at Planet PHP.