SET NAMES のいらない生活

PHPRubyMySQLクライアントライブラリを清く正しく使う方法*1をまとめてみた。Shift_JISが来てもU+00A5が来ても大丈夫なはず。
汚れた部分を見つけた方はぜひご指摘を!

Version

PHP

mysql
$link = mysql_connect('localhost', 'user', 'password');
mysql_select_db('test', $link);
mysql_set_charset('utf8', $link);

$result = mysql_query(
    sprintf("SELECT id FROM tb WHERE name = '%s'",
            mysql_real_escape_string('あいうえお'))
);

if ($result) {
    while ($row = mysql_fetch_assoc($result)) {
        printf("%d\n", $row['id']);
    }

    mysql_free_result($result);
}

mysql_close($link);
mysqli

OOP:

$mysqli = new mysqli('localhost', 'user', 'password', 'test');
$mysqli->set_charset('utf8');

$stmt = $mysqli->prepare("SELECT id FROM tb WHERE name = ?");
$name = 'あいうえお';
$stmt->bind_param('s', $name);
$stmt->bind_result($id);

$stmt->execute();

while ($stmt->fetch()) {
    printf("%d\n", $id);
}
$stmt->close();

$mysqli->close();

手続き型:

$link = mysqli_connect('localhost', 'user', 'password', 'test');
mysqli_set_charset($link, 'utf8');

$stmt = mysqli_prepare($link, "SELECT id FROM tb WHERE name = ?");
$name = 'あいうえお';
mysqli_stmt_bind_param($stmt, 's', $name);
mysqli_stmt_bind_result($stmt, $id);

mysqli_stmt_execute($stmt);

while (mysqli_stmt_fetch($stmt)) {
    printf("%d\n", $id);
}
mysqli_stmt_close($stmt);

mysqli_close($link);

非prepared statements:

$mysqli = new mysqli('localhost', 'user', 'password', 'test');
$mysqli->set_charset('utf8');

$result = $mysqli->query(
    sprintf("SELECT id FROM tb WHERE name = '%s'",
            $mysqli->real_escape_string('あいうえお'))
);

if ($result) {
    while ($row = $result->fetch_assoc()) {
        printf("%d\n", $row['id']);
    }
    
    $result->close();
}

$mysqli->close();
PDO_MYSQL
$dbh = new PDO('mysql:host=localhost;dbname=test', 'user', 'password',
               array(
                     PDO::MYSQL_ATTR_READ_DEFAULT_FILE => '/etc/my.cnf',
                     PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'pdo',
                     PDO::MYSQL_ATTR_DIRECT_QUERY => false  /* server-side prepared statements */
               ));
 
$stmt = $dbh->prepare("SELECT id FROM tb WHERE name = ?");
$stmt->bindValue(1, 'あいうえお', PDO::PARAM_STR);

$stmt->execute();

while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    printf("%d\n", $row['id']);
}

非prepared statements:

$dbh = new PDO('mysql:host=localhost;dbname=test', 'user', 'password',
               array(
                     PDO::MYSQL_ATTR_READ_DEFAULT_FILE => '/etc/my.cnf',
                     PDO::MYSQL_ATTR_READ_DEFAULT_GROUP => 'pdo',
                     PDO::MYSQL_ATTR_DIRECT_QUERY => true
               ));
 
$result = $dbh->query(sprintf("SELECT id FROM tb WHERE name = %s",
                              $dbh->quote('あいうえお', PDO::PARAM_STR)
));

while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
    printf("%d\n", $row['id']);
}

/etc/my.cnf

[pdo]
default-character-set = utf8

Ruby

MySQL/Ruby
my = Mysql.init
my.options(Mysql::SET_CHARSET_NAME, "utf8")
my.connect("localhost", "user", "password", "test")

st = my.prepare("SELECT id FROM tb WHERE name = ?")
st.execute("あいうえお")
st.each do |x|
  p x[0]
end
st.close

my.close

非prepared statements:

my = Mysql.init
my.options(Mysql::SET_CHARSET_NAME, "utf8")
my.connect("localhost", "user", "password", "test")

my.query(sprintf("SELECT id FROM tb WHERE name = '%s'",
         my.quote("あいうえお"))).each do |x|
  p x[0]
end

my.close