BICS Protocol Deep Dive
This guide covers the BICS (BI Consumer Services) interface in ERPL: how to discover InfoProviders and BEx queries, build OLAP cross-tabs, fetch result sets, and trace end-to-end lineage from source tables to BEx queries — all from SQL in DuckDB.
BICS (BI Consumer Services) is the SAP interface that tools like SAP Analysis for Office
use to consume SAP Business Warehouse (BW) data. ERPL talks to BICS through the SAP
NetWeaver RFC SDK — it calls the BICS_PROV_* RFC function modules to open a query,
manipulate its OLAP state, and read result sets. It is not a separate HTTP/web protocol:
there is no BICS port, no XML payload, and no SAML. Connectivity and authentication are
exactly the same as for the RFC protocol — a DuckDB secret of type
sap_rfc.
How it works
ERPL uses two RFC paths:
- Query execution drives an OLAP query through the BICS provider modules
(
BICS_CONS_CREATE_DATA_AREA,BICS_PROV_OPEN,BICS_PROV_GET_INITIAL_STATE,BICS_PROV_SET_STATE,BICS_PROV_GET_RESULT_SET,BICS_PROV_CLOSE). These powersap_bics_begin/rows/columns/filter/result. - Metadata & lineage read BW dictionary tables via
RFC_READ_TABLE(e.g.RSRREPDIR,RSZCOMPDIR,RSDCUBE,RSTRAN,ROOSFIELD,RSHIEDIR,RSOOBJXREF). These power thesap_bics_show*,sap_bics_meta_*, andsap_bics_lineage_*functions.
Connecting
Every BICS function uses a DuckDB secret of type sap_rfc — the same secret used by the RFC
extension. Create one once per session (the example below uses the ABAP Platform Trial
defaults):
CREATE SECRET abap_trial (
TYPE sap_rfc,
ASHOST 'localhost',
SYSNR '00',
CLIENT '001',
USER 'DEVELOPER',
PASSWD 'ABAPtr2023#00',
LANG 'EN'
);
If a single unnamed/default secret exists, ERPL uses it automatically. When you keep several
secrets, pass the one you want with the secret named parameter that every BICS function
accepts, e.g. sap_bics_show_cubes(secret => 'abap_trial'). For encrypted connections, add
the SNC parameters (SNC_QOP, SNC_MYNAME, SNC_PARTNERNAME, SNC_LIB) to the secret —
see the security guide. All examples below assume a usable secret
exists and omit the parameter for brevity.
Discovering objects
-- InfoProviders (cubes, ADSOs, CompositeProviders, …)
SELECT * FROM sap_bics_show(obj_type => 'INFOPROVIDER');
-- Just cubes, or just queries (dedicated helpers with search)
SELECT * FROM sap_bics_show_cubes();
SELECT * FROM sap_bics_show_queries();
-- Search by technical name or text
SELECT technical_name, text, type
FROM sap_bics_show_queries(search => '0D_FC_NW_C01_Q0011', search_in_key => true);
sap_bics_show(obj_type => ...) accepts INFOPROVIDER, CUBE, QUERY, or INFOAREA, and
returns technical_name, text, type, cube_name, is_folder, last_changed,
last_changed_by, and level.
Querying a cube (OLAP cross-tabs)
BICS queries are stateful. You open a query state, identify it with an id, mutate that
state with separate calls, and finally read the result set by the same id. Unlike ordinary
table functions, the BICS query functions are not nested inside one another — they are
chained by passing the state id string from one call to the next.
-- 1. Open a query state on the cube and give it an id
SELECT state_id, state_version
FROM sap_bics_begin('0D_NW_C01', id => 'q1');
-- 2. Place characteristics on the ROWS axis (the cross-tab "drilldown")
SELECT state_id, state_version
FROM sap_bics_rows('q1', '0D_NW_PROD', op => 'SET');
-- 3. Place a characteristic on the COLUMNS axis
SELECT state_id, state_version
FROM sap_bics_columns('q1', '0CALMONTH', op => 'SET');
-- 4. Read the result set for this state
SELECT * FROM sap_bics_result('q1');
Axes, not column projection
sap_bics_rows and sap_bics_columns are OLAP axes, not a SQL column projection. They
decide which characteristics are drilled into the rows vs. the columns of the cross-tab — the
same as dragging a characteristic onto Rows or Columns in Analysis for Office. The key
figures of the cube are aggregated for whatever drilldown you choose. The op parameter
controls how each call changes the axis:
op | Effect |
|---|---|
SET | Replace the axis with exactly these characteristics |
ADD | Append characteristics to the existing axis |
REMOVE | Remove the named characteristics from the axis |
Each mutating call returns the updated state_id and an incrementing state_version, so you
can confirm the state advanced. The columns of sap_bics_result are the cube's own
characteristic and key-figure technical names — for 0D_NW_C01 that includes "0D_NW_PROD",
"0D_NW_NETV" (net value), "0D_NW_QUANT" (quantity), and so on. Because these names start
with a digit, quote them with double quotes in SQL.
begin, rows, columns, and filter accept return => 'RESULT' to return the result set
directly instead of the default state description (return => 'DESCRIBE'). For example,
SELECT * FROM sap_bics_rows('q1', '0D_NW_PROD', op => 'SET', return => 'RESULT') applies the
axis change and hands back data in a single statement.
Filtering members
sap_bics_filter restricts a characteristic to one or more member values (a background
filter / "slice"). Pass the characteristic, then one or more member keys as positional
arguments:
SELECT state_id FROM sap_bics_begin('0D_NW_C01', id => 'f1');
SELECT state_id FROM sap_bics_rows('f1', '0D_NW_PROD', op => 'SET');
-- Single-member filter: Division = 7 ("High Tech")
SELECT state_id FROM sap_bics_filter('f1', '0D_NW_DIV', '7', op => 'SET');
SELECT * FROM sap_bics_result('f1');
-- Multi-member filter: pass several values to one filter() call
SELECT state_id FROM sap_bics_filter('f1', '0CALMONTH', '202401', '202402', '202403',
op => 'SET');
-- op => 'ADD' / 'REMOVE' adjust an existing selection instead of replacing it
SELECT state_id FROM sap_bics_filter('f1', '0D_NW_DIV', '15', op => 'ADD');
You can also seed a filter at begin time with the filters named parameter; ad-hoc
sap_bics_filter calls remain the flexible way to slice an open state.
Hierarchies
-- List hierarchies available for an InfoObject
SELECT * FROM sap_bics_show_hierarchies(info_object => '0D_NW_PROD');
-- Read a hierarchy as a flat node list
SELECT * FROM sap_bics_hierarchy('0D_NW_PROD_HIER');
-- Pin a version / key date and return a recursive tree
SELECT * FROM sap_bics_hierarchy('0D_NW_PROD_HIER', date_to => '20151231', as_tree => true);
sap_bics_hierarchy returns node_id, parent_id, child_id, next_id, info_object,
node_name, node_value, date_from, date_to, level, and path — enough to rebuild the
tree yourself or filter by level.
Describing structures
-- Describe a cube: characteristics + key figures
SELECT technical_name, text FROM sap_bics_describe('0D_NW_C01');
-- Describe a BEx query on a cube (adds its variables)
SELECT technical_name, text, variables
FROM sap_bics_describe('0D_NW_C01', '0D_FC_NW_C01_Q0011');
-- Describe an open query state by its id
SELECT * FROM sap_bics_describe(id => 'q1');
sap_bics_describe returns technical_name, text, and the characteristics / keyfigures
structs (plus variables for the query overload). For attributes of a single InfoObject:
SELECT info_object, data_type, length, decimals
FROM sap_bics_describe_infoobject('0D_NW_PROD');
sap_bics_describe_infoobject returns info_object, data_type, conv_exit,
output_length, length, and decimals.
Presentation properties (AO-style)
sap_bics_set_char_prop toggles per-characteristic display properties that match the radio
controls in SAP Analysis for Office's Properties panel. The mutation persists in the BICS
state and is honoured by the next sap_bics_result call.
-- Build a 1D cross-tab on country
SELECT * FROM sap_bics_begin('0D_NW_C01', id => 'q1');
SELECT * FROM sap_bics_rows('q1', '0D_NW_CNTRY', op => 'SET');
-- Display member texts instead of keys ("Germany" vs "DE")
SELECT * FROM sap_bics_set_char_prop('q1', '0D_NW_CNTRY', 'DISPLAY', 'TEXT');
-- Show both key and text concatenated
SELECT * FROM sap_bics_set_char_prop('q1', '0D_NW_CNTRY', 'DISPLAY', 'BOTH');
-- Sort by member descending
SELECT * FROM sap_bics_set_char_prop('q1', '0D_NW_CNTRY', 'SORT', 'DESC');
-- Fetch with the new presentation
SELECT * FROM sap_bics_result('q1');
prop | Allowed value | Maps to BICS state field |
|---|---|---|
DISPLAY | KEY | TEXT | BOTH | RESULT_SET_PRESENTATION bitflag (KEY=4, TEXT=32) |
TOTALS | SHOW | HIDE | RESULT_VISIBILITY ('A' / 'N') |
SORT | ASC | DESC | NONE | RESULT_SET_SORTING.DIRECTION ('A' / 'D' / '') |
The DESCRIBE payload of state_rows, state_columns, and state_free carries
{display, totals, sort} so clients can read the current values without an extra round-trip.
BICS does not expose a state field for the SUMME / "Overall Result" grand-total row.
TOTALS='HIDE' is persisted to per-characteristic RESULT_VISIBILITY but the server still
returns the grand-total row in sap_bics_result. Clients that want AO's "Hide Result"
behaviour can filter the row whose row-characteristic value matches SUMME /
Overall Result / localised variants — that's what AO itself does.
Interactive: bics-tui
bics-tui (in bics/examples/tui/)
is a terminal UI that wraps every BICS function above into a Textual app modelled on SAP
Analysis for Office: log on, browse cubes / queries, build a cross-tab by moving
characteristics between Rows / Columns / Background Filter, filter members, and toggle
Display / Sort / Totals for a focused characteristic or Scaling Factor / Decimal
Places for a focused key figure — all from a context-sensitive Properties panel on the
right. Every server-side action is mirrored into an always-on SQL recorder, so the resulting
script replays cleanly in a vanilla DuckDB shell.
Logon
The logon screen pre-fills the standard ABAP Platform Trial credentials — overwrite for your
own system. The fields are wired straight into a DuckDB CREATE SECRET of type sap_rfc.

