11# c-questdb-client
2- ** QuestDB - InfluxDB Line Protocol - Ingestion Client Library for C and C++**
2+ ** QuestDB - Client Library for Rust, C and C++**
33
44This library makes it easy to insert data into [ QuestDB] ( https://questdb.io/ ) .
55
66This client library implements the [ InfluxDB Line Protocol] (
77https://questdb.io/docs/reference/api/ilp/overview/ ) (ILP) over TCP.
88
99* Implementation is in Rust, with no additional
10- [ run-time or link-time dependencies] ( BUILD.md#pre-requisites-and-dependencies )
10+ [ run-time or link-time dependencies] ( doc/ BUILD.md#pre-requisites-and-dependencies)
1111 on the C++ standard library or other libraries.
1212* We ship both a static and a dynamic library.
13- * The library exposes both a C and a C++17 API .
13+ * The library exposes Rust, C11 and C++17 APIs .
1414* The C++ API is a header-only wrapper over the C API.
15+ * This library also has separate Python bindings.
1516
16- ## Protocol
17+ ## Insertion Protocols Overview
1718
1819Inserting data into QuestDB can be done via one of three protocols.
1920
@@ -23,296 +24,49 @@ Inserting data into QuestDB can be done via one of three protocols.
2324| [ CSV Upload via HTTP] ( https://questdb.io/docs/reference/api/rest/#imp---import-data ) | Configurable | Very Good |
2425| [ PostgreSQL] ( https://questdb.io/docs/reference/api/postgres/ ) | Transaction-level | Good |
2526
26- This library mitigates the lack of confirmation and error reporting by
27- validating data ahead of time before any data is sent to the database instance.
27+ This library implements the ** ILP protocol** and mitigates the lack of confirmation
28+ and error reporting by validating data ahead of time before any data is sent
29+ to the database instance.
2830
2931For example, the client library will report that a supplied string isn't encoded
3032in UTF-8. Some issues unfortunately can't be caught by the library and require
31- some [ care and diligence to avoid data problems] ( #data-quality-considerations ) .
33+ some [ care and diligence to avoid data problems] ( doc/CONSIDERATIONS.md ) .
3234
3335For an overview and code examples, see the
3436[ ILP page of the developer docs] ( https://questdb.io/docs/develop/insert-data/#influxdb-line-protocol ) .
3537
3638To understand the protocol in more depth, consult the
3739[ protocol reference docs] ( https://questdb.io/docs/reference/api/ilp/overview/ ) .
3840
39- ## Using this Library
41+ ## Getting Started
4042
41- Start with the [ build instructions] ( BUILD.md ) , then read the guide for including
42- this library as a [ dependency from your project] ( DEPENDENCY.md ) .
43+ To get started, read the language-specific guides.
4344
44- Once you've all set up, you can take a look at our examples:
45+ ** C**
46+ * [ Getting started with C] ( doc/C.md )
47+ * [ ` .h ` header file] ( include/questdb/ilp/line_sender.h )
4548
46- ### From a C program
49+ ** C++**
50+ * [ Getting started with C++] ( doc/CPP.md )
51+ * [ ` .hpp ` header file] ( include/questdb/ilp/line_sender.hpp )
4752
48- ``` c
49- #include < questdb/ilp/line_sender.h>
53+ ** Rust**
54+ * [ Getting started with Rust] ( questdb-rs/README.md )
55+ * [ ` questdb-rs ` crate on crates.io] ( https://crates.io/crates/questdb-rs )
56+ * [ API docs on docs.rs] ( https://docs.rs/questdb-rs/latest/ )
57+ * [ ` questdb-rs ` source code] ( questdb-rs )
58+ * [ ` questdb-rs-ffi ` source code] ( questdb-rs-ffi ) - C bindings code
5059
51- ...
60+ ** Python**
61+ * [ Python GitHub Repo] ( https://github.com/questdb/py-questdb-client/ )
62+ * [ ` questdb ` package on PyPI] ( https://pypi.org/project/questdb/ )
63+ * [ Documentation] ( https://py-questdb-client.readthedocs.io/en/latest/ )
5264
53- line_sender_error* err = NULL ;
54- line_sender_opts* opts = NULL ;
55- line_sender* sender = NULL ;
65+ ## Further Topics
5666
57- line_sender_utf8 host = QDB_UTF8_LITERAL(" localhost" );
58- opts = line_sender_opts_new(host, 9009 , &err);
59- if (!opts) {
60- /* ... handle error ... */
61- }
62-
63- sender = line_sender_connect(opts, &err);
64- line_sender_opts_free (opts);
65- opts = NULL;
66- if (!sender) {
67- /* ... handle error ... * /
68- }
69-
70- ```
71-
72- The `opts` object can additionally take parameters for the outbound interface,
73- authentication, full-connection encryption via TLS and more.
74-
75- Examples:
76- * [Basic example in C](examples/line_sender_c_example.c).
77- * [With authentication](examples/line_sender_c_example_auth.c).
78- * [With authentication and TLS](examples/line_sender_c_example_tls.c).
79-
80- ### From a C++ program
81-
82- ```cpp
83- #include <questdb/ilp/line_sender.hpp>
84-
85- ...
86-
87- // Automatically connects on object construction.
88- questdb::ilp::line_sender sender{
89- "localhost", // QuestDB hostname
90- 9009}; // QuestDB port
91-
92- ```
93-
94- For more advanced use cases, such as those requiring authentication or
95- full-connection encryption via TLS, first, create an ` opts ` object then call its
96- methods to populate its options and then pass the ` opts ` object to the
97- ` line_sender ` constructor.
98-
99- Examples:
100- * [ Basic example in C++] ( examples/line_sender_cpp_example.cpp ) .
101- * [ With authentication] ( examples/line_sender_cpp_example_auth.cpp ) .
102- * [ With authentication and TLS] ( examples/line_sender_cpp_example_tls.cpp ) .
103-
104- See a [ complete example in C++] ( examples/line_sender_cpp_example.cpp ) .
105-
106- ### How to use the API
107- The API is sequentially coupled, meaning that methods need to be called in a
108- specific order.
109-
110- For each row, you need to specify a table name and at least one symbol or
111- column. Symbols must be specified before columns.
112- Once you're done with a row you must add a timestamp calling ` at ` or ` at_now ` .
113-
114- This ordering of operations is documented for both the C and C++ APIs below.
115-
116- #### Buffer API
117-
118- The ` line_sender ` object is responsible for connecting to the network and
119- sending data.
120-
121- The buffer it sends is constructed separately through a ` line_sender_buffer `
122- object.
123-
124- To avoid malformed messages, this object's methods (` line_sender_buffer_* `
125- functions in C) must be called in a specific order.
126-
127- You can accumulate multiple lines (rows) with a given buffer and a buffer is
128- re-usable, but a buffer may only be flushed via the sender after a ` .at() ` or
129- ` .at_now() ` method call (or equivalent C function).
130-
131- ![ Sequential Coupling] ( api_seq/seq.svg )
132-
133- #### Threading Considerations
134-
135- By design, the sender and buffer objects perform all operations on the current
136- thread. The library will not spawn any threads internally.
137-
138- By constructing multiple buffers you can design your application to build ILP
139- messages on multiple threads whilst handling network connectivity in a separate
140- part of your application on a different thread (for example by passing buffers
141- that need sending over a concurrent queue and sending flushed buffers back over
142- another queue).
143-
144- Buffer and sender objects don't use any locks, so it's down to you to ensure
145- that a single thread owns a buffer or sender at any given point in time.
146-
147- #### Error handling in the C API
148-
149- In the C API, functions that can result in errors take a ` line_sender_error** `
150- parameter as the last argument. When calling such functions you must check the
151- return value for errors. Functions that return ` bool ` use ` false ` to indicate
152- a failure, whilst functions that return a pointer use NULL as the failure
153- sentinel value.
154-
155- You may then call ` line_sender_error_msg(err) ` and
156- ` line_sender_error_get_code(err) ` to extract error details.
157-
158- Once handled, the error object * must* be disposed of by calling
159- ` line_sender_error_free(err) ` .
160-
161- On error, you must also call ` line_sender_close(sender) ` .
162-
163- Here's a complete example of how to handle an error without leaks:
164-
165- ``` c
166- line_sender* sender = ...;
167- line_sender_error* err = NULL ;
168- if (!line_sender_flush(sender, &err))
169- {
170- size_t msg_len = 0;
171- const char* msg = line_sender_error_msg(err, &msg_len);
172- fprintf (stderr, "Could not set table name: %.* s", (int)msg_len, msg);
173-
174- // Clean-up
175- line_sender_error_free (err);
176- line_sender_close (sender);
177- return;
178- }
179- ```
180-
181- This type of error handling can get error-prone and verbose,
182- so you may want to use a ` goto ` to simplify handling
183- (see [ example] ( examples/line_sender_c_example.c ) ).
184-
185- #### Error handling in the C++ API
186-
187- Note that most methods in C++ may throw ` questdb::ilp::line_sender_error `
188- exceptions. The C++ ` line_sender_error ` type inherits from ` std::runtime_error `
189- and you can obtain an error message description by calling ` .what() ` and an
190- error code calling ` .code() ` .
191-
192- ### Data types
193-
194- The ILP protocol has its own set of data types which is smaller
195- that the set supported by QuestDB.
196- We map these types into QuestDB types and perform conversions
197- as necessary wherever possible.
198-
199- Strings may be recorded as either the ` STRING ` type or the ` SYMBOL ` type.
200-
201- ` SYMBOL ` s are strings with which are automatically
202- [ interned] ( https://en.wikipedia.org/wiki/String_interning ) by the database on a
203- per-column basis.
204- You should use this type if you expect the string to be re-used over and over.
205- This is common for identifiers, etc.
206-
207- For one-off strings use ` STRING ` columns which aren't interned.
208-
209- For more details see our
210- [ datatypes] ( https://questdb.io/docs/reference/sql/datatypes ) page.
211-
212- ## Data quality considerations
213-
214- When inserting data through the API, you must follow a set of considerations.
215-
216- ### Library-validated considerations
217-
218- * Strings and symbols must be passed in as valid UTF-8 which
219- need not be nul-terminated.
220- * Table names and column names must conform to valid names as accepted by the
221- database (see ` isValidTableName ` and ` isValidColumnName ` in the QuestDB java
222- [ codebase] ( https://github.com/questdb/questdb ) for details).
223- * Each row should contain, * in order* :
224- * table name
225- * at least one of:
226- * symbols, zero or more
227- * columns, zero or more
228- * timestamp, optionally
229-
230- Breaking these rules above will result in an error in the client library.
231-
232- ### Additional considerations
233-
234- Additionally you should also ensure that:
235-
236- * For a given row, a column name should not be repeated.
237- If it's repeated, only the first value will be kept.
238- This also applies to symbols.
239- * Values for a given column should always have the same type.
240- If changing types the whole row will be dropped (unless we can cast).
241- * If supplying timestamps these need to be at least equal to
242- previous ones in the same table, unless using the out of order
243- feature. Out of order rows would be dropped.
244- * The timestamp column should be written out through the provided
245- ` line_sender_at ` function (in C) or or ` .at() ` method in (C++).
246- It is also possible to write out additional timestamps values
247- as columns.
248-
249- The client library will not check any of these types of data issues.
250-
251- To debug these issues you may consult the QuestDB instance logs.
252-
253- #### Resuming after an error
254-
255- If you intend to retry, you must create a new sender object: The same sender
256- object can't be reused.
257-
258- ## Connection Security
259-
260- You may choose to enable authentication and/or TLS encryption by setting the
261- appropriate properties on the ` opts ` object used for connecting.
262-
263- ### Authentication
264-
265- We support QuestDB's ECDSA P256 SHA256 signing-based authentication.
266-
267- To create your own keys, follow the QuestDB's [ authentication documentation] ( https://questdb.io/docs/reference/api/ilp/authenticate/ ) .
268-
269- Authentication can be used independently of TLS encryption.
270-
271- ### TLS Encryption
272-
273- As of writing, whilst QuestDB itself can't be configured to support TLS natively
274- it is recommended that you use ` haproxy ` or other to secure the connection
275- for any public-facing servers.
276-
277- TLS can be used independently and provides no authentication itself.
278-
279- The ` tls_certs ` directory of this project contains tests certificates, its
280- [ README] ( tls_certs/README.md ) page describes generating your own certs.
281-
282- For API usage, see the C and C++ auth examples:
283- * [ examples/line_sender_c_example_auth.c] ( examples/line_sender_c_example_auth.c )
284- * [ examples/line_sender_cpp_example_auth.cpp] ( examples/line_sender_cpp_example_auth.cpp )
285-
286- ## If you don't see any data
287-
288- You may be experiencing one of these issues:
289-
290- ### QuestDB configuration
291-
292- If you can't initially see your data through a ` select ` query straight away,
293- this is normal: by default the database will only commit data it receives
294- though the line protocol periodically to maximize throughput.
295-
296- For dev/testing you may want to tune the following database configuration
297- parameters as so:
298-
299- ``` ini
300- # server.conf
301- cairo.max.uncommitted.rows =1
302- line.tcp.maintenance.job.interval =100
303- ```
304-
305- The defaults are more applicable for a production environment.
306-
307- For these and more configuration parameters refer to [ database configuration
308- ] ( https://questdb.io/docs/reference/configuration/ ) documentation.
309-
310- ### API usage
311- The API doesn't send any data over the network until the ` line_sender_flush `
312- function (if using the C API) or ` .flush() ` method (if using the C++ API API)
313- is called.
314-
315- * Closing the connection will not auto-flush.*
67+ * [ Data quality and threading considerations] ( doc/CONSIDERATIONS.md )
68+ * [ Authentication and TLS encryption] ( doc/SECURITY.md )
69+ * [ Troubleshooting] ( doc/TROUBLESHOOTING.md )
31670
31771## Community
31872
0 commit comments