h2내 MySQL 함수 사용

Kang JaeHyeon·2025년 4월 16일

테스트를 진행할 때 h2 데이터베이스를 사용
일부 SQL 함수 H2 데이터베이스에서는 지원하지 않음

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "AES_DECRYPT" not found; SQL statement:

MySQL 모드로 설정되어 있지만 여전히 사용 불가

jdbc:h2:~/test;MODE=MySQL

지원되지 않는 함수를 java로 사용자 정의 함수로 구현

CREATE ALIAS IF NOT EXISTS LAST_INSERT_ID_MAX AS '

@CODE
int lastInsertIdMax(int id) throws Exception {
    return id;
}
';

CREATE ALIAS IF NOT EXISTS DATE_FORMAT AS '

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
@CODE
String dateFormat(Timestamp ts, String pattern) throws Exception {
    if (ts == null || pattern == null || pattern.isEmpty()) {
        return null;
    }
    SimpleDateFormat sdf = new SimpleDateFormat(pattern);
    return sdf.format(ts);
}
';

CREATE ALIAS IF NOT EXISTS AES_ENCRYPT AS '

import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

@CODE
byte[] aesEncrypt(String plainText, String key) throws Exception {

	// MySQL에서는 암호화 할 때 어떤 길이의 key가 들어와도 내부에서 정규화 후 실행
    // java 에서는 16, 24, 32 길이의 key만 허용
    // key 길이 정규화 코드

	byte[] finalKey = new byte[16];
	byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
	for (int i = 0; i < keyBytes.length; i++) {
		finalKey[i % 16] ^= keyBytes[i];
	}
	
	if (plainText == null){
		plainText="";
	}

	SecretKeySpec secretKey = new SecretKeySpec(finalKey, "AES");
	
	Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
	cipher.init(Cipher.ENCRYPT_MODE, secretKey);
	return cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
}
';

CREATE ALIAS IF NOT EXISTS AES_DECRYPT AS '

import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

@CODE
String aesDecrypt(byte[] encrypted, String key) throws Exception {

	byte[] finalKey = new byte[16];
	byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
	for (int i = 0; i < keyBytes.length; i++) {
		finalKey[i % 16] ^= keyBytes[i];
	}
	
	SecretKeySpec secretKey = new SecretKeySpec(finalKey, "AES");
	
	Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
	cipher.init(Cipher.DECRYPT_MODE, secretKey);
	byte[] decrypted = cipher.doFinal(encrypted);
	return new String(decrypted, StandardCharsets.UTF_8);
}
';

CREATE ALIAS IF NOT EXISTS HEX AS '

@CODE
String hex(byte[] data) {
	StringBuilder sb = new StringBuilder();
	for (byte b : data) {
		sb.append(String.format("%02X", b));
	}
	return sb.toString();
}
';

CREATE ALIAS IF NOT EXISTS UNHEX AS '

@CODE
byte[] unhex(String hex) {
	int len = hex.length();
	byte[] data = new byte[len / 2];
	for (int i = 0; i < len; i += 2) {
		int hi = Character.digit(hex.charAt(i), 16);
		int lo = Character.digit(hex.charAt(i + 1), 16);
		data[i / 2] = (byte)((hi << 4) + lo);
	}
	return data;
}
';

0개의 댓글