iceberg 0.11.1 → 0.12.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.
@@ -1,7 +1,13 @@
1
+ use std::collections::HashMap;
2
+ use std::sync::{Arc, RwLock};
3
+
4
+ use arrow_array::RecordBatch;
1
5
  use arrow_array::ffi_stream::ArrowArrayStreamReader;
6
+ use arrow_cast::cast;
7
+ use arrow_schema::{ArrowError, DataType, Field, Schema};
2
8
  use iceberg::TableIdent;
3
9
  use iceberg::io::FileIO;
4
- use iceberg::spec::FormatVersion;
10
+ use iceberg::spec::{FormatVersion, TableMetadata};
5
11
  use iceberg::table::{StaticTable, Table};
6
12
  use iceberg::transaction::{ApplyTransactionAction, Transaction};
7
13
  use iceberg::writer::base_writer::data_file_writer::DataFileWriterBuilder;
@@ -11,29 +17,40 @@ use iceberg::writer::file_writer::location_generator::{
11
17
  };
12
18
  use iceberg::writer::file_writer::rolling_writer::RollingFileWriterBuilder;
13
19
  use iceberg::writer::{IcebergWriter, IcebergWriterBuilder};
14
- use magnus::{Error as RbErr, RArray, Ruby, Value};
20
+ use magnus::{RArray, Ruby};
15
21
  use parquet::file::properties::WriterProperties;
16
- use std::cell::RefCell;
17
- use std::collections::HashMap;
18
- use std::sync::Arc;
19
22
  use uuid::Uuid;
20
23
 
21
24
  use crate::RbResult;
22
- use crate::arrow::RbArrowType;
23
25
  use crate::catalog::RbCatalog;
26
+ use crate::encryption::RbEncryptedKey;
24
27
  use crate::error::to_rb_err;
28
+ use crate::partitioning::RbPartitionSpec;
29
+ use crate::ruby::GvlExt;
25
30
  use crate::runtime::runtime;
26
31
  use crate::scan::RbTableScan;
27
- use crate::utils::*;
32
+ use crate::schema::RbSchema;
33
+ use crate::snapshot::{RbMetadataLogEntry, RbSnapshot, RbSnapshotLogEntry};
34
+ use crate::sorting::RbSortOrder;
35
+ use crate::statistics::{RbPartitionStatisticsFile, RbStatisticsFile};
36
+ use crate::utils::Wrap;
28
37
 
29
38
  #[magnus::wrap(class = "Iceberg::RbTable")]
30
39
  pub struct RbTable {
31
- pub table: RefCell<Table>,
40
+ pub table: RwLock<Table>,
32
41
  }
33
42
 
