note
afoken
<p>I just wanted to demonstrate that DBI can't connect with <c>DBI->connect('DBD:MariaDB:...',...)</c>, but it can and does, if environment variables are set. I think that should not happen.</p>
<hr>
<p>[doc://DBI]'s connect method is pure perl. It contains some legacy stuff, but I don't really want to analyse every single line of it. So I just cleared the environment and ran a test:</p>
<c>
/tmp>env - perl -MDBI -e 'DBI->connect("DBD:MariaDB","","",{PrintError=>1})'
Can't connect to data source 'DBD:MariaDB' because I can't work out what driver to use (it doesn't seem to contain a 'dbi:driver:' prefix and the DBI_DRIVER env var is not set) at -e line 1.
</c>
<p>There is a hint hiding in the error message. The relevant part of the <c>connect()</c> documentation is this, at the very end:</p>
<blockquote>
<p>For compatibility with old DBI scripts, the driver can be specified by passing its name as the fourth argument to connect (instead of <c>\%attr</c>):</p>
<c>
$dbh = DBI->connect($data_source, $user, $pass, $driver);
</c>
<p>In this "old-style" form of connect, the <c>$data_source</c> should not start with "<c>dbi:driver_name:</c>". (If it does, the embedded driver_name will be ignored). Also note that in this older form of connect, the <c>$dbh->{AutoCommit}</c> attribute is undefined, the <c>$dbh->{PrintError}</c> attribute is off, and the old <c>DBI_DBNAME</c> environment variable is checked if <c>DBI_DSN</c> is not defined. Beware that this "old-style" connect will soon be withdrawn in a future version of DBI.</p>
</blockquote>
<p><c>connect()</c> assumes an old-style call, despite being called with an unblessed hash reference as fourth argument, not a string. The old-style call should have a driver name as fourth argument. This smells like a bug.</p>
<p>What happens if <c>$ENV{'DBI_DRIVER'}</c> is set?</p>
<c>
/tmp>env - DBI_DRIVER=NON::SENSE perl -MDBI -e 'DBI->connect("DBD:MariaDB","","",{PrintError=>1})'
install_driver(NON::SENSE) failed: Can't locate DBD/NON/SENSE.pm in @INC (you may need to install the DBD::NON::SENSE module) (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at (eval 5) line 3.
Perhaps a module that DBD::NON::SENSE requires hasn't been fully installed
at -e line 1.
</c>
<p>Again, <c>DBI->connect()</c> treats a new-style call with <c>\%attr</c>, but an invalid <c>$data_source</c>, as an old-style call.</p>
<p>What happens to the attributes?</p>
<c>
/tmp>env - perl -MDBI -e 'print DBI->connect("dbi:SQLite:foo","","",{PrintError=>1})->{PrintError}'
1
/tmp>env - DBI_DRIVER=SQLite perl -MDBI -e 'print DBI->connect("DBD:MariaDB:foo","","",{PrintError=>1})->{PrintError}'
1
/tmp>env - DBI_DRIVER=SQLite perl -MDBI -e 'print DBI->connect("DBD:MariaDB:foo","","",{})->{PrintError}'
1
</c>
<p><c>PrintError</c> is on, even by default. For "old-style" connects, it should be off. See the quoted documentation above.</p>
<p>What happens for a real old-style call?</p>
<c>
/tmp>env - perl -MDBI -e 'print DBI->connect("DBD:MariaDB:foo","","","SQLite")->{PrintError}'
DBI->connect using 'old-style' syntax is deprecated and will be an error in future versions at -e line 1.
/tmp>env - perl -MDBI -e 'print defined DBI->connect("DBD:MariaDB:foo","","","SQLite")->{PrintError}'
DBI->connect using 'old-style' syntax is deprecated and will be an error in future versions at -e line 1.
1
/tmp>env - perl -MDBI -e 'print DBI->connect("DBD:MariaDB:foo","","","SQLite")->{PrintError}+0'
DBI->connect using 'old-style' syntax is deprecated and will be an error in future versions at -e line 1.
0
</c>
<p>We get the expected deprecation warning, and <c>PrintError</c> is off (defined and empty).</p>
<p>What happens without <c>\%attr</c>? This:</p>
<c>
/tmp>env - perl -MDBI -e 'print DBI->connect("DBD:MariaDB:foo","","")'
Can't connect to data source 'DBD:MariaDB:foo' because I can't work out what driver to use (it doesn't seem to contain a 'dbi:driver:' prefix and the DBI_DRIVER env var is not set) at -e line 1.
</c>
<p>This is acceptable, as there is no fourth argument containing either a driver name or <c>\%attr</c>. So this could be an old-style call. The first argument lacks a "dbi:" prefix, so it must be an old-style call. (Or a confused coder.)</p>
<hr>
<p>So, an invalid modern-style <c>$data_source</c> confuses <c>connect()</c> to use the fall-back to old-style driver name handling, but at the same time to respect the <c>\%attr</c> parameter and to omit the deprecation warning. I think this is a bug.</p>
<p>[id://11123653]'s system obviously behaves the same, and someone must have set up DBI environment variables that hide the problem.</p>
<p>My DBI version:</p>
<c>
/tmp>perl -MDBI -e 'print $DBI::VERSION'
1.636
</c>
<p>I'm a little bit behind (CPAN currently has 1.643), but the relevant parts in DBI.pm are connect() and installl_driver(). The former has some changes related to the password, and keeps a copy of the original $data_source for an error message, but has no other changes. The latter is unchanged. So I think this bug still exists. Unfortunately, I don't have a spare system at hand to test the current version of DBI.</p>
<p>Alexander</p>
<div class="pmsig"><div class="pmsig-747201">
--<br>
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
</div></div>
11134291
11134357