Analysis screen
Three-column layout: cross-tab grid on the left, design panel in the middle (Data Source / Columns / Rows / Background Filter / Key Figures), context-sensitive Properties panel on the right. Hotkeys are shown next to each section header.

Properties — Characteristic on axis
Focus a characteristic in any axis list and the Properties panel switches to three radio
groups: Display (Key / Text / Both), Totals (Show / Hide / Conditional), Sort (None / Asc /
Desc). Display and Sort round-trip via
sap_bics_set_char_prop; Totals Hide is applied
client-side (BICS does not expose a state field for the grand-total row).

Properties — Key figure
Focus a key figure and the panel switches to Scaling Factor and Decimal Places. Both are client-side numeric formatting — BICS state carries no field for them. The KF columns in the cross-tab re-format live as you change the controls.

Run it
GEN=ninja make release # from erpl monorepo root
cd bics/examples/tui
uv sync
LD_LIBRARY_PATH=/path/to/erpl/nwrfcsdk/linux/lib uv run python -m bics_tui
The screenshots above are regenerated headlessly via
scripts/capture_screens.py
(Textual's export_screenshot → SVG → PNG with a mock session for layout-only capture; no SAP
connection needed).
Lineage Tracking (for SAP BW experts)
This section covers lineage tracking from ERP tables through DataSources, InfoProviders, and
BEx queries. It reads the BW dictionary tables via RFC_READ_TABLE, so it does not need an
open query state.
Complete lineage as edges
sap_bics_lineage_edges() returns the BW data flow as a flat edge list spanning ERP source
tables → DataSources → transformations → InfoProviders → BEx queries. Each row is one
source-to-target edge with these columns:
| Column | Description |
|---|---|
edge_type | Edge category (e.g. transformation, query-element) |
src_kind, src_name, src_field | Source object kind, name, and optional field |
tgt_kind, tgt_name, tgt_field | Target object kind, name, and optional field |
Use cases:
- Impact analysis — what happens if a source table changes?
- Data governance — track data flow and transformations
- Documentation — automatic lineage documentation
- Compliance — audit data lineage for regulations
-- All edges in the system
SELECT * FROM sap_bics_lineage_edges();
-- Edges related to a specific BEx query — filter in SQL
SELECT *
FROM sap_bics_lineage_edges()
WHERE tgt_name = '0D_FC_NW_C01_Q0008' OR src_name = '0D_FC_NW_C01_Q0008'
ORDER BY src_kind, tgt_kind;
-- Scope the underlying RFC reads to one object (faster on large landscapes)
SELECT * FROM sap_bics_lineage_edges(scope => '0D_NW_C01');
Forward trace from a source
sap_bics_lineage_trace() walks the graph forward from a specific source object/field —
perfect for "if I change this object, what downstream BW objects break?". The result includes
a hop column and a path column (the chain of objects walked) so you can see the full
downstream blast radius.
-- Everything downstream of an InfoProvider
SELECT * FROM sap_bics_lineage_trace(source_object => '0D_NW_C01')
ORDER BY hop;
-- Field-level trace
SELECT * FROM sap_bics_lineage_trace(
source_object => '0D_NW_C01',
source_field => '0D_NW_NETV'
);
Lineage of a single query
sap_bics_query_lineage() resolves the lineage rooted at one BEx query:
SELECT * FROM sap_bics_query_lineage('0D_FC_NW_C01_Q0011');
Lineage as a JSON graph
sap_bics_lineage_graph_json() returns the full lineage as a JSON document, suitable for
visualization libraries (D3, Cytoscape, etc.) or export to external graph tools.
SELECT * FROM sap_bics_lineage_graph_json();
Metadata mining
The sap_bics_meta_* functions expose the BW dictionary tables directly.
To avoid scanning an entire BW landscape by accident, some functions refuse a bare no-argument
call and return a message telling you which parameter to supply. The functions that require
at least one argument are sap_bics_meta_providers (type), sap_bics_meta_datasources
(appcomp), sap_bics_meta_transformations (active_only), sap_bics_meta_query_stats
(one of query_name / from_date / to_date), sap_bics_meta_objxref
(tlogo / objnm / tlogo_dep), and sap_bics_meta_hcpr_mapping (composite_provider).
The field-level helpers below take the object name positionally.
-- InfoProvider metadata (type is required: CUBE | ADSO | HCPR | ODSO | ODSVIEW)
SELECT * FROM sap_bics_meta_providers(type => 'CUBE');
-- DataSource metadata (application component is required)
SELECT * FROM sap_bics_meta_datasources(appcomp => 'NODE0000');
-- Transformation metadata
SELECT * FROM sap_bics_meta_transformations(active_only => true);
-- Query directory (no argument required)
SELECT * FROM sap_bics_meta_queries();
-- Query usage / runtime statistics
SELECT * FROM sap_bics_meta_query_usage('0D_FC_NW_C01_Q0011');
SELECT * FROM sap_bics_meta_query_stats(query_name => '0D_FC_NW_C01_Q0011');
-- Query elements (structures, selections, formulas)
SELECT * FROM sap_bics_meta_query_elements('0D_FC_NW_C01_Q0011');
Field-level & cross-reference metadata
-- DataSource fields (DataSource name is positional)
SELECT * FROM sap_bics_meta_datasource_fields('0FI_GL_4');
-- InfoProvider fields (provider name is positional; pass provider_type to disambiguate)
SELECT * FROM sap_bics_meta_provider_fields('0D_NW_C01', provider_type => 'CUBE');
-- Transformation field mappings (transformation id is positional)
SELECT * FROM sap_bics_meta_transform_fields('<transformation-id>');
-- CompositeProvider (HCPR) components and their part-provider mapping
SELECT * FROM sap_bics_meta_hcpr_components('<composite-provider>');
SELECT * FROM sap_bics_meta_hcpr_mapping(composite_provider => '<composite-provider>');
-- InfoObject catalog (no argument required; filter with iobjnm/iobjtp)
SELECT * FROM sap_bics_meta_infoobjects(iobjnm => '0D_NW_PROD');
-- Object cross-reference (which objects reference which)
SELECT * FROM sap_bics_meta_objxref(tlogo => 'CUBE', objnm => '0D_NW_C01');
The exact rows these return depend on what is configured in your BW system; the demo objects above are populated on the ABAP Platform Trial, while DataSources and transformations are typically richer on a productive landscape.
HCPR is the SAP TLOGO type for a HANA CompositeProvider, not a "hierarchy change
pointer". The *_hcpr_* helpers describe CompositeProviders and the part-providers they
union/join.
Real-world examples
Net value by product
Build the state with separate statements, then query the result. Each call returns the
state_id, so you can ignore those rows and read the data from sap_bics_result:
SELECT state_id FROM sap_bics_begin('0D_NW_C01', id => 'rep1');
SELECT state_id FROM sap_bics_rows('rep1', '0D_NW_PROD', op => 'SET');
SELECT state_id FROM sap_bics_filter('rep1', '0D_NW_DIV', '7', op => 'SET');
SELECT
"0D_NW_PROD" AS product,
"0D_NW_NETV" AS net_value,
"0D_NW_QUANT" AS quantity
FROM sap_bics_result('rep1')
ORDER BY net_value DESC
LIMIT 20;
Combine BW data with ERP master data
Once the rep1 state above exists, its result set joins to ERP master data read over RFC:
-- BW net value per product, joined to ERP material master via RFC
WITH bw_sales AS (
SELECT "0D_NW_PROD" AS product, "0D_NW_NETV" AS net_value
FROM sap_bics_result('rep1') -- the state built above
),
erp_materials AS (
SELECT MATNR AS material, MTART AS material_type, MEINS AS base_unit
FROM sap_read_table('MARA', MAX_ROWS => 10000)
)
SELECT
b.product, m.material_type, m.base_unit, b.net_value,
CASE
WHEN b.net_value > 1e9 THEN 'High Value'
WHEN b.net_value > 1e8 THEN 'Medium Value'
ELSE 'Low Value'
END AS value_category
FROM bw_sales b
LEFT JOIN erp_materials m ON b.product = m.material
ORDER BY b.net_value DESC;
Performance & good practice
- Slice early with filters and axes. Restricting members with
sap_bics_filterand limiting the drilldown withsap_bics_rows/sap_bics_columnsis what reduces the result set — there is no SQL-style column projection at the BICS layer. - Reuse the query state.
beginopens a server-side state; keep mutating the sameidrather than re-opening for each variation.state_versionconfirms each change landed. - Scope metadata reads. Pass
scope/object arguments to thelineage/metafunctions so the underlyingRFC_READ_TABLEcalls stay bounded on large landscapes. - Reuse connections. ERPL caches RFC connections per secret; running several BICS statements in one DuckDB session avoids repeated logons.
Troubleshooting
Query or cube not found
-- Names are case-sensitive; search the catalog
SELECT * FROM sap_bics_show_queries(search => 'Q0011');
SELECT * FROM sap_bics_show(obj_type => 'CUBE', search => '0D_NW_C01');
Empty result set
-- Re-check filter member keys (use keys, not display texts)
SELECT * FROM sap_bics_describe_infoobject('0D_NW_DIV');
-- Drop filters to confirm the cube has data at all
SELECT * FROM sap_bics_begin('0D_NW_C01', id => 'probe', return => 'RESULT');
Metadata function errors with "requires named parameters"
This is the guardrail described above — supply the named argument it asks for (e.g.
sap_bics_meta_providers(type => 'CUBE')).
Enable tracing
ERPL has a built-in trace facility. Enable it to see the exact RFC calls and payloads:
SET erpl_trace_enabled = TRUE;
SET erpl_trace_level = 'DEBUG'; -- TRACE | DEBUG | INFO | WARN | ERROR
SET erpl_trace_output = 'console'; -- console | file | both
For SAP BW experts: the BICS interface in detail
BICS in ERPL is an RFC interface, not a network protocol of its own: it drives the same
BICS_PROV_* consumer modules that SAP Analysis for Office uses, over the NetWeaver RFC SDK
with your sap_rfc secret. Expand the deep dive below for the wire-level mechanics.
BICS protocol deep dive — handle lifecycle, state model & versioning, result-set decoding, variables, metadata, security
The handle lifecycle
A BICS session juggles three server-side handles, each a 4-character token:
- Application handle —
BICS_CONS_CREATE_DATA_AREAcreates the consumer data area and returnsE_APPLICATION_HANDLE. This is the umbrella context for the session. - Data-provider handle —
BICS_PROV_OPENopens the InfoProvider (or BEx query) and returnsE_DATA_PROVIDER_HANDLEplusE_VARIABLE_CONTAINER_HANDLE. ERPL opens withI_STATE_VARIABLE_MODE = 'U'andI_OPTIMIZE_INIT_VERSION = 5. A variable-container handle of0000is normal for queries that declare no BEx variables — it is not an error. - Initial state —
BICS_PROV_GET_INITIAL_STATE(withI_RETRIEVE_SEL_SPACE_OPT = 'X') returns the complete default OLAP state: the characteristic catalog, the rows/columns/free axis assignments, the selection (filter) state, and the per-characteristic presentation state.
At session end BICS_PROV_CLOSE is called best-effort for the variable-container, data-provider,
and application handles in turn (failures are swallowed).
The full mapping from SQL function to RFC module:
| ERPL step | RFC function module(s) | Key parameters |
|---|---|---|
sap_bics_begin | BICS_CONS_CREATE_DATA_AREA → BICS_PROV_OPEN → BICS_PROV_GET_INITIAL_STATE | I_DATA_PROVIDER_INFO_PROVIDER, I_DATA_PROVIDER_NAME (query) |
sap_bics_rows / columns / filter / set_char_prop | BICS_PROV_SET_STATE | I_S_ROWS, I_S_COLUMNS, I_S_FREE, I_TH_CHARACTERISTICS, I_TSX_SELECTION_STATE, I_VALIDATE = 'X' |
sap_bics_result | BICS_PROV_GET_RESULT_SET | I_MAX_DATA_CELLS = 1000000 |
sap_bics_describe (query) | BICS_PROV_GET_DESIGN_TIME_INFO, BICS_PROV_VAR_GET_VARIABLES | I_VARIABLE_CONTAINER_HANDLE |
| (session end) | BICS_PROV_CLOSE | one call per handle |
The state model and state_version
Although the OLAP state physically lives on the BW server between SET_STATE calls, ERPL also
persists each state snapshot client-side in a DuckDB table keyed by (id, version). Every
mutation — placing a characteristic on an axis, adding a filter, or changing a display/sort/
totals property — saves a new snapshot and increments state_version. That is why a typical
begin → rows → columns → filter sequence returns versions 1 → 2 → 3 → 4. Because snapshots
are immutable and addressed by id, several independent query states can coexist in one DuckDB
session, and you can branch a state by re-using an earlier id.
BICS_PROV_SET_STATE carries the whole OLAP state, not a delta. The notable sub-structures:
- Axes —
I_S_ROWS/I_S_COLUMNS/I_S_FREEand their characteristic-reference tables describe which characteristics sit on the rows axis, the columns axis, and the free (background-filter) axis.op => 'SET'clears the target axis first (key figures are kept on the column axis),'ADD'appends, and'REMOVE'moves a characteristic to the free axis. - Selection state (
I_TSX_SELECTION_STATE) — one entry per filtered characteristic, each holding aSELECTIONlist of{SIGN ('I'/'E'), OPERATOR ('EQ'/'BT'/…), LOW, HIGH}rows. This is the BICS equivalent of an ABAP range table. - Per-characteristic presentation (
I_TH_CHARACTERISTICS) — the fieldssap_bics_set_char_propmanipulates:RESULT_SET_PRESENTATION(a bitflag,KEY=4,TEXT=32,BOTH=36),RESULT_VISIBILITY('A'show /'N'hide /'C'conditional for totals), andRESULT_SET_SORTING.DIRECTION('A'/'D'/'').
Decoding the result set
BICS_PROV_GET_RESULT_SET returns a multidimensional cross-tab, not a flat table, which ERPL
flattens:
- Members & presentation —
E_T_MEMBERlists the axis members; each points into aE_T_MEMBER_PRESENTATIONtable via aPRESENTATION_INDEX_FROM/TOrange. The display mode decides which presentation entry is used:KEYtakes the key,TEXTthe text,BOTHconcatenates them. - Row / column tuples —
E_T_ROWSandE_T_COLUMNSgive the member references per axis position, including aLEVELfield that becomes the synthetic"<char>_HIER_LEVEL"integer column you see for hierarchy drilldowns. - Data cells —
E_T_DATA_CELLSis a sparse{ROW, COLUMN, VALUE}list (cells equal to zero are omitted by the server). ERPL initialises every cell toNULLand fills only the returned ones, so an absent cell isNULL, not0.0. CellVALUEs are alwaysDOUBLE; axis member columns are alwaysVARCHAR. - Grand total — the "Overall Result" /
SUMMErow is an ordinary row inE_T_ROWSwhose member key is the literalSUMME; it is not a separate structure (see the note under Presentation properties above for hiding it). - Cell budget — ERPL requests up to
I_MAX_DATA_CELLS = 1,000,000cells per fetch. A drilldown that would exceed that must be narrowed with filters or fewer axis characteristics.
Variables
BICS_PROV_VAR_GET_VARIABLES retrieves a query's variable definitions (used by
sap_bics_describe), but variable filling is not implemented — there is no
BICS_PROV_VAR_SET_VARIABLES call. Queries that declare variables execute with their
default/empty values; restrict the result with sap_bics_filter instead.
Metadata and lineage
Discovery, sap_bics_meta_*, and sap_bics_lineage_* do not open a query. They read BW
dictionary tables through RFC_READ_TABLE — among them RSRREPDIR and RSZCOMPDIR (queries),
RSDCUBE (InfoCubes), RSTRAN (transformations), ROOSFIELD (DataSource fields), RSHIEDIR
(hierarchies), and RSOOBJXREF (cross-references). Hierarchy nodes come from
RSNDI_SHIE_STRUCTURE_GET3; single-InfoObject attributes from BAPI_IOBJ_GETDETAIL.
Security
Because BICS rides on RFC, its security model is the RFC model:
- Authentication — the
sap_rfcsecret (user/password) or SNC for certificate-based, encrypted logon. There is no Basic Auth or SAML at the BICS layer. - Authorization — standard BW analysis authorizations (RSEC) govern which InfoProviders, queries, and characteristic values a user may read.
- Transport security — use SNC (or an SSH tunnel) to encrypt the RFC connection on untrusted networks.
- Auditing — SAP-side security audit log (SM19/SM20) records the RFC logons.
Next steps
🚀 Ready for More?
- ODP Protocol Guide - Delta replication from SAP
- RFC Protocol Guide - Read SAP tables and call functions
- Function Reference - Complete API docs
🔧 Advanced Topics
- BICS Lineage Tracking - Track data lineage
- Performance Tuning - Optimize BW queries
- Real-World Use Cases - Complete scenarios
💡 Examples
- ERPL Examples - More real-world BICS examples
- Integration with Python - Use BICS data with Pandas
Need help? Check our troubleshooting guide or browse more examples.