duckdb 0.3.2-dev838.0 → 0.3.2-dev856.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/src/duckdb.cpp CHANGED
@@ -21139,12 +21139,14 @@ public:
21139
21139
 
21140
21140
  int64_t GetFileSize(FileHandle &handle) override;
21141
21141
 
21142
+ void Reset(FileHandle &handle) override;
21142
21143
  bool OnDiskFile(FileHandle &handle) override {
21143
21144
  return false;
21144
21145
  };
21145
21146
  bool CanSeek() override {
21146
21147
  return false;
21147
21148
  }
21149
+ void FileSync(FileHandle &handle) override;
21148
21150
 
21149
21151
  std::string GetName() const override {
21150
21152
  return "PipeFileSystem";
@@ -21181,6 +21183,10 @@ int64_t PipeFile::WriteChunk(void *buffer, int64_t nr_bytes) {
21181
21183
  return child_handle->Write(buffer, nr_bytes);
21182
21184
  }
21183
21185
 
21186
+ void PipeFileSystem::Reset(FileHandle &handle) {
21187
+ throw InternalException("Cannot reset pipe file system");
21188
+ }
21189
+
21184
21190
  int64_t PipeFileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes) {
21185
21191
  auto &pipe = (PipeFile &)handle;
21186
21192
  return pipe.ReadChunk(buffer, nr_bytes);
@@ -21195,6 +21201,9 @@ int64_t PipeFileSystem::GetFileSize(FileHandle &handle) {
21195
21201
  return 0;
21196
21202
  }
21197
21203
 
21204
+ void PipeFileSystem::FileSync(FileHandle &handle) {
21205
+ }
21206
+
21198
21207
  unique_ptr<FileHandle> PipeFileSystem::OpenPipe(unique_ptr<FileHandle> handle) {
21199
21208
  auto path = handle->path;
21200
21209
  return make_unique<PipeFile>(move(handle), path);
@@ -56617,6 +56626,125 @@ string PhysicalTopN::ParamsToString() const {
56617
56626
 
56618
56627
  namespace duckdb {
56619
56628
 
56629
+ struct CSVFileHandle {
56630
+ public:
56631
+ explicit CSVFileHandle(unique_ptr<FileHandle> file_handle_p) : file_handle(move(file_handle_p)) {
56632
+ can_seek = file_handle->CanSeek();
56633
+ plain_file_source = file_handle->OnDiskFile() && can_seek;
56634
+ file_size = file_handle->GetFileSize();
56635
+ }
56636
+
56637
+ bool CanSeek() {
56638
+ return can_seek;
56639
+ }
56640
+ void Seek(idx_t position) {
56641
+ if (!can_seek) {
56642
+ throw InternalException("Cannot seek in this file");
56643
+ }
56644
+ file_handle->Seek(position);
56645
+ }
56646
+ idx_t SeekPosition() {
56647
+ if (!can_seek) {
56648
+ throw InternalException("Cannot seek in this file");
56649
+ }
56650
+ return file_handle->SeekPosition();
56651
+ }
56652
+ void Reset() {
56653
+ if (plain_file_source) {
56654
+ file_handle->Reset();
56655
+ } else {
56656
+ if (!reset_enabled) {
56657
+ throw InternalException("Reset called but reset is not enabled for this CSV Handle");
56658
+ }
56659
+ read_position = 0;
56660
+ }
56661
+ }
56662
+ bool PlainFileSource() {
56663
+ return plain_file_source;
56664
+ }
56665
+
56666
+ idx_t FileSize() {
56667
+ return file_size;
56668
+ }
56669
+
56670
+ idx_t Read(void *buffer, idx_t nr_bytes) {
56671
+ if (!plain_file_source) {
56672
+ // not a plain file source: we need to do some bookkeeping around the reset functionality
56673
+ idx_t result_offset = 0;
56674
+ if (read_position < buffer_size) {
56675
+ // we need to read from our cached buffer
56676
+ auto buffer_read_count = MinValue<idx_t>(nr_bytes, buffer_size - read_position);
56677
+ memcpy(buffer, cached_buffer.get() + read_position, buffer_read_count);
56678
+ result_offset += buffer_read_count;
56679
+ read_position += buffer_read_count;
56680
+ if (result_offset == nr_bytes) {
56681
+ return nr_bytes;
56682
+ }
56683
+ } else if (!reset_enabled && cached_buffer) {
56684
+ // reset is disabled but we still have cached data
56685
+ // we can remove any cached data
56686
+ cached_buffer.reset();
56687
+ buffer_size = 0;
56688
+ buffer_capacity = 0;
56689
+ read_position = 0;
56690
+ }
56691
+ // we have data left to read from the file
56692
+ // read directly into the buffer
56693
+ auto bytes_read = file_handle->Read((char *)buffer + result_offset, nr_bytes - result_offset);
56694
+ read_position += bytes_read;
56695
+ if (reset_enabled) {
56696
+ // if reset caching is enabled, we need to cache the bytes that we have read
56697
+ if (buffer_size + bytes_read >= buffer_capacity) {
56698
+ // no space; first enlarge the buffer
56699
+ buffer_capacity = MaxValue<idx_t>(NextPowerOfTwo(buffer_size + bytes_read), buffer_capacity * 2);
56700
+
56701
+ auto new_buffer = unique_ptr<data_t[]>(new data_t[buffer_capacity]);
56702
+ if (buffer_size > 0) {
56703
+ memcpy(new_buffer.get(), cached_buffer.get(), buffer_size);
56704
+ }
56705
+ cached_buffer = move(new_buffer);
56706
+ }
56707
+ memcpy(cached_buffer.get() + buffer_size, (char *)buffer + result_offset, bytes_read);
56708
+ buffer_size += bytes_read;
56709
+ }
56710
+
56711
+ return result_offset + bytes_read;
56712
+ } else {
56713
+ return file_handle->Read(buffer, nr_bytes);
56714
+ }
56715
+ }
56716
+
56717
+ string ReadLine() {
56718
+ string result;
56719
+ char buffer[1];
56720
+ while (true) {
56721
+ idx_t tuples_read = Read(buffer, 1);
56722
+ if (tuples_read == 0 || buffer[0] == '\n') {
56723
+ return result;
56724
+ }
56725
+ if (buffer[0] != '\r') {
56726
+ result += buffer[0];
56727
+ }
56728
+ }
56729
+ }
56730
+
56731
+ void DisableReset() {
56732
+ this->reset_enabled = false;
56733
+ }
56734
+
56735
+ private:
56736
+ unique_ptr<FileHandle> file_handle;
56737
+ bool reset_enabled = true;
56738
+ bool can_seek = false;
56739
+ bool plain_file_source = false;
56740
+ idx_t file_size = 0;
56741
+ // reset support
56742
+ unique_ptr<data_t[]> cached_buffer;
56743
+ idx_t read_position = 0;
56744
+ idx_t buffer_size = 0;
56745
+ idx_t buffer_capacity = 0;
56746
+ };
56747
+
56620
56748
  void BufferedCSVReaderOptions::SetDelimiter(const string &input) {
56621
56749
  this->delimiter = StringUtil::Replace(input, "\\t", "\t");
56622
56750
  this->has_delimiter = true;
@@ -56749,6 +56877,13 @@ BufferedCSVReader::BufferedCSVReader(ClientContext &context, BufferedCSVReaderOp
56749
56877
  requested_types) {
56750
56878
  }
56751
56879
 
56880
+ BufferedCSVReader::~BufferedCSVReader() {
56881
+ }
56882
+
56883
+ idx_t BufferedCSVReader::GetFileSize() {
56884
+ return file_handle ? file_handle->FileSize() : 0;
56885
+ }
56886
+
56752
56887
  void BufferedCSVReader::Initialize(const vector<LogicalType> &requested_types) {
56753
56888
  PrepareComplexParser();
56754
56889
  if (options.auto_detect) {
@@ -56765,6 +56900,9 @@ void BufferedCSVReader::Initialize(const vector<LogicalType> &requested_types) {
56765
56900
  SkipRowsAndReadHeader(options.skip_rows, options.header);
56766
56901
  }
56767
56902
  InitParseChunk(sql_types.size());
56903
+ // we only need reset support during the automatic CSV type detection
56904
+ // since reset support might require caching (in the case of streams), we disable it for the remainder
56905
+ file_handle->DisableReset();
56768
56906
  }
56769
56907
 
56770
56908
  void BufferedCSVReader::PrepareComplexParser() {
@@ -56773,12 +56911,10 @@ void BufferedCSVReader::PrepareComplexParser() {
56773
56911
  quote_search = TextSearchShiftArray(options.quote);
56774
56912
  }
56775
56913
 
56776
- unique_ptr<FileHandle> BufferedCSVReader::OpenCSV(const BufferedCSVReaderOptions &options) {
56777
- auto result = fs.OpenFile(options.file_path.c_str(), FileFlags::FILE_FLAGS_READ, FileLockType::NO_LOCK,
56778
- options.compression, this->opener);
56779
- plain_file_source = result->OnDiskFile() && result->CanSeek();
56780
- file_size = result->GetFileSize();
56781
- return result;
56914
+ unique_ptr<CSVFileHandle> BufferedCSVReader::OpenCSV(const BufferedCSVReaderOptions &options) {
56915
+ auto file_handle = fs.OpenFile(options.file_path.c_str(), FileFlags::FILE_FLAGS_READ, FileLockType::NO_LOCK,
56916
+ options.compression, this->opener);
56917
+ return make_unique<CSVFileHandle>(move(file_handle));
56782
56918
  }
56783
56919
 
56784
56920
  // Helper function to generate column names
@@ -56944,7 +57080,7 @@ bool BufferedCSVReader::JumpToNextSample() {
56944
57080
  // assess if it makes sense to jump, based on size of the first chunk relative to size of the entire file
56945
57081
  if (sample_chunk_idx == 0) {
56946
57082
  idx_t bytes_first_chunk = bytes_in_chunk;
56947
- double chunks_fit = (file_size / (double)bytes_first_chunk);
57083
+ double chunks_fit = (file_handle->FileSize() / (double)bytes_first_chunk);
56948
57084
  jumping_samples = chunks_fit >= options.sample_chunks;
56949
57085
 
56950
57086
  // jump back to the beginning
@@ -56959,7 +57095,7 @@ bool BufferedCSVReader::JumpToNextSample() {
56959
57095
 
56960
57096
  // if we deal with any other sources than plaintext files, jumping_samples can be tricky. In that case
56961
57097
  // we just read x continuous chunks from the stream TODO: make jumps possible for zipfiles.
56962
- if (!plain_file_source || !jumping_samples) {
57098
+ if (!file_handle->PlainFileSource() || !jumping_samples) {
56963
57099
  sample_chunk_idx++;
56964
57100
  return true;
56965
57101
  }
@@ -56969,13 +57105,13 @@ bool BufferedCSVReader::JumpToNextSample() {
56969
57105
  bytes_per_line_avg = ((bytes_per_line_avg * (sample_chunk_idx)) + bytes_per_line) / (sample_chunk_idx + 1);
56970
57106
 
56971
57107
  // if none of the previous conditions were met, we can jump
56972
- idx_t partition_size = (idx_t)round(file_size / (double)options.sample_chunks);
57108
+ idx_t partition_size = (idx_t)round(file_handle->FileSize() / (double)options.sample_chunks);
56973
57109
 
56974
57110
  // calculate offset to end of the current partition
56975
57111
  int64_t offset = partition_size - bytes_in_chunk - remaining_bytes_in_buffer;
56976
57112
  auto current_pos = file_handle->SeekPosition();
56977
57113
 
56978
- if (current_pos + offset < file_size) {
57114
+ if (current_pos + offset < file_handle->FileSize()) {
56979
57115
  // set position in stream and clear failure bits
56980
57116
  file_handle->Seek(current_pos + offset);
56981
57117
 
@@ -56986,10 +57122,10 @@ bool BufferedCSVReader::JumpToNextSample() {
56986
57122
  // seek backwards from the end in last chunk and hope to catch the end of the file
56987
57123
  // TODO: actually it would be good to make sure that the end of file is being reached, because
56988
57124
  // messy end-lines are quite common. For this case, however, we first need a skip_end detection anyways.
56989
- file_handle->Seek(file_size - bytes_in_chunk);
57125
+ file_handle->Seek(file_handle->FileSize() - bytes_in_chunk);
56990
57126
 
56991
57127
  // estimate linenr
56992
- linenr = (idx_t)round((file_size - bytes_in_chunk) / bytes_per_line_avg);
57128
+ linenr = (idx_t)round((file_handle->FileSize() - bytes_in_chunk) / bytes_per_line_avg);
56993
57129
  linenr_estimated = true;
56994
57130
  }
56995
57131
 
@@ -57143,6 +57279,7 @@ void BufferedCSVReader::DetectDialect(const vector<LogicalType> &requested_types
57143
57279
 
57144
57280
  JumpToBeginning(original_options.skip_rows);
57145
57281
  sniffed_column_counts.clear();
57282
+
57146
57283
  if (!TryParseCSV(ParserMode::SNIFFING_DIALECT)) {
57147
57284
  continue;
57148
57285
  }
@@ -72253,7 +72390,7 @@ namespace duckdb {
72253
72390
  struct VariableReturnBindData : public FunctionData {
72254
72391
  LogicalType stype;
72255
72392
 
72256
- explicit VariableReturnBindData(LogicalType stype) : stype(stype) {
72393
+ explicit VariableReturnBindData(const LogicalType &stype_p) : stype(stype_p) {
72257
72394
  }
72258
72395
 
72259
72396
  unique_ptr<FunctionData> Copy() override {
@@ -73604,9 +73741,13 @@ static int64_t TargetTypeCost(const LogicalType &type) {
73604
73741
  case LogicalTypeId::TIMESTAMP:
73605
73742
  return 120;
73606
73743
  case LogicalTypeId::VARCHAR:
73607
- return 199;
73744
+ return 149;
73608
73745
  case LogicalTypeId::DECIMAL:
73609
73746
  return 104;
73747
+ case LogicalTypeId::STRUCT:
73748
+ case LogicalTypeId::MAP:
73749
+ case LogicalTypeId::LIST:
73750
+ return 160;
73610
73751
  default:
73611
73752
  return 110;
73612
73753
  }
@@ -75503,6 +75644,10 @@ void DateDiffFun::RegisterFunction(BuiltinFunctions &set) {
75503
75644
 
75504
75645
 
75505
75646
 
75647
+
75648
+
75649
+
75650
+
75506
75651
  namespace duckdb {
75507
75652
 
75508
75653
  bool TryGetDatePartSpecifier(const string &specifier_p, DatePartSpecifier &result) {
@@ -75569,6 +75714,73 @@ DatePartSpecifier GetDatePartSpecifier(const string &specifier) {
75569
75714
  return result;
75570
75715
  }
75571
75716
 
75717
+ DatePartSpecifier GetDateTypePartSpecifier(const string &specifier, LogicalType &type) {
75718
+ const auto part = GetDatePartSpecifier(specifier);
75719
+ switch (type.id()) {
75720
+ case LogicalType::TIMESTAMP:
75721
+ case LogicalType::TIMESTAMP_TZ:
75722
+ return part;
75723
+ case LogicalType::DATE:
75724
+ switch (part) {
75725
+ case DatePartSpecifier::YEAR:
75726
+ case DatePartSpecifier::MONTH:
75727
+ case DatePartSpecifier::DAY:
75728
+ case DatePartSpecifier::DECADE:
75729
+ case DatePartSpecifier::CENTURY:
75730
+ case DatePartSpecifier::MILLENNIUM:
75731
+ case DatePartSpecifier::DOW:
75732
+ case DatePartSpecifier::ISODOW:
75733
+ case DatePartSpecifier::WEEK:
75734
+ case DatePartSpecifier::QUARTER:
75735
+ case DatePartSpecifier::DOY:
75736
+ case DatePartSpecifier::YEARWEEK:
75737
+ case DatePartSpecifier::ERA:
75738
+ return part;
75739
+ default:
75740
+ break;
75741
+ }
75742
+ break;
75743
+ case LogicalType::TIME:
75744
+ switch (part) {
75745
+ case DatePartSpecifier::MICROSECONDS:
75746
+ case DatePartSpecifier::MILLISECONDS:
75747
+ case DatePartSpecifier::SECOND:
75748
+ case DatePartSpecifier::MINUTE:
75749
+ case DatePartSpecifier::HOUR:
75750
+ case DatePartSpecifier::EPOCH:
75751
+ case DatePartSpecifier::OFFSET:
75752
+ return part;
75753
+ default:
75754
+ break;
75755
+ }
75756
+ break;
75757
+ case LogicalType::INTERVAL:
75758
+ switch (part) {
75759
+ case DatePartSpecifier::YEAR:
75760
+ case DatePartSpecifier::MONTH:
75761
+ case DatePartSpecifier::DAY:
75762
+ case DatePartSpecifier::DECADE:
75763
+ case DatePartSpecifier::CENTURY:
75764
+ case DatePartSpecifier::QUARTER:
75765
+ case DatePartSpecifier::MILLENNIUM:
75766
+ case DatePartSpecifier::MICROSECONDS:
75767
+ case DatePartSpecifier::MILLISECONDS:
75768
+ case DatePartSpecifier::SECOND:
75769
+ case DatePartSpecifier::MINUTE:
75770
+ case DatePartSpecifier::HOUR:
75771
+ case DatePartSpecifier::EPOCH:
75772
+ return part;
75773
+ default:
75774
+ break;
75775
+ }
75776
+ break;
75777
+ default:
75778
+ break;
75779
+ }
75780
+
75781
+ throw NotImplementedException("\"%s\" units \"%s\" not recognized", LogicalTypeIdToString(type.id()), specifier);
75782
+ }
75783
+
75572
75784
  template <class T>
75573
75785
  static void LastYearFunction(DataChunk &args, ExpressionState &state, Vector &result) {
75574
75786
  int32_t last_year = 0;
@@ -75902,6 +76114,137 @@ struct DatePart {
75902
76114
  return PropagateSimpleDatePartStatistics<0, 0>(child_stats);
75903
76115
  }
75904
76116
  };
76117
+
76118
+ struct StructOperator {
76119
+ using part_codes_t = vector<DatePartSpecifier>;
76120
+ using part_mask_t = uint64_t;
76121
+
76122
+ enum MaskBits : uint8_t {
76123
+ YMD = 1 << 0,
76124
+ DOW = 1 << 1,
76125
+ DOY = 1 << 2,
76126
+ EPOCH = 1 << 3,
76127
+ TIME = 1 << 4,
76128
+ ZONE = 1 << 5
76129
+ };
76130
+
76131
+ static part_mask_t GetMask(const part_codes_t &part_codes) {
76132
+ part_mask_t mask = 0;
76133
+ for (const auto &part_code : part_codes) {
76134
+ switch (part_code) {
76135
+ case DatePartSpecifier::YEAR:
76136
+ case DatePartSpecifier::MONTH:
76137
+ case DatePartSpecifier::DAY:
76138
+ case DatePartSpecifier::DECADE:
76139
+ case DatePartSpecifier::CENTURY:
76140
+ case DatePartSpecifier::MILLENNIUM:
76141
+ case DatePartSpecifier::QUARTER:
76142
+ case DatePartSpecifier::ERA:
76143
+ mask |= YMD;
76144
+ break;
76145
+ case DatePartSpecifier::YEARWEEK:
76146
+ mask |= YMD;
76147
+ mask |= DOW;
76148
+ break;
76149
+ case DatePartSpecifier::DOW:
76150
+ case DatePartSpecifier::ISODOW:
76151
+ case DatePartSpecifier::WEEK:
76152
+ mask |= DOW;
76153
+ break;
76154
+ case DatePartSpecifier::DOY:
76155
+ mask |= DOY;
76156
+ break;
76157
+ case DatePartSpecifier::EPOCH:
76158
+ mask |= EPOCH;
76159
+ break;
76160
+ case DatePartSpecifier::MICROSECONDS:
76161
+ case DatePartSpecifier::MILLISECONDS:
76162
+ case DatePartSpecifier::SECOND:
76163
+ case DatePartSpecifier::MINUTE:
76164
+ case DatePartSpecifier::HOUR:
76165
+ mask |= TIME;
76166
+ break;
76167
+ case DatePartSpecifier::OFFSET:
76168
+ mask |= ZONE;
76169
+ break;
76170
+ }
76171
+ }
76172
+ return mask;
76173
+ }
76174
+
76175
+ template <typename P>
76176
+ static inline P HasPartValue(P *part_values, DatePartSpecifier part) {
76177
+ return part_values[int(part)];
76178
+ }
76179
+
76180
+ template <class TA, class TR>
76181
+ static inline void Operation(TR **part_values, const TA &input, const idx_t idx, const part_mask_t mask) {
76182
+ TR *part_data;
76183
+ // YMD calculations
76184
+ int32_t yyyy = 1970;
76185
+ int32_t mm = 0;
76186
+ int32_t dd = 1;
76187
+ if (mask & YMD) {
76188
+ Date::Convert(input, yyyy, mm, dd);
76189
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::YEAR))) {
76190
+ part_data[idx] = yyyy;
76191
+ }
76192
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MONTH))) {
76193
+ part_data[idx] = mm;
76194
+ }
76195
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::DAY))) {
76196
+ part_data[idx] = dd;
76197
+ }
76198
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::DECADE))) {
76199
+ part_data[idx] = yyyy / 10;
76200
+ }
76201
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::CENTURY))) {
76202
+ part_data[idx] = (yyyy - 1) / 100 + 1;
76203
+ }
76204
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MILLENNIUM))) {
76205
+ part_data[idx] = (yyyy - 1) / 1000 + 1;
76206
+ }
76207
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::QUARTER))) {
76208
+ part_data[idx] = (mm - 1) / Interval::MONTHS_PER_QUARTER + 1;
76209
+ }
76210
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::ERA))) {
76211
+ part_data[idx] = yyyy > 0 ? 1 : 0;
76212
+ }
76213
+ }
76214
+
76215
+ // Week calculations
76216
+ int32_t isodow = 0;
76217
+ int32_t ww = 0;
76218
+ if (mask & DOW) {
76219
+ isodow = Date::ExtractISODayOfTheWeek(input);
76220
+ ww = Date::ExtractISOWeekNumber(input);
76221
+ int32_t dow = isodow % 7;
76222
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::DOW))) {
76223
+ part_data[idx] = dow;
76224
+ }
76225
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::ISODOW))) {
76226
+ part_data[idx] = isodow;
76227
+ }
76228
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::WEEK))) {
76229
+ part_data[idx] = ww;
76230
+ }
76231
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::YEARWEEK))) {
76232
+ part_data[idx] = yyyy * 100 + ww;
76233
+ }
76234
+ }
76235
+
76236
+ if (mask & EPOCH) {
76237
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::EPOCH))) {
76238
+ part_data[idx] = Date::Epoch(input);
76239
+ }
76240
+ }
76241
+ if (mask & DOY) {
76242
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::DOY))) {
76243
+ part_data[idx] = Date::ExtractDayOfTheYear(input);
76244
+ }
76245
+ }
76246
+ }
76247
+ };
75905
76248
  };
