@Override
  public VDBMetaData getVDB() {
    ConnectionImpl connection = null;
    if (this.vdb == null) {
      try {
        connection = getConnection();
        LocalServerConnection lsc = (LocalServerConnection) connection.getServerConnection();
        VDBMetaData vdb = lsc.getWorkContext().getVDB();
        if (vdb == null) {
          throw new NotFoundException(
              ODataPlugin.Util.gs(ODataPlugin.Event.TEIID16001, this.vdbName, this.vdbVersion));
        }
        this.vdb = vdb;
      } catch (SQLException e) {
        throw new ServerErrorException(e.getMessage(), e);
      } finally {
        if (connection != null) {
          try {
            connection.close();
          } catch (SQLException e) {

          }
        }
      }
    }
    return this.vdb;
  }
  @Override
  public EntityList executeSQL(
      Query query,
      List<SQLParam> parameters,
      EdmEntitySet entitySet,
      LinkedHashMap<String, Boolean> projectedColumns,
      QueryInfo queryInfo) {
    ConnectionImpl connection = null;
    try {
      boolean cache = queryInfo != null && this.batchSize > 0;
      if (cache) {
        CacheHint hint = new CacheHint();
        hint.setTtl(this.cacheTime);
        hint.setScope(CacheDirective.Scope.USER);
        hint.setMinRows(Long.valueOf(this.batchSize));
        query.setCacheHint(hint);
      }

      boolean getCount = false;
      if (queryInfo != null) {
        getCount = queryInfo.inlineCount == InlineCount.ALLPAGES;
        if (!getCount && (queryInfo.top != null || queryInfo.skip != null)) {
          if (queryInfo.top != null && queryInfo.skip != null) {
            query.setLimit(new Limit(new Constant(queryInfo.skip), new Constant(queryInfo.top)));
          } else if (queryInfo.top != null) {
            query.setLimit(new Limit(new Constant(0), new Constant(queryInfo.top)));
          }
        }
      }

      connection = getConnection();
      String sessionId = connection.getServerConnection().getLogonResult().getSessionID();

      String skipToken = null;
      if (queryInfo != null && queryInfo.skipToken != null) {
        skipToken = queryInfo.skipToken;
        if (cache) {
          int idx = queryInfo.skipToken.indexOf(DELIMITER);
          sessionId = queryInfo.skipToken.substring(0, idx);
          skipToken = queryInfo.skipToken.substring(idx + 2);
        }
      }
      String sql = query.toString();
      if (cache) {
        sql += " /* " + sessionId + " */"; // $NON-NLS-1$ //$NON-NLS-2$
      }
      LogManager.logDetail(LogConstants.CTX_ODATA, "Teiid-Query:", sql); // $NON-NLS-1$

      final PreparedStatement stmt =
          connection.prepareStatement(
              sql,
              cache ? ResultSet.TYPE_SCROLL_INSENSITIVE : ResultSet.TYPE_FORWARD_ONLY,
              ResultSet.CONCUR_READ_ONLY);
      if (parameters != null && !parameters.isEmpty()) {
        for (int i = 0; i < parameters.size(); i++) {
          stmt.setObject(i + 1, parameters.get(i).value, parameters.get(i).sqlType);
        }
      }

      final ResultSet rs = stmt.executeQuery();

      if (projectedColumns == null) {
        projectedColumns = new LinkedHashMap<String, Boolean>();
        for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
          projectedColumns.put(rs.getMetaData().getColumnLabel(i + 1), Boolean.TRUE);
        }
      }

      EntityList result = new EntityList(invalidCharacterReplacement);

      HashMap<String, EdmProperty> propertyTypes = new HashMap<String, EdmProperty>();

      EdmEntityType entityType = entitySet.getType();
      Iterator<EdmProperty> propIter = entityType.getProperties().iterator();
      while (propIter.hasNext()) {
        EdmProperty prop = propIter.next();
        propertyTypes.put(prop.getName(), prop);
      }

      // skip to the initial position
      int count = 0;
      int skipSize = 0;
      // skip based upon the skip value
      if (getCount && queryInfo.skip != null) {
        skipSize = queryInfo.skip;
      }
      // skip based upon the skipToken
      if (skipToken != null) {
        skipSize += Integer.parseInt(skipToken);
      }
      if (skipSize > 0) {
        count += skip(cache, rs, skipSize);
      }

      // determine the number of records to return
      int size = batchSize;
      int top = Integer.MAX_VALUE;
      if (getCount && queryInfo.top != null) {
        top = queryInfo.top;
        size = top;
        if (batchSize > 0) {
          size = Math.min(batchSize, size);
        }
      } else if (size < 1) {
        size = Integer.MAX_VALUE;
      }

      // build the results
      for (int i = 0; i < size; i++) {
        if (!rs.next()) {
          break;
        }
        count++;
        result.addEntity(rs, propertyTypes, projectedColumns, entitySet);
      }

      // set the count
      if (getCount) {
        if (!cache) {
          while (rs.next()) {
            count++;
          }
        } else {
          rs.last();
          count = rs.getRow();
        }
      }
      result.setCount(count);

      // set the skipToken if needed
      if (cache && result.size() == this.batchSize) {
        int end = skipSize + result.size();
        if (getCount) {
          if (end < Math.min(top, count)) {
            result.setNextToken(nextToken(cache, sessionId, end));
          }
        } else if (rs.next()) {
          result.setNextToken(nextToken(cache, sessionId, end));
          // will force the entry to cache or is effectively a no-op when already cached
          rs.last();
        }
      }
      return result;
    } catch (Exception e) {
      throw new ServerErrorException(e.getMessage(), e);
    } finally {
      if (connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
        }
      }
    }
  }