OBP-API/obp-api/src/main/scala/code/api/util/DBUtil.scala

100 lines
3.7 KiB
Scala

package code.api.util
import code.api.Constant
import net.liftweb.db.{DB, DefaultConnectionIdentifier}
import net.liftweb.util.Helpers.tryo
import java.sql.{ResultSet, Types}
object DBUtil {
def dbUrl: String = APIUtil.getPropsValue("db.url") openOr Constant.h2DatabaseDefaultUrlValue
def isSqlServer: Boolean = dbUrl.contains("sqlserver")
/**
* SQL Server-safe alternative to Lift's DB.runQuery.
*
* Lift's DB.runQuery uses DB.asString which doesn't handle SQL Server's NVARCHAR type
* (JDBC type -9), causing MatchError. This function handles all JDBC types properly.
*
* @param query SQL query string
* @param params Query parameters (for prepared statement)
* @return Tuple of (column names, rows as List[List[String]])
*/
def runQuery(query: String, params: List[String] = Nil): (List[String], List[List[String]]) = {
DB.use(DefaultConnectionIdentifier) { conn =>
val stmt = conn.prepareStatement(query)
try {
// Set parameters
params.zipWithIndex.foreach { case (param, idx) =>
stmt.setString(idx + 1, param)
}
val rs = stmt.executeQuery()
val meta = rs.getMetaData
val colCount = meta.getColumnCount
// Get column names
val colNames = (1 to colCount).map(i => meta.getColumnName(i)).toList
// Get rows - convert all types to String safely
var rows = List[List[String]]()
while (rs.next()) {
val row = (1 to colCount).map { i =>
safeGetString(rs, i, meta.getColumnType(i))
}.toList
rows = rows :+ row
}
(colNames, rows)
} finally {
stmt.close()
}
}
}
/**
* Safely convert any JDBC type to String, including SQL Server's NVARCHAR (-9).
*/
private def safeGetString(rs: ResultSet, columnIndex: Int, jdbcType: Int): String = {
val value = jdbcType match {
case Types.NVARCHAR | Types.NCHAR | Types.LONGNVARCHAR | Types.NCLOB =>
// SQL Server NVARCHAR types that Lift doesn't handle
rs.getNString(columnIndex)
case Types.CLOB =>
val clob = rs.getClob(columnIndex)
if (clob != null) clob.getSubString(1, clob.length().toInt) else null
case Types.BLOB =>
val blob = rs.getBlob(columnIndex)
if (blob != null) new String(blob.getBytes(1, blob.length().toInt)) else null
case _ =>
rs.getString(columnIndex)
}
if (rs.wasNull()) null else value
}
def getDbConnectionParameters: (String, String, String) = {
dbUrl.contains("jdbc:h2") match {
case true => getH2DbConnectionParameters
case false => getOtherDbConnectionParameters
}
}
private def getOtherDbConnectionParameters: (String, String, String) = {
val usernameAndPassword = dbUrl.split("\\?").filter(_.contains("user")).mkString
val username = usernameAndPassword.split("&").filter(_.contains("user")).mkString.split("=")(1)
val password = usernameAndPassword.split("&").filter(_.contains("password")).mkString.split("=")(1)
val dbUser = APIUtil.getPropsValue("db.user").getOrElse(username)
val dbPassword = APIUtil.getPropsValue("db.password").getOrElse(password)
(dbUrl, dbUser, dbPassword)
}
// H2 database has specific bd url string which is different compared to other databases
private def getH2DbConnectionParameters: (String, String, String) = {
val username = dbUrl.split(";").filter(_.contains("user")).toList.headOption.map(_.split("=")(1))
val password = dbUrl.split(";").filter(_.contains("password")).toList.headOption.map(_.split("=")(1))
val dbUser = APIUtil.getPropsValue("db.user").orElse(username)
val dbPassword = APIUtil.getPropsValue("db.password").orElse(password)
(dbUrl, dbUser.getOrElse(""), dbPassword.getOrElse(""))
}
}