75906
76249
 
75907
76250
  template <>
@@ -76198,7 +76541,7 @@ int64_t DatePart::OffsetOperator::Operation(timestamp_t input) {
76198
76541
 
76199
76542
  template <>
76200
76543
  int64_t DatePart::OffsetOperator::Operation(interval_t input) {
76201
- return 0;
76544
+ throw NotImplementedException("\"interval\" units \"offset\" not recognized");
76202
76545
  }
76203
76546
 
76204
76547
  template <>
@@ -76206,7 +76549,110 @@ int64_t DatePart::OffsetOperator::Operation(dtime_t input) {
76206
76549
  return 0;
76207
76550
  }
76208
76551
 
76209
- template <class T>
76552
+ template <>
76553
+ void DatePart::StructOperator::Operation(int64_t **part_values, const dtime_t &input, const idx_t idx,
76554
+ const part_mask_t mask) {
76555
+ int64_t *part_data;
76556
+ if (mask & TIME) {
76557
+ const auto micros = MicrosecondsOperator::Operation<dtime_t, int64_t>(input);
76558
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MICROSECONDS))) {
76559
+ part_data[idx] = micros;
76560
+ }
76561
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MILLISECONDS))) {
76562
+ part_data[idx] = micros / Interval::MICROS_PER_MSEC;
76563
+ }
76564
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::SECOND))) {
76565
+ part_data[idx] = micros / Interval::MICROS_PER_SEC;
76566
+ }
76567
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MINUTE))) {
76568
+ part_data[idx] = MinutesOperator::Operation<dtime_t, int64_t>(input);
76569
+ }
76570
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::HOUR))) {
76571
+ part_data[idx] = HoursOperator::Operation<dtime_t, int64_t>(input);
76572
+ }
76573
+ }
76574
+
76575
+ if (mask & EPOCH) {
76576
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::EPOCH))) {
76577
+ part_data[idx] = EpochOperator::Operation<dtime_t, int64_t>(input);
76578
+ ;
76579
+ }
76580
+ }
76581
+
76582
+ if (mask & ZONE) {
76583
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::OFFSET))) {
76584
+ part_data[idx] = 0;
76585
+ }
76586
+ }
76587
+ }
76588
+
76589
+ template <>
76590
+ void DatePart::StructOperator::Operation(int64_t **part_values, const timestamp_t &input, const idx_t idx,
76591
+ const part_mask_t mask) {
76592
+ date_t d;
76593
+ dtime_t t;
76594
+ Timestamp::Convert(input, d, t);
76595
+ // Time first because they both define epoch.
76596
+ Operation(part_values, t, idx, mask);
76597
+ Operation(part_values, d, idx, mask);
76598
+ }
76599
+
76600
+ template <>
76601
+ void DatePart::StructOperator::Operation(int64_t **part_values, const interval_t &input, const idx_t idx,
76602
+ const part_mask_t mask) {
76603
+ int64_t *part_data;
76604
+ if (mask & YMD) {
76605
+ const auto mm = input.months % Interval::MONTHS_PER_YEAR;
76606
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::YEAR))) {
76607
+ part_data[idx] = input.months / Interval::MONTHS_PER_YEAR;
76608
+ }
76609
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MONTH))) {
76610
+ part_data[idx] = mm;
76611
+ }
76612
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::DAY))) {
76613
+ part_data[idx] = input.days;
76614
+ }
76615
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::DECADE))) {
76616
+ part_data[idx] = input.months / Interval::MONTHS_PER_DECADE;
76617
+ }
76618
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::CENTURY))) {
76619
+ part_data[idx] = input.months / Interval::MONTHS_PER_CENTURY;
76620
+ }
76621
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MILLENNIUM))) {
76622
+ part_data[idx] = input.months / Interval::MONTHS_PER_MILLENIUM;
76623
+ }
76624
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::QUARTER))) {
76625
+ part_data[idx] = mm / Interval::MONTHS_PER_QUARTER + 1;
76626
+ }
76627
+ }
76628
+
76629
+ if (mask & TIME) {
76630
+ const auto micros = MicrosecondsOperator::Operation<interval_t, int64_t>(input);
76631
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MICROSECONDS))) {
76632
+ part_data[idx] = micros;
76633
+ }
76634
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MILLISECONDS))) {
76635
+ part_data[idx] = micros / Interval::MICROS_PER_MSEC;
76636
+ }
76637
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::SECOND))) {
76638
+ part_data[idx] = micros / Interval::MICROS_PER_SEC;
76639
+ }
76640
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::MINUTE))) {
76641
+ part_data[idx] = MinutesOperator::Operation<interval_t, int64_t>(input);
76642
+ }
76643
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::HOUR))) {
76644
+ part_data[idx] = HoursOperator::Operation<interval_t, int64_t>(input);
76645
+ }
76646
+ }
76647
+
76648
+ if (mask & EPOCH) {
76649
+ if ((part_data = HasPartValue(part_values, DatePartSpecifier::EPOCH))) {
76650
+ part_data[idx] = EpochOperator::Operation<interval_t, int64_t>(input);
76651
+ }
76652
+ }
76653
+ }
76654
+
76655
+ template <typename T>
76210
76656
  static int64_t ExtractElement(DatePartSpecifier type, T element) {
76211
76657
  switch (type) {
76212
76658
  case DatePartSpecifier::YEAR:
@@ -76346,6 +76792,164 @@ struct DayNameOperator {
76346
76792
  }
76347
76793
  };
76348
76794
 
76795
+ struct StructDatePart {
76796
+ using part_codes_t = vector<DatePartSpecifier>;
76797
+
76798
+ struct BindData : public VariableReturnBindData {
76799
+ part_codes_t part_codes;
76800
+
76801
+ explicit BindData(const LogicalType &stype, const part_codes_t &part_codes_p)
76802
+ : VariableReturnBindData(stype), part_codes(part_codes_p) {
76803
+ }
76804
+
76805
+ unique_ptr<FunctionData> Copy() override {
76806
+ return make_unique<BindData>(stype, part_codes);
76807
+ }
76808
+ };
76809
+
76810
+ static unique_ptr<FunctionData> Bind(ClientContext &context, ScalarFunction &bound_function,
76811
+ vector<unique_ptr<Expression>> &arguments) {
76812
+ // collect names and deconflict, construct return type
76813
+ if (!arguments[0]->IsFoldable()) {
76814
+ throw BinderException("%s can only take constant lists of part names", bound_function.name);
76815
+ }
76816
+
76817
+ case_insensitive_set_t name_collision_set;
76818
+ child_list_t<LogicalType> struct_children;
76819
+ part_codes_t part_codes;
76820
+
76821
+ Value parts_list = ExpressionExecutor::EvaluateScalar(*arguments[0]);
76822
+ if (parts_list.type().id() == LogicalTypeId::LIST) {
76823
+ if (parts_list.list_value.empty()) {
76824
+ throw BinderException("%s requires non-empty lists of part names", bound_function.name);
76825
+ }
76826
+ for (const auto &part_value : parts_list.list_value) {
76827
+ if (part_value.is_null) {
76828
+ throw BinderException("NULL struct entry name in %s", bound_function.name);
76829
+ }
76830
+ const auto part_name = part_value.ToString();
76831
+ const auto part_code = GetDateTypePartSpecifier(part_name, arguments[1]->return_type);
76832
+ if (name_collision_set.find(part_name) != name_collision_set.end()) {
76833
+ throw BinderException("Duplicate struct entry name \"%s\" in %s", part_name, bound_function.name);
76834
+ }
76835
+ name_collision_set.insert(part_name);
76836
+ part_codes.emplace_back(part_code);
76837
+ struct_children.emplace_back(make_pair(part_name, LogicalType::BIGINT));
76838
+ }
76839
+ } else {
76840
+ throw BinderException("%s can only take constant lists of part names", bound_function.name);
76841
+ }
76842
+
76843
+ arguments.erase(arguments.begin());
76844
+ bound_function.arguments.erase(bound_function.arguments.begin());
76845
+ bound_function.return_type = LogicalType::STRUCT(move(struct_children));
76846
+ return make_unique<BindData>(bound_function.return_type, part_codes);
76847
+ }
76848
+
76849
+ template <typename INPUT_TYPE>
76850
+ static void Function(DataChunk &args, ExpressionState &state, Vector &result) {
76851
+ auto &func_expr = (BoundFunctionExpression &)state.expr;
76852
+ auto &info = (BindData &)*func_expr.bind_info;
76853
+ D_ASSERT(args.ColumnCount() == 1);
76854
+
76855
+ const auto count = args.size();
76856
+ Vector &input = args.data[0];
76857
+ vector<int64_t *> part_values(int(DatePartSpecifier::OFFSET) + 1, nullptr);
76858
+ const auto part_mask = DatePart::StructOperator::GetMask(info.part_codes);
76859
+
76860
+ auto &child_entries = StructVector::GetEntries(result);
76861
+
76862
+ // The first computer of a part "owns" it
76863
+ // and other requestors just reference the owner
76864
+ vector<size_t> owners(int(DatePartSpecifier::OFFSET) + 1, child_entries.size());
76865
+ for (size_t col = 0; col < child_entries.size(); ++col) {
76866
+ const auto part_index = size_t(info.part_codes[col]);
76867
+ if (owners[part_index] == child_entries.size()) {
76868
+ owners[part_index] = col;
76869
+ }
76870
+ }
76871
+
76872
+ if (input.GetVectorType() == VectorType::CONSTANT_VECTOR) {
76873
+ result.SetVectorType(VectorType::CONSTANT_VECTOR);
76874
+
76875
+ if (ConstantVector::IsNull(input)) {
76876
+ ConstantVector::SetNull(result, true);
76877
+ } else {
76878
+ ConstantVector::SetNull(result, false);
76879
+ for (size_t col = 0; col < child_entries.size(); ++col) {
76880
+ auto &child_entry = child_entries[col];
76881
+ ConstantVector::SetNull(*child_entry, false);
76882
+ const auto part_index = size_t(info.part_codes[col]);
76883
+ if (owners[part_index] == col) {
76884
+ part_values[part_index] = ConstantVector::GetData<int64_t>(*child_entry);
76885
+ }
76886
+ }
76887
+ auto tdata = ConstantVector::GetData<INPUT_TYPE>(input);
76888
+ DatePart::StructOperator::Operation(part_values.data(), tdata[0], 0, part_mask);
76889
+ }
76890
+ } else {
76891
+ VectorData rdata;
76892
+ input.Orrify(count, rdata);
76893
+
76894
+ const auto &arg_valid = rdata.validity;
76895
+ auto tdata = (const INPUT_TYPE *)rdata.data;
76896
+
76897
+ // Start with a valid flat vector
76898
+ result.SetVectorType(VectorType::FLAT_VECTOR);
76899
+ auto &res_valid = FlatVector::Validity(result);
76900
+ if (res_valid.GetData()) {
76901
+ res_valid.SetAllValid(count);
76902
+ }
76903
+
76904
+ // Start with valid children
76905
+ for (size_t col = 0; col < child_entries.size(); ++col) {
76906
+ auto &child_entry = child_entries[col];
76907
+ child_entry->SetVectorType(VectorType::FLAT_VECTOR);
76908
+ auto &child_validity = FlatVector::Validity(*child_entry);
76909
+ if (child_validity.GetData()) {
76910
+ child_validity.SetAllValid(count);
76911
+ }
76912
+
76913
+ // Pre-multiplex
76914
+ const auto part_index = size_t(info.part_codes[col]);
76915
+ if (owners[part_index] == col) {
76916
+ part_values[part_index] = FlatVector::GetData<int64_t>(*child_entry);
76917
+ }
76918
+ }
76919
+
76920
+ for (idx_t i = 0; i < count; ++i) {
76921
+ const auto idx = rdata.sel->get_index(i);
76922
+ if (arg_valid.RowIsValid(idx)) {
76923
+ DatePart::StructOperator::Operation(part_values.data(), tdata[idx], idx, part_mask);
76924
+ } else {
76925
+ res_valid.SetInvalid(idx);
76926
+ for (auto &child_entry : child_entries) {
76927
+ FlatVector::Validity(*child_entry).SetInvalid(idx);
76928
+ }
76929
+ }
76930
+ }
76931
+ }
76932
+
76933
+ // Reference any duplicate parts
76934
+ for (size_t col = 0; col < child_entries.size(); ++col) {
76935
+ const auto part_index = size_t(info.part_codes[col]);
76936
+ const auto owner = owners[part_index];
76937
+ if (owner != col) {
76938
+ child_entries[col]->Reference(*child_entries[owner]);
76939
+ }
76940
+ }
76941
+
76942
+ result.Verify(count);
76943
+ }
76944
+
76945
+ template <typename INPUT_TYPE>
76946
+ static ScalarFunction GetFunction(const LogicalType &temporal_type) {
76947
+ auto part_type = LogicalType::LIST(LogicalType::VARCHAR);
76948
+ auto result_type = LogicalType::STRUCT({});
76949
+ return ScalarFunction({part_type, temporal_type}, result_type, Function<INPUT_TYPE>, false, Bind);
76950
+ }
76951
+ };
76952
+
76349
76953
  void DatePartFun::RegisterFunction(BuiltinFunctions &set) {
76350
76954
  // register the individual operators
76351
76955
  AddGenericDatePartOperator(set, "year", LastYearFunction<date_t>, LastYearFunction<timestamp_t>,
@@ -76412,6 +77016,13 @@ void DatePartFun::RegisterFunction(BuiltinFunctions &set) {
76412
77016
  ScalarFunction({LogicalType::VARCHAR, LogicalType::TIME}, LogicalType::BIGINT, DatePartFunction<dtime_t>));
76413
77017
  date_part.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::INTERVAL}, LogicalType::BIGINT,
76414
77018
  DatePartFunction<interval_t>));
77019
+
77020
+ // struct variants
77021
+ date_part.AddFunction(StructDatePart::GetFunction<date_t>(LogicalType::DATE));
77022
+ date_part.AddFunction(StructDatePart::GetFunction<timestamp_t>(LogicalType::TIMESTAMP));
77023
+ date_part.AddFunction(StructDatePart::GetFunction<dtime_t>(LogicalType::TIME));
77024
+ date_part.AddFunction(StructDatePart::GetFunction<interval_t>(LogicalType::INTERVAL));
77025
+
76415
77026
  set.AddFunction(date_part);
76416
77027
  date_part.name = "datepart";
76417
77028
  set.AddFunction(date_part);
@@ -91542,7 +92153,7 @@ static unique_ptr<FunctionOperatorData> ReadCSVInit(ClientContext &context, cons
91542
92153
  result->csv_reader = make_unique<BufferedCSVReader>(context, bind_data.options, bind_data.sql_types);
91543
92154
  }
91544
92155
  bind_data.bytes_read = 0;
91545
- bind_data.file_size = result->csv_reader->file_size;
92156
+ bind_data.file_size = result->csv_reader->GetFileSize();
91546
92157
  result->file_index = 1;
91547
92158
  return move(result);
91548
92159
  }