/*
   * Create a property with vocabulary term from the Edmx property
   */
  public static EMProperty createEMProperty(EdmProperty property) {
    EMProperty emProperty = new EMProperty(property.getName());
    if (property.isNullable()) {
      emProperty.addVocabularyTerm(new EMTerm(TermMandatory.TERM_NAME, "true"));
    }

    // Set the value type vocabulary term
    EdmType type = property.getType();
    if (type.equals(EdmSimpleType.DATETIME)) {
      emProperty.addVocabularyTerm(new EMTerm(TermValueType.TERM_NAME, TermValueType.TIMESTAMP));
    } else if (type.equals(EdmSimpleType.TIME)) {
      emProperty.addVocabularyTerm(new EMTerm(TermValueType.TERM_NAME, TermValueType.TIME));
    } else if (type.equals(EdmSimpleType.INT64)
        || type.equals(EdmSimpleType.INT32)
        || type.equals(EdmSimpleType.INT16)) {
      emProperty.addVocabularyTerm(
          new EMTerm(TermValueType.TERM_NAME, TermValueType.INTEGER_NUMBER));
    } else if (type.equals(EdmSimpleType.SINGLE)
        || type.equals(EdmSimpleType.DOUBLE)
        || type.equals(EdmSimpleType.DECIMAL)) {
      emProperty.addVocabularyTerm(new EMTerm(TermValueType.TERM_NAME, TermValueType.NUMBER));
    } else if (type.equals(EdmSimpleType.BOOLEAN)) {
      emProperty.addVocabularyTerm(new EMTerm(TermValueType.TERM_NAME, TermValueType.BOOLEAN));
    }
    return emProperty;
  }
  /**
   * JSONオブジェクトの値を取得する.
   *
   * @param event JsonEvent
   * @param ees エンティティセット型
   * @param name プロパティ名
   * @param jsr JsonStreamReader
   * @param entry JsonEntry
   * @return JsonObjectPropertyValue
   */
  protected JsonObjectPropertyValue getValue(
      JsonEvent event, EdmEntitySet ees, String name, JsonStreamReader jsr, JsonEntry entry) {
    JsonObjectPropertyValue rt = new JsonObjectPropertyValue();

    ensureStartObject(event);
    event = jsr.nextEvent();
    ensureStartProperty(event);

    // ComplexObjectであればエンティティタイプ定義からプロパティ定義を取得する
    EdmProperty eprop = entry.getEntityType().findProperty(name);

    if (eprop == null) {
      // プロパティがスキーマ定義上に存在しなければエラーとする
      throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
    } else {
      // スキーマ定義からComplexType定義を取得する
      EdmComplexType ct = metadata.findEdmComplexType(eprop.getType().getFullyQualifiedTypeName());

      if (null != ct) {
        // ComplexTypeが存在する場合は、パースを実施してComplexTypeObjectを取得する
        Settings s = new Settings(version, metadata, entitySetName, entityKey, null, false, ct);
        DcJsonComplexObjectFormatParser cofp = new DcJsonComplexObjectFormatParser(s);
        rt.complexObject = cofp.parseSingleObject(jsr, event);
      } else {
        // ComplexTypeがスキーマ定義上に存在しなければエラーとする
        throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
      }
    }

    ensureEndProperty(jsr.nextEvent());
    return rt;
  }
