/* // // Licensed to Benedikt Kämpgen under one or more contributor license // agreements. See the NOTICE file distributed with this work for // additional information regarding copyright ownership. // // Benedikt Kämpgen licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except in // compliance with the License. You may obtain a copy of the License at: // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ package org.olap4j.driver.olap4ld; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.olap4j.CellSetListener; import org.olap4j.OlapConnection; import org.olap4j.OlapDatabaseMetaData; import org.olap4j.OlapException; import org.olap4j.driver.olap4ld.Olap4ldConnection.Context; import org.olap4j.driver.olap4ld.Olap4ldConnection.Handler; import org.olap4j.driver.olap4ld.Olap4ldConnection.MetadataRequest; import org.olap4j.driver.olap4ld.helper.LdHelper; import org.olap4j.driver.olap4ld.helper.Olap4ldLinkedDataUtil; import org.olap4j.driver.olap4ld.linkeddata.Restrictions; import org.olap4j.impl.Named; import org.olap4j.impl.Olap4jUtil; import org.olap4j.metadata.Member; import org.olap4j.metadata.Member.TreeOp; import org.semanticweb.yars.nx.Node; /** * Implementation of {@link org.olap4j.OlapDatabaseMetaData} for XML/A * providers. * * <p> * This class has sub-classes which implement JDBC 3.0 and JDBC 4.0 APIs; it is * instantiated using {@link Factory#newDatabaseMetaData}. * </p> * * @author jhyde, bkaempgen * @version $Id: XmlaOlap4jDatabaseMetaData.java 455 2011-05-24 10:01:26Z jhyde * $ * @since May 23, 2007 */ abstract class Olap4ldDatabaseMetaData implements OlapDatabaseMetaData { final Olap4ldConnection olap4jConnection; /** * Creates an XmlaOlap4jDatabaseMetaData. * * <p> * Note that this constructor should make zero non-trivial calls, which * could cause deadlocks due to java.sql.DriverManager synchronization * issues. * * @param olap4jConnection * Connection */ Olap4ldDatabaseMetaData(Olap4ldConnection olap4jConnection) { this.olap4jConnection = olap4jConnection; } /** * Own class for returning metadata (without overrides). * * @param metadataRequest * @param patternValues * @return * @throws OlapException */ private ResultSet getMetadataLd( Olap4ldConnection.MetadataRequest metadataRequest, Object... patternValues) throws OlapException { // create empty overrides. final Map<Olap4ldConnection.MetadataColumn, String> overrides = Collections .emptyMap(); // return getMetadata(metadataRequest, overrides, patternValues); return getMetadataLd(metadataRequest, overrides, patternValues); } /** * Executes a metadata query and returns the result as a JDBC * {@link ResultSet}. * * Here, three functionalities are implemented: * * - executeMetadataRequestOnLd works only on filter values and context * (which is empty) - after executeMetadataRequestOnLd, we filter for wild * cards - we override values - and we set values after transforming them * into MDX compliant format * * @param metadataRequest * Name of the metadata request. Corresponds to the XMLA method * name, e.g. "MDSCHEMA_CUBES" * * @param overrides * Map of metadata columns to forced values. Used to override the * value returned by the server for a list of columns. * * @param patternValues * Array of alternating parameter name and value pairs. If the * parameter value is null, it is ignored. * * @return Result set of metadata * * @throws org.olap4j.OlapException * on error */ @SuppressWarnings("unused") private ResultSet getMetadataLd( Olap4ldConnection.MetadataRequest metadataRequest, Map<Olap4ldConnection.MetadataColumn, String> overrides, Object... patternValues) throws OlapException { // Since pattern values oscillate between name and value, it needs to be // modulo 2 = 0 assert patternValues.length % 2 == 0; // Context is simply the connection final Olap4ldConnection.Context context = new Olap4ldConnection.Context( olap4jConnection, null, null, null, null, null, null, null); /* * Here, all patterns are gone through and (possibly sql) restrictions * are created * * In LD, we don't have such sql, therefore difficult. */ // For filter values List<String> patternValueList = new ArrayList<String>(); // For wildcard values Map<String, Matcher> predicateList = new HashMap<String, Matcher>(); for (int i = 0; i < patternValues.length; i += 2) { String name = (String) patternValues[i]; assert metadataRequest.getColumn(name) != null : "Request '" + metadataRequest + "' does not support column '" + name + "'"; Object value = patternValues[i + 1]; // Now, any result should match this value if (value == null) { // ignore, no restriction } else if (value instanceof Wildcard) { final Wildcard wildcard = (Wildcard) value; // For now, I switch off wildcards. if (true || (wildcard.pattern.indexOf('%') < 0 && wildcard.pattern .indexOf('_') < 0)) { // If no wildcard characters are used, simply use pattern patternValueList.add(name); patternValueList.add(wildcard.pattern); } else { /* * If wildcard is used, create java regex. Here, not XMLA is * doing the filtering, but we are doing it hereafter. */ String regexp = Olap4jUtil.wildcardToRegexp(Collections .singletonList(wildcard.pattern)); final Matcher matcher = Pattern.compile(regexp).matcher(""); predicateList.put(name, matcher); } } else { patternValueList.add(name); patternValueList.add((String) value); } } String[] restrictions = patternValueList.toArray(new String[patternValueList .size()]); /* * Specification of those metadata requests, see MetaDataRequest, * further below */ /* * TODO: We should throw proper OLAP execptions coming from the engine, * e.g. (see above): * * throw getHelper().createException( "XMLA provider gave exception: " + * XmlaOlap4jUtil.prettyPrint(fault) + "\n" + "Request was:\n" + * request); */ // Restrictions are wrapped in own object Restrictions myRestrictionsObject = new Restrictions(restrictions); // Request was created before, here, it is generated and then executed. List<Node[]> root = executeMetadataRequestOnLdce(context, metadataRequest, myRestrictionsObject); // String request = olap4jConnection.generateRequest(context, // metadataRequest, // patternValueList.toArray(new String[patternValueList.size()])); // // // Get XML // final Element root = // olap4jConnection.executeMetadataRequest(request); // Now, the results are worked with List<List<Object>> rowList = new ArrayList<List<Object>>(); boolean isFirst = true; Map<String, Integer> mapFields = new HashMap<String, Integer>(); rowLoop: for (Node[] row : root) { // We do not need to ignore any of the rows apart from the first // The first Node gives the fields if (isFirst) { mapFields = Olap4ldLinkedDataUtil.getNodeResultFields(row); isFirst = false; continue; } final ArrayList<Object> valueList = new ArrayList<Object>(); // Here, we simply check on the wildcard patterns for (Map.Entry<String, Matcher> entry : predicateList.entrySet()) { // For each pattern for columns final String column = entry.getKey(); // final String value = XmlaOlap4jUtil.stringElement(row, // column); /* * MetadataRequest uses certain column names which are also * returned by our LD. If not returned, we simply put in an * empty value. * * Existing values we convert into MDX format. */ String columName = "?" + column; final String value; if (mapFields.containsKey(columName)) { int index = mapFields.get(columName); // We convert every value into MDX format (no exceptions) value = Olap4ldLinkedDataUtil.convertNodeToMDX(row[index]); } else { value = ""; } final Matcher matcher = entry.getValue(); // If any matching does not succeed (if pattern does not match), // we // jump further processing. if (!matcher.reset(value).matches()) { continue rowLoop; } else { // in this case we continue with this row } } // For each column that is required, either override it, set it or // set it to "". for (Olap4ldConnection.MetadataColumn column : metadataRequest.columns) { // override possible values if (overrides.containsKey(column)) { valueList.add(overrides.get(column)); } else { // Get the value as used by xmla // final String value = XmlaOlap4jUtil.stringElement(row, // column.xmlaName); // MetadataRequest uses certain column names which are also // returned by our LD String columName = "?" + column.name; final String value; if (mapFields.containsKey(columName)) { int index = mapFields.get(columName); value = Olap4ldLinkedDataUtil.convertNodeToMDX(row[index]); } else { value = ""; } valueList.add(value); } } rowList.add(valueList); } // Create headers for the result row List<String> headerList = new ArrayList<String>(); for (Olap4ldConnection.MetadataColumn column : metadataRequest.columns) { headerList.add(column.name); } return olap4jConnection.factory.newFixedResultSet(olap4jConnection, headerList, rowList); } /** * Converts a string to a wildcard object. * * @param pattern * String pattern * @return wildcard object, or null if pattern was null */ private Wildcard wildcard(String pattern) { return pattern == null ? null : new Wildcard(pattern); } // implement DatabaseMetaData public boolean allProceduresAreCallable() throws SQLException { throw new UnsupportedOperationException(); } public boolean allTablesAreSelectable() throws SQLException { throw new UnsupportedOperationException(); } public String getURL() throws SQLException { return olap4jConnection.getURL(); } public String getUserName() throws SQLException { return ""; //throw new UnsupportedOperationException(); } public boolean isReadOnly() throws SQLException { // olap4j does not currently support writeback return true; } public boolean nullsAreSortedHigh() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullsAreSortedLow() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullsAreSortedAtStart() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullsAreSortedAtEnd() throws SQLException { throw new UnsupportedOperationException(); } /** * Uses getDatabaseProperties. * * Just take the first of our LinkedDataEngine. * */ public String getDatabaseProductName() throws SQLException { return Olap4ldLinkedDataUtil.convertNodeToMDX(olap4jConnection.myLinkedData .getDatabases(null).get(0)[0]); // final ResultSet rs = this.getDatabaseProperties(null, null); // try { // while (rs.next()) { // if (rs.getString(XmlaConstants.Literal.PROPERTY_NAME.name()) // .equals("ProviderName")) { // return rs.getString("PROPERTY_VALUE"); // } // } // return ""; // } finally { // rs.close(); // } } public String getDatabaseProductVersion() throws SQLException { return Olap4ldLinkedDataUtil.convertNodeToMDX(olap4jConnection.myLinkedData .getDatabases(null).get(0)[3]); // final ResultSet rs = this.getDatabaseProperties(null, null); // try { // while (rs.next()) { // if (rs.getString(XmlaConstants.Literal.PROPERTY_NAME.name()) // .equals("ProviderVersion")) { // return rs.getString("PROPERTY_VALUE"); // } // } // return ""; // } finally { // rs.close(); // } } public String getDriverName() throws SQLException { return olap4jConnection.driver.getName(); } public String getDriverVersion() throws SQLException { return olap4jConnection.driver.getVersion(); } public int getDriverMajorVersion() { return olap4jConnection.driver.getMajorVersion(); } public int getDriverMinorVersion() { return olap4jConnection.driver.getMinorVersion(); } public boolean usesLocalFiles() throws SQLException { throw new UnsupportedOperationException(); } public boolean usesLocalFilePerTable() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMixedCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesUpperCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesLowerCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesMixedCaseIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { throw new UnsupportedOperationException(); } public String getIdentifierQuoteString() throws SQLException { throw new UnsupportedOperationException(); } public String getSQLKeywords() throws SQLException { throw new UnsupportedOperationException(); } public String getNumericFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getStringFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getSystemFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getTimeDateFunctions() throws SQLException { throw new UnsupportedOperationException(); } public String getSearchStringEscape() throws SQLException { throw new UnsupportedOperationException(); } public String getExtraNameCharacters() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsAlterTableWithAddColumn() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsAlterTableWithDropColumn() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsColumnAliasing() throws SQLException { throw new UnsupportedOperationException(); } public boolean nullPlusNonNullIsNull() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsConvert() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsConvert(int fromType, int toType) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsTableCorrelationNames() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsDifferentTableCorrelationNames() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsExpressionsInOrderBy() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOrderByUnrelated() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGroupBy() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGroupByUnrelated() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGroupByBeyondSelect() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsLikeEscapeClause() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMultipleResultSets() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMultipleTransactions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsNonNullableColumns() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMinimumSQLGrammar() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCoreSQLGrammar() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsExtendedSQLGrammar() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsANSI92EntryLevelSQL() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsANSI92IntermediateSQL() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsANSI92FullSQL() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsIntegrityEnhancementFacility() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOuterJoins() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsFullOuterJoins() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsLimitedOuterJoins() throws SQLException { throw new UnsupportedOperationException(); } public String getSchemaTerm() throws SQLException { throw new UnsupportedOperationException(); } public String getProcedureTerm() throws SQLException { throw new UnsupportedOperationException(); } public String getCatalogTerm() throws SQLException { throw new UnsupportedOperationException(); } public boolean isCatalogAtStart() throws SQLException { throw new UnsupportedOperationException(); } public String getCatalogSeparator() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInDataManipulation() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInProcedureCalls() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInTableDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInIndexDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInDataManipulation() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInProcedureCalls() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInTableDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInIndexDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsPositionedDelete() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsPositionedUpdate() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSelectForUpdate() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsStoredProcedures() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInComparisons() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInExists() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInIns() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsSubqueriesInQuantifieds() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsCorrelatedSubqueries() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsUnion() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsUnionAll() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenCursorsAcrossCommit() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenCursorsAcrossRollback() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenStatementsAcrossCommit() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsOpenStatementsAcrossRollback() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxBinaryLiteralLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxCharLiteralLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInGroupBy() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInIndex() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInOrderBy() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInSelect() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxColumnsInTable() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxConnections() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxCursorNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxIndexLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxSchemaNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxProcedureNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxCatalogNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxRowSize() throws SQLException { throw new UnsupportedOperationException(); } public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxStatementLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxStatements() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxTableNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxTablesInSelect() throws SQLException { throw new UnsupportedOperationException(); } public int getMaxUserNameLength() throws SQLException { throw new UnsupportedOperationException(); } public int getDefaultTransactionIsolation() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsTransactions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsTransactionIsolationLevel(int level) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsDataManipulationTransactionsOnly() throws SQLException { throw new UnsupportedOperationException(); } public boolean dataDefinitionCausesTransactionCommit() throws SQLException { throw new UnsupportedOperationException(); } public boolean dataDefinitionIgnoredInTransactions() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSchemas() throws OlapException { Olap4ldUtil._log.config("MetaData resultset getSchemas()..."); return getMetadataLd(Olap4ldConnection.MetadataRequest.DBSCHEMA_SCHEMATA); } public ResultSet getCatalogs() throws OlapException { Olap4ldUtil._log.config("MetaData resultset getCatalogs()..."); return getMetadataLd(Olap4ldConnection.MetadataRequest.DBSCHEMA_CATALOGS); } public ResultSet getTableTypes() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getTypeInfo() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsResultSetType(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { throw new UnsupportedOperationException(); } public boolean ownUpdatesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean ownDeletesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean ownInsertsAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean othersUpdatesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean othersDeletesAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean othersInsertsAreVisible(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean updatesAreDetected(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean deletesAreDetected(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean insertsAreDetected(int type) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsBatchUpdates() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { throw new UnsupportedOperationException(); } public OlapConnection getConnection() { return olap4jConnection; } public boolean supportsSavepoints() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsNamedParameters() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsMultipleOpenResults() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsGetGeneratedKeys() throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsResultSetHoldability(int holdability) throws SQLException { throw new UnsupportedOperationException(); } public int getResultSetHoldability() throws SQLException { throw new UnsupportedOperationException(); } public int getDatabaseMajorVersion() throws SQLException { throw Olap4jUtil.needToImplement(this); } public int getDatabaseMinorVersion() throws SQLException { throw Olap4jUtil.needToImplement(this); } public int getJDBCMajorVersion() throws SQLException { // this driver supports jdbc 3.0 and jdbc 4.0 // FIXME: should return 3 if the current connection is jdbc 3.0 return 4; } public int getJDBCMinorVersion() throws SQLException { // this driver supports jdbc 3.0 and jdbc 4.0 return 0; } public int getSQLStateType() throws SQLException { throw new UnsupportedOperationException(); } public boolean locatorsUpdateCopy() throws SQLException { throw new UnsupportedOperationException(); } public boolean supportsStatementPooling() throws SQLException { throw new UnsupportedOperationException(); } // implement java.sql.Wrapper // straightforward implementation of unwrap and isWrapperFor, since this // class already implements the interface they most likely require: // DatabaseMetaData and OlapDatabaseMetaData public <T> T unwrap(Class<T> iface) throws SQLException { if (iface.isInstance(this)) { return iface.cast(this); } throw getHelper().createException("does not implement '" + iface + "'"); } /** * Returns the error-handler. * * @return Error handler */ private LdHelper getHelper() { return olap4jConnection.helper; } public boolean isWrapperFor(Class<?> iface) throws SQLException { return iface.isInstance(this); } // implement OlapDatabaseMetaData /* * Here, we always use the mondrian olap server. What we could do: - rather * than return the result sets from the mondrian, create them myself - * incrementally query the triple store and collect the information for * creating the xml and fill the database - before a real question is * issued: create the xml and fill the database */ public Set<CellSetListener.Granularity> getSupportedCellSetListenerGranularities() throws OlapException { // Set<CellSetListener.Granularity> betweenResult = // this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData() // .getSupportedCellSetListenerGranularities(); // return betweenResult; return Collections.emptySet(); } public ResultSet getActions(String catalog, String schemaPattern, String cubeNamePattern, String actionNamePattern) throws OlapException { Olap4ldUtil._log.config("Metadata resultset getActions()..."); // We simply return empty result set, since the relevance of those // methods is not clear return olap4jConnection.factory.newEmptyResultSet(olap4jConnection); // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getActions(catalog, schemaPattern, cubeNamePattern, // actionNamePattern); // return betweenResult; // return getMetadata( // XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_ACTIONS, // "CATALOG_NAME", catalog, "SCHEMA_NAME", // wildcard(schemaPattern), "CUBE_NAME", // wildcard(cubeNamePattern), "ACTION_NAME", // wildcard(actionNamePattern)); } public ResultSet getDatabases() throws OlapException { // We can really query LD Olap4ldUtil._log.config("MetaData resultset getDatabases()..."); // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData().getDatabases(); // return betweenResult; return getMetadataLd(Olap4ldConnection.MetadataRequest.DISCOVER_DATASOURCES); } public ResultSet getLiterals() throws OlapException { Olap4ldUtil._log.config("MetaData resultset getLiterals()..."); // We simply return empty result set, since the relevance of those // methods is not clear return olap4jConnection.factory.newEmptyResultSet(olap4jConnection); // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData().getLiterals(); // return betweenResult; // return getMetadata( // XmlaOlap4jConnection.MetadataRequest.DISCOVER_LITERALS); } public ResultSet getDatabaseProperties(String dataSourceName, String propertyNamePattern) throws OlapException { Olap4ldUtil._log.config("MetaData resultset getDatabaseProperties()..."); // We simply return empty result set, since the relevance of those // methods is not clear: It returns the specific features of the // database. return olap4jConnection.factory.newEmptyResultSet(olap4jConnection); // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData() // .getDatabaseProperties(dataSourceName, propertyNamePattern); // return betweenResult; // return // getMetadata(XmlaOlap4jConnection.MetadataRequest.DISCOVER_PROPERTIES); } public ResultSet getProperties(String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelUniqueName, String memberUniqueName, String propertyNamePattern) throws OlapException { Olap4ldUtil._log.config("MetaData resultset getProperties()..."); // We simply return empty result set, since the relevance of those // methods is not clear return olap4jConnection.factory.newEmptyResultSet(olap4jConnection); // // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getProperties(catalog, schemaPattern, cubeNamePattern, // dimensionUniqueName, hierarchyUniqueName, // levelUniqueName, memberUniqueName, propertyNamePattern); // return betweenResult; // return getMetadata( // XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_PROPERTIES, // "CATALOG_NAME", catalog, "SCHEMA_NAME", // wildcard(schemaPattern), "CUBE_NAME", // wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", // dimensionUniqueName, "HIERARCHY_UNIQUE_NAME", // hierarchyUniqueName, "LEVEL_UNIQUE_NAME", levelUniqueName, // "MEMBER_UNIQUE_NAME", memberUniqueName, "PROPERTY_NAME", // wildcard(propertyNamePattern)); } public String getMdxKeywords() throws OlapException { Olap4ldUtil._log.config("MetaData resultset getMdxKeywords()..."); // We simply return empty result set, since the relevance of those // methods is not clear return ""; // // final XmlaOlap4jConnection.MetadataRequest metadataRequest = // XmlaOlap4jConnection.MetadataRequest.DISCOVER_KEYWORDS; // final XmlaOlap4jConnection.Context context = new // XmlaOlap4jConnection.Context( // olap4jConnection, null, null, null, null, null, null, null); // String betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData().getMdxKeywords(); // return betweenResult; // String request = olap4jConnection.generateRequest(context, // metadataRequest, new Object[0]); // final Element root = // olap4jConnection.executeMetadataRequest(request); // StringBuilder buf = new StringBuilder(); // for (Element row : XmlaOlap4jUtil.childElements(root)) { // if (buf.length() > 0) { // buf.append(','); // } // final String keyword = XmlaOlap4jUtil.stringElement(row, "Keyword"); // buf.append(keyword); // } // return buf.toString(); } public ResultSet getCubes(String catalog, String schemaPattern, String cubeNamePattern) throws OlapException { // Test what is returned by mondrian // e.g., sql enabled false // ResultSet cubes = // olap4jConnection.myOlapServer.getOlapConnection().getMetaData().getCubes(null, // schemaPattern, cubeNamePattern); // We do not need to query OLAP server // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData() // .getCubes(catalog, schemaPattern, cubeNamePattern); // return betweenResult; // XMLA doesn't support drillthrough so override // whatever the server returns. Olap4ldUtil._log.config("MetaData resultset getCubes(catalog: "+catalog+", schemapattern"+schemaPattern+", cubenamepattern"+cubeNamePattern+")..."); final Map<Olap4ldConnection.MetadataColumn, String> overrides = new HashMap<Olap4ldConnection.MetadataColumn, String>(); overrides.put(Olap4ldConnection.MetadataRequest.MDSCHEMA_CUBES .getColumn("IS_DRILLTHROUGH_ENABLED"), "false"); return getMetadataLd(Olap4ldConnection.MetadataRequest.MDSCHEMA_CUBES, overrides, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern)); } public ResultSet getDimensions(String catalog, String schemaPattern, String cubeNamePattern, String dimensionNamePattern) throws OlapException { // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getDimensions(catalog, schemaPattern, cubeNamePattern, // dimensionNamePattern); // return betweenResult; Olap4ldUtil._log.config("MetaData resultset getDimensions(catalog: "+catalog+", schemaPattern: "+schemaPattern+", cubeNamePattern: "+cubeNamePattern+", dimensionNamePattern: "+dimensionNamePattern+")..."); return getMetadataLd( Olap4ldConnection.MetadataRequest.MDSCHEMA_DIMENSIONS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_NAME", wildcard(dimensionNamePattern)); } public ResultSet getOlapFunctions(String functionNamePattern) throws OlapException { Olap4ldUtil._log.config("MetaData resultset getOLapFunctions()..."); // We simply return empty result set, since the relevance of those // methods is not clear return olap4jConnection.factory.newEmptyResultSet(olap4jConnection); // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection().getMetaData() // .getOlapFunctions(functionNamePattern); // return betweenResult; // return getMetadata( // XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_FUNCTIONS, // "FUNCTION_NAME", wildcard(functionNamePattern)); } public ResultSet getHierarchies(String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyNamePattern) throws OlapException { // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getHierarchies(catalog, schemaPattern, cubeNamePattern, // dimensionUniqueName, hierarchyNamePattern); // return betweenResult; Olap4ldUtil._log.config("MetaData resultset getHierarchies(catalog: "+catalog+", schemaPattern: "+schemaPattern+", cubeNamePattern: "+cubeNamePattern+", dimensionUniqueName: "+dimensionUniqueName+", hierarchyNamePattern: "+hierarchyNamePattern); return getMetadataLd( Olap4ldConnection.MetadataRequest.MDSCHEMA_HIERARCHIES, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_NAME", wildcard(hierarchyNamePattern)); } public ResultSet getMeasures(String catalog, String schemaPattern, String cubeNamePattern, String measureNamePattern, String measureUniqueName) throws OlapException { // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getMeasures(catalog, schemaPattern, cubeNamePattern, // measureNamePattern, measureUniqueName); // return betweenResult; Olap4ldUtil._log.config("MetaData resultset getMeasures(catalog: "+catalog+", schemaPattern: "+schemaPattern+", cubeNamePattern: "+cubeNamePattern+", measureNamePattern: "+measureNamePattern+" measureUniqueName: "+measureUniqueName); return getMetadataLd( Olap4ldConnection.MetadataRequest.MDSCHEMA_MEASURES, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "MEASURE_NAME", wildcard(measureNamePattern), "MEASURE_UNIQUE_NAME", measureUniqueName); } public ResultSet getMembers(String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelUniqueName, String memberUniqueName, Set<Member.TreeOp> treeOps) throws OlapException { String treeOpRestriction; // What exactly is queried? if (treeOps == null) { treeOpRestriction = ""; } else { treeOpRestriction = ""; for (TreeOp treeOp : treeOps) { treeOpRestriction += treeOp.name(); } } Olap4ldUtil._log.config("MetaData resultset getMembers(" + catalog + "," + schemaPattern + "," + cubeNamePattern + "," + dimensionUniqueName + "," + hierarchyUniqueName + "," + levelUniqueName + "," + memberUniqueName + "," + treeOpRestriction + ")..."); String treeOpString; if (treeOps != null) { int op = 0; for (Member.TreeOp treeOp : treeOps) { op |= treeOp.xmlaOrdinal(); } treeOpString = String.valueOf(op); } else { treeOpString = null; } return getMetadataLd( Olap4ldConnection.MetadataRequest.MDSCHEMA_MEMBERS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, "LEVEL_UNIQUE_NAME", levelUniqueName, "MEMBER_UNIQUE_NAME", memberUniqueName, "TREE_OP", treeOpString); } public ResultSet getLevels(String catalog, String schemaPattern, String cubeNamePattern, String dimensionUniqueName, String hierarchyUniqueName, String levelNamePattern) throws OlapException { // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getLevels(catalog, schemaPattern, cubeNamePattern, // dimensionUniqueName, hierarchyUniqueName, // levelNamePattern); // return betweenResult; Olap4ldUtil._log.config("MetaData resultset getLevels(catalog: "+catalog+", schemaPattern: "+schemaPattern+", cubeNamePattern: "+cubeNamePattern+", dimensionUniqueName: "+dimensionUniqueName+", hierarchyUniqueName: "+hierarchyUniqueName+", levelNamePattern: "+levelNamePattern); return getMetadataLd( Olap4ldConnection.MetadataRequest.MDSCHEMA_LEVELS, "CATALOG_NAME", catalog, "SCHEMA_NAME", wildcard(schemaPattern), "CUBE_NAME", wildcard(cubeNamePattern), "DIMENSION_UNIQUE_NAME", dimensionUniqueName, "HIERARCHY_UNIQUE_NAME", hierarchyUniqueName, "LEVEL_NAME", wildcard(levelNamePattern)); } public ResultSet getSets(String catalog, String schemaPattern, String cubeNamePattern, String setNamePattern) throws OlapException { Olap4ldUtil._log.config("MetaData resultset getSets()..."); // We simply return empty result set, since the relevance of those // methods is not clear return olap4jConnection.factory.newEmptyResultSet(olap4jConnection); // ResultSet betweenResult = this.olap4jConnection.myOlapServer // .getOlapConnection() // .getMetaData() // .getSets(catalog, schemaPattern, cubeNamePattern, // setNamePattern); // return betweenResult; // return // getMetadata(XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_SETS, // "CATALOG_NAME", catalog, "SCHEMA_NAME", // wildcard(schemaPattern), "CUBE_NAME", // wildcard(cubeNamePattern), "SET_NAME", wildcard(setNamePattern)); } /** * Wrapper which indicates that a restriction is to be treated as a * SQL-style wildcard match. */ static class Wildcard { final String pattern; /** * Creates a Wildcard. * * @param pattern * Pattern */ Wildcard(String pattern) { assert pattern != null; this.pattern = pattern; } } /** * Here, a request is generated and executed. With that, we populate the * objects. * * For creating the metadata: There are two points, where Linked Data is * read from: getMetadataLd (to create Resultset), and populateList (to fill * in objects). * * @param list * @param context * @param metadataRequest * @param handler * @param restrictions * @throws OlapException */ <T extends Named> void populateList(List<T> list, Context context, MetadataRequest metadataRequest, Handler<T> handler, Object[] restrictions) throws OlapException { // String request = generateRequest(context, metadataRequest, // restrictions); // Element root = executeMetadataRequest(request); Restrictions myRestrictionsObject = new Restrictions(restrictions); // Here, we now query Linked Data // Here, the context helps, since deferred lists are filled with // contexts. List<org.semanticweb.yars.nx.Node[]> root = executeMetadataRequestOnLdce( context, metadataRequest, myRestrictionsObject); // Go through Nodes and change handlers to do so, as well. boolean isFirst = true; Map<String, Integer> mapFields = new HashMap<String, Integer>(); for (org.semanticweb.yars.nx.Node[] o : root) { // The first Node gives the fields if (isFirst) { mapFields = Olap4ldLinkedDataUtil.getNodeResultFields(o); isFirst = false; continue; } handler.handle(o, mapFields, context, list); } // for (Element o : childElements(root)) { // if (o.getLocalName().equals("row")) { // /* // * The results of the metadata request are wrapped as objects // */ // handler.handle(o, context, list); // } // } handler.sortList(list); } /** * * Querying Linked Data: There are two points, where Linked Data is read * from: getMetadataLd (to create Resultset), and populateList (to fill in * objects). * * Both are filled by calling methods in LinkedDataEngine. The problem is * that sometimes values returned by LinkedDataEngine need to be further * processed to be usable in ResultSet and metadata objects: * * * URIs used for unique names need to be translated into an MDX friendly * format * Instead of null values, nx format uses "null" (TODO: or by now * something else?) For certain returned values this needs to be transformed * into a proper null. * * This means: LinkedDataEngine should always return literal values if no * encoding needs to be done. URI that it returns should be transformed for * use in MDX. If LinkedDataEngine returns "null" (or similar), it is * transformed into proper null. All program logic, e.g., if no CAPTION is * available (so that CAPTION returns null) then use UNIQUE_NAME is either * implemented by the client or LinkedDataEngine. * * TODO: For DatabaseMetaData, we should replace values in here. * * @param context * @param metadataRequest * @param restrictions * @return Nodes to work with internally. */ private List<org.semanticweb.yars.nx.Node[]> executeMetadataRequestOnLdce( Context context, MetadataRequest metadataRequest, Restrictions myRestrictionsObject) throws OlapException { Olap4ldUtil._log.info("Execute metadata query on Linked Data Engine: "+metadataRequest.toString() + myRestrictionsObject.toString()); long time = System.currentTimeMillis(); List<org.semanticweb.yars.nx.Node[]> result = null; // Create result switch (metadataRequest) { case DISCOVER_DATASOURCES: result = olap4jConnection.myLinkedData.getDatabases(myRestrictionsObject); break; case DBSCHEMA_CATALOGS: result = olap4jConnection.myLinkedData.getCatalogs(myRestrictionsObject); break; case DBSCHEMA_SCHEMATA: result = olap4jConnection.myLinkedData.getSchemas(myRestrictionsObject); break; case MDSCHEMA_CUBES: result = olap4jConnection.myLinkedData.getCubes(myRestrictionsObject); break; case MDSCHEMA_DIMENSIONS: /* * Now, we have two possibilities: Either, here, the shared * dimensions are asked for, or the dimensions of certain cubes. */ result = olap4jConnection.myLinkedData.getDimensions(myRestrictionsObject); break; case MDSCHEMA_MEASURES: result = olap4jConnection.myLinkedData.getMeasures(myRestrictionsObject); break; case MDSCHEMA_SETS: result = olap4jConnection.myLinkedData.getSets(myRestrictionsObject); break; case MDSCHEMA_HIERARCHIES: result = olap4jConnection.myLinkedData.getHierarchies(myRestrictionsObject); break; case MDSCHEMA_LEVELS: result = olap4jConnection.myLinkedData.getLevels(myRestrictionsObject); break; case MDSCHEMA_MEMBERS: result = olap4jConnection.myLinkedData.getMembers(myRestrictionsObject); break; default: /* * If we haven't implemented it, yet, simply return empty list. * * In this case, an empty ResultSet should be created. */ result = new ArrayList<org.semanticweb.yars.nx.Node[]>(); } time = System.currentTimeMillis() - time; Olap4ldUtil._log.info("Execute metadata query on Linked Data Engine: finished in " + time + "ms."); return result; } } // End XmlaOlap4jDatabaseMetaData.java