Coverage Report

Created: 2026-05-19 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/duckdb/src/main/capi/duckdb-c.cpp
Line
Count
Source
1
#include "duckdb/main/capi/capi_internal.hpp"
2
3
using duckdb::CClientArrowOptionsWrapper;
4
using duckdb::CClientContextWrapper;
5
using duckdb::Connection;
6
using duckdb::DatabaseWrapper;
7
using duckdb::DBConfig;
8
using duckdb::DBInstanceCacheWrapper;
9
using duckdb::DuckDB;
10
using duckdb::ErrorData;
11
12
0
duckdb_instance_cache duckdb_create_instance_cache() {
13
0
  auto wrapper = new DBInstanceCacheWrapper();
14
0
  wrapper->instance_cache = duckdb::make_uniq<duckdb::DBInstanceCache>();
15
0
  return reinterpret_cast<duckdb_instance_cache>(wrapper);
16
0
}
17
18
0
void duckdb_destroy_instance_cache(duckdb_instance_cache *instance_cache) {
19
0
  if (instance_cache && *instance_cache) {
20
0
    auto wrapper = reinterpret_cast<DBInstanceCacheWrapper *>(*instance_cache);
21
0
    delete wrapper;
22
0
    *instance_cache = nullptr;
23
0
  }
24
0
}
25
26
duckdb_state duckdb_open_internal(DBInstanceCacheWrapper *cache, const char *path, duckdb_database *out,
27
0
                                  duckdb_config config, char **out_error) {
28
0
  auto wrapper = new DatabaseWrapper();
29
0
  try {
30
0
    DBConfig default_config;
31
0
    default_config.SetOptionByName("duckdb_api", "capi");
32
33
0
    DBConfig *db_config = &default_config;
34
0
    DBConfig *user_config = reinterpret_cast<DBConfig *>(config);
35
0
    if (user_config) {
36
0
      db_config = user_config;
37
0
    }
38
39
0
    if (cache) {
40
0
      duckdb::string path_str;
41
0
      if (path) {
42
0
        path_str = path;
43
0
      }
44
0
      wrapper->database = cache->instance_cache->GetOrCreateInstance(path_str, *db_config);
45
0
    } else {
46
0
      wrapper->database = duckdb::make_shared_ptr<DuckDB>(path, db_config);
47
0
    }
48
49
0
  } catch (std::exception &ex) {
50
0
    if (out_error) {
51
0
      ErrorData parsed_error(ex);
52
0
      *out_error = strdup(parsed_error.Message().c_str());
53
0
    }
54
0
    delete wrapper;
55
0
    return DuckDBError;
56
57
0
  } catch (...) { // LCOV_EXCL_START
58
0
    if (out_error) {
59
0
      *out_error = strdup("Unknown error");
60
0
    }
61
0
    delete wrapper;
62
0
    return DuckDBError;
63
0
  } // LCOV_EXCL_STOP
64
65
0
  *out = reinterpret_cast<duckdb_database>(wrapper);
66
0
  return DuckDBSuccess;
67
0
}
68
69
duckdb_state duckdb_get_or_create_from_cache(duckdb_instance_cache instance_cache, const char *path,
70
0
                                             duckdb_database *out_database, duckdb_config config, char **out_error) {
71
0
  if (!instance_cache) {
72
0
    if (out_error) {
73
0
      *out_error = strdup("instance cache cannot be nullptr");
74
0
    }
75
0
    return DuckDBError;
76
0
  }
77
0
  auto cache = reinterpret_cast<DBInstanceCacheWrapper *>(instance_cache);
78
0
  return duckdb_open_internal(cache, path, out_database, config, out_error);
79
0
}
80
81
0
duckdb_state duckdb_open_ext(const char *path, duckdb_database *out, duckdb_config config, char **error) {
82
0
  return duckdb_open_internal(nullptr, path, out, config, error);
83
0
}
84
85
0
duckdb_state duckdb_open(const char *path, duckdb_database *out) {
86
0
  return duckdb_open_ext(path, out, nullptr, nullptr);
87
0
}
88
89
0
void duckdb_close(duckdb_database *database) {
90
0
  if (database && *database) {
91
0
    auto wrapper = reinterpret_cast<DatabaseWrapper *>(*database);
92
0
    delete wrapper;
93
0
    *database = nullptr;
94
0
  }
95
0
}
96
97
0
duckdb_state duckdb_connect(duckdb_database database, duckdb_connection *out) {
98
0
  if (!database || !out) {
99
0
    return DuckDBError;
100
0
  }
101
102
0
  auto wrapper = reinterpret_cast<DatabaseWrapper *>(database);
103
0
  Connection *connection;
104
0
  try {
105
0
    connection = new Connection(*wrapper->database);
106
0
  } catch (...) { // LCOV_EXCL_START
107
0
    return DuckDBError;
108
0
  } // LCOV_EXCL_STOP
109
110
0
  *out = reinterpret_cast<duckdb_connection>(connection);
111
0
  return DuckDBSuccess;
112
0
}
113
114
0
void duckdb_interrupt(duckdb_connection connection) {
115
0
  if (!connection) {
116
0
    return;
117
0
  }
118
0
  Connection *conn = reinterpret_cast<Connection *>(connection);
119
0
  conn->Interrupt();
120
0
}
121
122
0
duckdb_query_progress_type duckdb_query_progress(duckdb_connection connection) {
123
0
  duckdb_query_progress_type query_progress_type;
124
0
  query_progress_type.percentage = -1;
125
0
  query_progress_type.total_rows_to_process = 0;
126
0
  query_progress_type.rows_processed = 0;
127
0
  if (!connection) {
128
0
    return query_progress_type;
129
0
  }
130
0
  Connection *conn = reinterpret_cast<Connection *>(connection);
131
0
  auto query_progress = conn->context->GetQueryProgress();
132
0
  query_progress_type.total_rows_to_process = query_progress.GetTotalRowsToProcess();
133
0
  query_progress_type.rows_processed = query_progress.GetRowsProcessed();
134
0
  query_progress_type.percentage = query_progress.GetPercentage();
135
0
  return query_progress_type;
136
0
}
137
138
0
void duckdb_disconnect(duckdb_connection *connection) {
139
0
  if (connection && *connection) {
140
0
    Connection *conn = reinterpret_cast<Connection *>(*connection);
141
0
    delete conn;
142
0
    *connection = nullptr;
143
0
  }
144
0
}
145
146
0
void duckdb_connection_get_client_context(duckdb_connection connection, duckdb_client_context *out_context) {
147
0
  if (!connection || !out_context) {
148
0
    return;
149
0
  }
150
0
  Connection *conn = reinterpret_cast<Connection *>(connection);
151
0
  try {
152
0
    auto wrapper = new CClientContextWrapper(*conn->context);
153
0
    *out_context = reinterpret_cast<duckdb_client_context>(wrapper);
154
0
  } catch (...) {
155
0
    *out_context = nullptr;
156
0
  }
157
0
}
158
159
0
void duckdb_connection_get_arrow_options(duckdb_connection connection, duckdb_arrow_options *out_arrow_options) {
160
0
  if (!connection || !out_arrow_options) {
161
0
    return;
162
0
  }
163
0
  Connection *conn = reinterpret_cast<Connection *>(connection);
164
0
  try {
165
0
    auto client_properties = conn->context->GetClientProperties();
166
0
    auto wrapper = new CClientArrowOptionsWrapper(client_properties);
167
0
    *out_arrow_options = reinterpret_cast<duckdb_arrow_options>(wrapper);
168
0
  } catch (...) {
169
0
    *out_arrow_options = nullptr;
170
0
  }
171
0
}
172
173
0
idx_t duckdb_client_context_get_connection_id(duckdb_client_context context) {
174
0
  auto wrapper = reinterpret_cast<CClientContextWrapper *>(context);
175
0
  return wrapper->context.GetConnectionId();
176
0
}
177
178
0
void duckdb_destroy_client_context(duckdb_client_context *context) {
179
0
  if (context && *context) {
180
0
    auto wrapper = reinterpret_cast<CClientContextWrapper *>(*context);
181
0
    delete wrapper;
182
0
    *context = nullptr;
183
0
  }
184
0
}
185
186
0
void duckdb_destroy_arrow_options(duckdb_arrow_options *arrow_options) {
187
0
  if (arrow_options && *arrow_options) {
188
0
    auto wrapper = reinterpret_cast<CClientArrowOptionsWrapper *>(*arrow_options);
189
0
    delete wrapper;
190
0
    *arrow_options = nullptr;
191
0
  }
192
0
}
193
194
0
duckdb_state duckdb_query(duckdb_connection connection, const char *query, duckdb_result *out) {
195
0
  Connection *conn = reinterpret_cast<Connection *>(connection);
196
0
  try {
197
0
    auto result = conn->Query(query);
198
0
    return DuckDBTranslateResult(std::move(result), out);
199
0
  } catch (...) {
200
0
    return DuckDBError;
201
0
  }
202
0
}
203
204
0
const char *duckdb_library_version() {
205
0
  return DuckDB::LibraryVersion();
206
0
}
207
208
0
duckdb_value duckdb_get_table_names(duckdb_connection connection, const char *query, bool qualified) {
209
0
  Connection *conn = reinterpret_cast<Connection *>(connection);
210
0
  try {
211
0
    auto table_names = conn->GetTableNames(query, qualified);
212
213
0
    auto count = table_names.size();
214
0
    auto ptr = malloc(count * sizeof(duckdb_value));
215
0
    if (!ptr) {
216
0
      return nullptr;
217
0
    }
218
0
    auto list_values = reinterpret_cast<duckdb_value *>(ptr);
219
220
0
    try {
221
0
      idx_t name_ix = 0;
222
0
      for (const auto &name : table_names) {
223
0
        list_values[name_ix] = duckdb_create_varchar(name.c_str());
224
0
        name_ix++;
225
0
      }
226
227
0
      auto varchar_type = duckdb_create_logical_type(DUCKDB_TYPE_VARCHAR);
228
0
      auto list_value = duckdb_create_list_value(varchar_type, list_values, count);
229
230
0
      for (idx_t i = 0; i < count; i++) {
231
0
        duckdb_destroy_value(&list_values[i]);
232
0
      }
233
0
      duckdb_free(ptr);
234
0
      duckdb_destroy_logical_type(&varchar_type);
235
236
0
      return list_value;
237
0
    } catch (...) {
238
0
      duckdb_free(ptr);
239
0
      return nullptr;
240
0
    }
241
0
  } catch (...) {
242
0
    return nullptr;
243
0
  }
244
0
}