Exemple #3
0
  /**
   * Create an OEntityKey instance for the specified entity id
   *
   * @param edmDataServices edmDataServices
   * @param entity Entity set name
   * @param id Id
   * @return An OEntityKey instance
   * @throws Exception Error creating key
   */
  public static OEntityKey createEntityKey(
      EdmDataServices edmDataServices, String entitySetName, String id) throws Exception {
    // Lookup type of entity key (simple keys only)
    String keyType = null;
    EdmEntitySet entitySet = edmDataServices.getEdmEntitySet(entitySetName);
    if (entitySet != null) {
      EdmEntityType entityType = entitySet.getType();
      List<String> keys = entityType.getKeys();
      if (keys.size() == 1) {
        EdmProperty prop = entityType.findDeclaredProperty(keys.get(0));
        if (prop != null && prop.getType() != null) {
          keyType = prop.getType().getFullyQualifiedTypeName();
        }
      }
    }
    assert (keyType != null) : "Should not be possible to get this far and find no key type";

    // Create an entity key
    OEntityKey key = null;
    try {
      if (keyType.equals("Edm.Int64")) {
        key = OEntityKey.parse(id);
      } else if (keyType.equals("Edm.Int32")) {
        key = OEntityKey.parse(id);
      } else if (keyType.equals("Edm.DateTime")) {
        key = OEntityKey.parse(id);
      } else if (keyType.equals("Edm.Time")) {
        key = OEntityKey.parse(id);
      } else if (keyType.equals("Edm.String")) {
        key = OEntityKey.parse(id);
      }
    } catch (Exception e) {
      logger.warn(
          "Entity key type "
              + keyType
              + " is not supported by CommandHelper, trying OEntityKey.parse");
    }
    // could not parse the key, have one last attempt with OEntityKey create
    if (key == null) {
      try {
        if (keyType.equals("Edm.Int64")) {
          key = OEntityKey.create(Long.parseLong(id));
        } else if (keyType.equals("Edm.Int32")) {
          key = OEntityKey.create(Integer.parseInt(id));
        } else {
          key = OEntityKey.create(id);
        }
      } catch (Exception e) {
        logger.error("OEntityKey.parse failed to parse id [" + id + "]");
      }
    }
    if (key == null) throw new Exception("Entity key type " + id + " is not supported.");
    return key;
  }
/** ReceivedMessageのPort用Edm 定義体. */
public class ReceivedMessagePort extends ReceivedMessage {
  private ReceivedMessagePort() {
    super();
  }

  /** Schemaプロパティの定義体. */
  public static final EdmProperty.Builder P_SCHEMA =
      EdmProperty.newBuilder("Schema")
          .setType(EdmSimpleType.BOOLEAN)
          .setNullable(true)
          .setDefaultValue("false");

