PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

संग्रहीत प्रक्रिया को कैसे कॉल करें और स्लिक में वापसी मूल्य प्राप्त करें (स्कैला का उपयोग करके)

खैर, बहुत शोध और परस्पर विरोधी दस्तावेज़ीकरण की समीक्षा के बाद, मुझे इसका उत्तर मिल गया। दुर्भाग्य से, यह वह नहीं था जिसकी मुझे तलाश थी:

लब्बोलुआब यह है कि स्लिक बॉक्स से बाहर संग्रहीत कार्यों या प्रक्रियाओं का समर्थन नहीं करता है, इसलिए हमें अपना खुद का लिखना होगा।

उत्तर सत्र ऑब्जेक्ट को पकड़कर स्लिक से बाहर निकलना है, और फिर प्रक्रिया कॉल को प्रबंधित करने के लिए मानक जेडीबीसी का उपयोग करना है। आप में से जो JDBC से परिचित हैं, उनके लिए यह कोई खुशी की बात नहीं है... लेकिन, सौभाग्य से, स्काला के साथ हम पैटर्न मिलान के साथ कुछ बहुत अच्छी तरकीबें कर सकते हैं जो काम को आसान बनाती हैं।

मेरे लिए पहला कदम एक स्वच्छ बाहरी एपीआई को एक साथ रखना था। अंत में यह इस तरह दिख रहा था:

val db = Database.forDataSource(DB.getDataSource)
var response: Option[GPInviteResponse] = None

db.withSession {
    implicit session => {
        val parameters = GPProcedureParameterSet(
            GPOut(Types.INTEGER) ::
            GPIn(Option(i.token), Types.VARCHAR) ::
            GPIn(recipientAccountId, Types.INTEGER) ::
            GPIn(Option(contactType), Types.INTEGER) ::
            GPIn(contactValue, Types.VARCHAR) ::
            GPIn(None, Types.INTEGER) :: 
            GPIn(Option(requestType), Types.CHAR) ::
            GPOut(Types.INTEGER) ::  
            Nil
        )

        val result = execute(session.conn, GPProcedure.SendInvitation, parameters)
        val rc = result.head.asInstanceOf[Int]

        Logger(s"FUNC return code: $rc")
        response = rc match {
            case 0 => Option(GPInviteResponse(true, None, None))
            case _ => Option(GPInviteResponse(false, None, Option(GPError.errorForCode(rc))))
        }
    }
}

db.close()

यहां एक त्वरित पूर्वाभ्यास है:मैंने संग्रहीत प्रक्रिया कॉल को मॉडल करने के लिए एक साधारण कंटेनर बनाया है। GPProcedureParameterSet में GPIn, GPOut, या GPInOut इंस्टेंस की सूची हो सकती है। इनमें से प्रत्येक मानचित्र एक JDBC प्रकार के लिए एक मान है। कंटेनर इस तरह दिखता है:

case class GPOut(parameterType: Int) extends GPProcedureParameter
object GPOut

case class GPIn(value: Option[Any], parameterType: Int) extends GPProcedureParameter
object GPIn

case class GPInOut(value: Option[Any], parameterType: Int) extends GPProcedureParameter
object GPInOut

case class GPProcedureParameterSet(parameters: List[GPProcedureParameter])
object GPProcedureParameterSet

object GPProcedure extends Enumeration {
    type GPProcedure = Value
    val SendInvitation = Value("{?=call app_glimpulse_invitation_pkg.n_send_invitation(?, ?, ?, ?, ?, ?, ?)}")
}

पूर्णता के लिए मैं GPProcedure एन्यूमरेशन को शामिल कर रहा हूं ताकि आप इसे एक साथ रख सकें।

यह सब मेरे execute() . को सौंप दिया जाता है समारोह। यह बड़ा और गंदा है, पुराने जमाने के JDBC की तरह खुशबू आ रही है, और मुझे यकीन है कि मैं स्काला में काफी सुधार करूंगा। मैंने इसे कल रात 3 बजे सचमुच समाप्त कर दिया ... लेकिन यह काम करता है, और यह वास्तव में अच्छी तरह से काम करता है। ध्यान दें कि यह विशेष execute() फ़ंक्शन एक List देता है सभी आउट पैरामीटर युक्त... मुझे एक अलग executeQuery() write लिखना होगा एक प्रक्रिया को संभालने के लिए कार्य करता है जो resultSet returns देता है . (हालांकि अंतर मामूली है:आप केवल एक लूप लिखते हैं जो resultSet.next पकड़ लेता है और यह सब एक List में भर दें या जो भी अन्य संरचना आप चाहते हैं)।

यहाँ बड़ा बुरा स्काला है<->JDBC मैपिंग execute() समारोह:

