Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion application/pivot/common/daanse.pivot.base.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -100,6 +99,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
58 changes: 54 additions & 4 deletions application/pivot/duckdb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Production Daanse OLAP (XMLA) server image for **DuckDB**. The image ships the
Daanse ROLAP engine, the XMLA endpoint, the DuckDB JDBC driver, the DataSource
and the matching SQL dialect. It is configured entirely through environment
variables. The DuckDB database is a file mounted into the container and is
opened read-only by default (an in-memory DuckDB would be private to each
opened read-only by default (DuckDB `access_mode=READ_ONLY`; an in-memory DuckDB would be private to each
connection and is therefore not useful here).

Note: this image is based on Debian (`eclipse-temurin:25-jre`) instead of
Expand Down Expand Up @@ -32,9 +32,59 @@ location and the server starts.

| Variable | Default | Description |
|---|---|---|
| `DAANSE_JDBC_DATABASE_NAME` | `/app/data/database.duckdb` | Path of the DuckDB database file inside the container |
| `DAANSE_JDBC_READ_ONLY` | `true` | Open the database read-only (allows other processes to read the same file); the connection pool inherits this mode |
| `DAANSE_JDBC_SETTINGS` | *(unset)* | Comma separated DuckDB settings, each as `name=value` |
| `DAANSE_JDBC_DATABASE_NAME` | `/app/data/database.duckdb` | Path of the DuckDB database file inside the container; must not contain `;` |
| `DAANSE_JDBC_READ_ONLY` | `true` | Open the database read-only (allows other processes to read the same file); the connection pool inherits this mode. Shorthand for the DuckDB setting `access_mode=READ_ONLY` |
| `DAANSE_JDBC_ACCESS_MODE` | *(unset)* | DuckDB `access_mode`: `AUTOMATIC`, `READ_ONLY` or `READ_WRITE`; replaces the read-only default |
| `DAANSE_JDBC_STREAM_RESULTS` | `false` | Stream result sets instead of materializing them (`jdbc_stream_results`) |
| `DAANSE_JDBC_AUTO_COMMIT` | `true` | Default auto-commit mode of the connections (`jdbc_auto_commit`) |
| `DAANSE_JDBC_CUSTOM_USER_AGENT` | *(unset)* | String appended to the user agent reported to DuckDB (`custom_user_agent`) |
| `DAANSE_JDBC_INSTANCE_CACHE` | `true` | Reuse the process-wide database instance for the same file (`jdbc_instance_cache`) |
| `DAANSE_JDBC_PIN_DB` | `false` | Keep the database instance alive after its last connection closes (`jdbc_pin_db`); the server holds the database open anyway |
| `DAANSE_JDBC_IGNORE_UNSUPPORTED_OPTIONS` | `false` | Drop settings DuckDB does not know instead of refusing to start (`jdbc_ignore_unsupported_options`) |
| `DAANSE_JDBC_JFR_MEMORY_MONITOR` | *(unset)* | Name under which the database is tracked in the `duckdb.MemoryUsage` JFR event (`jdbc_jfr_memory_monitor`) |
| `DAANSE_JDBC_SESSION_INIT_SQL_FILE` | *(unset)* | SQL file inside the container that is run before connections are used, see below |
| `DAANSE_JDBC_SESSION_INIT_SQL_FILE_SHA256` | *(unset)* | Expected SHA-256 digest (hex) of that file; the server refuses to connect on a mismatch |
| `DAANSE_JDBC_SETTINGS` | *(unset)* | Comma separated DuckDB settings, each as `name=value`, e.g. `threads=4,memory_limit=4GB` |

### Access mode

The database is opened with DuckDB's `access_mode=READ_ONLY` unless told
otherwise. The mode can be set either way:

| Configuration | Result |
|---|---|
| *(nothing)* | read-only |
| `DAANSE_JDBC_READ_ONLY=true` or `DAANSE_JDBC_ACCESS_MODE=READ_ONLY` | read-only |
| `DAANSE_JDBC_READ_ONLY=false` or `DAANSE_JDBC_ACCESS_MODE=READ_WRITE` | read-write (mount the file without `:ro`; DuckDB then locks it exclusively) |
| `DAANSE_JDBC_ACCESS_MODE=AUTOMATIC` | DuckDB decides (read-write for a file) |

`DAANSE_JDBC_ACCESS_MODE` replaces the read-only default, and the connection
pool follows the resulting mode. An `access_mode=...` entry in
`DAANSE_JDBC_SETTINGS` works the same way; `DAANSE_JDBC_ACCESS_MODE` wins over it. Do not set
`DAANSE_JDBC_READ_ONLY=true` together with a different `access_mode` — DuckDB
refuses to open the database.

### Session init SQL file

`DAANSE_JDBC_SESSION_INIT_SQL_FILE` names a SQL file (at most 1 MB, path without
`;` and `=`) mounted into the container. The part above the marker comment runs
once when the database is opened, the part below it for every connection:

```sql
CREATE OR REPLACE VIEW "Fact" AS SELECT * FROM "FactData";

/* DUCKDB_CONNECTION_INIT_BELOW_MARKER */

SET search_path = 'analytics';
```

The file runs with the full privileges of the connection — statements that
write need a read-write access mode. Pin its content with
`DAANSE_JDBC_SESSION_INIT_SQL_FILE_SHA256`.

`DAANSE_JDBC_SETTINGS` configures the database, not a single connection;
settings of session scope (`search_path`, `schema`, profiling) belong below the
marker of the session init SQL file instead.

## Source

Expand Down
2 changes: 1 addition & 1 deletion application/pivot/duckdb/daanse.pivot.duckdb.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -60,6 +59,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@
* variables and creates the BasicContext against it. Every attribute of
* {@link DsConfig} is supported. The database file defaults to
* {@code /app/data/database.duckdb} (mount it into the container) and is
* opened read-only unless {@code DAANSE_JDBC_READ_ONLY=false}.
* opened read-only unless {@code DAANSE_JDBC_READ_ONLY=false} or
* {@code DAANSE_JDBC_ACCESS_MODE} (or an {@code access_mode} entry of
* {@code DAANSE_JDBC_SETTINGS}) names another mode.
*/
@Component(immediate = true)
@RequireConfigurationAdmin
Expand All @@ -63,8 +65,12 @@ public void activate() throws IOException {
if (props.get(Constants.DATASOURCE_PROPERTY_DATABASENAME) == null) {
props.put(Constants.DATASOURCE_PROPERTY_DATABASENAME, DEFAULT_DATABASE_FILE);
}
// A given access mode decides; read-only is only the default where it
// is absent. DuckDB refuses the two contradicting.
String accessMode = accessMode(props);
boolean accessModeReadOnly = Constants.ACCESS_MODE_READ_ONLY.equalsIgnoreCase(accessMode);
if (props.get(Constants.DATASOURCE_PROPERTY_READ_ONLY) == null) {
props.put(Constants.DATASOURCE_PROPERTY_READ_ONLY, true);
props.put(Constants.DATASOURCE_PROPERTY_READ_ONLY, accessMode == null || accessModeReadOnly);
}
props.put(ServerConstants.PROP_IDENT, ServerConstants.IDENT_DATASOURCE);

Expand All @@ -74,11 +80,30 @@ public void activate() throws IOException {
// DuckDB connections are fixed to the read-only mode of the DataSource;
// the pool must mark its connections the same way or the driver refuses.
confPoolAndContext = BasicContextConfigs.createEnvPoolAndContext(ca, DIALECT_NAME,
(Boolean) props.get(Constants.DATASOURCE_PROPERTY_READ_ONLY));
accessModeReadOnly || (Boolean) props.get(Constants.DATASOURCE_PROPERTY_READ_ONLY));

logger.info("DuckDB DataSource, connection pool and context configured from environment");
}

/**
* The configured access mode - the attribute, else the {@code access_mode}
* entry of the settings - or {@code null}.
*/
static String accessMode(Dictionary<String, Object> props) {
if (props.get(Constants.DATASOURCE_PROPERTY_ACCESS_MODE) instanceof String attribute) {
return attribute.trim();
}
if (props.get(Constants.DATASOURCE_PROPERTY_SETTINGS) instanceof String[] entries) {
for (String entry : entries) {
int equals = entry.indexOf('=');
if (equals > 0 && Constants.SETTING_ACCESS_MODE.equalsIgnoreCase(entry.substring(0, equals).trim())) {
return entry.substring(equals + 1).trim();
}
}
}
return null;
}

@Deactivate
public void deactivate() throws IOException {
if (confDataSource != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.util.Map;
import java.util.concurrent.Future;

import org.eclipse.daanse.server.application.pivot.common.test.PivotContainers;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.testcontainers.containers.GenericContainer;
Expand All @@ -33,30 +36,105 @@
* End-to-end test: creates a DuckDB database file with the Fact table of the
* static test catalog, builds the daanse-pivot-duckdb image from its real
* Dockerfile, mounts database file and catalog and verifies via XMLA that the
* MDX sum over the VALUE column is queryable.
* MDX sum over the VALUE column is queryable - in the read-only and read-write
* access modes the image can be configured to.
*/
@Testcontainers(disabledWithoutDocker = true)
class DuckdbPivotIT {

/** Not writable for the container user: only a read-only open succeeds. */
private static final int MODE_NOT_WRITABLE = 0444;
private static final int MODE_WRITABLE = 0666;

@TempDir
static Path tempDir;

@Test
void sumMeasureIsQueryableViaXmla() throws Exception {
Path databaseFile = tempDir.resolve("database.duckdb");
private static Path databaseFile;
private static Future<String> image;

@BeforeAll
static void createDatabase() throws Exception {
databaseFile = tempDir.resolve("database.duckdb");
try (Connection connection = DriverManager.getConnection("jdbc:duckdb:" + databaseFile);
Statement statement = connection.createStatement()) {
statement.executeUpdate("CREATE TABLE \"Fact\" (\"KEY\" VARCHAR, \"VALUE\" INTEGER)");
statement.executeUpdate("INSERT INTO \"Fact\" VALUES ('A', 1), ('B', 2), ('C', 3)");
}
assertTrue(Files.exists(databaseFile));
image = PivotContainers.pivotImage("duckdb");
}

@Test
void sumMeasureIsQueryableViaXmla() throws Exception {
assertSumIsQueryable(Map.of(), MODE_WRITABLE);
}

@Test
void opensReadOnlyByDefault() throws Exception {
assertSumIsQueryable(Map.of(), MODE_NOT_WRITABLE);
}

@Test
void accessModeReadOnlyOpensReadOnly() throws Exception {
assertSumIsQueryable(Map.of("DAANSE_JDBC_ACCESS_MODE", "READ_ONLY"), MODE_NOT_WRITABLE);
}

/** The access mode decides, and the connection pool has to follow it. */
@Test
void accessModeReadOnlyWinsOverReadOnlyFalse() throws Exception {
assertSumIsQueryable(Map.of("DAANSE_JDBC_ACCESS_MODE", "READ_ONLY", "DAANSE_JDBC_READ_ONLY", "false"),
MODE_NOT_WRITABLE);
}

@Test
void accessModeSettingOpensReadOnly() throws Exception {
assertSumIsQueryable(Map.of("DAANSE_JDBC_SETTINGS", "access_mode=READ_ONLY,threads=2"), MODE_NOT_WRITABLE);
}

/** Replaces the read-only default instead of contradicting it. */
@Test
void accessModeReadWriteIsQueryable() throws Exception {
assertSumIsQueryable(Map.of("DAANSE_JDBC_ACCESS_MODE", "READ_WRITE"), MODE_WRITABLE);
}

@Test
void readOnlyFalseIsQueryable() throws Exception {
assertSumIsQueryable(Map.of("DAANSE_JDBC_READ_ONLY", "false"), MODE_WRITABLE);
}

/** The Fact table of the catalog only exists as the view the init file creates. */
@Test
void sessionInitSqlFileIsRun() throws Exception {
Path viewless = tempDir.resolve("viewless.duckdb");
try (Connection connection = DriverManager.getConnection("jdbc:duckdb:" + viewless);
Statement statement = connection.createStatement()) {
statement.executeUpdate("CREATE TABLE \"FactData\" (\"KEY\" VARCHAR, \"VALUE\" INTEGER)");
statement.executeUpdate("INSERT INTO \"FactData\" VALUES ('A', 1), ('B', 2), ('C', 3)");
}
Path initSql = tempDir.resolve("init.sql");
Files.writeString(initSql, "CREATE OR REPLACE VIEW \"Fact\" AS SELECT * FROM \"FactData\";");

assertSumIsQueryable(Map.of("DAANSE_JDBC_ACCESS_MODE", "READ_WRITE", "DAANSE_JDBC_SESSION_INIT_SQL_FILE",
"/app/init/init.sql"), viewless, MODE_WRITABLE, initSql);
}

private static void assertSumIsQueryable(Map<String, String> env, int databaseFileMode) throws Exception {
assertSumIsQueryable(env, databaseFile, databaseFileMode, null);
}

try (GenericContainer<?> pivot = new GenericContainer<>(PivotContainers.pivotImage("duckdb"))
private static void assertSumIsQueryable(Map<String, String> env, Path database, int databaseFileMode,
Path initSql) throws Exception {
try (GenericContainer<?> pivot = new GenericContainer<>(image)
.withCopyFileToContainer(MountableFile.forClasspathResource("catalog.xmi"),
"/app/catalog/catalog.xmi")
.withCopyFileToContainer(MountableFile.forHostPath(databaseFile), "/app/data/database.duckdb")
.withCopyFileToContainer(MountableFile.forHostPath(database, databaseFileMode),
"/app/data/database.duckdb")
.withEnv(env)
.withExposedPorts(8080)
.waitingFor(Wait.forListeningPort())) {
if (initSql != null) {
pivot.withCopyFileToContainer(MountableFile.forHostPath(initSql), "/app/init/init.sql");
}
pivot.start();

String response = PivotContainers.awaitMdxCell(pivot.getHost(), pivot.getMappedPort(8080),
Expand Down
2 changes: 1 addition & 1 deletion application/pivot/h2/daanse.pivot.h2.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -60,6 +59,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
2 changes: 1 addition & 1 deletion application/pivot/mariadb/daanse.pivot.mariadb.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
mariadb-java-client;version='[3.5.5,3.5.6)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -60,6 +59,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
2 changes: 1 addition & 1 deletion application/pivot/mssql/daanse.pivot.mssql.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -60,6 +59,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
2 changes: 1 addition & 1 deletion application/pivot/mysql/daanse.pivot.mysql.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -60,6 +59,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
2 changes: 1 addition & 1 deletion application/pivot/oracle/daanse.pivot.oracle.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -59,6 +58,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
2 changes: 1 addition & 1 deletion application/pivot/postgres/daanse.pivot.postgres.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
com.zaxxer.HikariCP;version='[7.1.0,7.1.1)',\
net.sf.jsqlparser;version='[5.3.167,5.3.168)',\
org.apache.aries.spifly.dynamic.bundle;version='[1.3.7,1.3.8)',\
org.apache.commons.commons-collections4;version='[4.5.0,4.5.1)',\
org.apache.felix.configadmin;version='[1.9.26,1.9.27)',\
org.apache.felix.http.jetty12;version='[2.0.4,2.0.5)',\
org.apache.felix.http.servlet-api;version='[6.1.0,6.1.1)',\
Expand Down Expand Up @@ -59,6 +58,7 @@
org.eclipse.daanse.olap.api;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.common;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.function;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.spi;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.util.format;version='[0.0.1,0.0.2)',\
org.eclipse.daanse.olap.xmla.connector;version='[0.0.1,0.0.2)',\
Expand Down
Loading
Loading