MySQL Connector/C++

repository·trunk·Indexed 20 days ago

https://github.com/mysql/mysql-connector-cpp

A C++ interface for communicating with MySQL servers, supporting traditional SQL and the modern X DevAPI for document store operations.

Tokens
31.1K
Snippets
62
Records
125
Agent score
72%

What's inside MySQL Connector/C++

  1. Supported C++ standards and platforms for OpenTelemetry C++

    trunk

    OpenTelemetry C++ supports multiple C++ standards and is designed to build on various development platforms.

    Supported C++ Standards

    • ISO/IEC 14882:2014 (C++14)
    • ISO/IEC 14882:2017 (C++17)
    • ISO/IEC 14882:2020 (C++20)

    Note: Supporting the C programming language is not a goal of this project.

    Supported Development Platforms (x86-64)

    PlatformBuild type
    ubuntu-22.04 (GCC 10, GCC 12, Clang 14)CMake, Bazel
    ubuntu-20.04 (GCC 9.4.0)CMake, Bazel
    ubuntu-20.04 (GCC 9.4.0 with -std=c++14/17/20 flags)CMake, Bazel
    macOS 12.7 (Xcode 14.2)Bazel
    Windows Server 2019 (Visual Studio Enterprise 2019)CMake, Bazel
    Windows Server 2022 (Visual Studio Enterprise 2022)CMake
  2. What is the Client Development Kit (CDK)?

    trunk

    The Client SDK (also known as CDK) is a foundation library designed for building C/C++ based connectors. It abstracts the complexities of data store communication and the underlying protocols.

    Key characteristics:

    • Protocol Abstraction: Connectors built on CDK can support different communication media or protocols without changing the core logic.
    • Resource Management: Uses the RAII (Resource Acquisition Is Initialization) pattern for transparent resource management.
    • Asynchronous Support: Built to support asynchronous operations.
    • Scope: CDK provides the communication foundation but does not handle connector-specific tasks like type conversions. Developers building connectors must implement their own specific API calls using CDK objects.
  3. Access result set meta-data using mysqlx::Meta_data

    trunk

    The mysqlx::Meta_data interface (implemented by mysqlx::Cursor) allows you to inspect the structure and types of rows in a result set. It provides access to information about columns, including their names, types, and representation formats.

    Key components include:

    • mysqlx::Type_info: Represents the type of values (e.g., NUMBER, STRING, DOCUMENT).
    • mysqlx::Format_info: Describes how a specific type is encoded.
    • mysqlx::Column_info: Provides metadata for a specific column, such as its name and its reference to the underlying table/schema.
  4. Check feature support with the Capability_info interface

    trunk

    Not all objects implementing an interface support all of its methods. To avoid runtime errors (like "unimplemented feature"), you can implement the Capability_info interface to check for feature support upfront.

    Use the has_capability(Capability) method, which returns:

    • YES: The capability is supported.
    • NO: The capability is not supported (calling it will throw an error).
    • UNKNOWN: Support status cannot be determined at this moment.

    Note that a Data_source might return UNKNOWN, but a Session created from that source might return NO for the same capability.

    // Checking capability on a data source
    Data_source ds(...);
    if (NO == ds.has_capability(PREPARED_STATEMENTS))
      throw "this code requires prepared statements";
    
    // Checking capability on a session
    Session s(ds, ...);
    if (NO == s.has_capability(PREPARED_STATEMENTS))
      throw "this code requires prepared statements";
  5. Binary Compatibility and Static Linkage

    trunk

    Protocol Buffers C++ runtime libraries do not guarantee ABI compatibility between different versions. Linking an executable against an older version of libprotobuf and then running it with a newer version will likely cause immediate startup failures.

    To avoid these issues, consider using static linkage. You can configure the build to install only static libraries by using the --disable-shared flag during configuration.

    ./configure --disable-shared
    ./configure --disable-shared
  6. Understand CDK namespaces

    trunk

    All CDK code resides within the cdk global namespace. To prevent name clashes and organize components, the project uses a hierarchical namespace structure:

    • cdk::: Top-level namespace for core classes (e.g., cdk::Session).
    • cdk::foundation::: For foundation-level code.
    • cdk::protocol::xxx::: For specific protocol implementations (e.g., cdk::protocol::mysqlx::Protocol).
    • cdk::xxx::: For CDK implementations built over a specific protocol (e.g., cdk::mysqlx::Session).

    Note: The project may use sub-namespaces like cdk::api:: to separate an API definition from its implementation (e.g., cdk::api::Session vs cdk::Session).

  7. Core Design Principles of the CDK

    trunk

    The Core Data Connector (CDK) follows several key architectural principles that influence how you write code with it:

    • Data Source Abstraction: Different types of data sources are identified by specific classes. Implementation details like drivers and driver managers are hidden behind these abstractions.
    • RAII (Resource Acquisition Is Initialization): Objects are designed to manage their own lifecycles. You should use stack-based allocation so that resources are automatically freed when objects go out of scope. Avoid manual management via smart pointers where possible.
    • Exception-based Error Handling: Methods are assumed to succeed if they return normally. If an operation fails (e.g., a commit() fails), an exception is thrown.
    • Visitor Pattern for Data Access: To avoid unnecessary internal buffering, the CDK uses the Visitor pattern (e.g., Row_processor and Cursor::next_row(Row_processor)) to process data.
    • Asynchronous Operations: Methods can return objects representing ongoing operations that can be queried, waited for, or cancelled. The design allows integration with async-io frameworks like boost::asio.
    • Ownership Model: Objects have strict ownership hierarchies. For example, a reply object belongs to a session; if the session is destroyed, the reply becomes invalid and using it will raise an exception.
    • Direct Data Access: The CDK provides direct access to raw bytes. Metadata handling and type conversions are the responsibility of the application code.
    // Recommended RAII pattern
    {
      Session s(...);
      // ... use session
    }
    // 's' is automatically cleaned up here
  8. How the Scalar Value Type System works

    trunk

    The CDK does not assume how data types are represented. Instead, it provides a framework for converting between raw bytes and native C++ types using Type_info and Format_info.

    Key Components

    • Type_info: An implementation-defined enumeration (e.g., STRING, NUMBER) describing the type of a column.
    • Format_info: Describes how a specific type is serialized (e.g., different character encodings for a STRING).
    • Codec<T>: An encoder/decoder used to convert between raw bytes and native C++ types.
    • Format<T>: An object used to examine the properties of a representation format (e.g., checking the character encoding name).

    Using Codecs and Formats

    To convert data, you first verify the format is applicable to the type, then instantiate a Codec or Format object.

    Format_info fi;
    assert(fi.for_type(STRING));
    
    // Create a codec for a specific type
    Codec<STRING> codec(fi);
    
    // Create a format object to inspect details
    Format<STRING> fmt(fi);
    cout << "character encoding: " << fmt.cs_name();
  9. How the Row_processor callback lifecycle works

    trunk

    When performing a rcv_Rows or rcv_CursorRows operation, the protocol uses a Row_processor to stream result set rows to the application. The lifecycle follows a nested loop pattern:

    1. Message Level: message_begin is called before any rows in a message, followed by message_end after all rows and the done callback.
    2. Row Level: For each row, row_begin(row_count_t row) is called, followed by column processing, and finally row_end(row_count_t row).
    3. Column Level: For each field in a row, the processor receives either col_null(col_count_t pos) (if the value is NULL) or a sequence of col_begin, col_data, and col_end (if the value contains data).

    Control Flow via Return Values:

    • row_begin returning false: The current row is skipped; row_end is still called, but no column callbacks occur.
    • row_end returning false: The entire row sequence is interrupted. To process the remaining rows, you must create a new asynchronous operation.
    • col_data returning 0: The remaining data for that specific field is discarded, and col_end is called immediately.
    // Conceptual flow of Row_processor callbacks
    // message_begin()
    //   row_begin(0)
    //     col_begin(0) -> col_data(...) -> col_end(0, len)
    //     col_null(1)
    //   row_end(0)
    //   done(eod, more)
    // message_end()
  10. Understand the CDK Object Hierarchy

    trunk

    The CDK is organized into two main layers: the Core CDK API (high-level) and Protocol-level objects (low-level).

    Core CDK API (Session-level)

    These objects are used for standard data manipulation:

    • data source: Represents the transactional data store.
    • options: Describes settings for a data store session.
    • session: The primary interface for accessing and manipulating data.
    • result: Describes the outcome of a session operation.
    • cursor: Used to iterate over rows in a result set.
    • row processor: An interface used with a cursor to process rows without buffering.
    • session listener: An object registered with a session to receive event notifications.

    Protocol-level Objects

    These handle the physical transport and communication:

    • endpoint: Represents a connection endpoint (e.g., TCP/IP).
    • connection options: Describes connection characteristics.
    • connection: Represents the physical connection to an endpoint.
    • protocol: Handles sending and receiving protocol messages over a connection.
    • message processor: Processes messages received by a protocol object.
  11. How to use common definitions in public API definitions

    trunk
    The common/ directory contains shared code used by X DevAPI and XAPI implementations. This code is not intended for direct use by end-users. If you are defining public APIs and require common definitions, you should include <include/mysqlx_common.h> instead of including headers directly from the common/ folder. Headers within the common/ folder are reserved for internal implementation use and should not be included in public headers.
  12. Implement custom expressions using api::Expression::Processor

    trunk

    To use expressions in CRUD requests, you must implement the api::Expression interface. The process method of your expression object must accept an api::Expression::Processor and use it to visit the expression's syntax tree.

    The Protocol implementation uses this visitor pattern to build the actual wire messages. You are responsible for ensuring that the process method correctly calls the appropriate processor methods to describe the intended expression.

    Example: Implementing an Operator

    If your expression represents an operation like foo > 7, your process implementation should call ep.op(">", args) where args is an Expr_list containing the operands.

    // Example of how a processor visits an expression tree
    void MyExpression::process(api::Expression::Processor *ep) {
        // If this expression is an operator like '>', we call ep.op
        // and pass an Expr_list containing the arguments.
        ep->op(">", args);
    }
    
    // Inside the processor's op callback, you can traverse arguments:
    // args.get_expr(0).process(this);
    // args.get_expr(1).process(this);