1#include "duckdb/parser/transformer.hpp"
2#include "duckdb/parser/parsed_data/sample_options.hpp"
3#include "duckdb/parser/expression/constant_expression.hpp"
4#include "duckdb/common/string_util.hpp"
5
6namespace duckdb {
7
8static SampleMethod GetSampleMethod(const string &method) {
9 auto lmethod = StringUtil::Lower(str: method);
10 if (lmethod == "system") {
11 return SampleMethod::SYSTEM_SAMPLE;
12 } else if (lmethod == "bernoulli") {
13 return SampleMethod::BERNOULLI_SAMPLE;
14 } else if (lmethod == "reservoir") {
15 return SampleMethod::RESERVOIR_SAMPLE;
16 } else {
17 throw ParserException("Unrecognized sampling method %s, expected system, bernoulli or reservoir", method);
18 }
19}
20
21unique_ptr<SampleOptions> Transformer::TransformSampleOptions(optional_ptr<duckdb_libpgquery::PGNode> options) {
22 if (!options) {
23 return nullptr;
24 }
25 auto result = make_uniq<SampleOptions>();
26 auto &sample_options = PGCast<duckdb_libpgquery::PGSampleOptions>(node&: *options);
27 auto &sample_size = *PGPointerCast<duckdb_libpgquery::PGSampleSize>(ptr: sample_options.sample_size);
28 auto sample_value = TransformValue(val: sample_size.sample_size)->value;
29 result->is_percentage = sample_size.is_percentage;
30 if (sample_size.is_percentage) {
31 // sample size is given in sample_size: use system sampling
32 auto percentage = sample_value.GetValue<double>();
33 if (percentage < 0 || percentage > 100) {
34 throw ParserException("Sample sample_size %llf out of range, must be between 0 and 100", percentage);
35 }
36 result->sample_size = Value::DOUBLE(value: percentage);
37 result->method = SampleMethod::SYSTEM_SAMPLE;
38 } else {
39 // sample size is given in rows: use reservoir sampling
40 auto rows = sample_value.GetValue<int64_t>();
41 if (rows < 0) {
42 throw ParserException("Sample rows %lld out of range, must be bigger than or equal to 0", rows);
43 }
44 result->sample_size = Value::BIGINT(value: rows);
45 result->method = SampleMethod::RESERVOIR_SAMPLE;
46 }
47 if (sample_options.method) {
48 result->method = GetSampleMethod(method: sample_options.method);
49 }
50 if (sample_options.has_seed) {
51 result->seed = sample_options.seed;
52 }
53 return result;
54}
55
56} // namespace duckdb
57