def execute(connection: Connection, procedure: GPProcedure, ps: GPProcedureParameterSet) = {
    val cs = connection.prepareCall(procedure.toString)
    var index = 0

    for (parameter <- ps.parameters) {
        index = index + 1
        parameter match {
            // Handle any IN (or INOUT) types: If the optional value is None, set it to NULL, otherwise, map it according to
            // the actual object value and type encoding:
            case p: GPOut => cs.registerOutParameter(index, p.parameterType)
            case GPIn(None, t) => cs.setNull(index, t)
            case GPIn(v: Some[_], Types.NUMERIC | Types.DECIMAL) => cs.setBigDecimal(index, v.get.asInstanceOf[java.math.BigDecimal])
            case GPIn(v: Some[_], Types.BIGINT) => cs.setLong(index, v.get.asInstanceOf[Long])
            case GPIn(v: Some[_], Types.INTEGER) => cs.setInt(index, v.get.asInstanceOf[Int])
            case GPIn(v: Some[_], Types.VARCHAR | Types.LONGVARCHAR) => cs.setString(index, v.get.asInstanceOf[String])
            case GPIn(v: Some[_], Types.CHAR) => cs.setString(index, v.get.asInstanceOf[String].head.toString)
            case GPInOut(None, t) => cs.setNull(index, t)

            // Now handle all of the OUT (or INOUT) parameters, these we just need to set the return value type:
            case GPInOut(v: Some[_], Types.NUMERIC) => {
                cs.setBigDecimal(index, v.get.asInstanceOf[java.math.BigDecimal]); cs.registerOutParameter(index, Types.NUMERIC)
            }
            case GPInOut(v: Some[_], Types.DECIMAL) => {
                cs.setBigDecimal(index, v.get.asInstanceOf[java.math.BigDecimal]); cs.registerOutParameter(index, Types.DECIMAL)
            }
            case GPInOut(v: Some[_], Types.BIGINT) => {
                cs.setLong(index, v.get.asInstanceOf[Long]); cs.registerOutParameter(index, Types.BIGINT)
            }
            case GPInOut(v: Some[_], Types.INTEGER) => {
                cs.setInt(index, v.get.asInstanceOf[Int]); cs.registerOutParameter(index, Types.INTEGER)
            }
            case GPInOut(v: Some[_], Types.VARCHAR) => {
                cs.setString(index, v.get.asInstanceOf[String]); cs.registerOutParameter(index, Types.VARCHAR)
            }
            case GPInOut(v: Some[_], Types.LONGVARCHAR) => {
                cs.setString(index, v.get.asInstanceOf[String]); cs.registerOutParameter(index, Types.LONGVARCHAR)
            }
            case GPInOut(v: Some[_], Types.CHAR) => {
                cs.setString(index, v.get.asInstanceOf[String].head.toString); cs.registerOutParameter(index, Types.CHAR)
            }
            case _ => { Logger(s"Failed to match GPProcedureParameter in executeFunction (IN): index $index (${parameter.toString})") }
        }
    }

    cs.execute()

    // Now, step through each of the parameters, and get the corresponding result from the execute statement. If there is
    // no result for the specified column (index), we'll basically end up getting a "nothing" back, which we strip out.

    index = 0

    val results: List[Any] = for (parameter <- ps.parameters) yield {
        index = index + 1
        parameter match {
            case GPOut(Types.NUMERIC) | GPOut(Types.DECIMAL) => cs.getBigDecimal(index)
            case GPOut(Types.BIGINT) => cs.getLong(index)
            case GPOut(Types.INTEGER) => cs.getInt(index)
            case GPOut(Types.VARCHAR | Types.LONGVARCHAR | Types.CHAR) => cs.getString(index)
            case GPInOut(v: Some[_], Types.NUMERIC | Types.DECIMAL) => cs.getInt(index)
            case GPInOut(v: Some[_], Types.BIGINT) => cs.getLong(index)
            case GPInOut(v: Some[_], Types.INTEGER) => cs.getInt(index)
            case GPInOut(v: Some[_], Types.VARCHAR | Types.LONGVARCHAR | Types.CHAR) => cs.getString(index)
            case _ => {
                Logger(s"Failed to match GPProcedureParameter in executeFunction (OUT): index $index (${parameter.toString})")
            }
        }
    }

    cs.close()

    // Return the function return parameters (there should always be one, the caller will get a List with as many return
    // parameters as we receive):

    results.filter(_ != (()))
}



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. रेल में एक ActiveRecord लेनदेन में एकाधिक रिकॉर्ड अपडेट करें

  2. पोस्टग्रेज के साथ sqlalchemy:उस तालिका में डालें जिसके कॉलम में कोष्ठक हों

  3. उपवर्गों पर हाइबरनेट में प्रति तालिका अलग अनुक्रम निर्दिष्ट करना

  4. PostgreSQL खाली सरणी के साथ अननेस्ट

  5. पोस्टग्रेज अप्सर्ट:नई और अपडेट की गई पंक्तियों के बीच अंतर करें