blob: 9ea8a4be1c1f2be56ecb7076bc08f87034b620f5 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#pragma once
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "paimon/result.h"
#include "paimon/visibility.h"
struct ArrowArray;
namespace paimon {
/// `RecordBatch` encapsulates a batch of data with the same schema, supporting different types such
/// as `INSERT`, `UPDATE_BEFORE`, `UPDATE_AFTER`, and `DELETE`. It is typically used in streaming
/// write or batch processing scenarios, with underlying data stored in the Apache Arrow format.
/// @note Do not use this class directly, use `RecordBatchBuilder` to build a `RecordBatch` which
/// has input validation.
class PAIMON_EXPORT RecordBatch {
public:
enum class PAIMON_EXPORT RowKind : int8_t {
INSERT = 0,
UPDATE_BEFORE = 1,
UPDATE_AFTER = 2,
DELETE = 3,
};
/// @note 1. Data cannot be reused, as it will be released after Write. 2. If a partition
/// field's value is null, it should be represented as "__DEFAULT_PARTITION__"(or a user-defined
/// default value) in the partition map. However, in the Arrow array, partition column values
/// MUST NOT be set to "__DEFAULT_PARTITION__" (or a user-defined default value). Instead, they
/// should be properly set as actual nulls. If used, it may lead to behavioral inconsistencies
/// between C++ Paimon and Java Paimon.
RecordBatch(const std::map<std::string, std::string>& partition, int32_t bucket,
const std::vector<RowKind>& row_kinds, ArrowArray* data);
~RecordBatch();
RecordBatch(RecordBatch&&);
RecordBatch& operator=(RecordBatch&&);
RecordBatch(const RecordBatch&) = delete;
RecordBatch& operator=(const RecordBatch&) = delete;
const std::map<std::string, std::string>& GetPartition() const {
return partition_;
}
int32_t GetBucket() const {
return bucket_;
}
ArrowArray* GetData() const {
return data_;
}
const std::vector<RecordBatch::RowKind>& GetRowKind() const {
return row_kinds_;
}
void SetBucket(int32_t bucket) {
bucket_ = bucket;
}
bool HasSpecifiedBucket() const;
private:
std::map<std::string, std::string> partition_;
int32_t bucket_;
std::vector<RecordBatch::RowKind> row_kinds_;
::ArrowArray* data_;
};
/// Builder for constructing `RecordBatch` instances.
///
/// This class provides a convenient way to build `RecordBatch` objects by setting
/// various properties such as data, row kinds, partition information, and bucket id.
class PAIMON_EXPORT RecordBatchBuilder {
public:
/// Constructs a `RecordBatchBuilder` with Arrow data
///
/// @note The `data` must conform to table schema:
/// - Each array in `data` corresponds to a field in table schema.
/// - If a field in table schema is marked as non-nullable (`nullable = false`),
/// the corresponding array in `data` must have zero null entries.
///
/// @note Consistency between `data` and table schema will be validated during the write
/// process.
///
/// @param data ArrowArray struct containing the columnar data (via C Data Interface)
explicit RecordBatchBuilder(::ArrowArray* data);
~RecordBatchBuilder();
/// Move new Arrow data into the builder, replacing existing data.
/// @param data New Arrow array data.
RecordBatchBuilder& MoveData(::ArrowArray* data);
/// Set the row kinds for each record in the batch.
/// @param row_kinds A vector of row kinds, including INSERT, UPDATE_BEFORE, UPDATE_AFTER and
/// DELETE. If not set, default value is `INSERT`.
/// @note `row_kinds` must have the same length as the number of records in the data.
RecordBatchBuilder& SetRowKinds(const std::vector<RecordBatch::RowKind>& row_kinds);
/// Set the partition information for this record batch.
/// @param data Map of partition column names to their string values.
RecordBatchBuilder& SetPartition(const std::map<std::string, std::string>& data);
/// Set the bucket id for this record batch. If not set, default value is `-2147483648`
/// (i.e., `HasSpecifiedBucket()` returns false), and the bucket will be auto-resolved
/// at write time based on the table's bucket option:
///
/// - **Unaware-bucket mode** (table option `bucket = -1`, append-only table without
/// primary keys): the bucket will be auto-filled with `UNAWARE_BUCKET (0)`. If the
/// caller does specify a bucket, it MUST be `UNAWARE_BUCKET (0)`, otherwise the
/// write fails.
/// - **Postpone-bucket mode** (table option `bucket = -2`, primary-key table whose
/// bucket assignment is deferred): the bucket will be auto-filled with
/// `POSTPONE_BUCKET (-2)`. If the caller does specify a bucket, it MUST be
/// `POSTPONE_BUCKET (-2)`, otherwise the write fails.
/// - **Fixed-bucket mode** (table option `bucket > 0`): the caller MUST explicitly
/// call `SetBucket()` with a value in `[0, bucket)`; not calling `SetBucket()`
/// (or passing an out-of-range value) will cause the write to fail.
///
/// @param bucket The bucket id for data distribution.
RecordBatchBuilder& SetBucket(int32_t bucket);
/// Build and return the final `RecordBatch` instance.
///
/// This method validates the configuration and creates `RecordBatch` with all
/// the specified properties.
Result<std::unique_ptr<RecordBatch>> Finish();
class Impl;
private:
std::unique_ptr<Impl> impl_;
};
} // namespace paimon