2017年1月21日土曜日

MySQL では、'a' = 0 が True になる。

オフィス狛 技術部です。

MySQL において、文字列と数値の比較は思わぬ結果になってしまう事があるので注意です。

まず、題名にもある通り、

「SELECT 0 = 'a';」はTrueになります。

・なぜこんな事が起きてしまうのか?

MySQLでは、型が違う値同士を比較すると、暗黙的な変換が発生します。
文字列の「1」は、数値の「1」になります。
しかし、数値に変換出来ないもの、例えば「a」という文字は、
変換出来ないので、「0」になります。
(変換は出来ないけど、型を一緒にする為に、無理やり数値にしてくれる)

変換出来ないなら、諦めて欲しいところなのですが、
頑張り屋さんなんですね、MySQLは。

という訳で、色々試して見た結果が以下の通りです。
SELECT 0 = 0;   -- True になる
SELECT 0 = 1;   -- False になる
SELECT 'a' = 'a'; -- True になる
SELECT 'a' = 'c'; -- False になる
SELECT 0 = '0';  -- True になる
SELECT 0 = 'a';  -- True になる
SELECT 1 = 'a';  -- False になる

やっぱり、「SELECT 0 = 'a'; 」が問題になりそうですね。

・他にもあった、頑張り屋さんならではの弊害

先程、「a」という文字列は数値に出来ませんでした。
では「1a」という文字列ではどうでしょう?
・・・・数値にしてくれるのです。そう、MySQLなら。

この場合、「1a」は「1」に変換されます。

こちらも色々試して見ました。
SELECT 1 = '1'; true
SELECT 1 = '1a'; true
SELECT 1 = '1abcd'; true
SELECT 1 = 'abcd1'; false
どうやら、先頭に数値が来ると、その数値に変換して比較するようです。

・でも、別にMySQLは悪くない

むしろ、頑張り屋さんで、良いと思います。

そもそも、SQLで文字列と数値を比較するような事を発生させないのが筋です。
そして、その制御はSQLに値を設定するプログラム側で行うべきだと思います。
(もっと言うと、そんな事が発生する場合、設計を見直した方が良いのかな、とも思います。)

・その他気になったところ

リファレンスマニュアルには、下記の式についても、 結果が異なると記載されています。
SELECT '18015376320243458' = 18015376320243458; true になる
SELECT '18015376320243459' = 18015376320243459; false になる
これを色々な環境で試してみたのですが、
SELECT '18015376320243458' = 18015376320243458; true
SELECT '18015376320243459' = 18015376320243459; true

間違った判定をされる事はありませんでした。

リファレンスをちゃんと読むと、
さらに、文字列から浮動小数点への変換および整数から浮動小数点への変換は、必ずしも同様に発生するとはかぎりません。整数は、CPU によって浮動小数点に変換される可能性があります。一方、文字列は、浮動小数点の乗算を伴う演算で 1 桁ずつ変換されます。 表示される結果はシステムによって異なり、コンピュータのアーキテクチャーやコンパイラのバージョンなどの要因、または最適化レベルの影響を受ける可能性があります。このような問題を回避する方法の 1 つは、値が暗黙的に浮動小数点値に変換されないように、CAST() を使用することです。
「MySQL 5.6 リファレンスマニュアル」『関数と演算子 / 式評価での型変換 / 12.2 式評価での型変換』より。
2017年1月17日 (火) 08:11 UTC
URL: https://dev.mysql.com/doc/refman/5.6/ja/type-conversion.html
なるほど、環境によって異なるのですね。

MySQL において、異なる型の比較は思わぬ結果になってしまう事がある、
という事で、注意しましょう。

2017年1月14日土曜日

AWS EC2 の GitLab へリポジトリを移行する

オフィス狛 技術部です。

GitLab のインストール・設定シリーズ第3回目の今回は、Git リポジトリの移行を行います。
(移行元と移行先はサーバー(EC2インスタンス)が別)

その他の記事は、以下をご覧下さい。
第1回(AWS EC2 に GitLab をインストールする)
第2回(AWS EC2 に GitLab をインストールする(メールの送信テスト編))

では、早速Git リポジトリの移行を始めて行こうと思います。

1)GitLab にリポジトリ(プロジェクト)を作成する。

作成の手順は記載しませんが、前もって移行するリポジトリと同じ名前で、
GitLab プロジェクト(=リポジトリ)を作成しておく必要があります。

ちなみに、GitLab では、ユーザー、またはグループに属する形でプロジェクトが作成されます。
なので弊社の場合、共有リポジトリ用グループ(例:hogehoge-dev)を作成し、
開発者用のプロジェクトは全て hogehoge-dev に属する様に作成しています。

※あくまで置き場所として用意しているだけなので、権限設定に関しては、
別のグループ等を作成し、プロジェクト単位にグループへの権限付与を行なっています。

以降の説明を簡単にする為に、各設定の名称を以下と仮定します。
 ・旧Gitが存在しているサーバー : old.hoge.co.jp
 ・移行したいリポジトリ名 : RipoTest.git
 ・GitLab(新Git)が存在しているサーバー : new.hoge.co.jp
 ・GitLab のグループ : hogehoge-dev
 ・GitLab のプロジェクト名 : RipoTest

2)旧リポジトリをクローンする

続いて旧リポジトリをクローンします。
(今回、作業は、ローカル(Mac)側のターミナルで行なっています。)
sshで接続するので、旧サーバー側の鍵が必要になります。
鍵は、Macだと「/Users/mac_user/.ssh」に格納します。
※[mac_user]は、現在Macにログインしているユーザーです。

