| 1 | #include "duckdb/main/capi/capi_internal.hpp" |
| 2 | #include "duckdb/main/query_result.hpp" |
| 3 | #include "duckdb/main/prepared_statement_data.hpp" |
| 4 | #include "duckdb/common/types/decimal.hpp" |
| 5 | |
| 6 | using duckdb::Connection; |
| 7 | using duckdb::date_t; |
| 8 | using duckdb::dtime_t; |
| 9 | using duckdb::ExtractStatementsWrapper; |
| 10 | using duckdb::hugeint_t; |
| 11 | using duckdb::LogicalType; |
| 12 | using duckdb::MaterializedQueryResult; |
| 13 | using duckdb::PreparedStatementWrapper; |
| 14 | using duckdb::QueryResultType; |
| 15 | using duckdb::timestamp_t; |
| 16 | using duckdb::Value; |
| 17 | |
| 18 | idx_t (duckdb_connection connection, const char *query, |
| 19 | duckdb_extracted_statements *) { |
| 20 | if (!connection || !query || !out_extracted_statements) { |
| 21 | return 0; |
| 22 | } |
| 23 | auto wrapper = new ExtractStatementsWrapper(); |
| 24 | Connection *conn = reinterpret_cast<Connection *>(connection); |
| 25 | try { |
| 26 | wrapper->statements = conn->ExtractStatements(query); |
| 27 | } catch (const duckdb::ParserException &e) { |
| 28 | wrapper->error = e.what(); |
| 29 | } |
| 30 | |
| 31 | *out_extracted_statements = (duckdb_extracted_statements)wrapper; |
| 32 | return wrapper->statements.size(); |
| 33 | } |
| 34 | |
| 35 | duckdb_state (duckdb_connection connection, |
| 36 | duckdb_extracted_statements , idx_t index, |
| 37 | duckdb_prepared_statement *out_prepared_statement) { |
| 38 | Connection *conn = reinterpret_cast<Connection *>(connection); |
| 39 | auto source_wrapper = (ExtractStatementsWrapper *)extracted_statements; |
| 40 | |
| 41 | if (!connection || !out_prepared_statement || index >= source_wrapper->statements.size()) { |
| 42 | return DuckDBError; |
| 43 | } |
| 44 | auto wrapper = new PreparedStatementWrapper(); |
| 45 | wrapper->statement = conn->Prepare(statement: std::move(source_wrapper->statements[index])); |
| 46 | |
| 47 | *out_prepared_statement = (duckdb_prepared_statement)wrapper; |
| 48 | return wrapper->statement->HasError() ? DuckDBError : DuckDBSuccess; |
| 49 | } |
| 50 | |
| 51 | const char *(duckdb_extracted_statements ) { |
| 52 | auto wrapper = (ExtractStatementsWrapper *)extracted_statements; |
| 53 | if (!wrapper || wrapper->error.empty()) { |
| 54 | return nullptr; |
| 55 | } |
| 56 | return wrapper->error.c_str(); |
| 57 | } |
| 58 | |
| 59 | duckdb_state duckdb_prepare(duckdb_connection connection, const char *query, |
| 60 | duckdb_prepared_statement *out_prepared_statement) { |
| 61 | if (!connection || !query || !out_prepared_statement) { |
| 62 | return DuckDBError; |
| 63 | } |
| 64 | auto wrapper = new PreparedStatementWrapper(); |
| 65 | Connection *conn = reinterpret_cast<Connection *>(connection); |
| 66 | wrapper->statement = conn->Prepare(query); |
| 67 | *out_prepared_statement = (duckdb_prepared_statement)wrapper; |
| 68 | return !wrapper->statement->HasError() ? DuckDBSuccess : DuckDBError; |
| 69 | } |
| 70 | |
| 71 | const char *duckdb_prepare_error(duckdb_prepared_statement prepared_statement) { |
| 72 | auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement); |
| 73 | if (!wrapper || !wrapper->statement || !wrapper->statement->HasError()) { |
| 74 | return nullptr; |
| 75 | } |
| 76 | return wrapper->statement->error.Message().c_str(); |
| 77 | } |
| 78 | |
| 79 | idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement) { |
| 80 | auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement); |
| 81 | if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { |
| 82 | return 0; |
| 83 | } |
| 84 | return wrapper->statement->n_param; |
| 85 | } |
| 86 | |
| 87 | duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) { |
| 88 | auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement); |
| 89 | if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { |
| 90 | return DUCKDB_TYPE_INVALID; |
| 91 | } |
| 92 | LogicalType param_type; |
| 93 | if (!wrapper->statement->data->TryGetType(param_idx, result&: param_type)) { |
| 94 | return DUCKDB_TYPE_INVALID; |
| 95 | } |
| 96 | return ConvertCPPTypeToC(sql_type: param_type); |
| 97 | } |
| 98 | |
| 99 | duckdb_state duckdb_clear_bindings(duckdb_prepared_statement prepared_statement) { |
| 100 | auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement); |
| 101 | if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { |
| 102 | return DuckDBError; |
| 103 | } |
| 104 | wrapper->values.clear(); |
| 105 | return DuckDBSuccess; |
| 106 | } |
| 107 | |
| 108 | static duckdb_state duckdb_bind_value(duckdb_prepared_statement prepared_statement, idx_t param_idx, Value val) { |
| 109 | auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement); |
| 110 | if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { |
| 111 | return DuckDBError; |
| 112 | } |
| 113 | if (param_idx <= 0 || param_idx > wrapper->statement->n_param) { |
| 114 | return DuckDBError; |
| 115 | } |
| 116 | if (param_idx > wrapper->values.size()) { |
| 117 | wrapper->values.resize(new_size: param_idx); |
| 118 | } |
| 119 | wrapper->values[param_idx - 1] = val; |
| 120 | return DuckDBSuccess; |
| 121 | } |
| 122 | |
| 123 | duckdb_state duckdb_bind_boolean(duckdb_prepared_statement prepared_statement, idx_t param_idx, bool val) { |
| 124 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::BOOLEAN(value: val)); |
| 125 | } |
| 126 | |
| 127 | duckdb_state duckdb_bind_int8(duckdb_prepared_statement prepared_statement, idx_t param_idx, int8_t val) { |
| 128 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::TINYINT(value: val)); |
| 129 | } |
| 130 | |
| 131 | duckdb_state duckdb_bind_int16(duckdb_prepared_statement prepared_statement, idx_t param_idx, int16_t val) { |
| 132 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::SMALLINT(value: val)); |
| 133 | } |
| 134 | |
| 135 | duckdb_state duckdb_bind_int32(duckdb_prepared_statement prepared_statement, idx_t param_idx, int32_t val) { |
| 136 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::INTEGER(value: val)); |
| 137 | } |
| 138 | |
| 139 | duckdb_state duckdb_bind_int64(duckdb_prepared_statement prepared_statement, idx_t param_idx, int64_t val) { |
| 140 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::BIGINT(value: val)); |
| 141 | } |
| 142 | |
| 143 | static hugeint_t duckdb_internal_hugeint(duckdb_hugeint val) { |
| 144 | hugeint_t internal; |
| 145 | internal.lower = val.lower; |
| 146 | internal.upper = val.upper; |
| 147 | return internal; |
| 148 | } |
| 149 | |
| 150 | duckdb_state duckdb_bind_hugeint(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_hugeint val) { |
| 151 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::HUGEINT(value: duckdb_internal_hugeint(val))); |
| 152 | } |
| 153 | |
| 154 | duckdb_state duckdb_bind_uint8(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint8_t val) { |
| 155 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::UTINYINT(value: val)); |
| 156 | } |
| 157 | |
| 158 | duckdb_state duckdb_bind_uint16(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint16_t val) { |
| 159 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::USMALLINT(value: val)); |
| 160 | } |
| 161 | |
| 162 | duckdb_state duckdb_bind_uint32(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint32_t val) { |
| 163 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::UINTEGER(value: val)); |
| 164 | } |
| 165 | |
| 166 | duckdb_state duckdb_bind_uint64(duckdb_prepared_statement prepared_statement, idx_t param_idx, uint64_t val) { |
| 167 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::UBIGINT(value: val)); |
| 168 | } |
| 169 | |
| 170 | duckdb_state duckdb_bind_float(duckdb_prepared_statement prepared_statement, idx_t param_idx, float val) { |
| 171 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::FLOAT(value: val)); |
| 172 | } |
| 173 | |
| 174 | duckdb_state duckdb_bind_double(duckdb_prepared_statement prepared_statement, idx_t param_idx, double val) { |
| 175 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::DOUBLE(value: val)); |
| 176 | } |
| 177 | |
| 178 | duckdb_state duckdb_bind_date(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_date val) { |
| 179 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::DATE(date: date_t(val.days))); |
| 180 | } |
| 181 | |
| 182 | duckdb_state duckdb_bind_time(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_time val) { |
| 183 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::TIME(time: dtime_t(val.micros))); |
| 184 | } |
| 185 | |
| 186 | duckdb_state duckdb_bind_timestamp(duckdb_prepared_statement prepared_statement, idx_t param_idx, |
| 187 | duckdb_timestamp val) { |
| 188 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::TIMESTAMP(timestamp: timestamp_t(val.micros))); |
| 189 | } |
| 190 | |
| 191 | duckdb_state duckdb_bind_interval(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_interval val) { |
| 192 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::INTERVAL(months: val.months, days: val.days, micros: val.micros)); |
| 193 | } |
| 194 | |
| 195 | duckdb_state duckdb_bind_varchar(duckdb_prepared_statement prepared_statement, idx_t param_idx, const char *val) { |
| 196 | try { |
| 197 | return duckdb_bind_value(prepared_statement, param_idx, val: Value(val)); |
| 198 | } catch (...) { |
| 199 | return DuckDBError; |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | duckdb_state duckdb_bind_varchar_length(duckdb_prepared_statement prepared_statement, idx_t param_idx, const char *val, |
| 204 | idx_t length) { |
| 205 | try { |
| 206 | return duckdb_bind_value(prepared_statement, param_idx, val: Value(std::string(val, length))); |
| 207 | } catch (...) { |
| 208 | return DuckDBError; |
| 209 | } |
| 210 | } |
| 211 | |
| 212 | duckdb_state duckdb_bind_decimal(duckdb_prepared_statement prepared_statement, idx_t param_idx, duckdb_decimal val) { |
| 213 | auto hugeint_val = duckdb_internal_hugeint(val: val.value); |
| 214 | if (val.width > duckdb::Decimal::MAX_WIDTH_INT64) { |
| 215 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::DECIMAL(value: hugeint_val, width: val.width, scale: val.scale)); |
| 216 | } |
| 217 | auto value = hugeint_val.lower; |
| 218 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::DECIMAL(value: (int64_t)value, width: val.width, scale: val.scale)); |
| 219 | } |
| 220 | |
| 221 | duckdb_state duckdb_bind_blob(duckdb_prepared_statement prepared_statement, idx_t param_idx, const void *data, |
| 222 | idx_t length) { |
| 223 | return duckdb_bind_value(prepared_statement, param_idx, val: Value::BLOB(data: duckdb::const_data_ptr_cast(src: data), len: length)); |
| 224 | } |
| 225 | |
| 226 | duckdb_state duckdb_bind_null(duckdb_prepared_statement prepared_statement, idx_t param_idx) { |
| 227 | return duckdb_bind_value(prepared_statement, param_idx, val: Value()); |
| 228 | } |
| 229 | |
| 230 | duckdb_state duckdb_execute_prepared(duckdb_prepared_statement prepared_statement, duckdb_result *out_result) { |
| 231 | auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement); |
| 232 | if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) { |
| 233 | return DuckDBError; |
| 234 | } |
| 235 | auto result = wrapper->statement->Execute(values&: wrapper->values, allow_stream_result: false); |
| 236 | return duckdb_translate_result(result: std::move(result), out: out_result); |
| 237 | } |
| 238 | |
| 239 | template <class T> |
| 240 | void duckdb_destroy(void **wrapper) { |
| 241 | if (!wrapper) { |
| 242 | return; |
| 243 | } |
| 244 | |
| 245 | auto casted = (T *)*wrapper; |
| 246 | if (casted) { |
| 247 | delete casted; |
| 248 | } |
| 249 | *wrapper = nullptr; |
| 250 | } |
| 251 | |
| 252 | void (duckdb_extracted_statements *) { |
| 253 | duckdb_destroy<ExtractStatementsWrapper>(wrapper: reinterpret_cast<void **>(extracted_statements)); |
| 254 | } |
| 255 | |
| 256 | void duckdb_destroy_prepare(duckdb_prepared_statement *prepared_statement) { |
| 257 | duckdb_destroy<PreparedStatementWrapper>(wrapper: reinterpret_cast<void **>(prepared_statement)); |
| 258 | } |
| 259 | |