  /** EntityType Builder. */
  public static final EdmEntityType.Builder EDM_TYPE_BUILDER =
      EdmEntityType.newBuilder()
          .setNamespace(Common.EDM_NS_CELL_CTL)
          .setName(EDM_TYPE_NAME)
          .addProperties(
              Enumerable.create(
                      P_ID,
                      P_SCHEMA,
                      P_IN_REPLY_TO,
                      P_FROM,
                      P_MULTICAST_TO,
                      P_TYPE,
                      P_TITLE,
                      P_BODY,
                      P_PRIORITY,
                      P_STATUS,
                      P_REQUEST_RELATION,
                      P_REQUEST_RELATION_TARGET,
                      P_BOX_NAME,
                      Common.P_PUBLISHED,
                      Common.P_UPDATED)
                  .toList())
          .addKeys(P_ID.getName());
}
  /**
   * adds the property. This property can be a navigation property too. In this case a link will be
   * added. If it's the meta data the information will be added to the entry too.
   *
   * @param entry JsonEntry
   * @param ees EdmEntitySet
   * @param name PropertyName
   * @param jsr JsonStreamReader
   * @return EdmEntitySet
   */
  protected EdmEntitySet addProperty(
      JsonEntry entry, EdmEntitySet ees, String name, JsonStreamReader jsr) {

    JsonEvent event = jsr.nextEvent();

    if (event.isEndProperty()) {
      // scalar property
      EdmProperty ep = entry.getEntityType().findProperty(name);
      if (ep == null) {
        // OpenEntityTypeの場合は、プロパティを追加する
        NamespacedAnnotation<?> openType =
            findAnnotation(ees.getType(), null, Edm.EntityType.OpenType);
        if (openType != null && openType.getValue() == "true") {
          Object propValue = null;
          try {
            propValue = event.asEndProperty().getObject();
          } catch (NumberFormatException e) {
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name).reason(e);
          }

          // 型によって登録するEntityPropertyを変更する
          if (propValue instanceof Boolean) {
            entry.properties.add(
                JsonTypeConverter.parse(
                    name, (EdmSimpleType<?>) EdmSimpleType.BOOLEAN, propValue.toString()));
          } else if (propValue instanceof Double) {
            entry.properties.add(
                JsonTypeConverter.parse(
                    name, (EdmSimpleType<?>) EdmSimpleType.DOUBLE, propValue.toString()));
          } else {
            if (propValue == null) {
              entry.properties.add(
                  JsonTypeConverter.parse(name, (EdmSimpleType<?>) EdmSimpleType.STRING, null));
            } else {
              entry.properties.add(
                  JsonTypeConverter.parse(
                      name, (EdmSimpleType<?>) EdmSimpleType.STRING, propValue.toString()));
            }
          }
        } else {
          throw DcCoreException.OData.FIELED_INVALID_ERROR.params(
              "unknown property " + name + " for " + entry.getEntityType().getName());
        }
      } else {
        // StaticPropertyの値チェック
        String propValue = event.asEndProperty().getValue();
        if (propValue != null) {
          EdmType type = ep.getType();
          if (type.equals(EdmSimpleType.BOOLEAN) && !ODataUtils.validateBoolean(propValue)) {
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
          } else if (type.equals(EdmSimpleType.STRING) && !ODataUtils.validateString(propValue)) {
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
          } else if (type.equals(EdmSimpleType.DATETIME)) {
            if (!ODataUtils.validateDateTime(propValue)) {
              throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
            }
            if (Common.SYSUTCDATETIME.equals(propValue)) {
              String crrTime = String.valueOf(getCurrentTimeMillis());
              propValue = String.format("/Date(%s)/", crrTime);
            }
          } else if (type.equals(EdmSimpleType.SINGLE) && !ODataUtils.validateSingle(propValue)) {
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
          } else if (type.equals(EdmSimpleType.INT32) && !ODataUtils.validateInt32(propValue)) {
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
          } else if (type.equals(EdmSimpleType.DOUBLE) && !ODataUtils.validateDouble(propValue)) {
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
          }
        }
        if (ep.getType().isSimple()) {
          // シンプル型(文字列や数値など)であればプロパティに追加する
          entry.properties.add(
              JsonTypeConverter.parse(name, (EdmSimpleType<?>) ep.getType(), propValue));
        } else {
          if (propValue == null) {
            // ComplexType型で、値がnullの場合はエラーにしない
            entry.properties.add(
                JsonTypeConverter.parse(name, (EdmSimpleType<?>) EdmSimpleType.STRING, null));
          } else {
            // ComplexType型で、ComplexType型以外の値が指定された場合("aaa")はエラーとする
            throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
          }
        }
      }
    } else if (event.isStartObject()) {
      // JSONオブジェクトの場合は値を取得する
      JsonObjectPropertyValue val = getValue(event, ees, name, jsr, entry);

      if (val.complexObject != null) {
        // ComplexTypeデータであればプロパティに追加する
        entry.properties.add(
            OProperties.complex(
                name,
                (EdmComplexType) val.complexObject.getType(),
                val.complexObject.getProperties()));
      } else {
        // ComplexTypeデータ以外はエラーとする
        throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
      }
    } else if (event.isStartArray()) {
      // 配列オブジェクトの場合
      JsonObjectPropertyValue val = new JsonObjectPropertyValue();

      // スキーマ定義が存在してCollectionKindがNoneでなければ、配列としてパースする
      EdmProperty eprop = entry.getEntityType().findProperty(name);
      if (null != eprop && eprop.getCollectionKind() != CollectionKind.NONE) {
        val.collectionType = new EdmCollectionType(eprop.getCollectionKind(), eprop.getType());
        DcJsonCollectionFormatParser cfp =
            new DcJsonCollectionFormatParser(val.collectionType, this.metadata, name);
        val.collection = cfp.parseCollection(jsr);
      }

      // パースに成功した場合は、プロパティに追加する
      if (val.collectionType != null && val.collection != null) {
        entry.properties.add(OProperties.collection(name, val.collectionType, val.collection));
      } else {
        throw DcCoreException.OData.REQUEST_FIELD_FORMAT_ERROR.params(name);
      }
    } else {
      throw DcCoreException.OData.INVALID_TYPE_ERROR.params(name);
    }
    return ees;
  }
  private static void buildFunctionImports(MetadataStore metadataStore, List<Builder> edmSchemas) {
    for (Schema schema : metadataStore.getSchemaList()) {

      EdmSchema.Builder odataSchema = findSchema(edmSchemas, schema.getName());
      EdmEntityContainer.Builder entityContainer =
          findEntityContainer(edmSchemas, schema.getName());

      // procedures
      for (Procedure proc : schema.getProcedures().values()) {
        EdmFunctionImport.Builder edmProcedure = EdmFunctionImport.newBuilder();
        edmProcedure.setName(proc.getName());
        String httpMethod = "POST";

        for (ProcedureParameter pp : proc.getParameters()) {
          if (pp.getName().equals("return")) {
            httpMethod = "GET";
            edmProcedure.setReturnType(
                ODataTypeManager.odataType(pp.getDatatype().getRuntimeTypeName()));
            continue;
          }

          EdmFunctionParameter.Builder param = EdmFunctionParameter.newBuilder();
          param.setName(pp.getName());
          param.setType(ODataTypeManager.odataType(pp.getDatatype().getRuntimeTypeName()));

          if (pp.getType() == ProcedureParameter.Type.In) {
            param.setMode(Mode.In);
          } else if (pp.getType() == ProcedureParameter.Type.InOut) {
            param.setMode(Mode.InOut);
          } else if (pp.getType() == ProcedureParameter.Type.Out) {
            param.setMode(Mode.Out);
          }

          param.setNullable(pp.getNullType() == NullType.Nullable);
          edmProcedure.addParameters(param);
        }

        // add a complex type for return resultset.
        ColumnSet<Procedure> returnColumns = proc.getResultSet();
        if (returnColumns != null) {
          httpMethod = "GET";
          EdmComplexType.Builder complexType = EdmComplexType.newBuilder();
          complexType.setName(proc.getName() + "_" + returnColumns.getName());
          complexType.setNamespace(schema.getName());
          for (Column c : returnColumns.getColumns()) {
            EdmProperty.Builder property =
                EdmProperty.newBuilder(c.getName())
                    .setType(ODataTypeManager.odataType(c.getDatatype().getRuntimeTypeName()))
                    .setNullable(c.getNullType() == NullType.Nullable);
            if (c.getDatatype()
                .getRuntimeTypeName()
                .equals(DataTypeManager.DefaultDataTypes.STRING)) {
              property
                  .setFixedLength(c.isFixedLength())
                  .setMaxLength(c.getLength())
                  .setUnicode(true);
            }
            complexType.addProperties(property);
          }
          odataSchema.addComplexTypes(complexType);
          edmProcedure.setIsCollection(true);
          edmProcedure.setReturnType(
              EdmCollectionType.newBuilder()
                  .setCollectionType(complexType)
                  .setKind(CollectionKind.Collection));
        }
        edmProcedure.setHttpMethod(httpMethod);
        entityContainer.addFunctionImports(edmProcedure);
      }
    }
  }
  private static void buildEntityTypes(
      MetadataStore metadataStore, List<EdmSchema.Builder> edmSchemas) {
    for (Schema schema : metadataStore.getSchemaList()) {

      List<EdmEntitySet.Builder> entitySets = new ArrayList<EdmEntitySet.Builder>();
      List<EdmEntityType.Builder> entityTypes = new ArrayList<EdmEntityType.Builder>();

      for (Table table : schema.getTables().values()) {

        KeyRecord primaryKey = table.getPrimaryKey();
        List<KeyRecord> uniques = table.getUniqueKeys();
        if (primaryKey == null && uniques.isEmpty()) {
          LogManager.logDetail(
              LogConstants.CTX_ODATA,
              ODataPlugin.Util.gs(ODataPlugin.Event.TEIID16002, table.getFullName()));
          continue;
        }

        EdmEntityType.Builder entityType =
            EdmEntityType.newBuilder().setName(table.getName()).setNamespace(schema.getName());

        // adding key
        if (primaryKey != null) {
          for (Column c : primaryKey.getColumns()) {
            entityType.addKeys(c.getName());
          }
        } else {
          for (Column c : uniques.get(0).getColumns()) {
            entityType.addKeys(c.getName());
          }
        }

        // adding properties
        for (Column c : table.getColumns()) {
          EdmProperty.Builder property =
              EdmProperty.newBuilder(c.getName())
                  .setType(ODataTypeManager.odataType(c.getDatatype().getRuntimeTypeName()))
                  .setNullable(c.getNullType() == NullType.Nullable);
          if (c.getDatatype()
              .getRuntimeTypeName()
              .equals(DataTypeManager.DefaultDataTypes.STRING)) {
            property.setFixedLength(c.isFixedLength()).setMaxLength(c.getLength()).setUnicode(true);
          }
          entityType.addProperties(property);
        }

        // entity set one for one entity type
        EdmEntitySet.Builder entitySet =
            EdmEntitySet.newBuilder().setName(table.getName()).setEntityType(entityType);

        entityType.setNamespace(schema.getName());
        entitySets.add(entitySet);

        // add enitity types for entity schema
        entityTypes.add(entityType);
      }

      // entity container is holder entity sets, association sets, function imports
      EdmEntityContainer.Builder entityContainer =
          EdmEntityContainer.newBuilder()
              .setName(schema.getName())
              .setIsDefault(false)
              .addEntitySets(entitySets);

      // build entity schema
      EdmSchema.Builder modelSchema =
          EdmSchema.newBuilder()
              .setNamespace(schema.getName())
              .addEntityTypes(entityTypes)
              .addEntityContainers(entityContainer);

      edmSchemas.add(modelSchema);
    }
  }
  private static void writeProperties(Iterable<EdmProperty> properties, XMLWriter2 writer) {
    for (EdmProperty prop : properties) {
      writer.startElement(new QName2("Property"));

      writer.writeAttribute("Name", prop.getName());
      writer.writeAttribute("Type", prop.getType().getFullyQualifiedTypeName());
      writer.writeAttribute("Nullable", Boolean.toString(prop.isNullable()));
      if (prop.getMaxLength() != null) {
        writer.writeAttribute("MaxLength", Integer.toString(prop.getMaxLength()));
      }
      if (!prop.getCollectionKind().equals(CollectionKind.NONE)) {
        writer.writeAttribute("CollectionKind", prop.getCollectionKind().toString());
      }
      if (prop.getDefaultValue() != null) {
        writer.writeAttribute("DefaultValue", prop.getDefaultValue());
      }
      if (prop.getPrecision() != null) {
        writer.writeAttribute("Precision", Integer.toString(prop.getPrecision()));
      }
      if (prop.getScale() != null) {
        writer.writeAttribute("Scale", Integer.toString(prop.getPrecision()));
      }
      writeAnnotationAttributes(prop, writer);
      writeAnnotationElements(prop, writer);
      writer.endElement("Property");
    }
  }
  private EdmProperty.Builder parseEdmProperty(XMLEventReader2 reader, XMLEvent2 event) {
    List<EdmAnnotation<?>> annotElements = new ArrayList<EdmAnnotation<?>>();
    StartElement2 startElement = event.asStartElement();
    String propertyName = getAttributeValueIfExists(startElement, "Name");
    String propertyType = getAttributeValueIfExists(startElement, "Type");
    String propertyNullable = getAttributeValueIfExists(startElement, "Nullable");
    String maxLength = getAttributeValueIfExists(startElement, "MaxLength");
    String unicode = getAttributeValueIfExists(startElement, "Unicode");
    String fixedLength = getAttributeValueIfExists(startElement, "FixedLength");
    String collation = getAttributeValueIfExists(startElement, "Collation");
    String collectionKindS = getAttributeValueIfExists(startElement, "CollectionKind");
    CollectionKind ckind = CollectionKind.NONE;
    if (collectionKindS != null) {
      ckind = Enum.valueOf(CollectionKind.class, collectionKindS);
    }
    String defaultValue = getAttributeValueIfExists(startElement, "DefaultValue");
    String precision = getAttributeValueIfExists(startElement, "Precision");
    String scale = getAttributeValueIfExists(startElement, "Scale");

    String storeGeneratedPattern =
        getAttributeValueIfExists(
            startElement, new QName2(NS_EDMANNOTATION, "StoreGeneratedPattern"));
    String concurrencyMode = getAttributeValueIfExists(startElement, "ConcurrencyMode");

    String mimeType = getAttributeValueIfExists(startElement, M_MIMETYPE);
    String fcTargetPath = getAttributeValueIfExists(startElement, M_FC_TARGETPATH);
    String fcContentKind = getAttributeValueIfExists(startElement, M_FC_CONTENTKIND);
    String fcKeepInContent = getAttributeValueIfExists(startElement, M_FC_KEEPINCONTENT);
    String fcEpmContentKind = getAttributeValueIfExists(startElement, M_FC_EPMCONTENTKIND);
    String fcEpmKeepInContent = getAttributeValueIfExists(startElement, M_FC_EPMKEEPINCONTENT);
    String fcNsPrefix = getAttributeValueIfExists(startElement, M_FC_NSPREFIX);
    String fcNsUri = getAttributeValueIfExists(startElement, M_FC_NSURI);

    while (reader.hasNext()) {
      XMLEvent2 event2 = reader.nextEvent();

      if (event2.isStartElement()) {
        EdmAnnotation<?> anElement = getAnnotationElements(event2, reader);
        if (anElement != null) {
          annotElements.add(anElement);
        }
      }

      if (isEndElement(event2, startElement.getName())) {
        return EdmProperty.newBuilder(propertyName)
            .setType(EdmType.newDeferredBuilder(propertyType, dataServices))
            .setNullable("true".equalsIgnoreCase(propertyNullable))
            .setMaxLength(
                maxLength == null
                    ? null
                    : maxLength.equals("Max") ? Integer.MAX_VALUE : Integer.parseInt(maxLength))
            .setUnicode(unicode == null ? null : "true".equalsIgnoreCase(unicode))
            .setFixedLength(fixedLength == null ? null : "true".equalsIgnoreCase(fixedLength))
            .setCollation(collation)
            .setConcurrencyMode(concurrencyMode)
            .setStoreGeneratedPattern(storeGeneratedPattern)
            .setMimeType(mimeType)
            .setFcTargetPath(fcTargetPath)
            .setFcContentKind(fcContentKind)
            .setFcKeepInContent(fcKeepInContent)
            .setFcEpmContentKind(fcEpmContentKind)
            .setFcEpmKeepInContent(fcEpmKeepInContent)
            .setFcNsPrefix(fcNsPrefix)
            .setFcNsUri(fcNsUri)
            .setCollectionKind(ckind)
            .setDefaultValue(defaultValue)
            .setPrecision(precision == null ? null : Integer.parseInt(precision))
            .setScale(scale == null ? null : Integer.parseInt(scale))
            .setAnnotations(getAnnotations(startElement))
            .setAnnotationElements(annotElements.isEmpty() ? null : annotElements);
      }
    }
    throw new UnsupportedOperationException();
  }
  @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) {
        }
      }
    }
  }
  @Override
  public BaseResponse executeCall(String sql, List<SQLParam> parameters, EdmType returnType) {
    ConnectionImpl connection = null;
    try {
      LogManager.logDetail(LogConstants.CTX_ODATA, "Teiid-Query:", sql); // $NON-NLS-1$
      connection = getConnection();
      final CallableStatementImpl stmt = connection.prepareCall(sql);

      int i = 1;
      if (returnType != null && returnType.isSimple()) {
        stmt.registerOutParameter(
            i++,
            JDBCSQLTypeInfo.getSQLType(
                ODataTypeManager.teiidType(returnType.getFullyQualifiedTypeName())));
      }

      if (!parameters.isEmpty()) {
        for (SQLParam param : parameters) {
          stmt.setObject(i++, param.value, param.sqlType);
        }
      }

      boolean results = stmt.execute();
      if (results) {
        final ResultSet rs = stmt.getResultSet();
        OCollection.Builder resultRows =
            OCollections.newBuilder(
                (EdmComplexType) ((EdmCollectionType) returnType).getItemType());
        while (rs.next()) {
          int idx = 1;
          List<OProperty<?>> row = new ArrayList<OProperty<?>>();
          Iterator<EdmProperty> props =
              ((EdmComplexType) ((EdmCollectionType) returnType).getItemType())
                  .getProperties()
                  .iterator();
          while (props.hasNext()) {
            EdmProperty prop = props.next();
            row.add(
                buildPropery(
                    prop.getName(),
                    prop.getType(),
                    rs.getObject(idx++),
                    invalidCharacterReplacement));
          }
          OComplexObject erow =
              OComplexObjects.create(
                  (EdmComplexType) ((EdmCollectionType) returnType).getItemType(), row);
          resultRows.add(erow);
        }
        String collectionName = returnType.getFullyQualifiedTypeName();
        collectionName = collectionName.replace("(", "_"); // $NON-NLS-1$ //$NON-NLS-2$
        collectionName = collectionName.replace(")", "_"); // $NON-NLS-1$ //$NON-NLS-2$
        return Responses.collection(resultRows.build(), null, null, null, collectionName);
      }

      if (returnType != null) {
        Object result = stmt.getObject(1);
        OProperty prop =
            buildPropery("return", returnType, result, invalidCharacterReplacement); // $NON-NLS-1$
        return Responses.property(prop);
      }
      return null;
    } catch (Exception e) {
      throw new ServerErrorException(e.getMessage(), e);
    } finally {
      if (connection != null) {
        try {
          connection.close();
        } catch (SQLException e) {
        }
      }
    }
  }