Read & write SAP IDoc files (flat + IDoc-XML) as SQL in DuckDB — a community extension in the erpl family.
Maintainer(s):
jrosskopf
Installing and Loading
INSTALL erpl_idoc FROM community;
LOAD erpl_idoc;
Added Functions
| function_name | function_type | description | comment | examples |
|---|---|---|---|---|
| sap_idoc_dict_from_fields | scalar | Normalize an IDOCTYPE_READ_COMPLETE PT_FIELDS list into the SPEC B4 dictionary schema (the transform used internally by the sap_idoc_dictionary macro). Pure — it only reshapes data that erpl_rfc already returned; no RFC is performed here. | NULL | [SELECT UNNEST(sap_idoc_dict_from_fields([{SEGMENTTYP: 'E1MARAM', FIELD_POS: '1', FIELDNAME: 'MATNR', BYTE_FIRST: '0', EXTLEN: '18', DATATYPE: 'CHAR', ROLLNAME: 'MATNR', DESCRP: 'Material number'}], 'MATMAS05', '', '620')), SELECT UNNEST(sap_idoc_dict_from_fields(r.PT_FIELDS,'MATMAS05','','620')) FROM sap_rfc_invoke('IDOCTYPE_READ_COMPLETE', sap_idoc_params('MATMAS05')) r] |
| sap_idoc_dict_offsets | table | Compute a segment dictionary's field offsets from lengths only: the 0-based SDATA offset of each field is the cumulative width of the preceding fields in the same segment. Input needs segnam, field_pos, field_name, length (datatype optional). 'src' is a .csv/.parquet path, a table/view name, or a relation expression. | NULL | [SELECT * FROM sap_idoc_dict_offsets('my_fields.csv')] |
| sap_idoc_dict_validate | table | Validate a segment dictionary: returns one row per structural problem (offset<0/length<=0, field exceeds SDATA(1000), overlaps the previous field, duplicate field_pos). An empty result means the dictionary is structurally sound. | NULL | [SELECT * FROM sap_idoc_dict_validate('my.dict.parquet')] |
| sap_idoc_dictionary | table_macro | Fetch and normalise a segment dictionary (SPEC B4 schema: segnam, field_pos, field_name, offset, length, datatype) from a live SAP system over erpl_rfc. 'params' must be a struct carrying PI_IDOCTYP/PI_CIMTYP/PI_VERSION – build it with sap_idoc_params. Requires erpl_rfc to be loaded; on a SAP-less host use a persisted dictionary file instead. | NULL | [SELECT * FROM sap_idoc_dictionary(sap_idoc_params('FLIGHTBOOKING_CREATEFROMDAT01'));] |
| sap_idoc_encode_control | scalar | Compose a 524-byte EDI_DC40 control record (BLOB) from up to 36 field values given in EDI_DC40 order (tabnam, mandt, docnum, docrel, …, serial); missing/short values are space-padded. | NULL | [SELECT sap_idoc_encode_control(['EDI_DC40','001','0000000000000042','740'])] |
| sap_idoc_encode_data_record | scalar | Compose a 1063-byte EDI_DD40 data record (BLOB). Numeric header fields (docnum, segnum, psgnum, hlevel) are zero-padded to SAP widths; segnam/mandt/sdata are placed as-is. | NULL | [SELECT sap_idoc_encode_data_record('E1BPSBONEW','001',0,2,1,2, sap_idoc_encode_sdata([0,3], [3,4], ['LH','0400']))] |
| sap_idoc_encode_sdata | scalar | Compose a 1000-byte IDoc SDATA payload by placing each value at its (offset, length) — the parallel lists come from the segment dictionary. Values are space-padded/truncated to width. | NULL | [SELECT sap_idoc_encode_sdata([0,3], [3,4], ['LH','0400'])] |
| sap_idoc_params | macro | Build the IDOCTYPE_READ_COMPLETE import-parameter struct that sap_idoc_dictionary passes to sap_rfc_invoke. Separate from sap_idoc_dictionary because sap_rfc_invoke executes the RFC at BIND time, so its argument must already be constant there; calling this with literals folds to one. | NULL | [sap_idoc_params('FLIGHTBOOKING_CREATEFROMDAT01')] |
| sap_idoc_read | table | Read one or many SAP IDoc flat files as generic long rows: one row per data (EDI_DD40) record with document_key, docnum, segnum, segnam, psgnum, hlevel, mandt and the raw 1000-char SDATA. The path may be a single file, a glob ('dir/.idoc', 's3://bucket/idocs/.idoc') resolved over DuckDB's filesystem, or a LIST of paths. Framing is auto-detected; 'lenient' salvages truncated files, 'encoding' decodes non-UTF-8 SDATA, and 'filename := true' adds the source-file column. | NULL | [SELECT * FROM sap_idoc_read('flight.idoc'), SELECT filename, segnam FROM sap_idoc_read('corpus/*.idoc', filename=true), SELECT * FROM sap_idoc_read(['a.idoc', 'b.idoc'])] |
| sap_idoc_read_control | table | Read the typed control record(s) of one or many SAP IDoc flat (or XML) files — all 36 EDI_DC40 fields (tabnam, docnum, idoctyp, mestyp, sndprn, rcvprn, …) plus a document_key. One row per IDoc; accepts a single path, a glob, or a LIST of paths, and 'filename := true'. | NULL | [SELECT idoctyp, mestyp, sndprn FROM sap_idoc_read_control('flight.idoc'), SELECT filename, idoctyp FROM sap_idoc_read_control('corpus/*.idoc', filename=true)] |
| sap_idoc_read_fields | table | Decode ALL fields of every record in an IDoc using a segment dictionary — one call, long form: one row per (record, field) with document_key, segnum, psgnum, hlevel, segnam, field_pos, field_name, datatype, value. SDATA is sliced byte-correctly (same decoding as sap_idoc_read_segment). Accepts a single path, a glob, or a LIST of paths (+ 'filename := true'). Segments absent from the dictionary yield one row with NULL field_name/field_pos and the raw trimmed SDATA (set include_unknown => false to drop them). 'dict' is any dictionary source: a .csv/.parquet path, a table/view name, or a relation expression. | NULL | [SELECT segnam, field_name, value FROM sap_idoc_read_fields('flight.idoc', 'flight_dict.csv'), SELECT * FROM sap_idoc_read_fields('corpus/*.idoc', 'dict', filename=true) WHERE segnam = 'E1BPSBONEW'] |
| sap_idoc_read_raw | table | Read every physical record of one or many SAP IDoc flat files with exact bytes: document_key, record_index, record_type ('C' control / 'D' data) and raw_record (BLOB). Byte-exact source for the writer — COPY (…) TO … (FORMAT sap_idoc). Accepts a single path, a glob, or a LIST, and 'filename := true'. | NULL | [COPY (SELECT raw_record FROM sap_idoc_read_raw('f.idoc') ORDER BY record_index) TO 'g.idoc' (FORMAT sap_idoc)] |
| sap_idoc_read_segment | table | Typed read of one IDoc segment type: split each segment's SDATA into named, typed columns using a segment dictionary. Accepts a single path, a glob, or a LIST of paths (+ 'filename := true'). 'dict' is the dictionary source — a .csv/.parquet path, a table/view name, or a relation expression (SPEC B4 columns: segnam, field_pos, field_name, offset, length, datatype). | NULL | [SELECT airlineid, flightdate FROM sap_idoc_read_segment('flight.idoc', 'E1BPSBONEW', 'flight_dict.csv'), SELECT * FROM sap_idoc_read_segment('corpus/*.idoc', 'E1BPSBONEW', 'dict_view')] |
| sap_idoc_read_xml | table | Read an IDoc-XML file as generic long rows: document_key, seq, segnam, hlevel, field_name, value (control fields appear as segnam='EDI_DC40', hlevel 0). IDoc-XML is self-describing, so no dictionary is needed. | NULL | [SELECT * FROM sap_idoc_read_xml('flight.xml')] |
| sap_idoc_to_xml | table | Convert a flat IDoc file to IDoc-XML (returns one row with the XML text). The dictionary names each SDATA field. Inverse of sap_idoc_xml_to_records. | NULL | [SELECT xml FROM sap_idoc_to_xml('flight.idoc', 'flight_dict.csv')] |
| sap_idoc_version | scalar | Smoke/echo function proving erpl_idoc is loaded; returns 'erpl_idoc |
NULL | [SELECT sap_idoc_version('ok')] |
| sap_idoc_xml_to_records | table | Convert an IDoc-XML file to flat records (document_key, record_index, record_type, raw_record BLOB), recomputing SEGNUM/PSGNUM from the XML nesting and packing SDATA per the dictionary. Feed raw_record to COPY (FORMAT sap_idoc) to write a flat file. | NULL | [COPY (SELECT raw_record FROM sap_idoc_xml_to_records('flight.xml','flight_dict.csv') ORDER BY record_index) TO 'flight.idoc' (FORMAT sap_idoc)] |
Overloaded Functions
This extension does not add any function overloads.
Added Types
This extension does not add any types.
Added Settings
| name | description | input_type | scope | aliases |
|---|---|---|---|---|
| datazoo_banner | Show the DataZoo feedback banner when an extension is loaded in an interactive terminal (at most once a day per extension). | BOOLEAN | GLOBAL | [] |
| erpl_telemetry_enabled | Enable anonymous ERPL telemetry (opt-out); see https://erpl.io/telemetry. | BOOLEAN | GLOBAL | [] |
| erpl_telemetry_key | PostHog project key for ERPL telemetry. | VARCHAR | GLOBAL | [] |