tranfi 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +177 -0
- package/NOTICE +8 -0
- package/README.md +272 -40
- package/app/assets/{index-pDFMluyz.js → index-BIAIKnrp.js} +1 -1
- package/app/index.html +1 -1
- package/binding.gyp +55 -3
- package/csrc/arena.c +7 -5
- package/csrc/batch.c +818 -71
- package/csrc/buffer.c +84 -8
- package/csrc/cJSON.c +262 -19
- package/csrc/cJSON.h +17 -1
- package/csrc/codec_csv.c +1074 -181
- package/csrc/codec_jsonl.c +830 -118
- package/csrc/codec_table.c +108 -78
- package/csrc/codec_text.c +286 -68
- package/csrc/compiler.c +31 -3
- package/csrc/config.h +21 -0
- package/csrc/dsl.c +4722 -485
- package/csrc/expr.c +363 -55
- package/csrc/expr.h +2 -0
- package/csrc/internal.h +316 -27
- package/csrc/ir.c +65 -18
- package/csrc/ir.h +41 -0
- package/csrc/ir_schema.c +20 -5
- package/csrc/ir_serialize.c +68 -6
- package/csrc/ir_sql.c +796 -185
- package/csrc/ir_validate.c +462 -6
- package/csrc/json_path.c +210 -0
- package/csrc/main.c +879 -30
- package/csrc/memory_estimate.c +477 -0
- package/csrc/op_acf.c +171 -21
- package/csrc/op_across.c +477 -0
- package/csrc/op_anomaly.c +167 -32
- package/csrc/op_assert.c +761 -0
- package/csrc/op_bin.c +168 -29
- package/csrc/op_cast.c +383 -55
- package/csrc/op_clip.c +30 -19
- package/csrc/op_date_trunc.c +208 -34
- package/csrc/op_datetime.c +259 -77
- package/csrc/op_derive.c +65 -97
- package/csrc/op_diff.c +146 -30
- package/csrc/op_ewma.c +149 -30
- package/csrc/op_explode.c +124 -26
- package/csrc/op_fill_down.c +125 -53
- package/csrc/op_fill_null.c +176 -31
- package/csrc/op_filter.c +89 -40
- package/csrc/op_frequency.c +571 -43
- package/csrc/op_grep.c +36 -18
- package/csrc/op_group_agg.c +1790 -119
- package/csrc/op_hash.c +48 -15
- package/csrc/op_head.c +21 -86
- package/csrc/op_interpolate.c +268 -62
- package/csrc/op_join.c +2700 -182
- package/csrc/op_json_extract.c +227 -0
- package/csrc/op_json_filter.c +384 -0
- package/csrc/op_json_flatten.c +293 -0
- package/csrc/op_json_schema.c +503 -0
- package/csrc/op_label_encode.c +328 -53
- package/csrc/op_lag.c +181 -0
- package/csrc/op_lead.c +141 -89
- package/csrc/op_normalize.c +363 -79
- package/csrc/op_onehot.c +345 -73
- package/csrc/op_pivot.c +1546 -162
- package/csrc/op_quarantine.c +189 -0
- package/csrc/op_registry.c +2062 -166
- package/csrc/op_rename.c +41 -50
- package/csrc/op_replace.c +270 -118
- package/csrc/op_rleid.c +297 -0
- package/csrc/op_rowid.c +559 -0
- package/csrc/op_sample.c +80 -23
- package/csrc/op_schema.c +1341 -0
- package/csrc/op_schema_infer.c +252 -0
- package/csrc/op_select.c +265 -65
- package/csrc/op_set.c +3449 -0
- package/csrc/op_skip.c +30 -87
- package/csrc/op_sort.c +670 -124
- package/csrc/op_source_name.c +120 -0
- package/csrc/op_split.c +65 -28
- package/csrc/op_split_data.c +41 -9
- package/csrc/op_stack.c +178 -222
- package/csrc/op_stats.c +206 -110
- package/csrc/op_step.c +217 -55
- package/csrc/op_tail.c +21 -12
- package/csrc/op_tee.c +338 -0
- package/csrc/op_top.c +260 -53
- package/csrc/op_trim.c +48 -19
- package/csrc/op_unique.c +1193 -150
- package/csrc/op_unpivot.c +100 -66
- package/csrc/op_validate.c +601 -24
- package/csrc/op_window.c +492 -51
- package/csrc/path_policy.c +85 -0
- package/csrc/pipeline.c +872 -99
- package/csrc/recipes.c +3 -1
- package/csrc/report.c +73 -30
- package/csrc/selector.c +1097 -0
- package/csrc/size_utils.c +348 -0
- package/csrc/spill.c +317 -0
- package/csrc/spill.h +21 -0
- package/csrc/tranfi.h +169 -1
- package/csrc/transform.h +209 -0
- package/csrc/transform_api.c +2237 -0
- package/csrc/transform_categorical.c +923 -0
- package/csrc/transform_internal.h +472 -0
- package/csrc/transform_json.c +3812 -0
- package/csrc/transform_numeric.c +1966 -0
- package/csrc/transform_sha256.c +154 -0
- package/csrc/transform_wasm.h +162 -0
- package/csrc/transform_wasm_api.c +1373 -0
- package/csrc/wasm_api.c +70 -9
- package/napi_api.c +219 -11
- package/napi_transform.c +1648 -0
- package/napi_transform.h +8 -0
- package/package.json +27 -11
- package/scripts/install-native.js +76 -0
- package/scripts/prepack.js +64 -0
- package/scripts/sync-csrc.js +23 -0
- package/src/cli.js +8 -11
- package/src/engines/duckdb.js +45 -12
- package/src/index.js +661 -42
- package/src/memory_policy.js +411 -0
- package/src/native.js +1 -5
- package/src/pipeline.js +454 -31
- package/src/recipe_json.js +80 -0
- package/src/server.js +10 -8
- package/src/transform.js +403 -0
- package/src/transform_error.js +10 -0
- package/src/wasm.js +6 -4
- package/wasm/index.js +498 -10
- package/wasm/tranfi_core.js +0 -0
- package/wasm/transform.js +1156 -0
- package/wasm/worker.js +786 -0
- package/csrc/plan.c +0 -206
package/csrc/internal.h
CHANGED
|
@@ -12,6 +12,71 @@
|
|
|
12
12
|
#include <stdint.h>
|
|
13
13
|
#include <stdbool.h>
|
|
14
14
|
|
|
15
|
+
typedef struct cJSON cJSON;
|
|
16
|
+
|
|
17
|
+
#define TF_MAX_BATCH_ROWS ((size_t)64u * 1024u)
|
|
18
|
+
#define TF_MAX_OUTPUT_ROWS_PER_BATCH ((size_t)1024u * 1024u)
|
|
19
|
+
#define TF_MAX_EXPANDING_ROWS_PER_INPUT TF_MAX_OUTPUT_ROWS_PER_BATCH
|
|
20
|
+
#define TF_MAX_EXPLODE_TOKENS_PER_ROW TF_MAX_OUTPUT_ROWS_PER_BATCH
|
|
21
|
+
#define TF_MAX_COLUMNS ((size_t)64u * 1024u)
|
|
22
|
+
#define TF_MAX_RECORD_BYTES ((size_t)1024u * 1024u * 1024u)
|
|
23
|
+
#define TF_MAX_CELL_BYTES ((size_t)64u * 1024u * 1024u)
|
|
24
|
+
#define TF_MAX_COLUMN_NAME_BYTES ((size_t)4096u)
|
|
25
|
+
#define TF_MAX_SCHEMA_BYTES ((size_t)16u * 1024u * 1024u)
|
|
26
|
+
#define TF_MAX_ERROR_BYTES ((size_t)64u * 1024u * 1024u)
|
|
27
|
+
#define TF_MAX_REGEX_PATTERN_BYTES ((size_t)4096u)
|
|
28
|
+
#define TF_MAX_REGEX_CELL_BYTES ((size_t)64u * 1024u)
|
|
29
|
+
#if SIZE_MAX > 9007199254740991ULL
|
|
30
|
+
#define TF_MAX_SAFE_SIZE_ARG ((size_t)9007199254740991ULL)
|
|
31
|
+
#else
|
|
32
|
+
#define TF_MAX_SAFE_SIZE_ARG ((size_t)SIZE_MAX)
|
|
33
|
+
#endif
|
|
34
|
+
#define TF_MAX_COUNT_ARG TF_MAX_SAFE_SIZE_ARG
|
|
35
|
+
#define TF_MAX_STATE_BYTES TF_MAX_SAFE_SIZE_ARG
|
|
36
|
+
#define TF_MAX_SPILL_MEMORY_BYTES TF_MAX_SAFE_SIZE_ARG
|
|
37
|
+
#define TF_MAX_SPILL_RUN_ROWS TF_MAX_COUNT_ARG
|
|
38
|
+
#define TF_MAX_SPILL_OUTPUT_ROWS TF_MAX_BATCH_ROWS
|
|
39
|
+
#define TF_MAX_AUDIT_RECORDS ((size_t)1000u * 1000u)
|
|
40
|
+
#define TF_MAX_TABLE_WIDTH ((size_t)4096u)
|
|
41
|
+
#define TF_MAX_TABLE_ROWS TF_MAX_COUNT_ARG
|
|
42
|
+
#define TF_MAX_WINDOW_SIZE TF_MAX_OUTPUT_ROWS_PER_BATCH
|
|
43
|
+
#define TF_FLOAT64_ROUNDTRIP_FORMAT "%.17g"
|
|
44
|
+
|
|
45
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
46
|
+
#define TF_WARN_UNUSED __attribute__((warn_unused_result))
|
|
47
|
+
#else
|
|
48
|
+
#define TF_WARN_UNUSED
|
|
49
|
+
#endif
|
|
50
|
+
|
|
51
|
+
TF_WARN_UNUSED int tf_format_float64(char *buf, size_t buf_size, double value);
|
|
52
|
+
TF_WARN_UNUSED int tf_size_add(size_t a, size_t b, size_t *out);
|
|
53
|
+
TF_WARN_UNUSED int tf_size_mul(size_t a, size_t b, size_t *out);
|
|
54
|
+
TF_WARN_UNUSED int tf_size_align(size_t x, size_t align, size_t *out);
|
|
55
|
+
TF_WARN_UNUSED int tf_size_grow_pow2(size_t current, size_t min_value, size_t min_capacity, size_t *out);
|
|
56
|
+
TF_WARN_UNUSED void *tf_mallocarray_checked(size_t count, size_t elem_size);
|
|
57
|
+
TF_WARN_UNUSED void *tf_callocarray_checked(size_t count, size_t elem_size);
|
|
58
|
+
TF_WARN_UNUSED void *tf_reallocarray_checked(void *ptr, size_t count, size_t elem_size);
|
|
59
|
+
TF_WARN_UNUSED char *tf_strdup_checked(const char *s);
|
|
60
|
+
TF_WARN_UNUSED char *tf_string_append_suffix_checked(const char *prefix, const char *suffix);
|
|
61
|
+
TF_WARN_UNUSED int tf_check_byte_limit(size_t n, size_t max_value,
|
|
62
|
+
const char *context, const char *name);
|
|
63
|
+
TF_WARN_UNUSED int tf_string_length_bounded(const char *s, size_t max_value,
|
|
64
|
+
size_t *out, const char *context,
|
|
65
|
+
const char *name);
|
|
66
|
+
TF_WARN_UNUSED int tf_json_get_size_arg(const cJSON *args, const char *name,
|
|
67
|
+
size_t min_value, size_t max_value,
|
|
68
|
+
size_t *out, const char *context);
|
|
69
|
+
TF_WARN_UNUSED int tf_json_size_value(const cJSON *item, const char *name,
|
|
70
|
+
size_t min_value, size_t max_value,
|
|
71
|
+
size_t *out, const char *context);
|
|
72
|
+
TF_WARN_UNUSED int tf_json_get_size_arg_any(const cJSON *args, const char *name,
|
|
73
|
+
const char *alt_name,
|
|
74
|
+
size_t min_value, size_t max_value,
|
|
75
|
+
size_t *out, const char *context);
|
|
76
|
+
|
|
77
|
+
typedef int (*tf_index_compare_fn)(const void *ctx, size_t a, size_t b);
|
|
78
|
+
void tf_sort_indices(size_t *indices, size_t n, tf_index_compare_fn compare, const void *ctx);
|
|
79
|
+
|
|
15
80
|
/* ---- Arena allocator ---- */
|
|
16
81
|
|
|
17
82
|
typedef struct tf_arena_block {
|
|
@@ -42,13 +107,21 @@ typedef struct tf_buffer {
|
|
|
42
107
|
size_t read_pos; /* consumer read position */
|
|
43
108
|
} tf_buffer;
|
|
44
109
|
|
|
45
|
-
void
|
|
46
|
-
int
|
|
110
|
+
void tf_buffer_init(tf_buffer *b);
|
|
111
|
+
TF_WARN_UNUSED int tf_buffer_write(tf_buffer *b, const uint8_t *data, size_t len);
|
|
47
112
|
size_t tf_buffer_read(tf_buffer *b, uint8_t *out, size_t len);
|
|
48
113
|
size_t tf_buffer_readable(const tf_buffer *b);
|
|
49
|
-
void
|
|
50
|
-
int
|
|
51
|
-
|
|
114
|
+
void tf_buffer_compact(tf_buffer *b);
|
|
115
|
+
TF_WARN_UNUSED int tf_buffer_write_str(tf_buffer *b, const char *s);
|
|
116
|
+
TF_WARN_UNUSED int tf_buffer_write_line(tf_buffer *b, const char *s);
|
|
117
|
+
TF_WARN_UNUSED int tf_buffer_write_json_line(tf_buffer *b, const cJSON *obj);
|
|
118
|
+
void tf_buffer_free(tf_buffer *b);
|
|
119
|
+
TF_WARN_UNUSED int tf_json_add_string(cJSON *obj, const char *name, const char *value);
|
|
120
|
+
TF_WARN_UNUSED int tf_json_add_number(cJSON *obj, const char *name, double value);
|
|
121
|
+
TF_WARN_UNUSED int tf_json_add_bool(cJSON *obj, const char *name, int value);
|
|
122
|
+
TF_WARN_UNUSED int tf_json_add_null(cJSON *obj, const char *name);
|
|
123
|
+
TF_WARN_UNUSED int tf_json_add_item(cJSON *obj, const char *name, cJSON *item);
|
|
124
|
+
TF_WARN_UNUSED int tf_json_add_array_item(cJSON *arr, cJSON *item);
|
|
52
125
|
|
|
53
126
|
/* ---- Columnar batch ---- */
|
|
54
127
|
/* (tf_type is defined in ir.h, included above) */
|
|
@@ -62,20 +135,47 @@ typedef struct tf_batch {
|
|
|
62
135
|
void **columns; /* array of typed column arrays */
|
|
63
136
|
uint8_t **nulls; /* null bitmap per column (1 byte per row for simplicity) */
|
|
64
137
|
tf_arena *arena; /* owns all memory for this batch */
|
|
138
|
+
size_t schema_name_bytes;
|
|
65
139
|
} tf_batch;
|
|
66
140
|
|
|
141
|
+
typedef union tf_cell_value {
|
|
142
|
+
bool b;
|
|
143
|
+
int64_t i64;
|
|
144
|
+
double f64;
|
|
145
|
+
const char *str;
|
|
146
|
+
int32_t date;
|
|
147
|
+
} tf_cell_value;
|
|
148
|
+
|
|
149
|
+
/* Owned string variant used by spill rows before copying into a batch arena. */
|
|
150
|
+
typedef union tf_owned_cell_value {
|
|
151
|
+
uint8_t b;
|
|
152
|
+
int64_t i64;
|
|
153
|
+
double f64;
|
|
154
|
+
int32_t date;
|
|
155
|
+
char *str;
|
|
156
|
+
} tf_owned_cell_value;
|
|
157
|
+
|
|
67
158
|
tf_batch *tf_batch_create(size_t n_cols, size_t capacity);
|
|
68
|
-
int
|
|
69
|
-
int
|
|
159
|
+
TF_WARN_UNUSED int tf_batch_set_schema(tf_batch *b, size_t col, const char *name, tf_type type);
|
|
160
|
+
TF_WARN_UNUSED int tf_batch_ensure_capacity(tf_batch *b, size_t min_rows);
|
|
161
|
+
TF_WARN_UNUSED int tf_batch_expose_row(tf_batch *b, size_t row);
|
|
70
162
|
|
|
71
163
|
/* Set a value in a specific cell. String values are copied into the arena. */
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
164
|
+
TF_WARN_UNUSED int tf_batch_set_null(tf_batch *b, size_t row, size_t col);
|
|
165
|
+
TF_WARN_UNUSED int tf_batch_set_bool(tf_batch *b, size_t row, size_t col, bool val);
|
|
166
|
+
TF_WARN_UNUSED int tf_batch_set_int64(tf_batch *b, size_t row, size_t col, int64_t val);
|
|
167
|
+
TF_WARN_UNUSED int tf_batch_set_float64(tf_batch *b, size_t row, size_t col, double val);
|
|
168
|
+
TF_WARN_UNUSED int tf_batch_set_string(tf_batch *b, size_t row, size_t col, const char *val);
|
|
169
|
+
TF_WARN_UNUSED int tf_batch_set_string_len(tf_batch *b, size_t row, size_t col,
|
|
170
|
+
const char *val, size_t len);
|
|
171
|
+
TF_WARN_UNUSED int tf_batch_set_date(tf_batch *b, size_t row, size_t col, int32_t val);
|
|
172
|
+
TF_WARN_UNUSED int tf_batch_set_timestamp(tf_batch *b, size_t row, size_t col, int64_t val);
|
|
173
|
+
TF_WARN_UNUSED int tf_batch_set_cell_value(tf_batch *b, size_t row, size_t col,
|
|
174
|
+
tf_type type, int is_null,
|
|
175
|
+
const tf_cell_value *value);
|
|
176
|
+
TF_WARN_UNUSED int tf_batch_set_owned_cell_value(tf_batch *b, size_t row, size_t col,
|
|
177
|
+
tf_type type, int is_null,
|
|
178
|
+
const tf_owned_cell_value *value);
|
|
79
179
|
|
|
80
180
|
/* Get values from a cell. */
|
|
81
181
|
bool tf_batch_is_null(const tf_batch *b, size_t row, size_t col);
|
|
@@ -89,11 +189,113 @@ int64_t tf_batch_get_timestamp(const tf_batch *b, size_t row, size_t col);
|
|
|
89
189
|
/* Find column index by name. Returns -1 if not found. */
|
|
90
190
|
int tf_batch_col_index(const tf_batch *b, const char *name);
|
|
91
191
|
|
|
92
|
-
/*
|
|
93
|
-
|
|
94
|
-
|
|
192
|
+
/* Schema and row-copy helpers. */
|
|
193
|
+
typedef enum tf_cell_string_format {
|
|
194
|
+
TF_CELL_STRING_ROUNDTRIP, /* round-trip floats, ISO dates/timestamps */
|
|
195
|
+
TF_CELL_STRING_HUMAN, /* short floats, ISO dates/timestamps */
|
|
196
|
+
TF_CELL_STRING_NUMERIC_TIME /* round-trip floats, numeric dates/timestamps */
|
|
197
|
+
} tf_cell_string_format;
|
|
198
|
+
|
|
199
|
+
TF_WARN_UNUSED int tf_batch_clone_schema(tf_batch *dst, const tf_batch *src);
|
|
200
|
+
TF_WARN_UNUSED int tf_batch_clone_with_extra_cols(tf_batch *dst, const tf_batch *src,
|
|
201
|
+
const char **names, const tf_type *types,
|
|
202
|
+
size_t n_extra);
|
|
203
|
+
TF_WARN_UNUSED int tf_batch_copy_cell(tf_batch *dst, size_t dst_row, size_t dst_col,
|
|
204
|
+
const tf_batch *src, size_t src_row, size_t src_col);
|
|
205
|
+
TF_WARN_UNUSED int tf_batch_copy_cell_index(tf_batch *dst, size_t dst_row, size_t dst_col,
|
|
206
|
+
const tf_batch *src, size_t src_row, int src_col);
|
|
207
|
+
TF_WARN_UNUSED int tf_batch_format_cell_as_string(const tf_batch *src, size_t src_row, size_t src_col,
|
|
208
|
+
tf_cell_string_format format,
|
|
209
|
+
char *buf, size_t buf_size,
|
|
210
|
+
const char **out);
|
|
211
|
+
TF_WARN_UNUSED int tf_batch_copy_cell_as_string(tf_batch *dst, size_t dst_row, size_t dst_col,
|
|
212
|
+
const tf_batch *src, size_t src_row, size_t src_col);
|
|
213
|
+
TF_WARN_UNUSED int tf_batch_copy_selected_row(tf_batch *dst, size_t dst_row,
|
|
214
|
+
const tf_batch *src, size_t src_row,
|
|
215
|
+
const size_t *cols, size_t n_cols);
|
|
216
|
+
TF_WARN_UNUSED int tf_batch_copy_selected_columns(tf_batch *dst,
|
|
217
|
+
const tf_batch *src,
|
|
218
|
+
const size_t *cols,
|
|
219
|
+
size_t n_cols);
|
|
220
|
+
TF_WARN_UNUSED int tf_batch_copy_row(tf_batch *dst, size_t dst_row,
|
|
221
|
+
const tf_batch *src, size_t src_row);
|
|
222
|
+
TF_WARN_UNUSED int tf_batch_clone_with_selected_extra_cols(tf_batch *dst,
|
|
223
|
+
const tf_batch *src,
|
|
224
|
+
const tf_batch *extra,
|
|
225
|
+
const int *extra_cols,
|
|
226
|
+
size_t n_extra);
|
|
227
|
+
TF_WARN_UNUSED int tf_batch_append_row(tf_batch *dst, const tf_batch *src,
|
|
228
|
+
size_t src_row);
|
|
229
|
+
TF_WARN_UNUSED int tf_batch_append_row_with_selected_extra(tf_batch *dst,
|
|
230
|
+
const tf_batch *left,
|
|
231
|
+
size_t left_row,
|
|
232
|
+
const tf_batch *extra,
|
|
233
|
+
size_t extra_row,
|
|
234
|
+
const int *extra_cols,
|
|
235
|
+
size_t n_extra);
|
|
236
|
+
TF_WARN_UNUSED int tf_batch_append_row_with_null_extra(tf_batch *dst,
|
|
237
|
+
const tf_batch *left,
|
|
238
|
+
size_t left_row,
|
|
239
|
+
size_t n_extra);
|
|
95
240
|
|
|
96
241
|
void tf_batch_free(tf_batch *b);
|
|
242
|
+
void tf_batch_array_free_items(tf_batch **batches, size_t n_batches);
|
|
243
|
+
void tf_batch_array_free(tf_batch **batches, size_t n_batches);
|
|
244
|
+
|
|
245
|
+
/* ---- Audit / side-channel row serialization helpers ---- */
|
|
246
|
+
|
|
247
|
+
typedef struct tf_audit_options {
|
|
248
|
+
int include_row;
|
|
249
|
+
char **columns;
|
|
250
|
+
size_t n_columns;
|
|
251
|
+
char **redact_columns;
|
|
252
|
+
size_t n_redact_columns;
|
|
253
|
+
char **hash_columns;
|
|
254
|
+
size_t n_hash_columns;
|
|
255
|
+
size_t max_bytes;
|
|
256
|
+
size_t max_cell_bytes;
|
|
257
|
+
} tf_audit_options;
|
|
258
|
+
|
|
259
|
+
void tf_audit_options_init(tf_audit_options *opts, int default_include_row);
|
|
260
|
+
int tf_audit_options_parse(tf_audit_options *opts, const cJSON *args, const char *context);
|
|
261
|
+
void tf_audit_options_free(tf_audit_options *opts);
|
|
262
|
+
int tf_audit_column_is_redacted(const tf_audit_options *opts, const char *column);
|
|
263
|
+
int tf_audit_column_is_hashed(const tf_audit_options *opts, const char *column);
|
|
264
|
+
int tf_audit_hash_string(const char *value, char *out, size_t out_size);
|
|
265
|
+
const char *tf_audit_format_string_for_column(const tf_audit_options *opts, const char *column,
|
|
266
|
+
const char *value, char *buf, size_t buf_size);
|
|
267
|
+
TF_WARN_UNUSED char *tf_audit_format_string_dup_for_column(const tf_audit_options *opts,
|
|
268
|
+
const char *column,
|
|
269
|
+
const char *value);
|
|
270
|
+
cJSON *tf_audit_string_to_json_for_column(const tf_audit_options *opts, const char *column,
|
|
271
|
+
const char *value);
|
|
272
|
+
TF_WARN_UNUSED int tf_json_add_audit_string(cJSON *obj, const char *name,
|
|
273
|
+
const tf_audit_options *opts,
|
|
274
|
+
const char *column, const char *value);
|
|
275
|
+
cJSON *tf_audit_cell_to_json(const tf_batch *b, size_t row, size_t col, const tf_audit_options *opts);
|
|
276
|
+
cJSON *tf_audit_row_to_json(const tf_batch *b, size_t row, const tf_audit_options *opts);
|
|
277
|
+
|
|
278
|
+
/* ---- Column selector helpers ---- */
|
|
279
|
+
|
|
280
|
+
int tf_json_path_validate(const char *path);
|
|
281
|
+
const cJSON *tf_json_path_resolve(const cJSON *root, const char *path);
|
|
282
|
+
|
|
283
|
+
int tf_column_selector_has_syntax(const char *raw);
|
|
284
|
+
int tf_column_selectors_have_syntax_json(const cJSON *selectors);
|
|
285
|
+
int tf_column_selectors_resolve(char **selectors, size_t n_selectors,
|
|
286
|
+
char **names, const tf_type *types, size_t n_cols,
|
|
287
|
+
int **out_indices, size_t *out_n,
|
|
288
|
+
char **error);
|
|
289
|
+
int tf_column_selectors_resolve_json(const cJSON *selectors,
|
|
290
|
+
char **names, const tf_type *types, size_t n_cols,
|
|
291
|
+
int **out_indices, size_t *out_n,
|
|
292
|
+
char **error);
|
|
293
|
+
|
|
294
|
+
int tf_estimate_step_state_bytes(const tf_ir_node *node, size_t *out,
|
|
295
|
+
char *reason, size_t reason_size);
|
|
296
|
+
int tf_estimate_key_state_plan_bytes(const tf_ir_plan *ir, size_t *out,
|
|
297
|
+
const tf_ir_node **failed_node,
|
|
298
|
+
char *reason, size_t reason_size);
|
|
97
299
|
|
|
98
300
|
/* ---- Step interface (transforms) ---- */
|
|
99
301
|
|
|
@@ -105,8 +307,18 @@ typedef struct tf_side_channels {
|
|
|
105
307
|
tf_buffer *errors;
|
|
106
308
|
tf_buffer *stats;
|
|
107
309
|
tf_buffer *samples;
|
|
310
|
+
const char *source_name;
|
|
108
311
|
} tf_side_channels;
|
|
109
312
|
|
|
313
|
+
TF_WARN_UNUSED int tf_side_write_error(tf_side_channels *side, const char *msg);
|
|
314
|
+
|
|
315
|
+
/* Hidden IR args added by the built-in workspace_root resolver. */
|
|
316
|
+
#define TF_POLICY_VALIDATED_FILE_PATH_ARG "_tf_validated_file_path"
|
|
317
|
+
#define TF_POLICY_VALIDATED_RULES_FILE_PATH_ARG "_tf_validated_rules_file_path"
|
|
318
|
+
|
|
319
|
+
const char *tf_policy_validated_path_arg(const cJSON *args, const char *path_arg);
|
|
320
|
+
FILE *tf_policy_fopen_read(const char *path, const char *validated_path);
|
|
321
|
+
|
|
110
322
|
typedef struct tf_step {
|
|
111
323
|
/* Process one input batch, produce zero or one output batch.
|
|
112
324
|
* *out is set to a new batch (caller frees) or NULL if filtered away. */
|
|
@@ -114,11 +326,38 @@ typedef struct tf_step {
|
|
|
114
326
|
tf_side_channels *side);
|
|
115
327
|
/* Flush any buffered state. */
|
|
116
328
|
int (*flush)(struct tf_step *self, tf_batch **out, tf_side_channels *side);
|
|
329
|
+
/* Optional continuation for flush-latent steps that emit multiple batches. */
|
|
330
|
+
int (*flush_next)(struct tf_step *self, tf_batch **out, tf_side_channels *side);
|
|
331
|
+
/* Optional JSON stats hook. Appends comma-prefixed fields to step_stats. */
|
|
332
|
+
int (*append_stats)(struct tf_step *self, tf_buffer *out);
|
|
117
333
|
/* Free all resources. */
|
|
118
334
|
void (*destroy)(struct tf_step *self);
|
|
119
335
|
void *state;
|
|
120
336
|
} tf_step;
|
|
121
337
|
|
|
338
|
+
#define TF_STEP_WARN_BLOCKING (1u << 0)
|
|
339
|
+
#define TF_STEP_WARN_FLUSH_LATENT (1u << 1)
|
|
340
|
+
#define TF_STEP_WARN_UNBOUNDED_STATE (1u << 2)
|
|
341
|
+
#define TF_STEP_WARN_DATA_DEPENDENT_SCHEMA (1u << 3)
|
|
342
|
+
|
|
343
|
+
typedef struct tf_step_run_stats {
|
|
344
|
+
char *op;
|
|
345
|
+
char *state_estimate;
|
|
346
|
+
char *state_bytes_reason;
|
|
347
|
+
char *execution_target;
|
|
348
|
+
size_t node_index;
|
|
349
|
+
size_t state_bytes_estimate;
|
|
350
|
+
int has_state_bytes_estimate;
|
|
351
|
+
uint32_t warnings;
|
|
352
|
+
tf_memory_class memory_class;
|
|
353
|
+
tf_emit_class emit_class;
|
|
354
|
+
tf_schema_class schema_class;
|
|
355
|
+
size_t batches_in;
|
|
356
|
+
size_t batches_out;
|
|
357
|
+
size_t rows_in;
|
|
358
|
+
size_t rows_out;
|
|
359
|
+
} tf_step_run_stats;
|
|
360
|
+
|
|
122
361
|
/* ---- Decoder interface (bytes → batches) ---- */
|
|
123
362
|
|
|
124
363
|
typedef struct tf_decoder {
|
|
@@ -128,9 +367,10 @@ typedef struct tf_decoder {
|
|
|
128
367
|
* Caller frees the array and each batch.
|
|
129
368
|
*/
|
|
130
369
|
int (*decode)(struct tf_decoder *self, const uint8_t *data, size_t len,
|
|
131
|
-
tf_batch ***out, size_t *n_out);
|
|
370
|
+
tf_batch ***out, size_t *n_out, tf_side_channels *side);
|
|
132
371
|
/* Flush remaining data (e.g. last partial line). */
|
|
133
|
-
int (*flush)(struct tf_decoder *self, tf_batch ***out, size_t *n_out
|
|
372
|
+
int (*flush)(struct tf_decoder *self, tf_batch ***out, size_t *n_out,
|
|
373
|
+
tf_side_channels *side);
|
|
134
374
|
void (*destroy)(struct tf_decoder *self);
|
|
135
375
|
void *state;
|
|
136
376
|
} tf_decoder;
|
|
@@ -154,21 +394,41 @@ struct tf_pipeline {
|
|
|
154
394
|
tf_decoder *decoder;
|
|
155
395
|
tf_step **steps;
|
|
156
396
|
size_t n_steps;
|
|
397
|
+
tf_step_run_stats *step_stats;
|
|
398
|
+
size_t n_step_stats;
|
|
157
399
|
tf_encoder *encoder;
|
|
158
400
|
tf_buffer output[TF_NUM_CHANNELS];
|
|
401
|
+
tf_pipeline_sink_fn sinks[TF_NUM_CHANNELS];
|
|
402
|
+
void *sink_users[TF_NUM_CHANNELS];
|
|
403
|
+
tf_pipeline_batch_sink_fn batch_sink;
|
|
404
|
+
void *batch_sink_user;
|
|
405
|
+
int encode_output;
|
|
406
|
+
tf_pipeline_progress_fn progress_cb;
|
|
407
|
+
void *progress_user;
|
|
408
|
+
size_t progress_interval_rows;
|
|
409
|
+
size_t progress_last_rows_in;
|
|
410
|
+
size_t progress_last_rows_out;
|
|
159
411
|
tf_side_channels side;
|
|
160
412
|
size_t rows_in;
|
|
161
413
|
size_t rows_out;
|
|
414
|
+
size_t batches_in;
|
|
415
|
+
size_t batches_out;
|
|
162
416
|
size_t bytes_in;
|
|
163
417
|
size_t bytes_out;
|
|
418
|
+
char *source_name;
|
|
164
419
|
char *error;
|
|
165
420
|
int finished;
|
|
421
|
+
int finish_started;
|
|
422
|
+
int finish_phase;
|
|
423
|
+
tf_batch **finish_batches;
|
|
424
|
+
size_t finish_n_batches;
|
|
425
|
+
size_t finish_batch_index;
|
|
426
|
+
size_t finish_step_index;
|
|
427
|
+
int finish_step_in_next;
|
|
166
428
|
};
|
|
167
429
|
|
|
168
430
|
/* ---- Codec constructors (used by plan parser) ---- */
|
|
169
431
|
|
|
170
|
-
typedef struct cJSON cJSON;
|
|
171
|
-
|
|
172
432
|
tf_decoder *tf_csv_decoder_create(const cJSON *args);
|
|
173
433
|
tf_encoder *tf_csv_encoder_create(const cJSON *args);
|
|
174
434
|
tf_decoder *tf_jsonl_decoder_create(const cJSON *args);
|
|
@@ -180,14 +440,23 @@ tf_encoder *tf_text_encoder_create(const cJSON *args);
|
|
|
180
440
|
|
|
181
441
|
tf_step *tf_filter_create(const cJSON *args);
|
|
182
442
|
tf_step *tf_select_create(const cJSON *args);
|
|
443
|
+
tf_step *tf_relocate_create(const cJSON *args);
|
|
183
444
|
tf_step *tf_rename_create(const cJSON *args);
|
|
184
445
|
tf_step *tf_head_create(const cJSON *args);
|
|
185
446
|
tf_step *tf_skip_create(const cJSON *args);
|
|
186
447
|
tf_step *tf_derive_create(const cJSON *args);
|
|
448
|
+
tf_step *tf_source_name_create(const cJSON *args);
|
|
449
|
+
tf_step *tf_across_create(const cJSON *args);
|
|
187
450
|
tf_step *tf_stats_create(const cJSON *args);
|
|
451
|
+
tf_step *tf_scan_create(const cJSON *args);
|
|
188
452
|
tf_step *tf_unique_create(const cJSON *args);
|
|
189
453
|
tf_step *tf_sort_create(const cJSON *args);
|
|
190
454
|
tf_step *tf_validate_create(const cJSON *args);
|
|
455
|
+
tf_step *tf_assert_create(const cJSON *args);
|
|
456
|
+
tf_step *tf_quarantine_create(const cJSON *args);
|
|
457
|
+
tf_step *tf_schema_create(const cJSON *args);
|
|
458
|
+
tf_step *tf_schema_infer_create(const cJSON *args);
|
|
459
|
+
tf_step *tf_tee_create(const cJSON *args);
|
|
191
460
|
tf_step *tf_trim_create(const cJSON *args);
|
|
192
461
|
tf_step *tf_fill_null_create(const cJSON *args);
|
|
193
462
|
tf_step *tf_cast_create(const cJSON *args);
|
|
@@ -198,20 +467,46 @@ tf_step *tf_bin_create(const cJSON *args);
|
|
|
198
467
|
tf_step *tf_fill_down_create(const cJSON *args);
|
|
199
468
|
tf_step *tf_step_create(const cJSON *args);
|
|
200
469
|
tf_step *tf_window_create(const cJSON *args);
|
|
470
|
+
tf_step *tf_rolling_sum_create(const cJSON *args);
|
|
471
|
+
tf_step *tf_rolling_mean_create(const cJSON *args);
|
|
472
|
+
tf_step *tf_rolling_min_create(const cJSON *args);
|
|
473
|
+
tf_step *tf_rolling_max_create(const cJSON *args);
|
|
474
|
+
tf_step *tf_rolling_any_create(const cJSON *args);
|
|
475
|
+
tf_step *tf_rolling_all_create(const cJSON *args);
|
|
201
476
|
tf_step *tf_explode_create(const cJSON *args);
|
|
202
477
|
tf_step *tf_split_create(const cJSON *args);
|
|
203
478
|
tf_step *tf_unpivot_create(const cJSON *args);
|
|
204
479
|
tf_step *tf_tail_create(const cJSON *args);
|
|
205
480
|
tf_step *tf_top_create(const cJSON *args);
|
|
481
|
+
tf_step *tf_top_k_create(const cJSON *args);
|
|
482
|
+
tf_step *tf_bottom_k_create(const cJSON *args);
|
|
483
|
+
tf_step *tf_slice_min_create(const cJSON *args);
|
|
484
|
+
tf_step *tf_slice_max_create(const cJSON *args);
|
|
206
485
|
tf_step *tf_sample_create(const cJSON *args);
|
|
207
486
|
tf_step *tf_group_agg_create(const cJSON *args);
|
|
208
487
|
tf_step *tf_frequency_create(const cJSON *args);
|
|
209
488
|
tf_step *tf_datetime_create(const cJSON *args);
|
|
210
489
|
tf_step *tf_grep_create(const cJSON *args);
|
|
490
|
+
tf_step *tf_json_extract_create(const cJSON *args);
|
|
491
|
+
tf_step *tf_json_filter_create(const cJSON *args);
|
|
492
|
+
tf_step *tf_json_schema_create(const cJSON *args);
|
|
493
|
+
tf_step *tf_json_flatten_create(const cJSON *args);
|
|
211
494
|
tf_step *tf_pivot_create(const cJSON *args);
|
|
212
495
|
tf_step *tf_join_create(const cJSON *args);
|
|
496
|
+
tf_step *tf_semi_join_create(const cJSON *args);
|
|
497
|
+
tf_step *tf_anti_join_create(const cJSON *args);
|
|
498
|
+
tf_step *tf_intersect_create(const cJSON *args);
|
|
499
|
+
tf_step *tf_setdiff_create(const cJSON *args);
|
|
500
|
+
tf_step *tf_intersect_all_create(const cJSON *args);
|
|
501
|
+
tf_step *tf_setdiff_all_create(const cJSON *args);
|
|
502
|
+
tf_step *tf_union_create(const cJSON *args);
|
|
503
|
+
tf_step *tf_union_all_create(const cJSON *args);
|
|
213
504
|
tf_step *tf_stack_create(const cJSON *args);
|
|
214
505
|
tf_step *tf_lead_create(const cJSON *args);
|
|
506
|
+
tf_step *tf_lag_create(const cJSON *args);
|
|
507
|
+
tf_step *tf_shift_create(const cJSON *args);
|
|
508
|
+
tf_step *tf_rowid_create(const cJSON *args);
|
|
509
|
+
tf_step *tf_rleid_create(const cJSON *args);
|
|
215
510
|
tf_step *tf_date_trunc_create(const cJSON *args);
|
|
216
511
|
tf_step *tf_onehot_create(const cJSON *args);
|
|
217
512
|
tf_step *tf_label_encode_create(const cJSON *args);
|
|
@@ -237,12 +532,6 @@ int tf_expr_eval_val(const tf_expr *e, const tf_batch *batch, size_t row
|
|
|
237
532
|
tf_eval_result *result);
|
|
238
533
|
void tf_expr_free(tf_expr *e);
|
|
239
534
|
|
|
240
|
-
/* ---- Plan parser ---- */
|
|
241
|
-
|
|
242
|
-
int tf_plan_parse(const char *json, size_t len,
|
|
243
|
-
tf_decoder **decoder, tf_step ***steps, size_t *n_steps,
|
|
244
|
-
tf_encoder **encoder, char **error);
|
|
245
|
-
|
|
246
535
|
/* ---- Global error ---- */
|
|
247
536
|
|
|
248
537
|
void tf_set_last_error(const char *msg);
|
package/csrc/ir.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ir.c — IR plan construction, cloning, and memory management.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
#include "
|
|
5
|
+
#include "internal.h"
|
|
6
6
|
#include "cJSON.h"
|
|
7
7
|
#include <stdlib.h>
|
|
8
8
|
#include <string.h>
|
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
|
|
12
12
|
void tf_schema_free(tf_schema *s) {
|
|
13
13
|
if (!s) return;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
if (s->col_names) {
|
|
15
|
+
for (size_t i = 0; i < s->n_cols; i++) {
|
|
16
|
+
free(s->col_names[i]);
|
|
17
|
+
}
|
|
16
18
|
}
|
|
17
19
|
free(s->col_names);
|
|
18
20
|
free(s->col_types);
|
|
@@ -22,20 +24,38 @@ void tf_schema_free(tf_schema *s) {
|
|
|
22
24
|
s->known = false;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
int tf_schema_copy_checked(tf_schema *dst, const tf_schema *src) {
|
|
28
|
+
if (!dst) return TF_ERROR;
|
|
29
|
+
dst->known = false;
|
|
30
|
+
dst->n_cols = 0;
|
|
31
|
+
dst->col_names = NULL;
|
|
32
|
+
dst->col_types = NULL;
|
|
33
|
+
if (!src) return TF_OK;
|
|
34
|
+
|
|
26
35
|
dst->known = src->known;
|
|
27
36
|
dst->n_cols = src->n_cols;
|
|
28
|
-
if (src->n_cols == 0 || !src->known)
|
|
29
|
-
|
|
30
|
-
dst->col_types = NULL;
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
37
|
+
if (src->n_cols == 0 || !src->known) return TF_OK;
|
|
38
|
+
|
|
33
39
|
dst->col_names = calloc(src->n_cols, sizeof(char *));
|
|
34
40
|
dst->col_types = calloc(src->n_cols, sizeof(tf_type));
|
|
41
|
+
if (!dst->col_names || !dst->col_types) {
|
|
42
|
+
tf_schema_free(dst);
|
|
43
|
+
return TF_ERROR;
|
|
44
|
+
}
|
|
35
45
|
for (size_t i = 0; i < src->n_cols; i++) {
|
|
36
|
-
dst->col_names[i] = strdup(src->col_names[i]);
|
|
46
|
+
dst->col_names[i] = strdup(src->col_names[i] ? src->col_names[i] : "");
|
|
47
|
+
if (!dst->col_names[i]) {
|
|
48
|
+
tf_schema_free(dst);
|
|
49
|
+
return TF_ERROR;
|
|
50
|
+
}
|
|
37
51
|
dst->col_types[i] = src->col_types[i];
|
|
38
52
|
}
|
|
53
|
+
dst->known = true;
|
|
54
|
+
return TF_OK;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
void tf_schema_copy(tf_schema *dst, const tf_schema *src) {
|
|
58
|
+
(void)tf_schema_copy_checked(dst, src);
|
|
39
59
|
}
|
|
40
60
|
|
|
41
61
|
/* ---- IR node helpers ---- */
|
|
@@ -59,9 +79,12 @@ tf_ir_plan *tf_ir_plan_create(void) {
|
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
int tf_ir_plan_add_node(tf_ir_plan *plan, const char *op, cJSON *args) {
|
|
82
|
+
if (!plan || !op) return -1;
|
|
62
83
|
if (plan->n_nodes >= plan->capacity) {
|
|
63
|
-
size_t new_cap =
|
|
64
|
-
|
|
84
|
+
size_t new_cap = 0;
|
|
85
|
+
if (tf_size_mul(plan->capacity, 2, &new_cap) != TF_OK) return -1;
|
|
86
|
+
tf_ir_node *new_nodes = tf_reallocarray_checked(plan->nodes, new_cap,
|
|
87
|
+
sizeof(tf_ir_node));
|
|
65
88
|
if (!new_nodes) return -1;
|
|
66
89
|
memset(new_nodes + plan->capacity, 0,
|
|
67
90
|
(new_cap - plan->capacity) * sizeof(tf_ir_node));
|
|
@@ -69,10 +92,18 @@ int tf_ir_plan_add_node(tf_ir_plan *plan, const char *op, cJSON *args) {
|
|
|
69
92
|
plan->capacity = new_cap;
|
|
70
93
|
}
|
|
71
94
|
|
|
95
|
+
char *op_copy = strdup(op);
|
|
96
|
+
cJSON *args_copy = args ? cJSON_Duplicate(args, 1) : cJSON_CreateObject();
|
|
97
|
+
if (!op_copy || !args_copy) {
|
|
98
|
+
free(op_copy);
|
|
99
|
+
if (args_copy) cJSON_Delete(args_copy);
|
|
100
|
+
return -1;
|
|
101
|
+
}
|
|
102
|
+
|
|
72
103
|
tf_ir_node *node = &plan->nodes[plan->n_nodes];
|
|
73
104
|
memset(node, 0, sizeof(tf_ir_node));
|
|
74
|
-
node->op =
|
|
75
|
-
node->args =
|
|
105
|
+
node->op = op_copy;
|
|
106
|
+
node->args = args_copy;
|
|
76
107
|
node->index = plan->n_nodes;
|
|
77
108
|
|
|
78
109
|
plan->n_nodes++;
|
|
@@ -93,16 +124,32 @@ tf_ir_plan *tf_ir_plan_clone(const tf_ir_plan *plan) {
|
|
|
93
124
|
}
|
|
94
125
|
/* Copy schemas if they were inferred */
|
|
95
126
|
tf_ir_node *dst = &clone->nodes[i];
|
|
96
|
-
|
|
97
|
-
|
|
127
|
+
if (tf_schema_copy_checked(&dst->input_schema, &src->input_schema) != TF_OK ||
|
|
128
|
+
tf_schema_copy_checked(&dst->output_schema, &src->output_schema) != TF_OK) {
|
|
129
|
+
tf_ir_plan_free(clone);
|
|
130
|
+
return NULL;
|
|
131
|
+
}
|
|
98
132
|
dst->caps = src->caps;
|
|
133
|
+
dst->memory_class = src->memory_class;
|
|
134
|
+
dst->emit_class = src->emit_class;
|
|
135
|
+
dst->schema_class = src->schema_class;
|
|
136
|
+
dst->state_estimate = src->state_estimate;
|
|
99
137
|
}
|
|
100
138
|
|
|
101
|
-
|
|
139
|
+
if (tf_schema_copy_checked(&clone->final_schema, &plan->final_schema) != TF_OK) {
|
|
140
|
+
tf_ir_plan_free(clone);
|
|
141
|
+
return NULL;
|
|
142
|
+
}
|
|
102
143
|
clone->plan_caps = plan->plan_caps;
|
|
103
144
|
clone->validated = plan->validated;
|
|
104
145
|
clone->schema_inferred = plan->schema_inferred;
|
|
105
|
-
if (plan->error)
|
|
146
|
+
if (plan->error) {
|
|
147
|
+
clone->error = strdup(plan->error);
|
|
148
|
+
if (!clone->error) {
|
|
149
|
+
tf_ir_plan_free(clone);
|
|
150
|
+
return NULL;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
106
153
|
|
|
107
154
|
return clone;
|
|
108
155
|
}
|