46

I want to select a MySQL database to use after a PHP PDO object has already been created. How do I do this?

// create PDO object and connect to MySQL
$dbh = new PDO( 'mysql:host=localhost;', 'name', 'pass' );

// create a database named 'database_name'

// select the database we just created ( this does not work )
$dbh->select_db( 'database_name' );

Is there a PDO equivalent to mysqli::select_db?

Perhaps I'm trying to use PDO improperly? Please help or explain.

EDIT

Should I not be using PDO to create new databases? I understand that the majority of benefits from using PDO are lost on a rarely used operation that does not insert data like CREATE DATABASE, but it seems strange to have to use a different connection to create the database, then create a PDO connection to make other calls.

T. Brian Jones
  • 13,002
  • 25
  • 78
  • 117
  • You will probably need to create a new PDO object to connect to another database. – Ignas Jan 02 '12 at 20:51
  • 3
    You can use `select table.field from database.table`, assuming that whatever user ID you've connected with has the appropriate rights on the other db/tables. – Marc B Jan 02 '12 at 20:53
  • What's wrong with creating a new object? Once you run your queries like "CREATE DATABASE" you can easily destroy it and continue working with a new connection. I don't really see an issue with it. – Ignas Jan 02 '12 at 21:11
  • 1
    That just seems like a silly thing to have to do, which generally means I'm doing something else wrong. Maybe this is just an edge case. PDO is probably not often used to create new databases. – T. Brian Jones Jan 02 '12 at 21:16
  • @Ignas: Takes about 23ms to open a connection to a database (instantiate PDO) in my tests. I have literally hundreds of databases; it makes my script take 4x longer than using a `use` statement. – mpen Jul 29 '13 at 23:59
  • Yeah I get your point (I'm using two connections though because I'd have to be switching databases every 50 lines of code so the initial overhead of those 23ms would be nothing compared to MANY use database statements :) I would probably wrap the `use database` statement in a method and use it like $this->Db()->query(""). Store the last selected database name in a variable and if the passed argument to the Db method is different, just switch the databases :) – Ignas Jul 30 '13 at 09:36

4 Answers4

60

Typically you would specify the database in the DSN when you connect. But if you're creating a new database, obviously you can't specify that database the DSN before you create it.

You can change your default database with the USE statement:

$dbh = new PDO("mysql:host=...;dbname=mysql", ...);

$dbh->query("create database newdatabase");

$dbh->query("use newdatabase");

Subsequent CREATE TABLE statements will be created in your newdatabase.


Re comment from @Mike:

When you switch databases like that it appears to force PDO to emulate prepared statements. Setting PDO::ATTR_EMULATE_PREPARES to false and then trying to use another database will fail.

I just did some tests and I don't see that happening. Changing the database only happens on the server, and it does not change anything about PDO's configuration in the client. Here's an example:

<?php

// connect to database
try {
    $pdo = new PDO('mysql:host=huey;dbname=test', 'root', 'root');
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch(PDOException $err) {
    die($err->getMessage());
}

$stmt = $pdo->prepare("select * from foo WHERE i = :i");
$result = $stmt->execute(array("i"=>123));
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));

$pdo->exec("use test2");

$stmt = $pdo->prepare("select * from foo2 WHERE i = :i AND i = :i");
$result = $stmt->execute(array("i"=>456));
print_r($stmt->fetchAll(PDO::FETCH_ASSOC));

If what you're saying is true, then this should work without error. PDO can use a given named parameter more than once only if PDO::ATTR_EMULATE_PREPARES is true. So if you're saying that this attribute is set to true as a side effect of changing databases, then it should work.

But it doesn't work -- it gets an error "Invalid parameter number" which indicates that non-emulated prepared statements remains in effect.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • 2
    Really? query? I'm pretty sure you're looking for exec – Tom van der Woerdt Jan 02 '12 at 21:27
  • 3
    @TomvanderWoerdt: I tested both query() and exec() and they both work. query() returns a PDOStatement object, and exec() returns the number of rows affected (1 for the create, 0 for the use). For these statements, the return values are nearly irrelevant. – Bill Karwin Jan 02 '12 at 21:34
  • 2
    The point is that it's easy to change the default database on an open db handle; there's no need to open a second db connection. – Bill Karwin Jan 02 '12 at 21:36
  • When you switch databases like that it appears to force PDO to emulate prepared statements. Setting `PDO::ATTR_EMULATE_PREPARES` to false and then trying to use another database will fail. – Mike Feb 12 '14 at 07:13
  • 1
    @Mike, I think you're mistaken. See test case above. – Bill Karwin Feb 12 '14 at 17:12
  • @BillKarwin ok I did a bit more testing, and I am able to reproduce the error if I use `PDO::query` to switch databases instead of `PDO::exec` as you have above. I get `Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2030 This command is not supported in the prepared statement protocol yet' in /test.php:41 Stack trace: #0 /test.php(41): PDO->query('USE db_name...') #1 {main} thrown in /test.php on line 41`. Any ideas why it would work with one but not the other? – Mike Feb 12 '14 at 20:30
  • From the manual, the only difference between those two methods should be what they return. – Mike Feb 12 '14 at 20:33
  • 6
    PDO::query() internally does a prepare() followed by an execute(). Not all MySQL statements can be run with prepare. See http://dev.mysql.com/doc/refman/5.6/en/sql-syntax-prepared-statements.html, under the section "SQL Syntax Allowed in Prepared Statements." – Bill Karwin Feb 12 '14 at 20:42
  • I get the same as @Mike, but is indeed resolved with ::exec() probably for the reasons you've shared Bill – Harvey Dobson Nov 19 '20 at 16:44
  • @BillKarwin The link is dead, but [here's one for MySQL 8](https://dev.mysql.com/doc/refman/8.0/en/sql-prepared-statements.html#prepared-statements-permitted)! – Adrian Wiik Jun 10 '22 at 07:07
0

Alternatively, you can select a MySQL database to use after a PHP PDO object has already been created as below:

With USE STATEMENT. But remember here USE STATEMENT is mysql command

try
{
    $conn = new PDO("mysql:host=$servername;", $username, $password);
    // set the PDO error mode to exception
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $conn->exec("use databasename");
    //application logic
}
catch(PDOException $e)
{
    echo $sql . "<br>" . $e->getMessage();
}

$conn = null;

I hope my code is helpful for requested

David
  • 3,285
  • 1
  • 37
  • 54
Varma Amit
  • 25
  • 1
  • 6
0

You should be setting the database when you create the PDO object. An example (from here)

<?php
$hostname = "localhost";
$username = "your_username";
$password = "your_password";

try {
    $dbh = new PDO("mysql:host=$hostname;dbname=mysql", $username, $password);
    echo "Connected to database"; // check for connection
    }
catch(PDOException $e)
    {
    echo $e->getMessage();
    }
?>
MrGlass
  • 9,094
  • 17
  • 64
  • 89
-1

As far as I know, you have to create a new object for each connection. You can always extend the PDO class with a method which connects to multiple databases. And then use it as you like:

public function pickDatabase($db) {
  if($db == 'main') {
    return $this->db['main']; //instance of PDO object
  else
    return $this->db['secondary']; //another instance of PDO object
}

and use it like $yourclass->pickDatabase('main')->fetchAll('your stuff');

Ignas
  • 1,965
  • 2
  • 17
  • 44