そして、コマンドを簡略化させる為に、同じディレクリに「config」というファイルを作成し、
Host config_name_1
  User connect_user
  HostName old.hoge.co.jp
  IdentityFile ~/.ssh/old_hoge_key_name
上記の内容を記述します。

 Host : コマンドに含める簡略名になります。 
 User : 接続するサーバーのユーザー
 HostName : 接続するサーバー
 IdentityFile : 使用する鍵の場所

これで準備が出来たので、早速クローンします。
$ git clone --mirror ssh://config_name_1/RipoTest.git
「mirror」を付ける事によって、履歴を含めたリポジトリのバックアップを取る感じでクローン出来ます。

3)GitLab(新Git)へプッシュする

続いて、先程クローンしたリポジトリをGitLab(新Git)へプッシュします。
こちらも先程と同じ様に、「config」を設定します。
Host config_name_2
  User git
  HostName new.hoge.co.jp
  IdentityFile ~/.ssh/new_hoge_key_name
※GitLabをインストールした時に、「git」ユーザーが作成されています。

これで準備が出来たので、早速プッシュします。
git push --mirror ssh://config_name_2/hogehoge-dev/RipoTest.git
「mirror」を付けること、そして、GitLab のグループ名をリポジトリ名の前に付ける事を忘れずに。

これで大抵のリポジトリは問題無くプッシュ出来るのですが、リポジトリの容量が大きいと・・・
Counting objects: 7400, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6246/6246), done.
Writing objects: 100% (7400/7400), 558.97 MiB | 6.24 MiB/s, done.
Total 7400 (delta 2794), reused 3512 (delta 452)
remote: fatal: Out of memory, malloc failed (tried to allocate 228733096 bytes)
error: unpack failed: index-pack abnormal exit
To ssh://config_name_2/hogehoge-dev/RipoTest.git
 ! [remote rejected] master -> master (unpacker error)
error: failed to push some refs to 'ssh://config_name_2/hogehoge-dev/RipoTest.git'
と、エラーになる事があります。
これ、中々解決出来ず、ちょっとハマったのですが、
結論から言うと、プッシュ先(ここで言うとGitLabがインストールしてある「new.hoge.co.jp」)のメモリを増やす事で解決しました。(*1

*1) プッシュ先のEC2 インスタンスを「t2.medium」から「t2.large」に一時的に変更しました。
弊社の場合、プッシュが全て終わったら、「t2.medium」へ戻しています。
「t2.large」は料金が高いので・・・。


これでリポジトリの移行が完了です。


, , ,

2017年1月8日日曜日

PHPで Fatal error: Arrays are not allowed as constants が発生した場合の対処方法

オフィス狛 技術部です。

弊社は Codeigniter を使ってWebシステムを作る事が多いのですが、
開発(ローカル)環境で作成したプロジェクトをLinuxサーバへ配置し、
いざURLに接続・・・と言う時に、

Fatal error: Arrays are not allowed as constants

が発生する事が多いです。

原因も分かっているので、毎回同じ対応するのですが、
とりあえず記録として残しておこうと思います。

まず、エラーの内容ですが、直訳でも通じる程シンプルで、
「配列は定数として使えませんよ」と言う事です。

配列を定数として使えるのは PHP 5.6 からで、
その前のバージョンでは使用出来ません。

Linux系のサーバーだと、デフォルトが PHP 5.5 というのが多くて、
毎回、サーバーに配置してから気付く、という感じです。

対処方法としては、PHPをバージョンアップさせるか、
それが無理なら、配列を定数として使う事を諦めるしかありません。

今回は、PHP のバージョンアップの手順を備忘録も兼ねて、残しておこうと思います。
なお、以降の手順は CetnOS の場合を想定しています。

1)現在のPHPのバージョンを確認する

何はともあれ、まずは現在のPHPのバージョンを確認します。
$ php -v
PHP 5.5.38 (cli) (built: Nov  9 2016 17:25:01) 
Copyright (c) 1997-2015 The PHP Group
Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
やはりバージョンは5.5 です。

2)異なるバージョンのPHPをインストールする

次は、現状のPHPとは異なるバージョンのPHPをインストールします。
今回は、PHP 5.6 をインストールします。
$ yum -y --enablerepo=epel,remi,remi-php56 install php56

これでインストールは出来たのですが、PATHは通っていない状態なので、下記を実行します。
$ source /opt/remi/php56/enable
ちなみに、「/opt/remi/php56/enable」の中身は、こんな感じです。
export PATH=/opt/remi/php56/root/usr/bin:/opt/remi/php56/root/usr/sbin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/opt/remi/php56/root/usr/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
export MANPATH=/opt/remi/php56/root/usr/share/man:${MANPATH}

次はphpコマンドのリンク先を変えていきます。
現状のリンク先を確認すると、
$ ls -lrt /usr/bin/php
lrwxrwxrwx. 1 root root 14 11月 15 21:42 /usr/bin/php -> /usr/bin/php55
現状はPHP 5.5にリンクされている事が分かります。
では、一旦リンクを外して、PHP 5.6へリンクするように変更します。
$ unlink php
$ sudo ln -s /usr/bin/php56 /usr/bin/php

正しく変更されているか確認します。
$ ls -lrt /usr/bin/php
lrwxrwxrwx. 1 root root 14 12月  3 12:35 /usr/bin/php -> /usr/bin/php56
$ php -v
PHP 5.6.28 (cli) (built: Nov  9 2016 06:57:19) 
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

これで、Fatal error: Arrays are not allowed as constants が発生しなくなるはずです。


,