34
43
  impl RbTable {
44
+ pub fn identifier(&self) -> Vec<String> {
45
+ let table = self.table.read().unwrap();
46
+ let ident = table.identifier();
47
+ let mut vec = ident.namespace.clone().inner();
48
+ vec.push(ident.name.clone());
49
+ vec
50
+ }
51
+
35
52
  pub fn scan(&self, snapshot_id: Option<i64>) -> RbResult<RbTableScan> {
36
- let table = self.table.borrow();
53
+ let table = self.table.read().unwrap();
37
54
  let mut builder = table.scan();
38
55
  if let Some(si) = snapshot_id {
39
56
  builder = builder.snapshot_id(si);
@@ -45,74 +62,98 @@ impl RbTable {
45
62
  pub fn append(
46
63
  ruby: &Ruby,
47
64
  rb_self: &Self,
48
- data: RbArrowType<ArrowArrayStreamReader>,
65
+ data: Wrap<ArrowArrayStreamReader>,
49
66
  catalog: &RbCatalog,
50
67
  ) -> RbResult<RbTable> {
51
- let runtime = runtime();
52
- let table = rb_self.table.borrow();
53
- let catalog = catalog.catalog.borrow();
54
-
55
- let table_schema: Arc<arrow_schema::Schema> = Arc::new(
56
- table
57
- .metadata()
58
- .current_schema()
59
- .as_ref()
60
- .try_into()
61
- .unwrap(),
62
- );
63
-
64
- let location_generator =
65
- DefaultLocationGenerator::new(table.metadata().clone()).map_err(to_rb_err)?;
66
- let file_name_generator = DefaultFileNameGenerator::new(
67
- // TODO move task id to suffix to match Python and Java
68
- "0".to_string(),
69
- Some(Uuid::new_v4().to_string()),
70
- iceberg::spec::DataFileFormat::Parquet,
71
- );
72
-
73
- let parquet_writer_builder = ParquetWriterBuilder::new(
74
- WriterProperties::default(),
75
- table.metadata().current_schema().clone(),
76
- );
77
- let rolling_file_writer_builder = RollingFileWriterBuilder::new_with_default_file_size(
78
- parquet_writer_builder,
79
- table.file_io().clone(),
80
- location_generator.clone(),
81
- file_name_generator.clone(),
82
- );
83
- let data_file_writer_builder = DataFileWriterBuilder::new(rolling_file_writer_builder);
84
- let mut data_file_writer = runtime
85
- .block_on(data_file_writer_builder.build(None))
68
+ let table = ruby
69
+ .detach(|| {
70
+ let runtime = runtime();
71
+ let table = rb_self.table.read().unwrap();
72
+ let catalog = catalog.catalog.read().unwrap();
73
+
74
+ let table_schema: Arc<arrow_schema::Schema> = Arc::new(
75
+ table
76
+ .metadata()
77
+ .current_schema()
78
+ .as_ref()
79
+ .try_into()
80
+ .unwrap(),
81
+ );
82
+
83
+ let location_generator = DefaultLocationGenerator::new(table.metadata())?;
84
+ let file_name_generator = DefaultFileNameGenerator::new(
85
+ // TODO move task id to suffix to match Python and Java
86
+ "0".to_string(),
87
+ Some(Uuid::new_v4().to_string()),
88
+ iceberg::spec::DataFileFormat::Parquet,
89
+ );
90
+
91
+ let parquet_writer_builder = ParquetWriterBuilder::new(
92
+ WriterProperties::default(),
93
+ table.metadata().current_schema().clone(),
94
+ );
95
+ let rolling_file_writer_builder =
96
+ RollingFileWriterBuilder::new_with_default_file_size(
97
+ parquet_writer_builder,
98
+ table.file_io().clone(),
99
+ location_generator.clone(),
100
+ file_name_generator.clone(),
101
+ );
102
+ let data_file_writer_builder =
103
+ DataFileWriterBuilder::new(rolling_file_writer_builder);
104
+ let mut data_file_writer =
105
+ runtime.block_on(data_file_writer_builder.build(None))?;
106
+
107
+ for batch in data.0 {
108
+ let batch = cast_batch(batch.unwrap(), table_schema.clone())?;
109
+ runtime.block_on(data_file_writer.write(batch))?;
110
+ }
111
+
112
+ let data_files = runtime.block_on(data_file_writer.close())?;
113
+
114
+ let tx = Transaction::new(&table);
115
+ let append_action = tx.fast_append().add_data_files(data_files.clone());
116
+ let tx = append_action.apply(tx)?;
117
+
118
+ runtime.block_on(tx.commit(catalog.as_catalog()))
119
+ })
86
120
  .map_err(to_rb_err)?;
87
121
 
88
- for batch in data.0 {
89
- let batch = batch
90
- .unwrap()
91
- .with_schema(table_schema.clone())
92
- .map_err(|e| RbErr::new(ruby.exception_arg_error(), e.to_string()))?;
93
- runtime
94
- .block_on(data_file_writer.write(batch))
95
- .map_err(to_rb_err)?;
96
- }
122
+ Ok(RbTable {
123
+ table: table.into(),
124
+ })
125
+ }
97
126
 
98
- let data_files = runtime
99
- .block_on(data_file_writer.close())
100
- .map_err(to_rb_err)?;
127
+ pub fn metadata(&self) -> RbTableMetadata {
128
+ RbTableMetadata {
129
+ metadata: self.table.read().unwrap().metadata().clone(),
130
+ }
131
+ }
101
132
 
102
- let tx = Transaction::new(&table);
103
- let append_action = tx.fast_append().add_data_files(data_files.clone());
104
- let tx = append_action.apply(tx).map_err(to_rb_err)?;
105
- let table = runtime
106
- .block_on(tx.commit(catalog.as_catalog()))
133
+ pub fn from_metadata_file(location: String) -> RbResult<Self> {
134
+ let file_io = FileIO::new_with_fs();
135
+ let table_ident = TableIdent::from_strs(["static-table", &location]).unwrap();
136
+ let static_table = runtime()
137
+ .block_on(StaticTable::from_metadata_file(
138
+ &location,
139
+ table_ident,
140
+ file_io,
141
+ ))
107
142
  .map_err(to_rb_err)?;
108
-
109
- Ok(RbTable {
110
- table: table.into(),
143
+ Ok(Self {
144
+ table: static_table.into_table().into(),
111
145
  })
112
146
  }
147
+ }
148
+
149
+ #[magnus::wrap(class = "Iceberg::TableMetadata")]
150
+ pub struct RbTableMetadata {
151
+ pub metadata: TableMetadata,
152
+ }
113
153
 
154
+ impl RbTableMetadata {
114
155
  pub fn format_version(&self) -> i32 {
115
- match self.table.borrow().metadata().format_version() {
156
+ match self.metadata.format_version() {
116
157
  FormatVersion::V1 => 1,
117
158
  FormatVersion::V2 => 2,
118
159
  FormatVersion::V3 => 3,
@@ -120,273 +161,224 @@ impl RbTable {
120
161
  }
121
162
 
122
163
  pub fn uuid(&self) -> String {
123
- self.table.borrow().metadata().uuid().to_string()
164
+ self.metadata.uuid().to_string()
124
165
  }
125
166
 
126
167
  pub fn location(&self) -> String {
127
- self.table.borrow().metadata().location().to_string()
168
+ self.metadata.location().to_string()
128
169
  }
129
170
 
130
171
  pub fn last_sequence_number(&self) -> i64 {
131
- self.table.borrow().metadata().last_sequence_number()
172
+ self.metadata.last_sequence_number()
132
173
  }
133
174
 
134
175
  pub fn next_sequence_number(&self) -> i64 {
135
- self.table.borrow().metadata().next_sequence_number()
176
+ self.metadata.next_sequence_number()
136
177
  }
137
178
 
138
179
  pub fn last_column_id(&self) -> i32 {
139
- self.table.borrow().metadata().last_column_id()
180
+ self.metadata.last_column_id()
140
181
  }
141
182
 
142
183
  pub fn last_partition_id(&self) -> i32 {
143
- self.table.borrow().metadata().last_partition_id()
184
+ self.metadata.last_partition_id()
144
185
  }
145
186
 
146
187
  pub fn last_updated_ms(&self) -> i64 {
147
- self.table.borrow().metadata().last_updated_ms()
188
+ self.metadata.last_updated_ms()
148
189
  }
149
190
 
150
- pub fn schemas(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
151
- let schemas = ruby.ary_new();
152
- for s in rb_self.table.borrow().metadata().schemas_iter() {
153
- schemas.push(rb_schema(ruby, s)?)?;
154
- }
155
- Ok(schemas)
191
+ pub fn schemas(ruby: &Ruby, rb_self: &Self) -> RArray {
192
+ ruby.ary_from_iter(rb_self.metadata.schemas_iter().map(RbSchema::from))
156
193
  }
157
194
 
158
- pub fn schema_by_id(ruby: &Ruby, rb_self: &Self, schema_id: i32) -> RbResult<Option<Value>> {
159
- let schema = match rb_self.table.borrow().metadata().schema_by_id(schema_id) {
160
- Some(s) => Some(rb_schema(ruby, s)?),
161
- None => None,
162
- };
163
- Ok(schema)
195
+ pub fn schema_by_id(&self, schema_id: i32) -> Option<RbSchema> {
196
+ self.metadata.schema_by_id(schema_id).map(|v| v.into())
164
197
  }
165
198
 
166
- pub fn current_schema(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
167
- rb_schema(ruby, rb_self.table.borrow().metadata().current_schema())
199
+ pub fn current_schema(&self) -> RbSchema {
200
+ self.metadata.current_schema().into()
168
201
  }
169
202
 
170
203
  pub fn current_schema_id(&self) -> i32 {
171
- self.table.borrow().metadata().current_schema_id()
204
+ self.metadata.current_schema_id()
172
205
  }
173
206
 
174
- pub fn partition_specs(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
175
- let partition_specs = ruby.ary_new();
176
- for s in rb_self.table.borrow().metadata().partition_specs_iter() {
177
- partition_specs.push(rb_partition_spec(s)?)?;
178
- }
179
- Ok(partition_specs)
207
+ pub fn partition_specs(ruby: &Ruby, rb_self: &Self) -> RArray {
208
+ ruby.ary_from_iter(
209
+ rb_self
210
+ .metadata
211
+ .partition_specs_iter()
212
+ .map(RbPartitionSpec::from),
213
+ )
180
214
  }
181
215
 
182
- pub fn partition_spec_by_id(&self, partition_spec_id: i32) -> RbResult<Option<Value>> {
183
- let partition_spec = match self
184
- .table
185
- .borrow()
186
- .metadata()
216
+ pub fn partition_spec_by_id(&self, partition_spec_id: i32) -> Option<RbPartitionSpec> {
217
+ self.metadata
187
218
  .partition_spec_by_id(partition_spec_id)
188
- {
189
- Some(s) => Some(rb_partition_spec(s)?),
190
- None => None,
191
- };
192
- Ok(partition_spec)
219
+ .map(|v| v.into())
193
220
  }
194
221
 
195
- pub fn default_partition_spec(&self) -> RbResult<Value> {
196
- rb_partition_spec(self.table.borrow().metadata().default_partition_spec())
222
+ pub fn default_partition_spec(&self) -> RbPartitionSpec {
223
+ self.metadata.default_partition_spec().into()
197
224
  }
198
225
 
199
226
  pub fn default_partition_spec_id(&self) -> i32 {
200
- self.table.borrow().metadata().default_partition_spec_id()
227
+ self.metadata.default_partition_spec_id()
201
228
  }
202
229
 
203
- pub fn snapshots(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
204
- let snapshots = ruby.ary_new();
205
- for s in rb_self.table.borrow().metadata().snapshots() {
206
- snapshots.push(rb_snapshot(ruby, s)?)?;
207
- }
208
- Ok(snapshots)
230
+ pub fn snapshots(ruby: &Ruby, rb_self: &Self) -> RArray {
231
+ ruby.ary_from_iter(rb_self.metadata.snapshots().map(RbSnapshot::from))
209
232
  }
210
233
 
211
- pub fn snapshot_by_id(
212
- ruby: &Ruby,
213
- rb_self: &Self,
214
- snapshot_id: i64,
215
- ) -> RbResult<Option<Value>> {
216
- let snapshot = match rb_self
217
- .table
218
- .borrow()
219
- .metadata()
220
- .snapshot_by_id(snapshot_id)
221
- {
222
- Some(s) => Some(rb_snapshot(ruby, s)?),
223
- None => None,
224
- };
225
- Ok(snapshot)
226
- }
227
-
228
- pub fn history(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
229
- let history = ruby.ary_new();
230
- for s in rb_self.table.borrow().metadata().history() {
231
- let snapshot_log = ruby.hash_new();
232
- snapshot_log.aset(ruby.to_symbol("snapshot_id"), s.snapshot_id)?;
233
- // TODO timestamp
234
- history.push(snapshot_log)?;
235
- }
236
- Ok(history)
237
- }
238
-
239
- pub fn metadata_log(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
240
- let metadata_logs = ruby.ary_new();
241
- for s in rb_self.table.borrow().metadata().metadata_log() {
242
- let metadata_log = ruby.hash_new();
243
- metadata_log.aset(
244
- ruby.to_symbol("metadata_file"),
245
- ruby.str_new(&s.metadata_file),
246
- )?;
247
- // TODO timestamp
248
- metadata_logs.push(metadata_log)?;
249
- }
250
- Ok(metadata_logs)
234
+ pub fn snapshot_by_id(&self, snapshot_id: i64) -> Option<RbSnapshot> {
235
+ self.metadata.snapshot_by_id(snapshot_id).map(|v| v.into())
251
236
  }
252
237
 
253
- pub fn current_snapshot(ruby: &Ruby, rb_self: &Self) -> RbResult<Option<Value>> {
254
- let snapshot = match rb_self.table.borrow().metadata().current_snapshot() {
255
- Some(s) => Some(rb_snapshot(ruby, s)?),
256
- None => None,
257
- };
258
- Ok(snapshot)
238
+ pub fn history(ruby: &Ruby, rb_self: &Self) -> RArray {
239
+ ruby.ary_from_iter(
240
+ rb_self
241
+ .metadata
242
+ .history()
243
+ .iter()
244
+ .map(RbSnapshotLogEntry::from),
245
+ )
246
+ }
247
+
248
+ pub fn metadata_log(ruby: &Ruby, rb_self: &Self) -> RArray {
249
+ ruby.ary_from_iter(
250
+ rb_self
251
+ .metadata
252
+ .metadata_log()
253
+ .iter()
254
+ .map(RbMetadataLogEntry::from),
255
+ )
256
+ }
257
+
258
+ pub fn current_snapshot(&self) -> Option<RbSnapshot> {
259
+ self.metadata.current_snapshot().map(|v| v.into())
259
260
  }
260
261
 
261
262
  pub fn current_snapshot_id(&self) -> Option<i64> {
262
- self.table.borrow().metadata().current_snapshot_id()
263
+ self.metadata.current_snapshot_id()
263
264
  }
264
265
 
265
- pub fn snapshot_for_ref(
266
- ruby: &Ruby,
267
- rb_self: &Self,
268
- ref_name: String,
269
- ) -> RbResult<Option<Value>> {
270
- let snapshot = match rb_self
271
- .table
272
- .borrow()
273
- .metadata()
274
- .snapshot_for_ref(&ref_name)
275
- {
276
- Some(s) => Some(rb_snapshot(ruby, s)?),
277
- None => None,
278
- };
279
- Ok(snapshot)
280
- }
281
-
282
- pub fn sort_orders(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
283
- let sort_orders = ruby.ary_new();
284
- for s in rb_self.table.borrow().metadata().sort_orders_iter() {
285
- sort_orders.push(rb_sort_order(s)?)?;
286
- }
287
- Ok(sort_orders)
266
+ pub fn snapshot_for_ref(&self, ref_name: String) -> Option<RbSnapshot> {
267
+ self.metadata.snapshot_for_ref(&ref_name).map(|v| v.into())
288
268
  }
289
269
 
290
- pub fn sort_order_by_id(&self, sort_order_id: i64) -> RbResult<Option<Value>> {
291
- let sort_order = match self
292
- .table
293
- .borrow()
294
- .metadata()
270
+ pub fn sort_orders(ruby: &Ruby, rb_self: &Self) -> RArray {
271
+ ruby.ary_from_iter(rb_self.metadata.sort_orders_iter().map(RbSortOrder::from))
272
+ }
273
+
274
+ pub fn sort_order_by_id(&self, sort_order_id: i64) -> Option<RbSortOrder> {
275
+ self.metadata
295
276
  .sort_order_by_id(sort_order_id)
296
- {
297
- Some(s) => Some(rb_sort_order(s)?),
298
- None => None,
299
- };
300
- Ok(sort_order)
277
+ .map(|v| v.into())
301
278
  }
302
279
 
303
- pub fn default_sort_order(&self) -> RbResult<Value> {
304
- rb_sort_order(self.table.borrow().metadata().default_sort_order())
280
+ pub fn default_sort_order(&self) -> RbSortOrder {
281
+ self.metadata.default_sort_order().into()
305
282
  }
306
283
 
307
284
  pub fn default_sort_order_id(&self) -> i64 {
308
- self.table.borrow().metadata().default_sort_order_id()
285
+ self.metadata.default_sort_order_id()
309
286
  }
310
287
 
311
288
  pub fn properties(&self) -> HashMap<String, String> {
312
- self.table.borrow().metadata().properties().clone()
289
+ self.metadata.properties().clone()
313
290
  }
314
291
 
315
- pub fn statistics(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
316
- let statistics = ruby.ary_new();
317
- for s in rb_self.table.borrow().metadata().statistics_iter() {
318
- statistics.push(rb_statistics_file(s)?)?;
319
- }
320
- Ok(statistics)
321
- }
322
-
323
- pub fn partition_statistics(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
324
- let statistics = ruby.ary_new();
325
- for s in rb_self
326
- .table
327
- .borrow()
328
- .metadata()
329
- .partition_statistics_iter()
330
- {
331
- statistics.push(rb_partition_statistics_file(s)?)?;
332
- }
333
- Ok(statistics)
292
+ pub fn statistics(ruby: &Ruby, rb_self: &Self) -> RArray {
293
+ ruby.ary_from_iter(
294
+ rb_self
295
+ .metadata
296
+ .statistics_iter()
297
+ .map(RbStatisticsFile::from),
298
+ )
334
299
  }
335
300
 
336
- pub fn statistics_for_snapshot(&self, snapshot_id: i64) -> RbResult<Option<Value>> {
337
- let statistics = match self
338
- .table
339
- .borrow()
340
- .metadata()
301
+ pub fn partition_statistics(ruby: &Ruby, rb_self: &Self) -> RArray {
302
+ ruby.ary_from_iter(
303
+ rb_self
304
+ .metadata
305
+ .partition_statistics_iter()
306
+ .map(RbPartitionStatisticsFile::from),
307
+ )
308
+ }
309
+
310
+ pub fn statistics_for_snapshot(&self, snapshot_id: i64) -> Option<RbStatisticsFile> {
311
+ self.metadata
341
312
  .statistics_for_snapshot(snapshot_id)
342
- {
343
- Some(s) => Some(rb_statistics_file(s)?),
344
- None => None,
345
- };
346
- Ok(statistics)
347
- }
348
-
349
- pub fn partition_statistics_for_snapshot(&self, snapshot_id: i64) -> RbResult<Option<Value>> {
350
- let statistics = match self
351
- .table
352
- .borrow()
353
- .metadata()
313
+ .map(|v| v.into())
314
+ }
315
+
316
+ pub fn partition_statistics_for_snapshot(
317
+ &self,
318
+ snapshot_id: i64,
319
+ ) -> Option<RbPartitionStatisticsFile> {
320
+ self.metadata
354
321
  .partition_statistics_for_snapshot(snapshot_id)
355
- {
356
- Some(s) => Some(rb_partition_statistics_file(s)?),
357
- None => None,
358
- };
359
- Ok(statistics)
322
+ .map(|v| v.into())
360
323
  }
361
324
 
362
- pub fn encryption_keys(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
363
- let encryption_keys = ruby.ary_new();
364
- for k in rb_self.table.borrow().metadata().encryption_keys_iter() {
365
- encryption_keys.push(rb_encrypted_key(k)?)?;
366
- }
367
- Ok(encryption_keys)
325
+ pub fn encryption_keys(ruby: &Ruby, rb_self: &Self) -> RArray {
326
+ ruby.ary_from_iter(
327
+ rb_self
328
+ .metadata
329
+ .encryption_keys_iter()
330
+ .map(RbEncryptedKey::from),
331
+ )
368
332
  }
369
333
 
370
- pub fn encryption_key(&self, key_id: String) -> RbResult<Option<Value>> {
371
- let key = match self.table.borrow().metadata().encryption_key(&key_id) {
372
- Some(k) => Some(rb_encrypted_key(k)?),
373
- None => None,
374
- };
375
- Ok(key)
334
+ pub fn encryption_key(&self, key_id: String) -> Option<RbEncryptedKey> {
335
+ self.metadata.encryption_key(&key_id).map(|v| v.into())
376
336
  }
377
337
 
378
- pub fn from_metadata_file(location: String) -> RbResult<Self> {
379
- let file_io = FileIO::new_with_fs();
380
- let table_ident = TableIdent::from_strs(["static-table", &location]).unwrap();
381
- let static_table = runtime()
382
- .block_on(StaticTable::from_metadata_file(
383
- &location,
384
- table_ident,
385
- file_io,
386
- ))
387
- .map_err(to_rb_err)?;
388
- Ok(Self {
389
- table: static_table.into_table().into(),
390
- })
338
+ pub fn next_row_id(&self) -> u64 {
339
+ self.metadata.next_row_id()
340
+ }
341
+ }
342
+
343
+ fn cast_batch(batch: RecordBatch, table_schema: Arc<Schema>) -> Result<RecordBatch, ArrowError> {
344
+ let mut fields = Vec::new();
345
+ let mut columns = Vec::new();
346
+ for (field, column) in batch.schema().fields.iter().zip(batch.columns()) {
347
+ match field.data_type() {
348
+ DataType::Utf8View => {
349
+ fields.push(Arc::new(Field::new(
350
+ field.name(),
351
+ DataType::Utf8,
352
+ field.is_nullable(),
353
+ )));
354
+ columns.push(cast(column, &DataType::Utf8)?);
355
+ }
356
+ DataType::BinaryView => {
357
+ // TODO convert to FixedSizeBinary if needed
358
+ fields.push(Arc::new(Field::new(
359
+ field.name(),
360
+ DataType::LargeBinary,
361
+ field.is_nullable(),
362
+ )));
363
+ columns.push(cast(column, &DataType::LargeBinary)?);
364
+ }
365
+ DataType::Timestamp(time_unit, Some(_)) => {
366
+ fields.push(Arc::new(Field::new(
367
+ field.name(),
368
+ DataType::Timestamp(*time_unit, Some("+00:00".into())),
369
+ field.is_nullable(),
370
+ )));
371
+ columns.push(cast(
372
+ column,
373
+ &DataType::Timestamp(*time_unit, Some("+00:00".into())),
374
+ )?);
375
+ }
376
+ _ => {
377
+ // cloning Arc is cheap
378
+ fields.push(field.clone());
379
+ columns.push(column.clone());
380
+ }
381
+ }
391
382
  }
383
+ RecordBatch::try_new(Arc::new(Schema::new(fields)), columns)?.with_schema(table_schema)
392
384
  }