Repository: duckdb/duckdb
File: src/main/capi/prepared-c.cpp (C++)

Code before:
}

idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement) {
	auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement);
	if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
		return 0;
	}
	return wrapper->statement->named_param_map.size();
}

static duckdb::string duckdb_parameter_name_internal(duckdb_prepared_statement prepared_statement, idx_t index) {
	auto wrapper = (PreparedStatementWrapper *)prepared_statement;
	if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
		return duckdb::string();
	}
	auto &named = wrapper->statement->named_param_map;
	if (index == 0 || index > named.size()) {
		return duckdb::string();
	}

	auto &cache = wrapper->param_index_to_name;
	if (cache.size() != named.size() + 1) {
		cache.assign(named.size() + 1, duckdb::string());
		for (auto &kv : named) {
			auto idx = kv.second;
			if (idx < cache.size() && cache[idx].empty()) {
				cache[idx] = kv.first;
			}
		}
	}
	// No parameter was found with this index when there is nothing in the cache (default value is `duckdb::string()`)
	return cache[index];
}

const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, idx_t index) {
	auto identifier = duckdb_parameter_name_internal(prepared_statement, index);
	if (identifier == duckdb::string()) {
		return NULL;
	}
	return strdup(identifier.c_str());
}

duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) {
	auto logical_type = duckdb_param_logical_type(prepared_statement, param_idx);
	if (!logical_type) {
		return DUCKDB_TYPE_INVALID;
	}

	auto type = duckdb_get_type_id(logical_type);
	duckdb_destroy_logical_type(&logical_type);


Review comment (performance):
`idx < cache.size()` - is that allowed? Can an index be outside the cache size? If so, then I think the cache needs to be a `idx_t -> string` map instead of a vector.

Code after:
		return DuckDBError;
	}
}

const char *duckdb_prepare_error(duckdb_prepared_statement prepared_statement) {
	auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement);
	if (!wrapper) {
		return nullptr;
	}
	if (!wrapper->success) {
		return wrapper->error_data.Message().c_str();
	}
	if (!wrapper->statement || !wrapper->statement->HasError()) {
		return nullptr;
	}
	return wrapper->statement->error.Message().c_str();
}

idx_t duckdb_nparams(duckdb_prepared_statement prepared_statement) {
	auto wrapper = reinterpret_cast<PreparedStatementWrapper *>(prepared_statement);
	if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
		return 0;
	}
	return wrapper->statement->named_param_map.size();
}

static duckdb::string duckdb_parameter_name_internal(duckdb_prepared_statement prepared_statement, idx_t index) {
	auto wrapper = (PreparedStatementWrapper *)prepared_statement;
	if (!wrapper || !wrapper->statement || wrapper->statement->HasError()) {
		return duckdb::string();
	}
	auto &cache = wrapper->param_index_to_name;
	auto it = cache.find(index);
	if (it == cache.end()) {
		return duckdb::string();
	}
	return it->second;
}

const char *duckdb_parameter_name(duckdb_prepared_statement prepared_statement, idx_t index) {
	auto identifier = duckdb_parameter_name_internal(prepared_statement, index);
	if (identifier == duckdb::string()) {
		return NULL;
	}
	return strdup(identifier.c_str());
}

duckdb_type duckdb_param_type(duckdb_prepared_statement prepared_statement, idx_t param_idx) {
	auto logical_type = duckdb_param_logical_type(prepared_statement, param_idx);
	if (!logical_type) {
		return DUCKDB_TYPE_INVALID;