perlでHibernateのsqlログからテーブル名を抽出

前回の実際

とりあえず必要なものはなんとなく抜き出せてるみたいなんでこれでいいです。正規表現が冗長だとかいろいろありますが少しずつです。


AppleScriptかなんかからPerlを呼ぶようにしますかね。Windowsならバッチファイルかなんかにして、僕の場合はClaunchから起動とかでとりあえずやります。副問い合わせには再帰的に対応したけれど、insertとupdateに対応してなかったって気づいた。ま、それはすぐできるし必要ないので、やらない。


わかる人が見るとずいぶん冗長なコードなんだろうね。

ゆるーく仕様説明

  1. Hibernateのログ行だけでなく、今回の私のお仕事の都合から「^(.*?):sql:」の行も対象にしてます。sqlログ的なやつ。
  2. 基本「from」の後をテーブル名として抽出します。
  3. テーブル名の重複は省きます。
  4. テーブル名はすべて大文字に変換して抽出します。
  5. スキーマ名も一緒に抜き出すか抜き出さないかは「n」をパラメータに渡すか渡さないかで判断します。


今回、perl復習がてらに作ったのですが一応Javaでも書いてみてはいるんでいずれはEclipseプラグインで作りたいです。そうすれば、コンソールに出たログを対象にそのままボタン一発で抽出できるからね。そのうちね。

#####
##### Hibernateのselectクエリログからテーブル名のみ抽出。重複するテーブル名は省く
#####
open( IN,  "< input.txt" );
open( OUT, "> out.txt" );
my @list = ();
while ( my $line = <IN> ) {
	if ( $line =~ m/^Hibernate:|^(.*?):sql:/ ) {
		&isSubQuery( $line, 1 );
	}
}

my @array;
foreach my $value (@list) {
	chomp($value);
	push( @array, split( /,/, $value ) );
}

my @tables;
foreach my $value (@array) {
	chomp($value);
	$value = uc $value;
	$value =~ s/^\s//;
	$value =~ s/(.+?)\s.+/$1/;
	if ( $ARGV[0] eq "n" ) {
		$value =~ s/.+\.(.+)/$1/;
	}
	push( @tables, $value );
}

#@tablesの重複を省く
%temp;
@sort = grep( !$tmp{$_}++, @tables );

foreach my $value (@sort) {
	chomp($value);
	print( OUT "$value\n" );
}

sub isSubQuery {
	if ( $_[0] =~ m/^(.*)\((\s?select(.+))\)(.*)$/ ) {
		my $one  = $1;
		my $two  = $2;
		my $four = $4;
		&isSubQuery($two);
		&extractTables( $one, $four );
	} else {
		&extractTables( $_[0] );
	}
}

sub extractTables {
	foreach my $value (@_) {
		if ( $value =~ m/^(.*?)from\s(.+?)(?:left outer join\s(.+?))?((?:\swhere|\son|\sgroup by|\sorder by|:$|$))/ ) {
			push( @list, "$2\n" );
			push( @list, "$3\n" );
		}
	}
}