A Windows DLL (and Python + R wrappers) for connecting to Microsoft Analysis Services OLAP cubes — both multidimensional (MDX) and tabular (DAX) models — via the MSOLAP OLE DB provider.
olapclient.h C API header (share with callers)
olapclient.cpp DLL implementation
olapclient.vcxproj Visual Studio 2022 DLL project
olapclient.sln Solution file
python/
olapclient/
__init__.py Python package (ctypes-based)
setup.py
R/
olapclientR/
DESCRIPTION
NAMESPACE
R/olap.R R package functions
src/
r_wrapper.cpp R ↔ DLL glue (.Call API)
Makevars.win Windows build settings
| Component | Where to get it |
|---|---|
| Windows 10/11 (64-bit) | — |
| Visual Studio 2019/2022 with C++ workload | visualstudio.microsoft.com |
| MSOLAP OLE DB provider | Installed with SQL Server, SSMS, or the standalone download |
| Python ≥ 3.7 (Python wrapper) | python.org |
| R ≥ 4.0 with Rtools (R wrapper) | r-project.org |
Note on cross-platform use: The DLL itself relies on Windows COM/OLE DB and only runs on Windows. The Python and R packages are structured so they can be distributed cross-platform; on non-Windows systems they will raise a clear error directing users to XMLA/JDBC alternatives.
- Open
olapclient.slnin Visual Studio 2022. - Select Release | x64 (or the architecture that matches your Python/R install).
- Build → the DLL lands in
bin\x64\Release\olapclient.dll.
MSOLAP type library: The project imports ADO via its COM GUID (
libid:00000205-0000-0010-8000-00AA006D2EA4), so no hard-coded path tomsado15.dllis needed.
Provider=MSOLAP;Data Source=<server>\<instance>;Initial Catalog=<database>;
Provider=MSOLAP;Data Source=asazure://<region>.asazure.windows.net/<server>;
Initial Catalog=<database>;
User ID=<upn>;Password=<password>;Persist Security Info=True;
Provider=MSOLAP;Data Source=powerbi://api.powerbi.com/v1.0/myorg/<workspace>;
Initial Catalog=<dataset>;User ID=app:<app_id>@<tenant_id>;Password=<secret>;
from olapclient import OlapClient, QueryType
conn_str = "Provider=MSOLAP;Data Source=myserver;Initial Catalog=AdventureWorks;"
# --- MDX (multidimensional) ---
with OlapClient(conn_str) as client:
result = client.execute_mdx("""
SELECT
NON EMPTY {[Measures].[Internet Sales Amount]} ON COLUMNS,
NON EMPTY {[Date].[Calendar Year].Members} ON ROWS
FROM [Internet Sales]
""")
print(result.columns)
print(result.rows[0]) # first row as list of strings
df = result.to_df() # pandas DataFrame (requires pandas)
# --- DAX (tabular) ---
with OlapClient(conn_str) as client:
df = client.execute_dax(
"EVALUATE SUMMARIZECOLUMNS('Date'[Calendar Year], "
"\"Sales\", [Internet Sales Amount])"
)# 1. Build olapclient.dll (see above) and copy to python/olapclient/
cp bin/x64/Release/olapclient.dll python/olapclient/
# 2. Install the package
pip install ./python
# Optional pandas support
pip install "./python[pandas]"
library(olapclientR)
conn_str <- "Provider=MSOLAP;Data Source=myserver;Initial Catalog=AdventureWorks;"
conn <- olap_connect(conn_str)
# MDX – multidimensional cube
df_mdx <- olap_execute_mdx(conn, "
SELECT
NON EMPTY {[Measures].[Internet Sales Amount]} ON COLUMNS,
NON EMPTY {[Date].[Calendar Year].Members} ON ROWS
FROM [Internet Sales]
")
# DAX – tabular model
df_dax <- olap_execute_dax(conn,
"EVALUATE SUMMARIZECOLUMNS('Date'[Calendar Year], \"Sales\", [Internet Sales Amount])"
)
olap_disconnect(conn)# 1. Set the path to the folder containing olapclient.h and olapclient.lib
Sys.setenv(OLAPCLIENT_DIR = "C:/path/to/olapclient/bin/x64/Release")
# 2. Install from source
install.packages("R/olapclientR", repos = NULL, type = "source")Tip: The
.libimport library is generated by MSVC alongside the DLL. PointOLAPCLIENT_DIRat the directory containing botholapclient.dll,olapclient.lib, andolapclient.h.
| Function | Description |
|---|---|
olap_connect(conn_str) |
Open a connection; returns OLAP_CONN or NULL |
olap_disconnect(conn) |
Close and free the connection |
olap_is_connected(conn) |
Returns 1 if open |
olap_execute(conn, query, type) |
Run MDX/DAX; returns OLAP_RESULT or NULL |
olap_free_result(result) |
Release result memory |
olap_get_column_count(result) |
Number of columns |
olap_get_row_count(result) |
Number of rows |
olap_get_column_name(result, col) |
Column name string |
olap_get_value(result, row, col) |
Cell value as UTF-8 string |
olap_get_last_error() |
Last error message (thread-local) |
olap_get_version() |
DLL version string |
query_type constants: OLAP_QUERY_MDX = 0, OLAP_QUERY_DAX = 1
- MDX flattened results: ADO + MSOLAP returns MDX results as a flat
two-dimensional recordset. Use
NON EMPTYand axis ordering to control which dimensions appear as columns. - DAX dialect: MSOLAP 11+ (SQL Server 2012+) auto-detects DAX vs MDX.
Pass
OLAP_QUERY_DAXas an explicit hint; the implementation also sets the dialect on the connection when supported. - Thread safety: Each thread should call
olap_connectseparately; connections are not shared across threads. Error messages are stored thread-locally. - NULL values: Empty cells and server-side NULLs are returned as an empty
string
""in C/Python and asNA_character_in R.