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

com.yahoo.maha.executor.postgres.PostgresQueryExecutor.scala Maven / Gradle / Ivy

// Copyright 2017, Yahoo Holdings Inc.
// Licensed under the terms of the Apache License 2.0. Please see LICENSE file in project root for terms.
package com.yahoo.maha.executor.postgres

import java.sql.ResultSetMetaData

import com.yahoo.maha.core._
import com.yahoo.maha.core.query._
import com.yahoo.maha.jdbc.JdbcConnection
import grizzled.slf4j.Logging

import scala.util.{Failure, Try}

/**
 * Created by hiral on 12/22/15.
 */

class PostgresQueryExecutor(jdbcConnection: JdbcConnection, lifecycleListener: ExecutionLifecycleListener) extends QueryExecutor with Logging {
  val engine: Engine = PostgresEngine

  val columnValueExtractor = new ColumnValueExtractor

  def execute[T <: RowList](query: Query, rowList: T, queryAttributes: QueryAttributes) : QueryResult[T] = {
    val acquiredQueryAttributes = lifecycleListener.acquired(query, queryAttributes)
    val debugEnabled = query.queryContext.requestModel.isDebugEnabled
    if(!acceptEngine(query.engine)) {
      throw new UnsupportedOperationException(s"PostgresQueryExecutor does not support query with engine=${query.engine}")
    } else {
      var rowCount = 0
      rowList match {
        //if we have a indexed row list that's populated, we need to perform join
        case rl if rl.isInstanceOf[IndexedRowList] =>
          //do default row processing
          val irl = rl.asInstanceOf[IndexedRowList]
          val columnIndexMap = new collection.mutable.HashMap[String, Int]
          val aliasColumnMap = query.aliasColumnMap
          var index = -1
          val indexColumn = aliasColumnMap(irl.rowGrouping.indexAlias)

          if(debugEnabled) {
            info(s"Running query : ${query.asString}")
          }
          val result : Try[Unit] = jdbcConnection.queryForObject(query.asString) { resultSet =>
            if (resultSet.next()) {
              var metaData: ResultSetMetaData = null
              if (metaData == null) {
                metaData = resultSet.getMetaData
                var count = 1
                while (count <= metaData.getColumnCount) {
                  //get alias
                  val alias = metaData.getColumnLabel(count)
                  if (alias == irl.rowGrouping.indexAlias) {
                    index = count
                    columnIndexMap += alias -> count
                  } else {
                    columnIndexMap += alias -> count
                  }
                  if (debugEnabled) {
                    info(s"metaData index=$count label=$alias")
                  }
                  count += 1
                }
                if (debugEnabled) {
                  info(s"columnIndexMap from metaData ${columnIndexMap.toList.sortBy(_._1).mkString("\n", "\n", "\n")}")
                  info(s"aliasColumnMap from query ${aliasColumnMap.mapValues(_.name).toList.sortBy(_._1).mkString("\n", "\n", "\n")}")
                }
              }


              do {
                //get existing index row or create new one
                val rowSet = {
                  val indexValue = columnValueExtractor.getColumnValue(index, indexColumn, resultSet)
                  val rowSet = irl.getRowByIndex(RowGrouping(indexValue.toString, List(indexValue.toString)))
                  //no row, create one
                  if(rowSet.isEmpty) {
                    val r = irl.newRow
                    r.addValue(irl.rowGrouping.indexAlias, indexValue)
                    irl.updateRow(r)
                    Set(r)
                  } else {
                    rowSet
                  }
                }

                val aliasValueMap =
                  for {
                    (alias, column) <- aliasColumnMap
                  } yield {
                    val index = columnIndexMap(alias)
                    val value = columnValueExtractor.getColumnValue(index, column, resultSet)
                    (alias, value)
                  }

                rowSet.foreach {
                  row =>
                    aliasValueMap.foreach {
                      entry =>
                        row.addValue(entry._1, entry._2)
                    }
                }
                rowCount += 1
              } while (resultSet.next())
              if(debugEnabled) {
                info(s"rowCount = $rowCount, rowList.size = ${irl.size}, rowList.updatedSize = ${irl.updatedSize}")
              }
            }
          }
          result match {
            case Failure(e) =>
              Try(lifecycleListener.failed(query, acquiredQueryAttributes, e))
              error(s"Failed query : ${query.asString}")
              QueryResult(rl, acquiredQueryAttributes, QueryResultStatus.FAILURE, Option(e))
            case _ =>
              QueryResult(rl, lifecycleListener.completed(query, acquiredQueryAttributes), QueryResultStatus.SUCCESS)
          }
        case rl if rl.isInstanceOf[QueryRowList] =>
          val qrl = rl.asInstanceOf[QueryRowList]
          var metaData : ResultSetMetaData = null
          val columnIndexMap = new collection.mutable.HashMap[String, Int]
          val aliasColumnMap = query.aliasColumnMap
          if(debugEnabled) {
            info(s"Running query : ${query.asString}")
          }
          val result : Try[Unit] = jdbcConnection.queryForObject(query.asString) { resultSet =>
            if (resultSet.next()) {
              if (metaData == null) {
                metaData = resultSet.getMetaData
                var count = 1
                while (count <= metaData.getColumnCount) {
                  //get alias
                  val alias = metaData.getColumnLabel(count)
                  columnIndexMap += alias -> count
                  if (debugEnabled) {
                    info(s"metaData index=$count label=$alias")
                  }
                  count += 1
                }
                if (debugEnabled) {
                  info(s"columnIndexMap from metaData ${columnIndexMap.toList.sortBy(_._1).mkString("\n", "\n", "\n")}")
                  info(s"aliasColumnMap from query ${aliasColumnMap.mapValues(_.name).toList.sortBy(_._1).mkString("\n", "\n", "\n")}")
                }
              }

              //process all columns
              do {
                val row = qrl.newRow
                for {
                  (alias, column) <- aliasColumnMap
                } {
                  val index = columnIndexMap(alias)
                  val value = columnValueExtractor.getColumnValue(index, column, resultSet)
                  row.addValue(alias, value)
                }
                qrl.addRow(row)
                rowCount += 1
              } while (resultSet.next())
              if(debugEnabled) {
                info(s"rowCount = $rowCount")
              }
            }
          }
          result match {
            case Failure(e) =>
              Try(lifecycleListener.failed(query, acquiredQueryAttributes, e))
              error(s"Failed query : ${query.asString}")
              QueryResult(rl, acquiredQueryAttributes, QueryResultStatus.FAILURE, Option(e))
            case _ =>
              QueryResult(rl, lifecycleListener.completed(query, acquiredQueryAttributes), QueryResultStatus.SUCCESS)
          }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy