| 129 | options_(std::move(options)) {} |
| 130 | |
| 131 | static Result<ScanV2Options> NormalizeAndValidate(const ScanV2Options& options, |
| 132 | compute::ExecContext* ctx) { |
| 133 | ScanV2Options normalized(options); |
| 134 | if (!normalized.dataset) { |
| 135 | return Status::Invalid("Scan options must include a dataset"); |
| 136 | } |
| 137 | |
| 138 | if (options.fragment_readahead < 0) { |
| 139 | return Status::Invalid( |
| 140 | "Fragment readahead may not be less than 0. Set to 0 to disable readahead"); |
| 141 | } |
| 142 | |
| 143 | if (options.target_bytes_readahead < 0) { |
| 144 | return Status::Invalid( |
| 145 | "Batch readahead may not be less than 0. Set to 0 to disable readahead"); |
| 146 | } |
| 147 | |
| 148 | if (!normalized.filter.is_valid()) { |
| 149 | normalized.filter = compute::literal(true); |
| 150 | } |
| 151 | |
| 152 | if (normalized.filter.call() && normalized.filter.IsBound()) { |
| 153 | // There is no easy way to make sure a filter was bound against the same |
| 154 | // function registry as the one in ctx so we just require it to be unbound |
| 155 | // FIXME - Do we care if it was bound to a different function registry? |
| 156 | return Status::Invalid("Scan filter must be unbound"); |
| 157 | } else { |
| 158 | ARROW_ASSIGN_OR_RAISE(normalized.filter, |
| 159 | normalized.filter.Bind(*options.dataset->schema(), ctx)); |
| 160 | ARROW_ASSIGN_OR_RAISE(normalized.filter, |
| 161 | compute::RemoveNamedRefs(std::move(normalized.filter))); |
| 162 | } // Else we must have some simple filter like literal(true) which might be bound |
| 163 | // but we don't care |
| 164 | |
| 165 | if (normalized.filter.type()->id() != Type::BOOL) { |
| 166 | return Status::Invalid("A scan filter must be a boolean expression"); |
| 167 | } |
| 168 | |
| 169 | return normalized; |
| 170 | } |
| 171 | |
| 172 | static Result<acero::ExecNode*> Make(acero::ExecPlan* plan, |
| 173 | std::vector<acero::ExecNode*> inputs, |
nothing calls this directly
no test coverage detected