1#include "duckdb/main/capi/capi_internal.hpp"
2#include "duckdb/common/types/date.hpp"
3#include "duckdb/common/types/time.hpp"
4#include "duckdb/common/types/timestamp.hpp"
5#include "duckdb/common/types.hpp"
6
7#include "duckdb/main/capi/cast/generic.hpp"
8
9#include <cstring>
10
11using duckdb::date_t;
12using duckdb::dtime_t;
13using duckdb::FetchDefaultValue;
14using duckdb::GetInternalCValue;
15using duckdb::hugeint_t;
16using duckdb::interval_t;
17using duckdb::StringCast;
18using duckdb::timestamp_t;
19using duckdb::ToCStringCastWrapper;
20using duckdb::UnsafeFetch;
21
22bool duckdb_value_boolean(duckdb_result *result, idx_t col, idx_t row) {
23 return GetInternalCValue<bool>(result, col, row);
24}
25
26int8_t duckdb_value_int8(duckdb_result *result, idx_t col, idx_t row) {
27 return GetInternalCValue<int8_t>(result, col, row);
28}
29
30int16_t duckdb_value_int16(duckdb_result *result, idx_t col, idx_t row) {
31 return GetInternalCValue<int16_t>(result, col, row);
32}
33
34int32_t duckdb_value_int32(duckdb_result *result, idx_t col, idx_t row) {
35 return GetInternalCValue<int32_t>(result, col, row);
36}
37
38int64_t duckdb_value_int64(duckdb_result *result, idx_t col, idx_t row) {
39 return GetInternalCValue<int64_t>(result, col, row);
40}
41
42static bool ResultIsDecimal(duckdb_result *result, idx_t col) {
43 if (!result) {
44 return false;
45 }
46 if (!result->internal_data) {
47 return false;
48 }
49 auto result_data = (duckdb::DuckDBResultData *)result->internal_data;
50 auto &query_result = result_data->result;
51 auto &source_type = query_result->types[col];
52 return source_type.id() == duckdb::LogicalTypeId::DECIMAL;
53}
54
55duckdb_decimal duckdb_value_decimal(duckdb_result *result, idx_t col, idx_t row) {
56 if (!CanFetchValue(result, col, row) || !ResultIsDecimal(result, col)) {
57 return FetchDefaultValue::Operation<duckdb_decimal>();
58 }
59
60 return GetInternalCValue<duckdb_decimal>(result, col, row);
61}
62
63duckdb_hugeint duckdb_value_hugeint(duckdb_result *result, idx_t col, idx_t row) {
64 duckdb_hugeint result_value;
65 auto internal_value = GetInternalCValue<hugeint_t>(result, col, row);
66 result_value.lower = internal_value.lower;
67 result_value.upper = internal_value.upper;
68 return result_value;
69}
70
71uint8_t duckdb_value_uint8(duckdb_result *result, idx_t col, idx_t row) {
72 return GetInternalCValue<uint8_t>(result, col, row);
73}
74
75uint16_t duckdb_value_uint16(duckdb_result *result, idx_t col, idx_t row) {
76 return GetInternalCValue<uint16_t>(result, col, row);
77}
78
79uint32_t duckdb_value_uint32(duckdb_result *result, idx_t col, idx_t row) {
80 return GetInternalCValue<uint32_t>(result, col, row);
81}
82
83uint64_t duckdb_value_uint64(duckdb_result *result, idx_t col, idx_t row) {
84 return GetInternalCValue<uint64_t>(result, col, row);
85}
86
87float duckdb_value_float(duckdb_result *result, idx_t col, idx_t row) {
88 return GetInternalCValue<float>(result, col, row);
89}
90
91double duckdb_value_double(duckdb_result *result, idx_t col, idx_t row) {
92 return GetInternalCValue<double>(result, col, row);
93}
94
95duckdb_date duckdb_value_date(duckdb_result *result, idx_t col, idx_t row) {
96 duckdb_date result_value;
97 result_value.days = GetInternalCValue<date_t>(result, col, row).days;
98 return result_value;
99}
100
101duckdb_time duckdb_value_time(duckdb_result *result, idx_t col, idx_t row) {
102 duckdb_time result_value;
103 result_value.micros = GetInternalCValue<dtime_t>(result, col, row).micros;
104 return result_value;
105}
106
107duckdb_timestamp duckdb_value_timestamp(duckdb_result *result, idx_t col, idx_t row) {
108 duckdb_timestamp result_value;
109 result_value.micros = GetInternalCValue<timestamp_t>(result, col, row).value;
110 return result_value;
111}
112
113duckdb_interval duckdb_value_interval(duckdb_result *result, idx_t col, idx_t row) {
114 duckdb_interval result_value;
115 auto ival = GetInternalCValue<interval_t>(result, col, row);
116 result_value.months = ival.months;
117 result_value.days = ival.days;
118 result_value.micros = ival.micros;
119 return result_value;
120}
121
122char *duckdb_value_varchar(duckdb_result *result, idx_t col, idx_t row) {
123 return duckdb_value_string(result, col, row).data;
124}
125
126duckdb_string duckdb_value_string(duckdb_result *result, idx_t col, idx_t row) {
127 return GetInternalCValue<duckdb_string, ToCStringCastWrapper<StringCast>>(result, col, row);
128}
129
130char *duckdb_value_varchar_internal(duckdb_result *result, idx_t col, idx_t row) {
131 return duckdb_value_string_internal(result, col, row).data;
132}
133
134duckdb_string duckdb_value_string_internal(duckdb_result *result, idx_t col, idx_t row) {
135 if (!CanFetchValue(result, col, row)) {
136 return FetchDefaultValue::Operation<duckdb_string>();
137 }
138 if (duckdb_column_type(result, col) != DUCKDB_TYPE_VARCHAR) {
139 return FetchDefaultValue::Operation<duckdb_string>();
140 }
141 // FIXME: this obviously does not work when there are null bytes in the string
142 // we need to remove the deprecated C result materialization to get that to work correctly
143 // since the deprecated C result materialization stores strings as null-terminated
144 duckdb_string res;
145 res.data = UnsafeFetch<char *>(result, col, row);
146 res.size = strlen(s: res.data);
147 return res;
148}
149
150duckdb_blob duckdb_value_blob(duckdb_result *result, idx_t col, idx_t row) {
151 if (CanFetchValue(result, col, row) && result->__deprecated_columns[col].__deprecated_type == DUCKDB_TYPE_BLOB) {
152 auto internal_result = UnsafeFetch<duckdb_blob>(result, col, row);
153
154 duckdb_blob result_blob;
155 result_blob.data = malloc(size: internal_result.size);
156 result_blob.size = internal_result.size;
157 memcpy(dest: result_blob.data, src: internal_result.data, n: internal_result.size);
158 return result_blob;
159 }
160 return FetchDefaultValue::Operation<duckdb_blob>();
161}
162
163bool duckdb_value_is_null(duckdb_result *result, idx_t col, idx_t row) {
164 if (!CanUseDeprecatedFetch(result, col, row)) {
165 return false;
166 }
167 return result->__deprecated_columns[col].__deprecated_nullmask[row];
168}
169