Skip to content

Commit

Permalink
Tons of performance enhancing modifications for the XML/A driver.
Browse files Browse the repository at this point in the history
  • Loading branch information
lucboudreau committed Jul 18, 2008
1 parent 5abb967 commit 1d0e3a2
Show file tree
Hide file tree
Showing 24 changed files with 2,202 additions and 164 deletions.
3 changes: 2 additions & 1 deletion src/org/olap4j/driver/xmla/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.olap4j.driver.xmla;

import org.olap4j.OlapException;
import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy;

import java.sql.*;
import java.util.Properties;
Expand All @@ -27,7 +28,7 @@
*/
interface Factory {
Connection newConnection(
XmlaOlap4jDriver.Proxy proxy,
XmlaOlap4jProxy proxy,
String url,
Properties info) throws SQLException;

Expand Down
5 changes: 3 additions & 2 deletions src/org/olap4j/driver/xmla/FactoryJdbc3Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package org.olap4j.driver.xmla;

import org.olap4j.OlapException;
import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy;

import java.sql.*;
import java.util.*;
Expand All @@ -22,7 +23,7 @@
*/
class FactoryJdbc3Impl implements Factory {
public Connection newConnection(
XmlaOlap4jDriver.Proxy proxy,
XmlaOlap4jProxy proxy,
String url,
Properties info)
throws SQLException
Expand Down Expand Up @@ -105,7 +106,7 @@ public EmptyResultSetJdbc3(

private class XmlaOlap4jConnectionJdbc3 extends XmlaOlap4jConnection {
public XmlaOlap4jConnectionJdbc3(
XmlaOlap4jDriver.Proxy proxy,
XmlaOlap4jProxy proxy,
String url,
Properties info)
throws SQLException
Expand Down
5 changes: 3 additions & 2 deletions src/org/olap4j/driver/xmla/FactoryJdbc4Impl.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.io.InputStream;

import org.olap4j.*;
import org.olap4j.driver.xmla.proxy.XmlaOlap4jProxy;

/**
* Implementation of {@link Factory} for JDBC 4.0.
Expand All @@ -24,7 +25,7 @@
*/
class FactoryJdbc4Impl implements Factory {
public Connection newConnection(
XmlaOlap4jDriver.Proxy proxy,
XmlaOlap4jProxy proxy,
String url,
Properties info)
throws SQLException
Expand Down Expand Up @@ -331,7 +332,7 @@ private static class XmlaOlap4jConnectionJdbc4
{
public XmlaOlap4jConnectionJdbc4(
Factory factory,
XmlaOlap4jDriver.Proxy proxy,
XmlaOlap4jProxy proxy,
String url,
Properties info) throws SQLException
{
Expand Down
14 changes: 12 additions & 2 deletions src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,25 @@ class XmlaOlap4jCatalog implements Catalog, Named {
assert name != null;
this.olap4jDatabaseMetaData = olap4jDatabaseMetaData;
this.name = name;

/*
* Fetching the schemas is a tricky part. There are no XMLA requests to obtain the
* available schemas for a given catalog. We therefore need to ask for the cubes,
* restricting results on the catalog, and while iterating on the cubes, take the schema
* name from this recordset.
*
* Many servers (SSAS for example) won't support the schema name column in the
* returned rowset. This has to be taken into account.
*/
this.schemas =
new DeferredNamedListImpl<XmlaOlap4jSchema>(
XmlaOlap4jConnection.MetadataRequest.DBSCHEMA_CATALOGS,
XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_CUBES,
new XmlaOlap4jConnection.Context(
olap4jDatabaseMetaData.olap4jConnection,
olap4jDatabaseMetaData,
this,
null, null, null, null, null),
new XmlaOlap4jConnection.SchemaHandler());
new XmlaOlap4jConnection.CatalogSchemaHandler(this.name));
}

public int hashCode() {
Expand Down
196 changes: 141 additions & 55 deletions src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import org.olap4j.*;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*;

import org.olap4j.driver.xmla.proxy.*;
import org.olap4j.impl.*;
import org.olap4j.mdx.ParseTreeWriter;
import org.olap4j.mdx.SelectNode;
Expand All @@ -25,7 +27,8 @@
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.regex.Pattern;
import java.util.Map.*;
import java.util.regex.*;

/**
* Implementation of {@link org.olap4j.OlapConnection}
Expand Down Expand Up @@ -55,7 +58,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection {

final Factory factory;

final XmlaOlap4jDriver.Proxy proxy;
final XmlaOlap4jProxy proxy;

private boolean closed;

Expand Down Expand Up @@ -120,7 +123,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
*/
XmlaOlap4jConnection(
Factory factory,
XmlaOlap4jDriver.Proxy proxy,
XmlaOlap4jProxy proxy,
String url,
Properties info)
throws SQLException
Expand All @@ -138,7 +141,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
this.providerName = map.get(XmlaOlap4jDriver.Property.Provider.name());
this.datasourceName = map.get(XmlaOlap4jDriver.Property.DataSource.name());
this.catalogName = map.get(XmlaOlap4jDriver.Property.Catalog.name());

// Set URL of HTTP server.
String serverUrl = map.get(XmlaOlap4jDriver.Property.Server.name());
if (serverUrl == null) {
Expand All @@ -159,6 +162,9 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
.concat(map.get("password")
.concat("@")));
}

// Initialize the SOAP cache if needed
initSoapCache(map);

try {
this.serverUrl = new URL(serverUrl);
Expand All @@ -173,8 +179,48 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
(XmlaOlap4jCatalog)
this.olap4jDatabaseMetaData.getCatalogObjects().get(
catalogName);
this.olap4jSchema = new XmlaOlap4jSchema(catalog, catalogName);
this.olap4jSchema = (XmlaOlap4jSchema) catalog.getSchemas()
.get(0);
}


/**
* Initializes a cache object and configures it if cache
* parameters were specified in the jdbc url.
*
* @param map The parameters from the jdbc url.
* @throws OlapException Thrown when there is an error encountered
* while creating the cache.
*/
private void initSoapCache(Map<String, String> map) throws OlapException {

// Test if a SOAP cache class was defined
if (map.containsKey(XmlaOlap4jDriver.Property.Cache.name()
.toUpperCase()))
{
// Create a properties object to pass to the proxy
// so it can configure it's cache
Map<String,String> props = new HashMap<String, String>();
// Iterate over map entries to find those related to
// the cache config
for (Entry<String, String> entry : map.entrySet()) {
// Check if the current entry relates to cache config.
if (entry.getKey().startsWith(
XmlaOlap4jDriver.Property.Cache.name().toUpperCase()
+ ".")) //$NON-NLS-1$
{
props.put(entry.getKey().substring(
XmlaOlap4jDriver.Property.Cache.name()
.length() + 1), entry.getValue());
}
}

// Init the cache
((XmlaOlap4jCachedProxy) this.proxy).setCache(map, props);
}
}



static Map<String, String> parseConnectString(String url, Properties info) {
String x = url.substring(CONNECT_STRING_PREFIX.length());
Expand All @@ -200,69 +246,69 @@ static boolean acceptsURL(String url) {
* @throws OlapException if cannot find a datasource that matches
*/
String getDataSourceInfo() throws OlapException {
// If we already know it, return it.
// If we already know it, return it.
if (this.nativeDatasourceName != null) {
return this.nativeDatasourceName;
return this.nativeDatasourceName;
}

ResultSet rSet = null;
try {
// We need to query for it
rSet = this.olap4jDatabaseMetaData.getDatasources();

// Check if the user requested a particular one.
if (this.datasourceName != null || this.providerName != null) {
// We iterate through the datasources
while (rSet.next()) {
// Get current values
String currentDatasource = rSet.getString(DATA_SOURCE_NAME);
String currentProvider = rSet.getString(PROVIDER_NAME);

// If datasource and provider match, we got it.
// If datasource matches but no provider is specified, we
try {
// We need to query for it
rSet = this.olap4jDatabaseMetaData.getDatasources();

// Check if the user requested a particular one.
if (this.datasourceName != null || this.providerName != null) {
// We iterate through the datasources
while (rSet.next()) {
// Get current values
String currentDatasource = rSet.getString(DATA_SOURCE_NAME);
String currentProvider = rSet.getString(PROVIDER_NAME);

// If datasource and provider match, we got it.
// If datasource matches but no provider is specified, we
// got it.
// If provider matches but no datasource specified, we
// If provider matches but no datasource specified, we
// consider it good.
if (currentDatasource.equals(this.datasourceName)
&& currentProvider.equals(this.providerName)
|| currentDatasource.equals(this.datasourceName)
&& this.providerName == null
|| currentProvider.equals(this.providerName)
&& this.datasourceName == null)
{
// Got it
this.nativeDatasourceName = currentDatasource;
break;
}
}
} else {
// Use first
if (rSet.first()) {
{
// Got it
this.nativeDatasourceName = currentDatasource;
break;
}
}
} else {
// Use first
if (rSet.first()) {
this.nativeDatasourceName = rSet.getString(DATA_SOURCE_NAME);
}
}

// Throws exception to the client.
//Tells that there are no datasource corresponding to the search criterias.
if (this.nativeDatasourceName == null) {
throw new OlapException("No datasource could be found.");
}
// If there is a provider
return this.nativeDatasourceName;
} catch (OlapException e) {
throw e;
} catch (SQLException e) {
throw new OlapException("Datasource name not found.", e);
} finally {
try {
if (rSet != null) {
// Throws exception to the client.
//Tells that there are no datasource corresponding to the search criterias.
if (this.nativeDatasourceName == null) {
throw new OlapException("No datasource could be found.");
}
// If there is a provider
return this.nativeDatasourceName;
} catch (OlapException e) {
throw e;
} catch (SQLException e) {
throw new OlapException("Datasource name not found.", e);
} finally {
try {
if (rSet != null) {
rSet.close();
}
} catch (SQLException e) {
} catch (SQLException e) {
// ignore
}
}
}
}
}

public OlapStatement createStatement() {
Expand Down Expand Up @@ -666,12 +712,12 @@ public String generateRequest(

// Add the datasource node only if this request requires it.
if (datasourceDependentRequest) {
buf.append(" <DataSourceInfo>");
buf.append(xmlEncode(context.olap4jConnection.getDataSourceInfo()));
buf.append("</DataSourceInfo>\n"
buf.append(" <DataSourceInfo>");
buf.append(xmlEncode(context.olap4jConnection.getDataSourceInfo()));
buf.append("</DataSourceInfo>\n"
+ " <Catalog>");
buf.append(xmlEncode(catalog));
buf.append("</Catalog>\n");
buf.append(xmlEncode(catalog));
buf.append("</Catalog>\n");
}

buf.append(" <Content>");
Expand Down Expand Up @@ -1104,13 +1150,53 @@ public void handle(Element row, Context context, List<XmlaOlap4jSchema> list) {
<SCHEMA_OWNER>dbo</SCHEMA_OWNER>
</row>
*/
String schemaName = stringElement(row, "CATALOG_NAME");
String schemaName = stringElement(row, "SCHEMA_NAME");
list.add(
new XmlaOlap4jSchema(
context.getCatalog(row),
schemaName));
}
}

static class CatalogSchemaHandler extends HandlerImpl<XmlaOlap4jSchema> {

private String catalogName;

public CatalogSchemaHandler(String catalogName) {
super();
if (catalogName == null)
throw new RuntimeException("The CatalogSchemaHandler handler requires a catalog name.");
this.catalogName = catalogName;
}

public void handle(Element row, Context context, List<XmlaOlap4jSchema> list)
{
/*
<row>
<CATALOG_NAME>CatalogName</CATLAOG_NAME>
<SCHEMA_NAME>FoodMart</SCHEMA_NAME>
<SCHEMA_OWNER>dbo</SCHEMA_OWNER>
</row>
*/

/*
* We are looking for a schema name from the cubes query restricted on the
* catalog name. Some servers don't support nor include the SCHEMA_NAME column
* in it's response. If it's null, we convert it to an empty string as to not cause
* problems later on.
*/

String schemaName = stringElement(row, "SCHEMA_NAME");
String catalogName = stringElement(row, "CATALOG_NAME");

if (this.catalogName.equals(catalogName)) {
list.add(
new XmlaOlap4jSchema(
context.getCatalog(row),
(schemaName == null) ? "" : schemaName));
}
}
}

static class PropertyHandler extends HandlerImpl<XmlaOlap4jProperty> {
public void handle(
Expand Down
Loading

0 comments on commit 1d0e3a2

Please sign in to comment.