Modern C++ vs ODBC API

Modern C++ vs ODBC API

Our C++ microservices platform includes a header-only library that encapsulates ODBC API in a very pragmatic way, just like we like it, and also coherent with C++ high-level style, like RAII concepts.

ODBC API is old stuff, it feels somewhat anachronic these days, completely C-oriented, but on the other hand, works very fast and gives you generic database access to most SQL databases, so it looks like a smart choice to use in your C++ projects, plus, you can write portable C++ database code that compiles on Windows, Linux, and Unix, a big plus.

We had to struggle with these old APIs that receive pointers and SQLCHAR arrays, in order to create the illusion of simplicity, in this case, to retrieve a resultset as a JSON std::string...

No alt text provided for this image

This library (dblib.h) was created to be used in a multithreaded HTTPS server, it considers topics like connection pooling and reducing heap allocations, it does retrieve all data as SQLCHAR type because it will generate a JSON string, and here starts the fun with C++.

Since it is pretty generic, every data retrieval microservice must execute a SQL query and then retrieve some metadata to read column names, data types, and the data itself converted to an SQLCHAR array (unsigned char).

We could go the C-way, with some native C-style arrays, but there is no need for that, and we won't gain any speed but we will sacrifice safety and flexibility.

Modern C++ to the rescue, std::vector

We need a container for the columns' metadata and the columns' data too, after executing the query we retrieve the number of columns of the resultset, and then std::vector serves the purpose of a fast and flexible container:

No alt text provided for this image

As a good practice, we reserve enough space in the vector to avoid repeated allocations, since we know the number of columns this is no challenge. We proceed to add colInfo objects to the vector using an efficient method, and then proceed to bind the column's data buffer (which is of the required size for the data type). All these low-level ODBC mechanics gets hidden from the user of the library. We will come back to the SQLBindCol() line in a minute because something interesting happened in that line.

SQLBind() expects an SQLCHAR buffer to store the retrieved data once we start fetching rows, but we can use another high-level modern C++ abstraction to solve it...

No alt text provided for this image

This struct represents a column's metadata and its data, the std::vector<SQLCHAR> field does the magic, no need for dynamic heap allocation with new/free by ourselves, C++ STL will do all the work thanks to the RAII mechanism inherent to the vector, all memory will be properly managed by the abstraction, we just make sure there will be enough space in the container for each column, using the struct's constructor.

Back to the SQLBindCol() line, ODBC API expects a pointer to the first element of an SQLCHAR buffer, we solve this using:

&col.data[0]

No alt text provided for this image

col represents a colInfo object, and data is a vector of SQLCHAR, so data[0] is the first element of the vector, since the vector is very efficient when storing its data, like a C-array, we can use it in this way for this particular case, so &col.data[0] gives to ODBC the pointer to the start of the vector's internal buffer that has enough space for this column represented as a null-terminated string.

Reading the data is also a task enhanced by the use of a modern C++ FOR loop and compile-time type deduction:

No alt text provided for this image

For each row, we use our vector to read each column's data and name.

That's it. Modern C++ saves the day, by providing high-level abstractions, type safety, and efficient native code. Don't try to be smarter than the STL, that was a lesson we learned in the process, even when using stack instead of the heap and native C-arrays, we did not enhance the performance under load in a multithreaded process but we did introduce safety concerns like buffer overflows and lack of flexibility, among others, and for what? more fun less pain, we prefer the modern C++ way, elegant simplicity.

No alt text provided for this image

At the end of the day, uncle Bjarne was right, you are not smarter than an optimizing compiler, and you won't beat the high-level abstractions of the standard library, we should have listened!

Long live Bjarne Stroustrup, the father of C++.

Are you curious about our C++ microservices platform? please read our presentation, "Anatomy of a C++ microservice"

要查看或添加评论,请登录

Martín Córdova的更多文章

  • C++ Server - QuickStart with Kubernetes - Part 1

    C++ Server - QuickStart with Kubernetes - Part 1

    In a few minutes, using your Windows 10 Pro PC or Laptop, you can install and test our free C++ microservices engine…

  • QuickStart con CPPServer y Kubernetes

    QuickStart con CPPServer y Kubernetes

    Llegó la hora, hemos liberado para uso gratuito nuestro engine de microservicios en C++, este es un QuickStart para…

    2 条评论
  • Observability you said? C++? Ok

    Observability you said? C++? Ok

    CPPServer, nuestro engine de microservicios escrito en C++, pesa 300K, compilado a código nativo optimizado y lo…

  • Kubernetes-Fest en Windows 10 cortesía de Ubuntu

    Kubernetes-Fest en Windows 10 cortesía de Ubuntu

    Multipass de Canonical vino a cambiar el juego en cuanto a virtualización, y que lo haga en Windows 10 Pro es aun más…

  • Instalación express de una BD de demo con PostgreSQL y Docker

    Instalación express de una BD de demo con PostgreSQL y Docker

    Estamos próximos a liberar para uso gratuito nuestra plataforma de microservicios C++, corre en Kubernetes y en Azure…

    13 条评论
  • Renovación automática de certificados con Docker y HAProxy

    Renovación automática de certificados con Docker y HAProxy

    Los certificados SSL gratuitos con Let's Encrypt están muy de moda, obtenerlos y renovarlos son tareas que se pueden…

  • World's smallest thread pool in C++

    World's smallest thread pool in C++

    OK, the title is a trap, maybe it won't be the smallest but close I hope, I finally put the sacred red book into good…

  • Entonando acceso a la red en Docker

    Entonando acceso a la red en Docker

    Vamos a mostrar como mejorar la configuración de red de los containers Docker, sobre todo para los servidores, pero es…

  • Automatizando OCSP SSL con Docker y HAProxy

    Automatizando OCSP SSL con Docker y HAProxy

    Voy a mostrar como resolvemos la renovación automática del archivo OCSP emitido por la entidad que generó el…

  • C++ RAII at the process-level

    C++ RAII at the process-level

    Problem: Your application is a webserver with an associated ODBC connection pool (per-process pool), you want to…

    1 条评论

社区洞察

其他会员也浏览了