All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ai.platon.pulsar.ql.h2.H2SessionFactory.kt Maven / Gradle / Ivy

There is a newer version: 1.13.2
Show newest version
package ai.platon.pulsar.ql.h2

import ai.platon.pulsar.common.config.CapabilityTypes
import ai.platon.pulsar.skeleton.context.PulsarContexts
import ai.platon.pulsar.ql.*
import ai.platon.pulsar.ql.context.SQLContexts
import ai.platon.pulsar.ql.SQLSession
import ai.platon.pulsar.ql.common.H2Config
import org.h2.engine.*
import org.h2.jdbc.JdbcConnection
import org.h2.message.TraceSystem
import org.h2.util.JdbcUtils
import org.h2.util.Utils
import org.slf4j.LoggerFactory
import java.sql.Connection

object H2SessionFactory : org.h2.engine.SessionFactory {

    private val log = LoggerFactory.getLogger(H2SessionFactory::class.java)!!

    private val sqlContext get() = SQLContexts.create()

    init {
        H2Config.config()
        JdbcUtils.addClassFactory(ClassFactory())
    }

    /**
     * Required by h2 database runtime
     * */
    @Suppress("unused")
    @JvmStatic
    fun getInstance(): H2SessionFactory {
        return H2SessionFactory
    }

    fun isColumnRetrieval(conn: Connection): Boolean {
        return Constants.CONN_URL_COLUMNLIST in conn.metaData.url
    }

    /**
     * Create a h2 session and an associated query session, the h2 session is returned by h2 runtime
     *
     * @param ci The h2 connection info
     * @return The h2 session
     */
    @Synchronized
    override fun createSession(ci: ConnectionInfo): Session {
        val h2session = org.h2.engine.Engine.getInstance().createSession(ci)

        if (!sqlContext.isActive) {
            // Note: it's proven that we can not just return a h2session, never do this !!!
            // log.info("Context is closed, can not create a Scent SQL session, fallback to H2database to handle this")
            // return h2session
            throw IllegalStateException("[H2SessionFactory] SQL context is closed, will not create SQL session")
        }

        log.debug("Creating SQL session for h2 connection | {}", ci.url)

        SysProperties.serializeJavaObject = ci.isPersistent

        val h2Log = LoggerFactory.getLogger("org.h2")
        if (h2Log.isTraceEnabled) {
            h2session.trace.setLevel(TraceSystem.ADAPTER)
        }

        val sqlSession = sqlContext.createSession(H2SessionDelegate(h2session.serialId, h2session))
        sqlSession.sessionConfig.set(CapabilityTypes.SCENT_EXTRACT_TABULATE_CELL_TYPE, "DATABASE")
        require(sqlSession.id == h2session.serialId)

        log.info("SQLSession {} is created for h2session <{}>, connection: <{}>",
            sqlSession, h2session, ci.url)

        return h2session
    }

    @Synchronized
    fun getSession(serialId: Int): SQLSession {
        return sqlContext.getSession(serialId)
    }

    @Synchronized
    fun getSession(connection: Connection): SQLSession {
        val conn = connection as JdbcConnection
        return getSession(conn.session)
    }

    @Synchronized
    fun getH2Session(connection: Connection): Session {
        val conn = connection as JdbcConnection
        val s = getSession(conn.session)
        return s.sessionDelegate.implementation as Session
    }

    @Synchronized
    fun getSession(sessionInterface: SessionInterface): SQLSession {
        val h2session = sessionInterface as Session
        // TODO: or just use hash code so no need to modify h2database to expose serialId
        return sqlContext.getSession(h2session.serialId)
    }

    @Synchronized
    override fun closeSession(serialId: Int) {
        sqlContext.closeSession(serialId)
    }

    @Synchronized
    fun shutdown() {
        PulsarContexts.shutdown()
    }

    /**
     * @see org.h2.engine.SessionRemote.shutdownSessionFactory
     * */
    @Synchronized
    fun shutdownNow() {
        PulsarContexts.shutdown()
    }
}

class ClassFactory : Utils.ClassFactory {
    override fun match(name: String): Boolean {
        return name.startsWith(this.javaClass.`package`.name)
    }

    @Throws(ClassNotFoundException::class)
    override fun loadClass(name: String): Class<*> {
        return this.javaClass.classLoader.loadClass(name)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy