diff --git a/source/docs-libmongoc/authentication.txt b/source/docs-libmongoc/authentication.txt index fddda72f..6780e7c6 100644 --- a/source/docs-libmongoc/authentication.txt +++ b/source/docs-libmongoc/authentication.txt @@ -1,4 +1,4 @@ -.. _mongoc_authentication +.. _mongoc_authentication: Authentication ============== @@ -8,7 +8,7 @@ Authentication :backlinks: none :depth: 2 :class: singlecol - + This guide covers the use of authentication options with the MongoDB C Driver. Ensure that the MongoDB server is also properly configured for authentication before making a connection. For more information, see the `MongoDB security documentation `_. The MongoDB C driver supports several authentication mechanisms through the use of MongoDB connection URIs. diff --git a/source/docs-libmongoc/guides/advanced-connections.rst b/source/docs-libmongoc/guides/advanced-connections.rst deleted file mode 100644 index 64822ab7..00000000 --- a/source/docs-libmongoc/guides/advanced-connections.rst +++ /dev/null @@ -1,179 +0,0 @@ -.. _mongoc_advanced_connections - -Advanced Connections -==================== - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -The following guide contains information specific to certain types of MongoDB configurations. - -For an example of connecting to a simple standalone server, see the :ref:`Tutorial `. To establish a connection with authentication options enabled, see the :doc:`Authentication ` page. To see an example of a connection with data compression, see the :doc:`Data Compression ` page. - -Connecting to a Replica Set ---------------------------- - -Connecting to a `replica set `_ is much like connecting to a standalone MongoDB server. Simply specify the replica set name using the ``?replicaSet=myreplset`` URI option. - -.. code-block:: c - - #include - #include - - int - main (int argc, char *argv[]) - { - mongoc_client_t *client; - - mongoc_init (); - - /* Create our MongoDB Client */ - client = mongoc_client_new ( - "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset"); - - /* Do some work */ - /* TODO */ - - /* Clean up */ - mongoc_client_destroy (client); - mongoc_cleanup (); - - return 0; - } - -.. tip:: - - Multiple hostnames can be specified in the MongoDB connection string URI, with a comma separating hosts in the seed list. - - It is recommended to use a seed list of members of the replica set to allow the driver to connect to any node. - -Connecting to a Sharded Cluster -------------------------------- - -To connect to a `sharded cluster `_, specify the ``mongos`` nodes the client should connect to. The C Driver will automatically detect that it has connected to a ``mongos`` sharding server. - -If more than one hostname is specified, a seed list will be created to attempt failover between the ``mongos`` instances. - -.. warning:: - - Specifying the ``replicaSet`` parameter when connecting to a ``mongos`` sharding server is invalid. - -.. code-block:: c - - #include - #include - - int - main (int argc, char *argv[]) - { - mongoc_client_t *client; - - mongoc_init (); - - /* Create our MongoDB Client */ - client = mongoc_client_new ("mongodb://myshard01:27017/"); - - /* Do something with client ... */ - - /* Free the client */ - mongoc_client_destroy (client); - - mongoc_cleanup (); - - return 0; - } - -Connecting to an IPv6 Address ------------------------------ - -The MongoDB C Driver will automatically resolve IPv6 addresses from host names. However, to specify an IPv6 address directly, wrap the address in ``[]``. - -.. code-block:: none - - mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017"); - -Connecting with IPv4 and IPv6 ------------------------------ - -.. include:: includes/ipv4-and-ipv6.txt - -Connecting to a UNIX Domain Socket ----------------------------------- - -On UNIX-like systems, the C Driver can connect directly to a MongoDB server using a UNIX domain socket. Pass the URL-encoded path to the socket, which *must* be suffixed with ``.sock``. For example, to connect to a domain socket at ``/tmp/mongodb-27017.sock``: - -.. code-block:: none - - mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock"); - -Include username and password like so: - -.. code-block:: none - - mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock"); - - -Connecting to a server over TLS -------------------------------- - -These are instructions for configuring TLS/SSL connections. - -To run a server locally (on port 27017, for example): - -.. code-block:: none - - $ mongod --port 27017 --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem - -Add ``/?tls=true`` to the end of a client URI. - -.. code-block:: none - - mongoc_client_t *client = NULL; - client = mongoc_client_new ("mongodb://localhost:27017/?tls=true"); - -MongoDB requires client certificates by default, unless the ``--tlsAllowConnectionsWithoutCertificates`` is provided. The C Driver can be configured to present a client certificate using the URI option ``tlsCertificateKeyFile``, which may be referenced through the constant ``MONGOC_URI_TLSCERTIFICATEKEYFILE``. - -.. code-block:: none - - mongoc_client_t *client = NULL; - mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/?tls=true"); - mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "client.pem"); - - client = mongoc_client_new_from_uri (uri); - -The client certificate provided by ``tlsCertificateKeyFile`` must be issued by one of the server trusted Certificate Authorities listed in ``--tlsCAFile``, or issued by a CA in the native certificate store on the server when omitted. - -See :doc:`configuring_tls` for more information on the various TLS related options. - -Compressing data to and from MongoDB ------------------------------------- - -This content has been relocated to the :doc:`Data Compression ` page. - -Additional Connection Options ------------------------------ - -The full list of connection options can be found in the :ref:`mongoc_uri_t` docs. - -Certain socket/connection related options are not configurable: - -============== ===================================================== ====================== -Option Description Value -============== ===================================================== ====================== -SO_KEEPALIVE TCP Keep Alive Enabled --------------- ----------------------------------------------------- ---------------------- -TCP_KEEPIDLE How long a connection needs to remain idle before TCP 120 seconds - starts sending keepalive probes --------------- ----------------------------------------------------- ---------------------- -TCP_KEEPINTVL The time in seconds between TCP probes 10 seconds --------------- ----------------------------------------------------- ---------------------- -TCP_KEEPCNT How many probes to send, without acknowledgement, 9 probes - before dropping the connection --------------- ----------------------------------------------------- ---------------------- -TCP_NODELAY Send packets as soon as possible or buffer small Enabled (no buffering) - packets (Nagle algorithm) -============== ===================================================== ====================== - diff --git a/source/docs-libmongoc/guides/advanced-connections.txt b/source/docs-libmongoc/guides/advanced-connections.txt new file mode 100644 index 00000000..0ab035c3 --- /dev/null +++ b/source/docs-libmongoc/guides/advanced-connections.txt @@ -0,0 +1,205 @@ +.. _mongoc_advanced_connections: + +==================== +Advanced Connections +==================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +The following guide contains information specific to certain types of MongoDB configurations. + +For an example of connecting to a simple standalone server, see the :ref:`Tutorial `. +To establish a connection with authentication options enabled, see the :ref:`Authentication ` +page. To see an example of a connection with data compression, see the :ref:`Data Compression ` +page. + +Connecting to a Replica Set +--------------------------- + +Connecting to a `replica set `_ is much like connecting to +a standalone MongoDB server. Simply specify the replica set name using the ``?replicaSet=myreplset`` URI option. + +.. code-block:: c + + #include + #include + + int + main (int argc, char *argv[]) + { + mongoc_client_t *client; + + mongoc_init (); + + /* Create our MongoDB Client */ + client = mongoc_client_new ( + "mongodb://host01:27017,host02:27017,host03:27017/?replicaSet=myreplset"); + + /* Do some work */ + /* TODO */ + + /* Clean up */ + mongoc_client_destroy (client); + mongoc_cleanup (); + + return 0; + } + +.. tip:: + + Multiple hostnames can be specified in the MongoDB connection string URI, with a comma separating + hosts in the seed list. + + It is recommended to use a seed list of members of the replica set to allow the driver to connect + to any node. + +Connecting to a Sharded Cluster +------------------------------- + +To connect to a `sharded cluster `_, specify the ``mongos`` nodes +the client should connect to. The C Driver will automatically detect that it has connected to a ``mongos`` sharding +server. + +If more than one hostname is specified, a seed list will be created to attempt failover between the ``mongos`` +instances. + +.. warning:: + + Specifying the ``replicaSet`` parameter when connecting to a ``mongos`` sharding server is invalid. + +.. code-block:: c + + #include + #include + + int + main (int argc, char *argv[]) + { + mongoc_client_t *client; + + mongoc_init (); + + /* Create our MongoDB Client */ + client = mongoc_client_new ("mongodb://myshard01:27017/"); + + /* Do something with client ... */ + + /* Free the client */ + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return 0; + } + +Connecting to an IPv6 Address +----------------------------- + +The MongoDB C Driver will automatically resolve IPv6 addresses from host names. However, to specify +an IPv6 address directly, wrap the address in ``[]``. + +.. code-block:: none + + mongoc_uri_t *uri = mongoc_uri_new ("mongodb://[::1]:27017"); + +Connecting with IPv4 and IPv6 +----------------------------- + +.. include:: includes/ipv4-and-ipv6.txt + +Connecting to a UNIX Domain Socket +---------------------------------- + +On UNIX-like systems, the C Driver can connect directly to a MongoDB server using a UNIX domain socket. +Pass the URL-encoded path to the socket, which *must* be suffixed with ``.sock``. For example, to connect +to a domain socket at ``/tmp/mongodb-27017.sock``: + +.. code-block:: none + + mongoc_uri_t *uri = mongoc_uri_new ("mongodb://%2Ftmp%2Fmongodb-27017.sock"); + +Include username and password like so: + +.. code-block:: none + + mongoc_uri_t *uri = mongoc_uri_new ("mongodb://user:pass@%2Ftmp%2Fmongodb-27017.sock"); + +Connecting to a server over TLS +------------------------------- + +These are instructions for configuring TLS/SSL connections. + +To run a server locally (on port 27017, for example): + +.. code-block:: none + + $ mongod --port 27017 --tlsMode requireTLS --tlsCertificateKeyFile server.pem --tlsCAFile ca.pem + +Add ``/?tls=true`` to the end of a client URI. + +.. code-block:: none + + mongoc_client_t *client = NULL; + client = mongoc_client_new ("mongodb://localhost:27017/?tls=true"); + +MongoDB requires client certificates by default, unless the ``--tlsAllowConnectionsWithoutCertificates`` is provided. +The C Driver can be configured to present a client certificate using the URI option ``tlsCertificateKeyFile``, which +may be referenced through the constant ``MONGOC_URI_TLSCERTIFICATEKEYFILE``. + +.. code-block:: none + + mongoc_client_t *client = NULL; + mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/?tls=true"); + mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "client.pem"); + + client = mongoc_client_new_from_uri (uri); + +The client certificate provided by ``tlsCertificateKeyFile`` must be issued by one of the server trusted Certificate +Authorities listed in ``--tlsCAFile``, or issued by a CA in the native certificate store on the server when omitted. + +See :ref:`mongoc_configuring_tls` for more information on the various TLS related options. + +Compressing data to and from MongoDB +------------------------------------ + +This content has been relocated to the :ref:`Data Compression ` page. + +Additional Connection Options +----------------------------- + +The full list of connection options can be found in the :ref:`mongoc_uri_t` docs. + +Certain socket/connection related options are not configurable: + +.. list-table:: + :widths: 1 2 1 + :stub-columns: 1 + :header-rows: 1 + + * - Option + - Description + - Value + + * - | SO_KEEPALIVE + - | TCP Keep Alive + - | Enabled + + * - TCP_KEEPIDLE + - How long a connection needs to remain idle before TCP starts sending keepalive probes + - 120 seconds + + * - | TCP_KEEPINTVL + - | The time in seconds between TCP probes + - | 10 seconds + + * - TCP_KEEPCNT + - How many probes to send, without acknowledgement, before dropping the connection + - 9 probes + + * - | TCP_NODELAY + - | Send packets as soon as possible or buffer small packets (Nagle algorithm) + - | Enabled (no buffering) diff --git a/source/docs-libmongoc/guides/aggregate.rst b/source/docs-libmongoc/guides/aggregate.rst deleted file mode 100644 index d22c938d..00000000 --- a/source/docs-libmongoc/guides/aggregate.rst +++ /dev/null @@ -1,144 +0,0 @@ -.. _mongoc_aggregate - -Aggregation Framework Examples -============================== - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This document provides a number of practical examples that display the capabilities of the aggregation framework. - -The `Aggregations using the Zip Codes Data Set `_ examples uses a publicly available data set of all zipcodes and populations in the United States. These data are available at: `zips.json `_. - -Requirements ------------- - -Let's check if everything is installed. - -Use the following command to load zips.json data set into mongod instance: - -.. code-block:: none - - $ mongoimport --drop -d test -c zipcodes zips.json - -Let's use the MongoDB shell to verify that everything was imported successfully. - -.. code-block:: none - - $ mongo test - connecting to: test - > db.zipcodes.count() - 29467 - > db.zipcodes.findOne() - { - "_id" : "35004", - "city" : "ACMAR", - "loc" : [ - -86.51557, - 33.584132 - ], - "pop" : 6055, - "state" : "AL" - } - -Aggregations using the Zip Codes Data Set ------------------------------------------ - -Each document in this collection has the following form: - -.. code-block:: json - - { - "_id" : "35004", - "city" : "Acmar", - "state" : "AL", - "pop" : 6055, - "loc" : [-86.51557, 33.584132] - } - -In these documents: - -* The ``_id`` field holds the zipcode as a string. -* The ``city`` field holds the city name. -* The ``state`` field holds the two letter state abbreviation. -* The ``pop`` field holds the population. -* The ``loc`` field holds the location as a ``[latitude, longitude]`` array. - -States with Populations Over 10 Million ---------------------------------------- - -To get all states with a population greater than 10 million, use the following aggregation pipeline: - -.. literalinclude:: ../examples/aggregation/aggregation1.c - :language: c - :caption: aggregation1.c - -You should see a result like the following: - -.. code-block:: json - - { "_id" : "PA", "total_pop" : 11881643 } - { "_id" : "OH", "total_pop" : 10847115 } - { "_id" : "NY", "total_pop" : 17990455 } - { "_id" : "FL", "total_pop" : 12937284 } - { "_id" : "TX", "total_pop" : 16986510 } - { "_id" : "IL", "total_pop" : 11430472 } - { "_id" : "CA", "total_pop" : 29760021 } - -The above aggregation pipeline is build from two pipeline operators: ``$group`` and ``$match``. - -The ``$group`` pipeline operator requires _id field where we specify grouping; remaining fields specify how to generate composite value and must use one of the group aggregation functions: ``$addToSet``, ``$first``, ``$last``, ``$max``, ``$min``, ``$avg``, ``$push``, ``$sum``. The ``$match`` pipeline operator syntax is the same as the read operation query syntax. - -The ``$group`` process reads all documents and for each state it creates a separate document, for example: - -.. code-block:: json - - { "_id" : "WA", "total_pop" : 4866692 } - -The ``total_pop`` field uses the $sum aggregation function to sum the values of all pop fields in the source documents. - -Documents created by ``$group`` are piped to the ``$match`` pipeline operator. It returns the documents with the value of ``total_pop`` field greater than or equal to 10 million. - -Average City Population by State --------------------------------- - -To get the first three states with the greatest average population per city, use the following aggregation: - -.. code-block:: c - - pipeline = BCON_NEW ("pipeline", "[", - "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}", - "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}", - "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}", - "{", "$limit", BCON_INT32 (3) "}", - "]"); - -This aggregate pipeline produces: - -.. code-block:: json - - { "_id" : "DC", "avg_city_pop" : 303450.0 } - { "_id" : "FL", "avg_city_pop" : 27942.29805615551 } - { "_id" : "CA", "avg_city_pop" : 27735.341099720412 } - -The above aggregation pipeline is build from three pipeline operators: ``$group``, ``$sort`` and ``$limit``. - -The first ``$group`` operator creates the following documents: - -.. code-block:: json - - { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 } - -Note, that the ``$group`` operator can't use nested documents except the ``_id`` field. - -The second ``$group`` uses these documents to create the following documents: - -.. code-block:: json - - { "_id" : "FL", "avg_city_pop" : 27942.29805615551 } - -These documents are sorted by the ``avg_city_pop`` field in descending order. Finally, the ``$limit`` pipeline operator returns the first 3 documents from the sorted set. - diff --git a/source/docs-libmongoc/guides/aggregate.txt b/source/docs-libmongoc/guides/aggregate.txt new file mode 100644 index 00000000..05ac89df --- /dev/null +++ b/source/docs-libmongoc/guides/aggregate.txt @@ -0,0 +1,153 @@ +.. _mongoc_aggregate: + +============================== +Aggregation Framework Examples +============================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +This document provides a number of practical examples that display the capabilities of the +aggregation framework. + +The `Aggregations using the Zip Codes Data Set `_ +examples uses a publicly available data set of all zipcodes and populations in the United States. +This data is available at: `zips.json `_. + +Requirements +------------ + +Let's check if everything is installed. + +Use the following command to load zips.json data set into mongod instance: + +.. code-block:: none + + $ mongoimport --drop -d test -c zipcodes zips.json + +Let's use the MongoDB shell to verify that everything was imported successfully. + +.. code-block:: none + + $ mongo test + connecting to: test + > db.zipcodes.count() + 29467 + > db.zipcodes.findOne() + { + "_id" : "35004", + "city" : "ACMAR", + "loc" : [ + -86.51557, + 33.584132 + ], + "pop" : 6055, + "state" : "AL" + } + +Aggregations using the Zip Codes Data Set +----------------------------------------- + +Each document in this collection has the following form: + +.. code-block:: json + + { + "_id" : "35004", + "city" : "Acmar", + "state" : "AL", + "pop" : 6055, + "loc" : [-86.51557, 33.584132] + } + +In these documents: + +- The ``_id`` field holds the zipcode as a string. +- The ``city`` field holds the city name. +- The ``state`` field holds the two letter state abbreviation. +- The ``pop`` field holds the population. +- The ``loc`` field holds the location as a ``[latitude, longitude]`` array. + +States with Populations Over 10 Million +--------------------------------------- + +To get all states with a population greater than 10 million, use the following aggregation pipeline: + +.. literalinclude:: ../includes/examples/aggregation/aggregation1.c + :language: c + :caption: aggregation1.c + +You should see a result like the following: + +.. code-block:: json + + { "_id" : "PA", "total_pop" : 11881643 } + { "_id" : "OH", "total_pop" : 10847115 } + { "_id" : "NY", "total_pop" : 17990455 } + { "_id" : "FL", "total_pop" : 12937284 } + { "_id" : "TX", "total_pop" : 16986510 } + { "_id" : "IL", "total_pop" : 11430472 } + { "_id" : "CA", "total_pop" : 29760021 } + +The above aggregation pipeline is build from two pipeline operators: ``$group`` and ``$match``. + +The ``$group`` pipeline operator requires _id field where we specify grouping; remaining fields specify how +to generate composite value and must use one of the group aggregation functions: ``$addToSet``, ``$first``, +``$last``, ``$max``, ``$min``, ``$avg``, ``$push``, ``$sum``. The ``$match`` pipeline operator syntax is the +same as the read operation query syntax. + +The ``$group`` process reads all documents and for each state it creates a separate document, for example: + +.. code-block:: json + + { "_id" : "WA", "total_pop" : 4866692 } + +The ``total_pop`` field uses the $sum aggregation function to sum the values of all pop fields in the source documents. + +Documents created by ``$group`` are piped to the ``$match`` pipeline operator. It returns the documents with the value +of ``total_pop`` field greater than or equal to 10 million. + +Average City Population by State +-------------------------------- + +To get the first three states with the greatest average population per city, use the following aggregation: + +.. code-block:: c + + pipeline = BCON_NEW ("pipeline", "[", + "{", "$group", "{", "_id", "{", "state", "$state", "city", "$city", "}", "pop", "{", "$sum", "$pop", "}", "}", "}", + "{", "$group", "{", "_id", "$_id.state", "avg_city_pop", "{", "$avg", "$pop", "}", "}", "}", + "{", "$sort", "{", "avg_city_pop", BCON_INT32 (-1), "}", "}", + "{", "$limit", BCON_INT32 (3) "}", + "]"); + +This aggregate pipeline produces: + +.. code-block:: json + + { "_id" : "DC", "avg_city_pop" : 303450.0 } + { "_id" : "FL", "avg_city_pop" : 27942.29805615551 } + { "_id" : "CA", "avg_city_pop" : 27735.341099720412 } + +The above aggregation pipeline is build from three pipeline operators: ``$group``, ``$sort`` and ``$limit``. + +The first ``$group`` operator creates the following documents: + +.. code-block:: json + + { "_id" : { "state" : "WY", "city" : "Smoot" }, "pop" : 414 } + +Note, that the ``$group`` operator can't use nested documents except the ``_id`` field. + +The second ``$group`` uses these documents to create the following documents: + +.. code-block:: json + + { "_id" : "FL", "avg_city_pop" : 27942.29805615551 } + +These documents are sorted by the ``avg_city_pop`` field in descending order. Finally, the ``$limit`` +pipeline operator returns the first 3 documents from the sorted set. + diff --git a/source/docs-libmongoc/guides/bulk.rst b/source/docs-libmongoc/guides/bulk.rst deleted file mode 100644 index 11754aa0..00000000 --- a/source/docs-libmongoc/guides/bulk.rst +++ /dev/null @@ -1,216 +0,0 @@ -.. _mongoc_bulk - -Bulk Write Operations -===================== - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -This tutorial explains how to take advantage of MongoDB C driver bulk write operation features. Executing write operations in batches reduces the number of network round trips, increasing write throughput. - -Bulk Insert ------------ - -First we need to fetch a bulk operation handle from the :ref:`mongoc_collection_t`. - -.. code-block:: c - - mongoc_bulk_operation_t *bulk = - mongoc_collection_create_bulk_operation_with_opts (collection, NULL); - -We can now start inserting documents to the bulk operation. These will be buffered until we execute the operation. - -The bulk operation will coalesce insertions as a single batch for each consecutive call to :ref:`mongoc_bulk_operation_insert()`. This creates a pipelined effect when possible. - -To execute the bulk operation and receive the result we call :ref:`mongoc_bulk_operation_execute()`. - -.. literalinclude:: ../examples/bulk/bulk1.c - :language: c - :caption: bulk1.c - -Example ``reply`` document: - -.. code-block:: none - - {"nInserted" : 10000, - "nMatched" : 0, - "nModified" : 0, - "nRemoved" : 0, - "nUpserted" : 0, - "writeErrors" : [] - "writeConcernErrors" : [] } - -Mixed Bulk Write Operations ---------------------------- - -MongoDB C driver also supports executing mixed bulk write operations. A batch of insert, update, and remove operations can be executed together using the bulk write operations API. - -Ordered Bulk Write Operations ------------------------------ - -Ordered bulk write operations are batched and sent to the server in the order provided for serial execution. The ``reply`` document describes the type and count of operations performed. - -.. literalinclude:: ../examples/bulk/bulk2.c - :language: c - :caption: bulk2.c - -Example ``reply`` document: - -.. code-block:: none - - { "nInserted" : 3, - "nMatched" : 2, - "nModified" : 2, - "nRemoved" : 10000, - "nUpserted" : 1, - "upserted" : [{"index" : 5, "_id" : 4}], - "writeErrors" : [] - "writeConcernErrors" : [] } - -The ``index`` field in the ``upserted`` array is the 0-based index of the upsert operation; in this example, the sixth operation of the overall bulk operation was an upsert, so its index is 5. - -Unordered Bulk Write Operations -------------------------------- - -Unordered bulk write operations are batched and sent to the server in *arbitrary order* where they may be executed in parallel. Any errors that occur are reported after all operations are attempted. - -In the next example the first and third operations fail due to the unique constraint on ``_id``. Since we are doing unordered execution the second and fourth operations succeed. - -.. literalinclude:: ../examples/bulk/bulk3.c - :language: c - :caption: bulk3.c - -Example ``reply`` document: - -.. code-block:: none - - { "nInserted" : 0, - "nMatched" : 1, - "nModified" : 1, - "nRemoved" : 1, - "nUpserted" : 0, - "writeErrors" : [ - { "index" : 0, - "code" : 11000, - "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" }, - { "index" : 2, - "code" : 11000, - "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ], - "writeConcernErrors" : [] } - - Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 } - -The :symbol:`bson_error_t ` domain is ``MONGOC_ERROR_COMMAND`` and its code is 11000. - -.. _bulk_operation_bypassing_document_validation: - -Bulk Operation Bypassing Document Validation --------------------------------------------- - -This feature is only available when using MongoDB 3.2 and later. - -By default bulk operations are validated against the schema, if any is defined. In certain cases however it may be necessary to bypass the document validation. - -.. literalinclude:: ../examples/bulk/bulk5.c - :language: c - :caption: bulk5.c - -Running the above example will result in: - -.. code-block:: none - - { "nInserted" : 0, - "nMatched" : 0, - "nModified" : 0, - "nRemoved" : 0, - "nUpserted" : 0, - "writeErrors" : [ - { "index" : 0, - "code" : 121, - "errmsg" : "Document failed validation" } ] } - - Error: Document failed validation - - { "nInserted" : 2, - "nMatched" : 0, - "nModified" : 0, - "nRemoved" : 0, - "nUpserted" : 0, - "writeErrors" : [] } - -The :symbol:`bson_error_t ` domain is ``MONGOC_ERROR_COMMAND``. - -Bulk Operation Write Concerns ------------------------------ - -By default bulk operations are executed with the :symbol:`write_concern ` of the collection they are executed against. A custom write concern can be passed to the :ref:`mongoc_collection_create_bulk_operation_with_opts()` method. Write concern errors (e.g. wtimeout) will be reported after all operations are attempted, regardless of execution order. - -.. literalinclude:: ../examples/bulk/bulk4.c - :language: c - :caption: bulk4.c - -Example ``reply`` document and error message: - -.. code-block:: none - - { "nInserted" : 2, - "nMatched" : 0, - "nModified" : 0, - "nRemoved" : 0, - "nUpserted" : 0, - "writeErrors" : [], - "writeConcernErrors" : [ - { "code" : 64, - "errmsg" : "waiting for replication timed out" } - ] } - - Error: waiting for replication timed out - -The :symbol:`bson_error_t ` domain is ``MONGOC_ERROR_WRITE_CONCERN`` if there are write concern errors and no write errors. Write errors indicate failed operations, so they take precedence over write concern errors, which mean merely that the write concern is not satisfied *yet*. - -.. _setting_collation_order: - -Setting Collation Order ------------------------ - -This feature is only available when using MongoDB 3.4 and later. - -.. literalinclude:: ../examples/bulk/bulk-collation.c - :language: c - :caption: bulk-collation.c - -Running the above example will result in: - -.. code-block:: none - - { "nInserted" : 2, - "nMatched" : 1, - "nModified" : 1, - "nRemoved" : 0, - "nUpserted" : 0, - "writeErrors" : [ ] - } - -Unacknowledged Bulk Writes --------------------------- - -Set "w" to zero for an unacknowledged write. The driver sends unacknowledged writes using the legacy opcodes ``OP_INSERT``, ``OP_UPDATE``, and ``OP_DELETE``. - -.. literalinclude:: ../examples/bulk/bulk6.c - :language: c - :caption: bulk6.c - -The ``reply`` document is empty: - -.. code-block:: none - - { } - -Further Reading ---------------- - -See the `Driver Bulk API Spec `_, which describes bulk write operations for all MongoDB drivers. - diff --git a/source/docs-libmongoc/guides/bulk.txt b/source/docs-libmongoc/guides/bulk.txt new file mode 100644 index 00000000..fd030ef4 --- /dev/null +++ b/source/docs-libmongoc/guides/bulk.txt @@ -0,0 +1,234 @@ +.. _mongoc_bulk: + +===================== +Bulk Write Operations +===================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +This tutorial explains how to take advantage of MongoDB C driver bulk write operation features. +Executing write operations in batches reduces the number of network round trips, increasing write +throughput. + +Bulk Insert +----------- + +First we need to fetch a bulk operation handle from the :ref:`mongoc_collection_t`. + +.. code-block:: c + + mongoc_bulk_operation_t *bulk = + mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + +We can now start inserting documents to the bulk operation. These will be buffered until we execute the +operation. + +The bulk operation will coalesce insertions as a single batch for each consecutive call to +:ref:`mongoc_bulk_operation_insert`. This creates a pipelined effect when possible. + +To execute the bulk operation and receive the result we call :ref:`mongoc_bulk_operation_execute`. + +.. literalinclude:: ../includes/examples/bulk/bulk1.c + :language: c + :caption: bulk1.c + +Example ``reply`` document: + +.. code-block:: none + + {"nInserted" : 10000, + "nMatched" : 0, + "nModified" : 0, + "nRemoved" : 0, + "nUpserted" : 0, + "writeErrors" : [] + "writeConcernErrors" : [] } + +Mixed Bulk Write Operations +--------------------------- + +MongoDB C driver also supports executing mixed bulk write operations. A batch of insert, update, +and remove operations can be executed together using the bulk write operations API. + +Ordered Bulk Write Operations +----------------------------- + +Ordered bulk write operations are batched and sent to the server in the order provided for serial +execution. The ``reply`` document describes the type and count of operations performed. + +.. literalinclude:: ../includes/examples/bulk/bulk2.c + :language: c + :caption: bulk2.c + +Example ``reply`` document: + +.. code-block:: none + + { "nInserted" : 3, + "nMatched" : 2, + "nModified" : 2, + "nRemoved" : 10000, + "nUpserted" : 1, + "upserted" : [{"index" : 5, "_id" : 4}], + "writeErrors" : [] + "writeConcernErrors" : [] } + +The ``index`` field in the ``upserted`` array is the 0-based index of the upsert operation; in this example, +the sixth operation of the overall bulk operation was an upsert, so its index is 5. + +Unordered Bulk Write Operations +------------------------------- + +Unordered bulk write operations are batched and sent to the server in *arbitrary order* where they may +be executed in parallel. Any errors that occur are reported after all operations are attempted. + +In the next example the first and third operations fail due to the unique constraint on ``_id``. Since +we are doing unordered execution the second and fourth operations succeed. + +.. literalinclude:: ../includes/examples/bulk/bulk3.c + :language: c + :caption: bulk3.c + +Example ``reply`` document: + +.. code-block:: none + + { "nInserted" : 0, + "nMatched" : 1, + "nModified" : 1, + "nRemoved" : 1, + "nUpserted" : 0, + "writeErrors" : [ + { "index" : 0, + "code" : 11000, + "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 }" }, + { "index" : 2, + "code" : 11000, + "errmsg" : "E11000 duplicate key error index: test.test.$_id_ dup key: { : 3 }" } ], + "writeConcernErrors" : [] } + + Error: E11000 duplicate key error index: test.test.$_id_ dup key: { : 1 } + +The :ref:`bson_error_t` domain is ``MONGOC_ERROR_COMMAND`` and its code is 11000. + +.. _bulk_operation_bypassing_document_validation: + +Bulk Operation Bypassing Document Validation +-------------------------------------------- + +This feature is only available when using MongoDB 3.2 and later. + +By default bulk operations are validated against the schema, if any is defined. In certain cases however +it may be necessary to bypass the document validation. + +.. literalinclude:: ../includes/examples/bulk/bulk5.c + :language: c + :caption: bulk5.c + +Running the above example will result in: + +.. code-block:: none + + { "nInserted" : 0, + "nMatched" : 0, + "nModified" : 0, + "nRemoved" : 0, + "nUpserted" : 0, + "writeErrors" : [ + { "index" : 0, + "code" : 121, + "errmsg" : "Document failed validation" } ] } + + Error: Document failed validation + + { "nInserted" : 2, + "nMatched" : 0, + "nModified" : 0, + "nRemoved" : 0, + "nUpserted" : 0, + "writeErrors" : [] } + +The :ref:`bson_error_t` domain is ``MONGOC_ERROR_COMMAND``. + +Bulk Operation Write Concerns +----------------------------- + +By default bulk operations are executed with the :ref:`mongoc_write_concern_t` of the collection they +are executed against. A custom write concern can be passed to the :ref:`mongoc_collection_create_bulk_operation_with_opts` +method. Write concern errors (e.g. wtimeout) will be reported after all operations are attempted, +regardless of execution order. + +.. literalinclude:: ../includes/examples/bulk/bulk4.c + :language: c + :caption: bulk4.c + +Example ``reply`` document and error message: + +.. code-block:: none + + { "nInserted" : 2, + "nMatched" : 0, + "nModified" : 0, + "nRemoved" : 0, + "nUpserted" : 0, + "writeErrors" : [], + "writeConcernErrors" : [ + { "code" : 64, + "errmsg" : "waiting for replication timed out" } + ] } + + Error: waiting for replication timed out + +The :ref:`bson_error_t` domain is ``MONGOC_ERROR_WRITE_CONCERN`` if there are write concern errors and no +write errors. Write errors indicate failed operations, so they take precedence over write concern errors, +which mean merely that the write concern is not satisfied *yet*. + +.. _setting_collation_order: + +Setting Collation Order +----------------------- + +This feature is only available when using MongoDB 3.4 and later. + +.. literalinclude:: ../includes/examples/bulk/bulk-collation.c + :language: c + :caption: bulk-collation.c + +Running the above example will result in: + +.. code-block:: none + + { "nInserted" : 2, + "nMatched" : 1, + "nModified" : 1, + "nRemoved" : 0, + "nUpserted" : 0, + "writeErrors" : [ ] + } + +Unacknowledged Bulk Writes +-------------------------- + +Set "w" to zero for an unacknowledged write. The driver sends unacknowledged writes using the legacy +opcodes ``OP_INSERT``, ``OP_UPDATE``, and ``OP_DELETE``. + +.. literalinclude:: ../includes/examples/bulk/bulk6.c + :language: c + :caption: bulk6.c + +The ``reply`` document is empty: + +.. code-block:: none + + { } + +Further Reading +--------------- + +See the `Driver Bulk API Spec `_, +which describes bulk write operations for all MongoDB drivers. + diff --git a/source/docs-libmongoc/guides/client-side-field-level-encryption.txt b/source/docs-libmongoc/guides/client-side-field-level-encryption.txt index 7dcc7afd..ff5d5e8b 100644 --- a/source/docs-libmongoc/guides/client-side-field-level-encryption.txt +++ b/source/docs-libmongoc/guides/client-side-field-level-encryption.txt @@ -9,7 +9,7 @@ Client-Side Field Level Encryption :backlinks: none :depth: 2 :class: singlecol - + New in MongoDB 4.2, Client-Side Field Level Encryption (also referred to as CSFLE) allows administrators and developers to encrypt specific data fields in addition to other MongoDB encryption features. @@ -38,10 +38,10 @@ a new encryption data key. version of the server supports automatic decryption as well as :ref:`explicit-client-side-encryption`. Providing Local Automatic Encryption Rules -`````````````````````````````````````````` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following example shows how to specify automatic encryption rules using a schema map set with -:ref:`mongoc_auto_encryption_opts_set_schema_map()`. The automatic encryption rules are expressed using a strict +:ref:`mongoc_auto_encryption_opts_set_schema_map`. The automatic encryption rules are expressed using a strict subset of the JSON Schema syntax. Supplying a schema map provides more security than relying on JSON Schemas obtained from the server. It protects @@ -51,12 +51,12 @@ data that should be encrypted. JSON Schemas supplied in the schema map only apply to configuring automatic encryption. Other validation rules in the JSON schema will not be enforced by the driver and will result in an error: -.. literalinclude:: ../examples/client-side-encryption-schema-map.c +.. literalinclude:: ../includes/examples/client-side-encryption-schema-map.c :caption: client-side-encryption-schema-map.c :language: c Server-Side Field Level Encryption Enforcement -`````````````````````````````````````````````` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The MongoDB 4.2 server supports using schema validation to enforce encryption of specific fields in a collection. This schema validation will prevent an application from inserting unencrypted values for any fields marked with @@ -65,29 +65,29 @@ the "encrypt" JSON schema keyword. The following example shows how to set up automatic encryption using :ref:`mongoc_client_encryption_t` to create a new encryption data key and create a collection with the necessary JSON Schema: -.. literalinclude:: ../examples/client-side-encryption-server-schema.c +.. literalinclude:: ../includes/examples/client-side-encryption-server-schema.c :caption: client-side-encryption-server-schema.c :language: c .. _explicit-client-side-encryption: Explicit Encryption -``````````````````` +~~~~~~~~~~~~~~~~~~~ Explicit encryption is a MongoDB community feature and does not use :ref:`query_analysis` (``mongocryptd`` or ``crypt_shared``). Explicit encryption is provided by the :ref:`mongoc_client_encryption_t` class, for example: -.. literalinclude:: ../examples/client-side-encryption-explicit.c +.. literalinclude:: ../includes/examples/client-side-encryption-explicit.c :caption: client-side-encryption-explicit.c :language: c Explicit Encryption with Automatic Decryption -````````````````````````````````````````````` +--------------------------------------------- Although automatic encryption requires MongoDB 4.2 enterprise or a MongoDB 4.2 Atlas cluster, automatic decryption is supported for all users. To configure automatic decryption without automatic encryption set ``bypass_auto_encryption=True`` in :ref:`mongoc_auto_encryption_opts_t`: -.. literalinclude:: ../examples/client-side-encryption-auto-decryption.c +.. literalinclude:: ../includes/examples/client-side-encryption-auto-decryption.c :caption: client-side-encryption-auto-decryption.c :language: c diff --git a/source/docs-libmongoc/guides/configuring_tls.rst b/source/docs-libmongoc/guides/configuring_tls.rst deleted file mode 100644 index 9cd9e3af..00000000 --- a/source/docs-libmongoc/guides/configuring_tls.rst +++ /dev/null @@ -1,152 +0,0 @@ -.. _mongoc_configuring_tls - -Configuring TLS -=============== - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Configuration with URI options ------------------------------- - -Enable TLS by including ``tls=true`` in the URI. - -.. code:: c - - mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/"); - mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true); - - mongoc_client_t *client = mongoc_client_new_from_uri (uri); - - -The following URI options may be used to further configure TLS: - -.. include:: includes/tls-options.txt - -Configuration with mongoc_ssl_opt_t ------------------------------------ - -Alternatively, the :ref:`mongoc_ssl_opt_t` struct may be used to configure TLS with :ref:`mongoc_client_set_ssl_opts()` or :ref:`mongoc_client_pool_set_ssl_opts()`. Most of the configurable options can be set using the `Connection String URI `_. - -=============================== =============================== -**mongoc_ssl_opt_t key** **URI key** -=============================== =============================== -pem_file tlsClientCertificateKeyFile -pem_pwd tlsClientCertificateKeyPassword -ca_file tlsCAFile -weak_cert_validation tlsAllowInvalidCertificates -allow_invalid_hostname tlsAllowInvalidHostnames -=============================== =============================== - -The only exclusions are ``crl_file`` and ``ca_dir``. Those may only be set with :ref:`mongoc_ssl_opt_t`. - -Client Authentication ---------------------- - -When MongoDB is started with TLS enabled, it will by default require the client to provide a client certificate issued by a certificate authority specified by ``--tlsCAFile``, or an authority trusted by the native certificate store in use on the server. - -To provide the client certificate, set the ``tlsCertificateKeyFile`` in the URI to a PEM armored certificate file. - -.. code-block:: c - - mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/"); - mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true); - mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "/path/to/client-certificate.pem"); - - mongoc_client_t *client = mongoc_client_new_from_uri (uri); - -Server Certificate Verification -------------------------------- - -The MongoDB C Driver will automatically verify the validity of the server certificate, such as issued by configured Certificate Authority, hostname validation, and expiration. - -To overwrite this behavior, it is possible to disable hostname validation, OCSP endpoint revocation checking, revocation checking entirely, and allow invalid certificates. - -This behavior is controlled using the ``tlsAllowInvalidHostnames``, ``tlsDisableOCSPEndpointCheck``, ``tlsDisableCertificateRevocationCheck``, and ``tlsAllowInvalidCertificates`` options respectively. By default, all are set to ``false``. - -It is not recommended to change these defaults as it exposes the client to *Man In The Middle* attacks (when ``tlsAllowInvalidHostnames`` is set), invalid certificates (when ``tlsAllowInvalidCertificates`` is set), or potentially revoked certificates (when ``tlsDisableOCSPEndpointCheck`` or ``tlsDisableCertificateRevocationCheck`` are set). - -Supported Libraries -------------------- - -By default, libmongoc will attempt to find a supported TLS library and enable TLS support. This is controlled by the cmake flag ``ENABLE_SSL``, which is set to ``AUTO`` by default. Valid values are: - -- ``AUTO`` the default behavior. Link to the system's native TLS library, or attempt to find OpenSSL. -- ``DARWIN`` link to Secure Transport, the native TLS library on macOS. -- ``WINDOWS`` link to Secure Channel, the native TLS library on Windows. -- ``OPENSSL`` link to OpenSSL (libssl). An optional install path may be specified with ``OPENSSL_ROOT``. -- ``LIBRESSL`` link to LibreSSL's libtls. (LibreSSL's compatible libssl may be linked to by setting ``OPENSSL``). -- ``OFF`` disable TLS support. - -OpenSSL -``````` - -The MongoDB C Driver uses OpenSSL, if available, on Linux and Unix platforms (besides macOS). Industry best practices and some regulations require the use of TLS 1.1 or newer, which requires at least OpenSSL 1.0.1. Check your OpenSSL version like so:: - - $ openssl version - -Ensure your system's OpenSSL is a recent version (at least 1.0.1), or install a recent version in a non-system path and build against it with:: - - cmake -DOPENSSL_ROOT_DIR=/absolute/path/to/openssl - -When compiled against OpenSSL, the driver will attempt to load the system default certificate store, as configured by the distribution. That can be overridden by setting the ``tlsCAFile`` URI option or with the fields ``ca_file`` and ``ca_dir`` in the :ref:`mongoc_ssl_opt_t`. - -The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `_) is fully supported when using OpenSSL 1.0.1+ with the following notes: - -- When a ``crl_file`` is set with :ref:`mongoc_ssl_opt_t`, and the ``crl_file`` revokes the server's certificate, the certificate is considered revoked (even if the certificate has a valid stapled OCSP response) - -LibreSSL / libtls -````````````````` - -The MongoDB C Driver supports LibreSSL through the use of OpenSSL compatibility checks when configured to compile against ``openssl``. It also supports the new ``libtls`` library when configured to build against ``libressl``. - -When compiled against the Windows native libraries, the ``crl_file`` option of a :ref:`mongoc_ssl_opt_t` is not supported, and will issue an error if used. - -Setting ``tlsDisableOCSPEndpointCheck`` and ``tlsDisableCertificateRevocationCheck`` has no effect. - -The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `_) is partially supported with the following notes: - -- The Must-Staple extension (see `RFC 7633 `_) is ignored. Connection may continue if a Must-Staple certificate is presented with no stapled response (unless the client receives a revoked response from an OCSP responder). -- Connection will continue if a Must-Staple certificate is presented without a stapled response and the OCSP responder is down. - -Native TLS Support on Windows (Secure Channel) -`````````````````````````````````````````````` - -The MongoDB C Driver supports the Windows native TLS library (Secure Channel, or SChannel), and its native crypto library (Cryptography API: Next Generation, or CNG). - -When compiled against the Windows native libraries, the ``ca_dir`` option of a :ref:`mongoc_ssl_opt_t` is not supported, and will issue an error if used. - -Encrypted PEM files (e.g., setting ``tlsCertificateKeyPassword``) are also not supported, and will result in error when attempting to load them. - -When ``tlsCAFile`` is set, the driver will only allow server certificates issued by the authority (or authorities) provided. When no ``tlsCAFile`` is set, the driver will look up the Certificate Authority using the ``System Local Machine Root`` certificate store to confirm the provided certificate. - -When ``crl_file`` is set with :ref:`mongoc_ssl_opt_t`, the driver will import the revocation list to the ``System Local Machine Root`` certificate store. - -Setting ``tlsDisableOCSPEndpointCheck`` has no effect. - -The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `_) is partially supported with the following notes: - -- The Must-Staple extension (see `RFC 7633 `_) is ignored. Connection may continue if a Must-Staple certificate is presented with no stapled response (unless the client receives a revoked response from an OCSP responder). -- When a ``crl_file`` is set with :ref:`mongoc_ssl_opt_t`, and the ``crl_file`` revokes the server's certificate, the OCSP response takes precedence. E.g. if the server presents a certificate with a valid stapled OCSP response, the certificate is considered valid even if the ``crl_file`` marks it as revoked. -- Connection will continue if a Must-Staple certificate is presented without a stapled response and the OCSP responder is down. - -.. _Secure Transport: - -Native TLS Support on macOS / Darwin (Secure Transport) -``````````````````````````````````````````````````````` - -The MongoDB C Driver supports the Darwin (OS X, macOS, iOS, etc.) native TLS library (Secure Transport), and its native crypto library (Common Crypto, or CC). - -When compiled against Secure Transport, the ``ca_dir`` and ``crl_file`` options of a :ref:`mongoc_ssl_opt_t` are not supported. An error is issued if either are used. - -When ``tlsCAFile`` is set, the driver will only allow server certificates issued by the authority (or authorities) provided. When no ``tlsCAFile`` is set, the driver will use the Certificate Authorities in the currently unlocked keychains. - -Setting ``tlsDisableOCSPEndpointCheck`` and ``tlsDisableCertificateRevocationCheck`` has no effect. - -The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `_) is partially supported with the following notes. - -- The Must-Staple extension (see `RFC 7633 `_) is ignored. Connection may continue if a Must-Staple certificate is presented with no stapled response (unless the client receives a revoked response from an OCSP responder). -- Connection will continue if a Must-Staple certificate is presented without a stapled response and the OCSP responder is down. diff --git a/source/docs-libmongoc/guides/configuring_tls.txt b/source/docs-libmongoc/guides/configuring_tls.txt new file mode 100644 index 00000000..06f296ea --- /dev/null +++ b/source/docs-libmongoc/guides/configuring_tls.txt @@ -0,0 +1,209 @@ +.. _mongoc_configuring_tls: + +=============== +Configuring TLS +=============== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Configuration with URI options +------------------------------ + +Enable TLS by including ``tls=true`` in the URI. + +.. code-block:: c + + mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/"); + mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true); + + mongoc_client_t *client = mongoc_client_new_from_uri (uri); + + +The following URI options may be used to further configure TLS: + +.. include:: includes/tls-options.txt + +Configuration with mongoc_ssl_opt_t +----------------------------------- + +Alternatively, the :ref:`mongoc_ssl_opt_t` struct may be used to configure TLS with :ref:`mongoc_client_set_ssl_opts` +or :ref:`mongoc_client_pool_set_ssl_opts`. Most of the configurable options can be set using the +:manual:`Connection String URI `. + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - **mongoc_ssl_opt_t key** + - **URI key** + + * - | pem_file + - | tlsClientCertificateKeyFile + + * - pem_pwd + - tlsClientCertificateKeyPassword + + * - | ca_file + - | tlsCAFile + + * - weak_cert_validation + - tlsAllowInvalidCertificates + + * - | allow_invalid_hostname + - | tlsAllowInvalidHostnames + +The only exclusions are ``crl_file`` and ``ca_dir``. Those may only be set with :ref:`mongoc_ssl_opt_t`. + +Client Authentication +--------------------- + +When MongoDB is started with TLS enabled, it will by default require the client to provide a client +certificate issued by a certificate authority specified by ``--tlsCAFile``, or an authority trusted +by the native certificate store in use on the server. + +To provide the client certificate, set the ``tlsCertificateKeyFile`` in the URI to a PEM armored +certificate file. + +.. code-block:: c + + mongoc_uri_t *uri = mongoc_uri_new ("mongodb://localhost:27017/"); + mongoc_uri_set_option_as_bool (uri, MONGOC_URI_TLS, true); + mongoc_uri_set_option_as_utf8 (uri, MONGOC_URI_TLSCERTIFICATEKEYFILE, "/path/to/client-certificate.pem"); + + mongoc_client_t *client = mongoc_client_new_from_uri (uri); + +Server Certificate Verification +------------------------------- + +The MongoDB C Driver will automatically verify the validity of the server certificate, such as issued +by configured Certificate Authority, hostname validation, and expiration. + +To overwrite this behavior, it is possible to disable hostname validation, OCSP endpoint revocation checking, +revocation checking entirely, and allow invalid certificates. + +This behavior is controlled using the ``tlsAllowInvalidHostnames``, ``tlsDisableOCSPEndpointCheck``, +``tlsDisableCertificateRevocationCheck``, and ``tlsAllowInvalidCertificates`` options respectively. By default, +all are set to ``false``. + +It is not recommended to change these defaults as it exposes the client to *Man In The Middle* attacks (when +``tlsAllowInvalidHostnames`` is set), invalid certificates (when ``tlsAllowInvalidCertificates`` is set), or +potentially revoked certificates (when ``tlsDisableOCSPEndpointCheck`` or ``tlsDisableCertificateRevocationCheck`` +are set). + +Supported Libraries +------------------- + +By default, libmongoc will attempt to find a supported TLS library and enable TLS support. This is controlled +by the cmake flag ``ENABLE_SSL``, which is set to ``AUTO`` by default. Valid values are: + +- ``AUTO`` the default behavior. Link to the system's native TLS library, or attempt to find OpenSSL. +- ``DARWIN`` link to Secure Transport, the native TLS library on macOS. +- ``WINDOWS`` link to Secure Channel, the native TLS library on Windows. +- ``OPENSSL`` link to OpenSSL (libssl). An optional install path may be specified with ``OPENSSL_ROOT``. +- ``LIBRESSL`` link to LibreSSL's libtls. (LibreSSL's compatible libssl may be linked to by setting ``OPENSSL``). +- ``OFF`` disable TLS support. + +OpenSSL +~~~~~~~ + +The MongoDB C Driver uses OpenSSL, if available, on Linux and Unix platforms (besides macOS). Industry best practices +and some regulations require the use of TLS 1.1 or newer, which requires at least OpenSSL 1.0.1. Check your OpenSSL +version like so: + +.. code-block:: bash + + $ openssl version + +Ensure your system's OpenSSL is a recent version (at least 1.0.1), or install a recent version in a non-system path and +build against it with: + +.. code-block:: bash + + cmake -DOPENSSL_ROOT_DIR=/absolute/path/to/openssl + +When compiled against OpenSSL, the driver will attempt to load the system default certificate store, as configured by the +distribution. That can be overridden by setting the ``tlsCAFile`` URI option or with the fields ``ca_file`` and ``ca_dir`` +in the :ref:`mongoc_ssl_opt_t`. + +The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `__) is fully supported +when using OpenSSL 1.0.1+ with the following notes: + +- When a ``crl_file`` is set with :ref:`mongoc_ssl_opt_t`, and the ``crl_file`` revokes the server's certificate, the certificate + is considered revoked (even if the certificate has a valid stapled OCSP response) + +LibreSSL / libtls +~~~~~~~~~~~~~~~~~ + +The MongoDB C Driver supports LibreSSL through the use of OpenSSL compatibility checks when configured to compile against +``openssl``. It also supports the new ``libtls`` library when configured to build against ``libressl``. + +When compiled against the Windows native libraries, the ``crl_file`` option of a :ref:`mongoc_ssl_opt_t` is not supported, +and will issue an error if used. + +Setting ``tlsDisableOCSPEndpointCheck`` and ``tlsDisableCertificateRevocationCheck`` has no effect. + +The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `__) is partially supported +with the following notes: + +- The Must-Staple extension (see `RFC 7633 `__) is ignored. Connection may continue if a +- Must-Staple certificate is presented with no stapled response (unless the client receives a revoked response from an OCSP + responder). +- Connection will continue if a Must-Staple certificate is presented without a stapled response and the OCSP responder is down. + +Native TLS Support on Windows (Secure Channel) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The MongoDB C Driver supports the Windows native TLS library (Secure Channel, or SChannel), and its native crypto library +(Cryptography API: Next Generation, or CNG). + +When compiled against the Windows native libraries, the ``ca_dir`` option of a :ref:`mongoc_ssl_opt_t` is not supported, +and will issue an error if used. + +Encrypted PEM files (e.g., setting ``tlsCertificateKeyPassword``) are also not supported, and will result in error when +attempting to load them. + +When ``tlsCAFile`` is set, the driver will only allow server certificates issued by the authority (or authorities) provided. +When no ``tlsCAFile`` is set, the driver will look up the Certificate Authority using the ``System Local Machine Root`` +certificate store to confirm the provided certificate. + +When ``crl_file`` is set with :ref:`mongoc_ssl_opt_t`, the driver will import the revocation list to the +``System Local Machine Root`` certificate store. + +Setting ``tlsDisableOCSPEndpointCheck`` has no effect. + +The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `__) is partially supported +with the following notes: + +- The Must-Staple extension (see `RFC 7633 `__) is ignored. Connection may continue if a + Must-Staple certificate is presented with no stapled response (unless the client receives a revoked response from an OCSP responder). +- When a ``crl_file`` is set with :ref:`mongoc_ssl_opt_t`, and the ``crl_file`` revokes the server's certificate, the OCSP response + takes precedence. E.g. if the server presents a certificate with a valid stapled OCSP response, the certificate is considered + valid even if the ``crl_file`` marks it as revoked. +- Connection will continue if a Must-Staple certificate is presented without a stapled response and the OCSP responder is down. + +.. _secure-transport: + +Native TLS Support on macOS / Darwin (Secure Transport) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The MongoDB C Driver supports the Darwin (OS X, macOS, iOS, etc.) native TLS library (Secure Transport), and its native crypto +library (Common Crypto, or CC). + +When compiled against Secure Transport, the ``ca_dir`` and ``crl_file`` options of a :ref:`mongoc_ssl_opt_t` are not supported. +An error is issued if either are used. + +When ``tlsCAFile`` is set, the driver will only allow server certificates issued by the authority (or authorities) provided. +When no ``tlsCAFile`` is set, the driver will use the Certificate Authorities in the currently unlocked keychains. + +Setting ``tlsDisableOCSPEndpointCheck`` and ``tlsDisableCertificateRevocationCheck`` has no effect. + +The Online Certificate Status Protocol (OCSP) (see `RFC 6960 `_) is partially supported +with the following notes. + +- The Must-Staple extension (see `RFC 7633 `_) is ignored. Connection may continue + if a Must-Staple certificate is presented with no stapled response (unless the client receives a revoked response from an OCSP responder). +- Connection will continue if a Must-Staple certificate is presented without a stapled response and the OCSP responder is down. diff --git a/source/docs-libmongoc/guides/connection-pooling.rst b/source/docs-libmongoc/guides/connection-pooling.rst deleted file mode 100644 index 9ba16797..00000000 --- a/source/docs-libmongoc/guides/connection-pooling.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. _mongoc_connection_pooling - -Connection Pooling -================== - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -The MongoDB C driver has two connection modes: single-threaded and pooled. Single-threaded mode is optimized for embedding the driver within languages like PHP. Multi-threaded programs should use pooled mode: this mode minimizes the total connection count, and in pooled mode background threads monitor the MongoDB server topology, so the program need not block to scan it. - -Single Mode ------------ - -In single mode, your program creates a :ref:`mongoc_client_t` directly: - -.. code-block:: c - - mongoc_client_t *client = mongoc_client_new ( - "mongodb://hostA,hostB/?replicaSet=my_rs"); - -The client connects on demand when your program first uses it for a MongoDB operation. Using a non-blocking socket per server, it begins a check on each server concurrently, and uses the asynchronous ``poll`` or ``select`` function to receive events from the sockets, until all have responded or timed out. Put another way, in single-threaded mode the C Driver fans out to begin all checks concurrently, then fans in once all checks have completed or timed out. Once the scan completes, the client executes your program's operation and returns. - -In single mode, the client re-scans the server topology roughly once per minute. If more than a minute has elapsed since the previous scan, the next operation on the client will block while the client completes its scan. This interval is configurable with ``heartbeatFrequencyMS`` in the connection string. (See :ref:`mongoc_uri_t`.) - -A single client opens one connection per server in your topology: these connections are used both for scanning the topology and performing normal operations. - -Pooled Mode ------------ - -To activate pooled mode, create a :ref:`mongoc_client_pool_t`: - -.. code-block:: c - - mongoc_uri_t *uri = mongoc_uri_new ( - "mongodb://hostA,hostB/?replicaSet=my_rs"); - - mongoc_client_pool_t *pool = mongoc_client_pool_new (uri); - -When your program first calls :ref:`mongoc_client_pool_pop`, the pool launches monitoring threads in the background. Monitoring threads independently connect to all servers in the connection string. As monitoring threads receive hello responses from the servers, they update the shared view of the server topology. Additional monitoring threads and connections are created as new servers are discovered. Monitoring threads are terminated when servers are removed from the shared view of the server topology. - -Each thread that executes MongoDB operations must check out a client from the pool: - -.. code-block:: c - - mongoc_client_t *client = mongoc_client_pool_pop (pool); - - /* use the client for operations ... */ - - mongoc_client_pool_push (pool, client); - -The :ref:`mongoc_client_t` object is not thread-safe, only the :ref:`mongoc_client_pool_t` is. - -When the driver is in pooled mode, your program's operations are unblocked as soon as monitoring discovers a usable server. For example, if a thread in your program is waiting to execute an "insert" on the primary, it is unblocked as soon as the primary is discovered, rather than waiting for all secondaries to be checked as well. - -The pool opens one connection per server for monitoring, and each client opens its own connection to each server it uses for application operations. Background monitoring threads re-scan servers independently roughly every 10 seconds. This interval is configurable with ``heartbeatFrequencyMS`` in the connection string. (See :ref:`mongoc_uri_t`.) - -The connection string can also specify ``waitQueueTimeoutMS`` to limit the time that :ref:`mongoc_client_pool_pop` will wait for a client from the pool. (See :ref:`mongoc_uri_t`.) If ``waitQueueTimeoutMS`` is specified, then it is necessary to confirm that a client was actually returned: - -.. code-block:: c - - mongoc_uri_t *uri = mongoc_uri_new ( - "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000"); - - mongoc_client_pool_t *pool = mongoc_client_pool_new (uri); - - mongoc_client_t *client = mongoc_client_pool_pop (pool); - - if (client) { - /* use the client for operations ... */ - - mongoc_client_pool_push (pool, client); - } else { - /* take appropriate action for a timeout */ - } - -See :ref:`connection_pool_options` to configure pool size and behavior, and see :ref:`mongoc_client_pool_t` for an extended example of a multi-threaded program that uses the driver in pooled mode. diff --git a/source/docs-libmongoc/guides/connection-pooling.txt b/source/docs-libmongoc/guides/connection-pooling.txt new file mode 100644 index 00000000..d52a2211 --- /dev/null +++ b/source/docs-libmongoc/guides/connection-pooling.txt @@ -0,0 +1,101 @@ +.. _mongoc_connection_pooling: + +================== +Connection Pooling +================== + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +The MongoDB C driver has two connection modes: single-threaded and pooled. Single-threaded mode +is optimized for embedding the driver within languages like PHP. Multi-threaded programs should use +pooled mode: this mode minimizes the total connection count, and in pooled mode background threads +monitor the MongoDB server topology, so the program need not block to scan it. + +Single Mode +----------- + +In single mode, your program creates a :ref:`mongoc_client_t` directly: + +.. code-block:: c + + mongoc_client_t *client = mongoc_client_new ( + "mongodb://hostA,hostB/?replicaSet=my_rs"); + +The client connects on demand when your program first uses it for a MongoDB operation. Using a non-blocking +socket per server, it begins a check on each server concurrently, and uses the asynchronous ``poll`` or +``select`` function to receive events from the sockets, until all have responded or timed out. Put another way, +in single-threaded mode the C Driver fans out to begin all checks concurrently, then fans in once all checks +have completed or timed out. Once the scan completes, the client executes your program's operation and returns. + +In single mode, the client re-scans the server topology roughly once per minute. If more than a minute has +elapsed since the previous scan, the next operation on the client will block while the client completes its +scan. This interval is configurable with ``heartbeatFrequencyMS`` in the connection string. (See :ref:`mongoc_uri_t`.) + +A single client opens one connection per server in your topology: these connections are used both for scanning +the topology and performing normal operations. + +Pooled Mode +----------- + +To activate pooled mode, create a :ref:`mongoc_client_pool_t`: + +.. code-block:: c + + mongoc_uri_t *uri = mongoc_uri_new ( + "mongodb://hostA,hostB/?replicaSet=my_rs"); + + mongoc_client_pool_t *pool = mongoc_client_pool_new (uri); + +When your program first calls :ref:`mongoc_client_pool_pop`, the pool launches monitoring threads in the background. +Monitoring threads independently connect to all servers in the connection string. As monitoring threads receive hello +responses from the servers, they update the shared view of the server topology. Additional monitoring threads and +connections are created as new servers are discovered. Monitoring threads are terminated when servers are removed from +the shared view of the server topology. + +Each thread that executes MongoDB operations must check out a client from the pool: + +.. code-block:: c + + mongoc_client_t *client = mongoc_client_pool_pop (pool); + + /* use the client for operations ... */ + + mongoc_client_pool_push (pool, client); + +The :ref:`mongoc_client_t` object is not thread-safe, only the :ref:`mongoc_client_pool_t` is. + +When the driver is in pooled mode, your program's operations are unblocked as soon as monitoring discovers a usable +server. For example, if a thread in your program is waiting to execute an "insert" on the primary, it is unblocked +as soon as the primary is discovered, rather than waiting for all secondaries to be checked as well. + +The pool opens one connection per server for monitoring, and each client opens its own connection to each server +it uses for application operations. Background monitoring threads re-scan servers independently roughly every 10 +seconds. This interval is configurable with ``heartbeatFrequencyMS`` in the connection string. (See :ref:`mongoc_uri_t`.) + +The connection string can also specify ``waitQueueTimeoutMS`` to limit the time that :ref:`mongoc_client_pool_pop` will +wait for a client from the pool. (See :ref:`mongoc_uri_t`.) If ``waitQueueTimeoutMS`` is specified, then it is necessary +to confirm that a client was actually returned: + +.. code-block:: c + + mongoc_uri_t *uri = mongoc_uri_new ( + "mongodb://hostA,hostB/?replicaSet=my_rs&waitQueueTimeoutMS=1000"); + + mongoc_client_pool_t *pool = mongoc_client_pool_new (uri); + + mongoc_client_t *client = mongoc_client_pool_pop (pool); + + if (client) { + /* use the client for operations ... */ + + mongoc_client_pool_push (pool, client); + } else { + /* take appropriate action for a timeout */ + } + +See :ref:`connection_pool_options` to configure pool size and behavior, and see :ref:`mongoc_client_pool_t` +for an extended example of a multi-threaded program that uses the driver in pooled mode. diff --git a/source/docs-libmongoc/guides/cursors.rst b/source/docs-libmongoc/guides/cursors.rst deleted file mode 100644 index d0489c2f..00000000 --- a/source/docs-libmongoc/guides/cursors.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. _mongoc_cursors - -Cursors -======= - -.. contents:: On this page - :local: - :backlinks: none - :depth: 2 - :class: singlecol - -Handling Cursor Failures ------------------------- - -Cursors exist on a MongoDB server. However, the ``mongoc_cursor_t`` structure gives the local process a handle to the cursor. It is possible for errors to occur on the server while iterating a cursor on the client. Even a network partition may occur. This means that applications should be robust in handling cursor failures. - -While iterating cursors, you should check to see if an error has occurred. See the following example for how to robustly check for errors. - -.. code-block:: c - - static void - print_all_documents (mongoc_collection_t *collection) - { - mongoc_cursor_t *cursor; - const bson_t *doc; - bson_error_t error; - bson_t query = BSON_INITIALIZER; - char *str; - - cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL); - - while (mongoc_cursor_next (cursor, &doc)) { - str = bson_as_canonical_extended_json (doc, NULL); - printf ("%s\n", str); - bson_free (str); - } - - if (mongoc_cursor_error (cursor, &error)) { - fprintf (stderr, "Failed to iterate all documents: %s\n", error.message); - } - - mongoc_cursor_destroy (cursor); - } - -Destroying Server-Side Cursors ------------------------------- - -The MongoDB C driver will automatically destroy a server-side cursor when :ref:`mongoc_cursor_destroy()` is called. Failure to call this function when done with a cursor will leak memory client side as well as consume extra memory server side. If the cursor was configured to never timeout, it will become a memory leak on the server. - -.. _cursors_tailable: - -Tailable Cursors ----------------- - -Tailable cursors are cursors that remain open even after they've returned a final result. This way, if more documents are added to a collection (i.e., to the cursor's result set), then you can continue to call :ref:`mongoc_cursor_next()` to retrieve those additional results. - -Here's a complete test case that demonstrates the use of tailable cursors. - -.. note:: - - Tailable cursors are for capped collections only. - -An example to tail the oplog from a replica set. - -.. literalinclude:: ../examples/mongoc-tail.c - :language: c - :caption: mongoc-tail.c - -Let's compile and run this example against a replica set to see updates as they are made. - -.. code-block:: none - - $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0) - $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet - { - "h" : -8458503739429355503, - "ns" : "test.test", - "o" : { - "_id" : { - "$oid" : "5372ab0a25164be923d10d50" - } - }, - "op" : "i", - "ts" : { - "$timestamp" : { - "i" : 1, - "t" : 1400023818 - } - }, - "v" : 2 - } - -The line of output is a sample from performing ``db.test.insert({})`` from the mongo shell on the replica set. - -.. seealso:: - - | :ref:`mongoc_cursor_set_max_await_time_ms`. - diff --git a/source/docs-libmongoc/guides/cursors.txt b/source/docs-libmongoc/guides/cursors.txt new file mode 100644 index 00000000..ab8dfb60 --- /dev/null +++ b/source/docs-libmongoc/guides/cursors.txt @@ -0,0 +1,108 @@ +.. _mongoc_cursors: + +======= +Cursors +======= + +.. contents:: On this page + :local: + :backlinks: none + :depth: 2 + :class: singlecol + +Handling Cursor Failures +------------------------ + +Cursors exist on a MongoDB server. However, the ``mongoc_cursor_t`` structure gives the local process +a handle to the cursor. It is possible for errors to occur on the server while iterating a cursor on +the client. Even a network partition may occur. This means that applications should be robust in handling +cursor failures. + +While iterating cursors, you should check to see if an error has occurred. See the following example for +how to robustly check for errors. + +.. code-block:: c + + static void + print_all_documents (mongoc_collection_t *collection) + { + mongoc_cursor_t *cursor; + const bson_t *doc; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + char *str; + + cursor = mongoc_collection_find_with_opts (collection, query, NULL, NULL); + + while (mongoc_cursor_next (cursor, &doc)) { + str = bson_as_canonical_extended_json (doc, NULL); + printf ("%s\n", str); + bson_free (str); + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "Failed to iterate all documents: %s\n", error.message); + } + + mongoc_cursor_destroy (cursor); + } + +Destroying Server-Side Cursors +------------------------------ + +The MongoDB C driver will automatically destroy a server-side cursor when :ref:`mongoc_cursor_destroy` +is called. Failure to call this function when done with a cursor will leak memory client side as well +as consume extra memory server side. If the cursor was configured to never timeout, it will become a +memory leak on the server. + +.. _cursors_tailable: + +Tailable Cursors +---------------- + +Tailable cursors are cursors that remain open even after they've returned a final result. This way, if +more documents are added to a collection (i.e., to the cursor's result set), then you can continue to +call :ref:`mongoc_cursor_next` to retrieve those additional results. + +Here's a complete test case that demonstrates the use of tailable cursors. + +.. note:: + + Tailable cursors are for capped collections only. + +An example to tail the oplog from a replica set. + +.. literalinclude:: ../includes/examples/mongoc-tail.c + :language: c + :caption: mongoc-tail.c + +Let's compile and run this example against a replica set to see updates as they are made. + +.. code-block:: none + + $ gcc -Wall -o mongoc-tail mongoc-tail.c $(pkg-config --cflags --libs libmongoc-1.0) + $ ./mongoc-tail mongodb://example.com/?replicaSet=myReplSet + { + "h" : -8458503739429355503, + "ns" : "test.test", + "o" : { + "_id" : { + "$oid" : "5372ab0a25164be923d10d50" + } + }, + "op" : "i", + "ts" : { + "$timestamp" : { + "i" : 1, + "t" : 1400023818 + } + }, + "v" : 2 + } + +The line of output is a sample from performing ``db.test.insert({})`` from the mongo shell on the replica set. + +.. seealso:: + + | :ref:`mongoc_cursor_set_max_await_time_ms`. + diff --git a/source/docs-libmongoc/guides/data-compression.rst b/source/docs-libmongoc/guides/data-compression.rst index 42cb511e..926c89d4 100644 --- a/source/docs-libmongoc/guides/data-compression.rst +++ b/source/docs-libmongoc/guides/data-compression.rst @@ -1,4 +1,4 @@ -.. _mongoc_data_compression +.. _mongoc_data_compression: Data Compression ================ diff --git a/source/docs-libmongoc/guides/in-use-encryption.txt b/source/docs-libmongoc/guides/in-use-encryption.txt index 7d919d6d..5ee3b3a6 100644 --- a/source/docs-libmongoc/guides/in-use-encryption.txt +++ b/source/docs-libmongoc/guides/in-use-encryption.txt @@ -39,8 +39,6 @@ The Queryable Encryption and CSFLE features share much of the same API with some - :ref:`mongoc_auto_encryption_opts_set_encrypted_fields_map` only applies to Queryable Encryption. - :ref:`mongoc_auto_encryption_opts_set_schema_map` only applies to CSFLE. - - .. _query_analysis: Query Analysis @@ -51,4 +49,7 @@ To support the automatic encryption feature, one of the following dependencies a - The ``mongocryptd`` executable. See the MongoDB Manual documentation: `Install and Configure mongocryptd `_ - The ``crypt_shared`` library. See the MongoDB Manual documentation: `Automatic Encryption Shared Library `_ -A :ref:`mongoc_client_t` or :ref:`mongoc_client_pool_t` configured with auto encryption will automatically try to load the ``crypt_shared`` library. If loading the ``crypt_shared`` library fails, the :ref:`mongoc_client_t` or :ref:`mongoc_client_pool_t` will try to spawn the ``mongocryptd`` process from the application's ``PATH``. To configure use of ``crypt_shared`` and ``mongocryptd`` see :ref:`mongoc_auto_encryption_opts_set_extra()`. +A :ref:`mongoc_client_t` or :ref:`mongoc_client_pool_t` configured with auto encryption will automatically +try to load the ``crypt_shared`` library. If loading the ``crypt_shared`` library fails, the :ref:`mongoc_client_t` +or :ref:`mongoc_client_pool_t` will try to spawn the ``mongocryptd`` process from the application's ``PATH``. +To configure use of ``crypt_shared`` and ``mongocryptd`` see :ref:`mongoc_auto_encryption_opts_set_extra`. diff --git a/source/docs-libmongoc/includes/examples/.gitignore b/source/docs-libmongoc/includes/examples/.gitignore new file mode 100644 index 00000000..aa8e8726 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/.gitignore @@ -0,0 +1,3 @@ +cmake_install.cmake +hello_mongoc +build diff --git a/source/docs-libmongoc/includes/examples/aggregation/aggregation1.c b/source/docs-libmongoc/includes/examples/aggregation/aggregation1.c new file mode 100644 index 00000000..9ca29fdd --- /dev/null +++ b/source/docs-libmongoc/includes/examples/aggregation/aggregation1.c @@ -0,0 +1,93 @@ +#include +#include + +static void +print_pipeline (mongoc_collection_t *collection) +{ + mongoc_cursor_t *cursor; + bson_error_t error; + const bson_t *doc; + bson_t *pipeline; + char *str; + + pipeline = BCON_NEW ("pipeline", + "[", + "{", + "$group", + "{", + "_id", + "$state", + "total_pop", + "{", + "$sum", + "$pop", + "}", + "}", + "}", + "{", + "$match", + "{", + "total_pop", + "{", + "$gte", + BCON_INT32 (10000000), + "}", + "}", + "}", + "]"); + + cursor = mongoc_collection_aggregate (collection, MONGOC_QUERY_NONE, pipeline, NULL, NULL); + + while (mongoc_cursor_next (cursor, &doc)) { + str = bson_as_canonical_extended_json (doc, NULL); + printf ("%s\n", str); + bson_free (str); + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "Cursor Failure: %s\n", error.message); + } + + mongoc_cursor_destroy (cursor); + bson_destroy (pipeline); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost:27017/?appname=aggregation-example"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "zipcodes"); + + print_pipeline (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/basic_aggregation/basic-aggregation.c b/source/docs-libmongoc/includes/examples/basic_aggregation/basic-aggregation.c new file mode 100644 index 00000000..512ed755 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/basic_aggregation/basic-aggregation.c @@ -0,0 +1,125 @@ +/* + * Copyright 2016 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + + +#include "constants.c" + +#include "../doc-common-insert.c" +#include "distinct.c" +#include "map-reduce-basic.c" +#include "map-reduce-advanced.c" + + +int +main (int argc, char *argv[]) +{ + mongoc_database_t *database = NULL; + mongoc_client_t *client = NULL; + mongoc_collection_t *collection = NULL; + mongoc_uri_t *uri = NULL; + bson_error_t error; + char *host_and_port = NULL; + int exit_code = EXIT_FAILURE; + + if (argc != 2) { + fprintf (stderr, "usage: %s CONNECTION-STRING\n", argv[0]); + fprintf (stderr, "the connection string can be of the following forms:\n"); + fprintf (stderr, "localhost\t\t\t\tlocal machine\n"); + fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n"); + fprintf (stderr, + "mongodb://user:pass@localhost:27017\t" + "local machine on port 27017, and authenticate with username " + "user and password pass\n"); + return exit_code; + } + + mongoc_init (); + + if (strncmp (argv[1], "mongodb://", 10) == 0) { + host_and_port = bson_strdup (argv[1]); + } else { + host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]); + } + + uri = mongoc_uri_new_with_error (host_and_port, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + host_and_port, + error.message); + goto cleanup; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto cleanup; + } + + mongoc_client_set_error_api (client, 2); + database = mongoc_client_get_database (client, "test"); + collection = mongoc_database_get_collection (database, COLLECTION_NAME); + + printf ("Inserting data\n"); + if (!insert_data (collection)) { + goto cleanup; + } + + printf ("distinct\n"); + if (!distinct (database)) { + goto cleanup; + } + + printf ("map reduce\n"); + if (!map_reduce_basic (database)) { + goto cleanup; + } + + printf ("more complicated map reduce\n"); + if (!map_reduce_advanced (database)) { + goto cleanup; + } + + exit_code = EXIT_SUCCESS; + +cleanup: + if (collection) { + mongoc_collection_destroy (collection); + } + + if (database) { + mongoc_database_destroy (database); + } + + if (client) { + mongoc_client_destroy (client); + } + + if (uri) { + mongoc_uri_destroy (uri); + } + + if (host_and_port) { + bson_free (host_and_port); + } + + mongoc_cleanup (); + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/basic_aggregation/constants.c b/source/docs-libmongoc/includes/examples/basic_aggregation/constants.c new file mode 100644 index 00000000..cd94fa83 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/basic_aggregation/constants.c @@ -0,0 +1,22 @@ +const char *const COLLECTION_NAME = "things"; + +/* Our map function just emits a single (key, 1) pair for each tag + in the array: */ +const char *const MAPPER = "function () {" + "this.tags.forEach(function(z) {" + "emit(z, 1);" + "});" + "}"; + +/* The reduce function sums over all of the emitted values for a + given key: */ +const char *const REDUCER = "function (key, values) {" + "var total = 0;" + "for (var i = 0; i < values.length; i++) {" + "total += values[i];" + "}" + "return total;" + "}"; +/* Note We can't just return values.length as the reduce function + might be called iteratively on the results of other reduce + steps. */ diff --git a/source/docs-libmongoc/includes/examples/basic_aggregation/distinct.c b/source/docs-libmongoc/includes/examples/basic_aggregation/distinct.c new file mode 100644 index 00000000..14951cc5 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/basic_aggregation/distinct.c @@ -0,0 +1,49 @@ +bool +distinct (mongoc_database_t *database) +{ + bson_t *command; + bson_t reply; + bson_error_t error; + bool res; + bson_iter_t iter; + bson_iter_t array_iter; + double val; + + command = BCON_NEW ("distinct", + BCON_UTF8 (COLLECTION_NAME), + "key", + BCON_UTF8 ("x"), + "query", + "{", + "x", + "{", + "$gt", + BCON_DOUBLE (1.0), + "}", + "}"); + res = mongoc_database_command_simple (database, command, NULL, &reply, &error); + if (!res) { + fprintf (stderr, "Error with distinct: %s\n", error.message); + goto cleanup; + } + + /* Do something with reply (in this case iterate through the values) */ + if (!(bson_iter_init_find (&iter, &reply, "values") && BSON_ITER_HOLDS_ARRAY (&iter) && + bson_iter_recurse (&iter, &array_iter))) { + fprintf (stderr, "Couldn't extract \"values\" field from response\n"); + goto cleanup; + } + + while (bson_iter_next (&array_iter)) { + if (BSON_ITER_HOLDS_DOUBLE (&array_iter)) { + val = bson_iter_double (&array_iter); + printf ("Next double: %f\n", val); + } + } + +cleanup: + /* cleanup */ + bson_destroy (command); + bson_destroy (&reply); + return res; +} diff --git a/source/docs-libmongoc/includes/examples/basic_aggregation/map-reduce-advanced.c b/source/docs-libmongoc/includes/examples/basic_aggregation/map-reduce-advanced.c new file mode 100644 index 00000000..ebc0989d --- /dev/null +++ b/source/docs-libmongoc/includes/examples/basic_aggregation/map-reduce-advanced.c @@ -0,0 +1,46 @@ +bool +map_reduce_advanced (mongoc_database_t *database) +{ + bson_t *command; + bson_error_t error; + bool res = true; + mongoc_cursor_t *cursor; + mongoc_read_prefs_t *read_pref; + const bson_t *doc; + + /* Construct the mapReduce command */ + /* Other arguments can also be specified here, like "query" or "limit" + and so on */ + + /* Read the results inline from a secondary replica */ + command = BCON_NEW ("mapReduce", + BCON_UTF8 (COLLECTION_NAME), + "map", + BCON_CODE (MAPPER), + "reduce", + BCON_CODE (REDUCER), + "out", + "{", + "inline", + "1", + "}"); + + read_pref = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); + cursor = mongoc_database_command (database, MONGOC_QUERY_NONE, 0, 0, 0, command, NULL, read_pref); + + /* Do something with the results */ + while (mongoc_cursor_next (cursor, &doc)) { + print_res (doc); + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "ERROR: %s\n", error.message); + res = false; + } + + mongoc_cursor_destroy (cursor); + mongoc_read_prefs_destroy (read_pref); + bson_destroy (command); + + return res; +} diff --git a/source/docs-libmongoc/includes/examples/basic_aggregation/map-reduce-basic.c b/source/docs-libmongoc/includes/examples/basic_aggregation/map-reduce-basic.c new file mode 100644 index 00000000..72e3d8c8 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/basic_aggregation/map-reduce-basic.c @@ -0,0 +1,67 @@ +bool +map_reduce_basic (mongoc_database_t *database) +{ + bson_t reply; + bool res = false; + bson_error_t error; + mongoc_cursor_t *cursor = NULL; + + bool query_done = false; + + const char *out_collection_name = "outCollection"; + mongoc_collection_t *out_collection = NULL; + + /* Empty find query */ + bson_t find_query = BSON_INITIALIZER; + + /* Construct the mapReduce command */ + + /* Other arguments can also be specified here, like "query" or + "limit" and so on */ + bson_t *const command = BCON_NEW ("mapReduce", + BCON_UTF8 (COLLECTION_NAME), + "map", + BCON_CODE (MAPPER), + "reduce", + BCON_CODE (REDUCER), + "out", + BCON_UTF8 (out_collection_name)); + res = mongoc_database_command_simple (database, command, NULL, &reply, &error); + + if (!res) { + fprintf (stderr, "MapReduce failed: %s\n", error.message); + goto cleanup; + } + + /* Do something with the reply (it doesn't contain the mapReduce results) */ + print_res (&reply); + + /* Now we'll query outCollection to see what the results are */ + out_collection = mongoc_database_get_collection (database, out_collection_name); + cursor = mongoc_collection_find_with_opts (out_collection, &find_query, NULL, NULL); + query_done = true; + + /* Do something with the results */ + const bson_t *doc = NULL; + while (mongoc_cursor_next (cursor, &doc)) { + print_res (doc); + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "ERROR: %s\n", error.message); + res = false; + goto cleanup; + } + +cleanup: + /* cleanup */ + if (query_done) { + mongoc_cursor_destroy (cursor); + mongoc_collection_destroy (out_collection); + } + + bson_destroy (&reply); + bson_destroy (command); + + return res; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk-collation.c b/source/docs-libmongoc/includes/examples/bulk/bulk-collation.c new file mode 100644 index 00000000..2b0f6248 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk-collation.c @@ -0,0 +1,89 @@ +#include +#include + +static void +bulk_collation (mongoc_collection_t *collection) +{ + mongoc_bulk_operation_t *bulk; + bson_t *opts; + bson_t *doc; + bson_t *selector; + bson_t *update; + bson_error_t error; + bson_t reply; + char *str; + uint32_t ret; + + /* insert {_id: "one"} and {_id: "One"} */ + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + doc = BCON_NEW ("_id", BCON_UTF8 ("one")); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + doc = BCON_NEW ("_id", BCON_UTF8 ("One")); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + /* "One" normally sorts before "one"; make "one" come first */ + opts = BCON_NEW ("collation", "{", "locale", BCON_UTF8 ("en_US"), "caseFirst", BCON_UTF8 ("lower"), "}"); + + /* set x=1 on the document with _id "One", which now sorts after "one" */ + update = BCON_NEW ("$set", "{", "x", BCON_INT64 (1), "}"); + selector = BCON_NEW ("_id", "{", "$gt", BCON_UTF8 ("one"), "}"); + mongoc_bulk_operation_update_one_with_opts (bulk, selector, update, opts, &error); + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + bson_destroy (update); + bson_destroy (selector); + bson_destroy (opts); + mongoc_bulk_operation_destroy (bulk); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost/?appname=bulk-collation"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "db", "collection"); + bulk_collation (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk1.c b/source/docs-libmongoc/includes/examples/bulk/bulk1.c new file mode 100644 index 00000000..05810610 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk1.c @@ -0,0 +1,76 @@ +#include +#include +#include + +static void +bulk1 (mongoc_collection_t *collection) +{ + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *doc; + bson_t reply; + char *str; + bool ret; + int i; + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + + for (i = 0; i < 10000; i++) { + doc = BCON_NEW ("i", BCON_INT32 (i)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + } + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + fprintf (stderr, "Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost/?appname=bulk1-example"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "test"); + + bulk1 (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk2.c b/source/docs-libmongoc/includes/examples/bulk/bulk2.c new file mode 100644 index 00000000..c3d9cf70 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk2.c @@ -0,0 +1,107 @@ +#include +#include +#include + +static void +bulk2 (mongoc_collection_t *collection) +{ + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *query; + bson_t *doc; + bson_t *opts; + bson_t reply; + char *str; + bool ret; + int i; + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + + /* Remove everything */ + query = bson_new (); + mongoc_bulk_operation_remove (bulk, query); + bson_destroy (query); + + /* Add a few documents */ + for (i = 1; i < 4; i++) { + doc = BCON_NEW ("_id", BCON_INT32 (i)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + } + + /* {_id: 1} => {$set: {foo: "bar"}} */ + query = BCON_NEW ("_id", BCON_INT32 (1)); + doc = BCON_NEW ("$set", "{", "foo", BCON_UTF8 ("bar"), "}"); + mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, NULL, &error); + bson_destroy (query); + bson_destroy (doc); + + /* {_id: 4} => {'$inc': {'j': 1}} (upsert) */ + opts = BCON_NEW ("upsert", BCON_BOOL (true)); + query = BCON_NEW ("_id", BCON_INT32 (4)); + doc = BCON_NEW ("$inc", "{", "j", BCON_INT32 (1), "}"); + mongoc_bulk_operation_update_many_with_opts (bulk, query, doc, opts, &error); + bson_destroy (query); + bson_destroy (doc); + bson_destroy (opts); + + /* replace {j:1} with {j:2} */ + query = BCON_NEW ("j", BCON_INT32 (1)); + doc = BCON_NEW ("j", BCON_INT32 (2)); + mongoc_bulk_operation_replace_one_with_opts (bulk, query, doc, NULL, &error); + bson_destroy (query); + bson_destroy (doc); + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost/?appname=bulk2-example"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "test"); + + bulk2 (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk3.c b/source/docs-libmongoc/includes/examples/bulk/bulk3.c new file mode 100644 index 00000000..88c513b4 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk3.c @@ -0,0 +1,97 @@ +#include +#include +#include + +static void +bulk3 (mongoc_collection_t *collection) +{ + bson_t opts = BSON_INITIALIZER; + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *query; + bson_t *doc; + bson_t reply; + char *str; + bool ret; + + /* false indicates unordered */ + BSON_APPEND_BOOL (&opts, "ordered", false); + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts); + bson_destroy (&opts); + + /* Add a document */ + doc = BCON_NEW ("_id", BCON_INT32 (1)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + /* remove {_id: 2} */ + query = BCON_NEW ("_id", BCON_INT32 (2)); + mongoc_bulk_operation_remove_one (bulk, query); + bson_destroy (query); + + /* insert {_id: 3} */ + doc = BCON_NEW ("_id", BCON_INT32 (3)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + /* replace {_id:4} {'i': 1} */ + query = BCON_NEW ("_id", BCON_INT32 (4)); + doc = BCON_NEW ("i", BCON_INT32 (1)); + mongoc_bulk_operation_replace_one (bulk, query, doc, false); + bson_destroy (query); + bson_destroy (doc); + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); + bson_destroy (&opts); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost/?appname=bulk3-example"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "test"); + + bulk3 (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk4.c b/source/docs-libmongoc/includes/examples/bulk/bulk4.c new file mode 100644 index 00000000..d0f43e9f --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk4.c @@ -0,0 +1,87 @@ +#include +#include +#include + +static void +bulk4 (mongoc_collection_t *collection) +{ + bson_t opts = BSON_INITIALIZER; + mongoc_write_concern_t *wc; + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *doc; + bson_t reply; + char *str; + bool ret; + + wc = mongoc_write_concern_new (); + mongoc_write_concern_set_w (wc, 4); + mongoc_write_concern_set_wtimeout_int64 (wc, 100); /* milliseconds */ + mongoc_write_concern_append (wc, &opts); + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts); + + /* Two inserts */ + doc = BCON_NEW ("_id", BCON_INT32 (10)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + doc = BCON_NEW ("_id", BCON_INT32 (11)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); + mongoc_write_concern_destroy (wc); + bson_destroy (&opts); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost/?appname=bulk4-example"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "test"); + + bulk4 (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk5.c b/source/docs-libmongoc/includes/examples/bulk/bulk5.c new file mode 100644 index 00000000..9fad7a3c --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk5.c @@ -0,0 +1,133 @@ +#include +#include +#include + +static void +bulk5_fail (mongoc_collection_t *collection) +{ + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *doc; + bson_t reply; + char *str; + bool ret; + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + + /* Two inserts */ + doc = BCON_NEW ("_id", BCON_INT32 (31)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + doc = BCON_NEW ("_id", BCON_INT32 (32)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + /* The above documents do not comply to the schema validation rules + * we created previously, so this will result in an error */ + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); +} + +static void +bulk5_success (mongoc_collection_t *collection) +{ + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *doc; + bson_t reply; + char *str; + bool ret; + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + + /* Allow this document to bypass document validation. + * NOTE: When authentication is enabled, the authenticated user must have + * either the "dbadmin" or "restore" roles to bypass document validation */ + mongoc_bulk_operation_set_bypass_document_validation (bulk, true); + + /* Two inserts */ + doc = BCON_NEW ("_id", BCON_INT32 (31)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + doc = BCON_NEW ("_id", BCON_INT32 (32)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); +} + +int +main (void) +{ + bson_t *options; + bson_error_t error; + mongoc_client_t *client; + mongoc_collection_t *collection; + mongoc_database_t *database; + const char *uri_string = "mongodb://localhost/?appname=bulk5-example"; + mongoc_uri_t *uri; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + database = mongoc_client_get_database (client, "testasdf"); + + /* Create schema validator */ + options = BCON_NEW ("validator", "{", "number", "{", "$gte", BCON_INT32 (5), "}", "}"); + collection = mongoc_database_create_collection (database, "collname", options, &error); + + if (collection) { + bulk5_fail (collection); + bulk5_success (collection); + mongoc_collection_destroy (collection); + } else { + fprintf (stderr, "Couldn't create collection: '%s'\n", error.message); + } + + bson_free (options); + mongoc_uri_destroy (uri); + mongoc_database_destroy (database); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/bulk/bulk6.c b/source/docs-libmongoc/includes/examples/bulk/bulk6.c new file mode 100644 index 00000000..c904f29c --- /dev/null +++ b/source/docs-libmongoc/includes/examples/bulk/bulk6.c @@ -0,0 +1,85 @@ +#include +#include + +static void +bulk6 (mongoc_collection_t *collection) +{ + bson_t opts = BSON_INITIALIZER; + mongoc_write_concern_t *wc; + mongoc_bulk_operation_t *bulk; + bson_error_t error; + bson_t *doc; + bson_t *selector; + bson_t reply; + char *str; + bool ret; + + wc = mongoc_write_concern_new (); + mongoc_write_concern_set_w (wc, 0); + mongoc_write_concern_append (wc, &opts); + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, &opts); + + doc = BCON_NEW ("_id", BCON_INT32 (10)); + mongoc_bulk_operation_insert (bulk, doc); + bson_destroy (doc); + + selector = BCON_NEW ("_id", BCON_INT32 (11)); + mongoc_bulk_operation_remove_one (bulk, selector); + bson_destroy (selector); + + ret = mongoc_bulk_operation_execute (bulk, &reply, &error); + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + if (!ret) { + printf ("Error: %s\n", error.message); + } + + bson_destroy (&reply); + mongoc_bulk_operation_destroy (bulk); + mongoc_write_concern_destroy (wc); + bson_destroy (&opts); +} + +int +main (void) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + const char *uri_string = "mongodb://localhost/?appname=bulk6-example"; + mongoc_uri_t *uri; + bson_error_t error; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "test"); + + bulk6 (collection); + + mongoc_uri_destroy (uri); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-auto-decryption.c b/source/docs-libmongoc/includes/examples/client-side-encryption-auto-decryption.c new file mode 100644 index 00000000..016cdca6 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-auto-decryption.c @@ -0,0 +1,209 @@ +#include +#include +#include + +#include "client-side-encryption-helpers.h" + +/* This example demonstrates how to set up automatic decryption without + * automatic encryption using the community version of MongoDB */ +int +main (void) +{ +/* The collection used to store the encryption data keys. */ +#define KEYVAULT_DB "encryption" +#define KEYVAULT_COLL "__libmongocTestKeyVault" +/* The collection used to store the encrypted documents in this example. */ +#define ENCRYPTED_DB "test" +#define ENCRYPTED_COLL "coll" + + int exit_status = EXIT_FAILURE; + bool ret; + uint8_t *local_masterkey = NULL; + uint32_t local_masterkey_len; + bson_t *kms_providers = NULL; + bson_error_t error = {0}; + bson_t *index_keys = NULL; + bson_t *index_opts = NULL; + mongoc_index_model_t *index_model = NULL; + bson_t *schema = NULL; + mongoc_client_t *client = NULL; + mongoc_collection_t *coll = NULL; + mongoc_collection_t *keyvault_coll = NULL; + bson_t *to_insert = NULL; + bson_t *create_cmd = NULL; + bson_t *create_cmd_opts = NULL; + mongoc_write_concern_t *wc = NULL; + mongoc_client_encryption_t *client_encryption = NULL; + mongoc_client_encryption_opts_t *client_encryption_opts = NULL; + mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; + char *keyaltnames[] = {"mongoc_encryption_example_4"}; + bson_value_t datakey_id = {0}; + bson_value_t encrypted_field = {0}; + bson_value_t to_encrypt = {0}; + mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL; + bson_value_t decrypted = {0}; + mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL; + mongoc_client_t *unencrypted_client = NULL; + mongoc_collection_t *unencrypted_coll = NULL; + + mongoc_init (); + + /* Configure the master key. This must be the same master key that was used + * to create the encryption key. */ + local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); + if (!local_masterkey || local_masterkey_len != 96) { + fprintf (stderr, + "Specify LOCAL_MASTERKEY environment variable as a " + "secure random 96 byte hex value.\n"); + goto fail; + } + + kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); + + client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); + auto_encryption_opts = mongoc_auto_encryption_opts_new (); + mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts, kms_providers); + + /* Setting bypass_auto_encryption to true disables automatic encryption but + * keeps the automatic decryption behavior. bypass_auto_encryption will also + * disable spawning mongocryptd */ + mongoc_auto_encryption_opts_set_bypass_auto_encryption (auto_encryption_opts, true); + + /* Once bypass_auto_encryption is set, community users can enable auto + * encryption on the client. This will, in fact, only perform automatic + * decryption. */ + ret = mongoc_client_enable_auto_encryption (client, auto_encryption_opts, &error); + if (!ret) { + goto fail; + } + + /* Now that automatic decryption is on, we can test it by inserting a + * document with an explicitly encrypted value into the collection. When we + * look up the document later, it should be automatically decrypted for us. + */ + coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); + + /* Clear old data */ + mongoc_collection_drop (coll, NULL); + + /* Set up the key vault for this example. */ + keyvault_coll = mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_collection_drop (keyvault_coll, NULL); + + /* Create a unique index to ensure that two data keys cannot share the same + * keyAltName. This is recommended practice for the key vault. */ + index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); + index_opts = BCON_NEW ("unique", + BCON_BOOL (true), + "partialFilterExpression", + "{", + "keyAltNames", + "{", + "$exists", + BCON_BOOL (true), + "}", + "}"); + index_model = mongoc_index_model_new (index_keys, index_opts); + ret = mongoc_collection_create_indexes_with_opts ( + keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); + + if (!ret) { + goto fail; + } + + client_encryption_opts = mongoc_client_encryption_opts_new (); + mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); + mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); + + /* The key vault client is used for reading to/from the key vault. This can + * be the same mongoc_client_t used by the application. */ + mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, client); + client_encryption = mongoc_client_encryption_new (client_encryption_opts, &error); + if (!client_encryption) { + goto fail; + } + + /* Create a new data key for the encryptedField. + * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules + */ + datakey_opts = mongoc_client_encryption_datakey_opts_new (); + mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); + ret = mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, &error); + if (!ret) { + goto fail; + } + + /* Explicitly encrypt a field. */ + encrypt_opts = mongoc_client_encryption_encrypt_opts_new (); + mongoc_client_encryption_encrypt_opts_set_algorithm (encrypt_opts, + MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC); + mongoc_client_encryption_encrypt_opts_set_keyaltname (encrypt_opts, "mongoc_encryption_example_4"); + to_encrypt.value_type = BSON_TYPE_UTF8; + to_encrypt.value.v_utf8.str = "123456789"; + const size_t len = strlen (to_encrypt.value.v_utf8.str); + BSON_ASSERT (bson_in_range_unsigned (uint32_t, len)); + to_encrypt.value.v_utf8.len = (uint32_t) len; + + ret = mongoc_client_encryption_encrypt (client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error); + if (!ret) { + goto fail; + } + + to_insert = bson_new (); + BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field); + ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); + if (!ret) { + goto fail; + } + + /* When we retrieve the document, any encrypted fields will get automatically + * decrypted by the driver. */ + printf ("decrypted document: "); + if (!print_one_document (coll, &error)) { + goto fail; + } + printf ("\n"); + + unencrypted_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); + unencrypted_coll = mongoc_client_get_collection (unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL); + + printf ("encrypted document: "); + if (!print_one_document (unencrypted_coll, &error)) { + goto fail; + } + printf ("\n"); + + exit_status = EXIT_SUCCESS; +fail: + if (error.code) { + fprintf (stderr, "error: %s\n", error.message); + } + + bson_free (local_masterkey); + bson_destroy (kms_providers); + mongoc_collection_destroy (keyvault_coll); + mongoc_index_model_destroy (index_model); + bson_destroy (index_opts); + bson_destroy (index_keys); + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + bson_destroy (to_insert); + bson_destroy (schema); + bson_destroy (create_cmd); + bson_destroy (create_cmd_opts); + mongoc_write_concern_destroy (wc); + mongoc_client_encryption_destroy (client_encryption); + mongoc_client_encryption_datakey_opts_destroy (datakey_opts); + mongoc_client_encryption_opts_destroy (client_encryption_opts); + bson_value_destroy (&encrypted_field); + mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts); + bson_value_destroy (&decrypted); + bson_value_destroy (&datakey_id); + mongoc_collection_destroy (unencrypted_coll); + mongoc_client_destroy (unencrypted_client); + mongoc_auto_encryption_opts_destroy (auto_encryption_opts); + + mongoc_cleanup (); + return exit_status; +} diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-doc-snippets.c b/source/docs-libmongoc/includes/examples/client-side-encryption-doc-snippets.c new file mode 100644 index 00000000..f4d08aab --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-doc-snippets.c @@ -0,0 +1,41 @@ +#include +#include +#include + +/* Includes code snippets for RST documentation. */ +int +main (void) +{ + mongoc_init (); + + { + /* BEGIN:mongoc_auto_encryption_opts_set_tls_opts. */ + mongoc_auto_encryption_opts_t *ae_opts = mongoc_auto_encryption_opts_new (); + bson_t *tls_opts = bson_new (); + + BCON_APPEND (tls_opts, "kmip", "{", MONGOC_URI_TLSCAFILE, "ca1.pem", "}"); + BCON_APPEND (tls_opts, "aws", "{", MONGOC_URI_TLSCAFILE, "ca2.pem", "}"); + mongoc_auto_encryption_opts_set_tls_opts (ae_opts, tls_opts); + /* END:mongoc_auto_encryption_opts_set_tls_opts. */ + + bson_destroy (tls_opts); + mongoc_auto_encryption_opts_destroy (ae_opts); + } + + { + /* BEGIN:mongoc_client_encryption_opts_set_tls_opts. */ + mongoc_client_encryption_opts_t *ce_opts = mongoc_client_encryption_opts_new (); + bson_t *tls_opts = bson_new (); + + BCON_APPEND (tls_opts, "kmip", "{", MONGOC_URI_TLSCAFILE, "ca1.pem", "}"); + BCON_APPEND (tls_opts, "aws", "{", MONGOC_URI_TLSCAFILE, "ca2.pem", "}"); + mongoc_client_encryption_opts_set_tls_opts (ce_opts, tls_opts); + /* END:mongoc_client_encryption_opts_set_tls_opts. */ + + bson_destroy (tls_opts); + mongoc_client_encryption_opts_destroy (ce_opts); + } + + mongoc_cleanup (); + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-explicit.c b/source/docs-libmongoc/includes/examples/client-side-encryption-explicit.c new file mode 100644 index 00000000..4bf23588 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-explicit.c @@ -0,0 +1,178 @@ +#include +#include +#include + +#include "client-side-encryption-helpers.h" + +/* This example demonstrates how to use explicit encryption and decryption using + * the community version of MongoDB */ +int +main (void) +{ +/* The collection used to store the encryption data keys. */ +#define KEYVAULT_DB "encryption" +#define KEYVAULT_COLL "__libmongocTestKeyVault" +/* The collection used to store the encrypted documents in this example. */ +#define ENCRYPTED_DB "test" +#define ENCRYPTED_COLL "coll" + + int exit_status = EXIT_FAILURE; + bool ret; + uint8_t *local_masterkey = NULL; + uint32_t local_masterkey_len; + bson_t *kms_providers = NULL; + bson_error_t error = {0}; + bson_t *index_keys = NULL; + bson_t *index_opts = NULL; + mongoc_index_model_t *index_model = NULL; + bson_t *schema = NULL; + mongoc_client_t *client = NULL; + mongoc_collection_t *coll = NULL; + mongoc_collection_t *keyvault_coll = NULL; + bson_t *to_insert = NULL; + bson_t *create_cmd = NULL; + bson_t *create_cmd_opts = NULL; + mongoc_write_concern_t *wc = NULL; + mongoc_client_encryption_t *client_encryption = NULL; + mongoc_client_encryption_opts_t *client_encryption_opts = NULL; + mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; + char *keyaltnames[] = {"mongoc_encryption_example_3"}; + bson_value_t datakey_id = {0}; + bson_value_t encrypted_field = {0}; + bson_value_t to_encrypt = {0}; + mongoc_client_encryption_encrypt_opts_t *encrypt_opts = NULL; + bson_value_t decrypted = {0}; + + mongoc_init (); + + /* Configure the master key. This must be the same master key that was used + * to create the encryption key. */ + local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); + if (!local_masterkey || local_masterkey_len != 96) { + fprintf (stderr, + "Specify LOCAL_MASTERKEY environment variable as a " + "secure random 96 byte hex value.\n"); + goto fail; + } + + kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); + + /* The mongoc_client_t used to read/write application data. */ + client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); + coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); + + /* Clear old data */ + mongoc_collection_drop (coll, NULL); + + /* Set up the key vault for this example. */ + keyvault_coll = mongoc_client_get_collection (client, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_collection_drop (keyvault_coll, NULL); + + /* Create a unique index to ensure that two data keys cannot share the same + * keyAltName. This is recommended practice for the key vault. */ + index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); + index_opts = BCON_NEW ("unique", + BCON_BOOL (true), + "partialFilterExpression", + "{", + "keyAltNames", + "{", + "$exists", + BCON_BOOL (true), + "}", + "}"); + index_model = mongoc_index_model_new (index_keys, index_opts); + ret = mongoc_collection_create_indexes_with_opts ( + keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); + + if (!ret) { + goto fail; + } + + client_encryption_opts = mongoc_client_encryption_opts_new (); + mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); + mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); + + /* Set a mongoc_client_t to use for reading/writing to the key vault. This + * can be the same mongoc_client_t used by the main application. */ + mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, client); + client_encryption = mongoc_client_encryption_new (client_encryption_opts, &error); + if (!client_encryption) { + goto fail; + } + + /* Create a new data key for the encryptedField. + * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules + */ + datakey_opts = mongoc_client_encryption_datakey_opts_new (); + mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); + if (!mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, &error)) { + goto fail; + } + + /* Explicitly encrypt a field */ + encrypt_opts = mongoc_client_encryption_encrypt_opts_new (); + mongoc_client_encryption_encrypt_opts_set_algorithm (encrypt_opts, + MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC); + mongoc_client_encryption_encrypt_opts_set_keyid (encrypt_opts, &datakey_id); + to_encrypt.value_type = BSON_TYPE_UTF8; + to_encrypt.value.v_utf8.str = "123456789"; + const size_t len = strlen (to_encrypt.value.v_utf8.str); + BSON_ASSERT (bson_in_range_unsigned (uint32_t, len)); + to_encrypt.value.v_utf8.len = (uint32_t) len; + + ret = mongoc_client_encryption_encrypt (client_encryption, &to_encrypt, encrypt_opts, &encrypted_field, &error); + if (!ret) { + goto fail; + } + + to_insert = bson_new (); + BSON_APPEND_VALUE (to_insert, "encryptedField", &encrypted_field); + ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); + if (!ret) { + goto fail; + } + + printf ("encrypted document: "); + if (!print_one_document (coll, &error)) { + goto fail; + } + printf ("\n"); + + /* Explicitly decrypt a field */ + ret = mongoc_client_encryption_decrypt (client_encryption, &encrypted_field, &decrypted, &error); + if (!ret) { + goto fail; + } + printf ("decrypted value: %s\n", decrypted.value.v_utf8.str); + + exit_status = EXIT_SUCCESS; +fail: + if (error.code) { + fprintf (stderr, "error: %s\n", error.message); + } + + bson_free (local_masterkey); + bson_destroy (kms_providers); + mongoc_collection_destroy (keyvault_coll); + mongoc_index_model_destroy (index_model); + bson_destroy (index_opts); + bson_destroy (index_keys); + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + bson_destroy (to_insert); + bson_destroy (schema); + bson_destroy (create_cmd); + bson_destroy (create_cmd_opts); + mongoc_write_concern_destroy (wc); + mongoc_client_encryption_destroy (client_encryption); + mongoc_client_encryption_datakey_opts_destroy (datakey_opts); + mongoc_client_encryption_opts_destroy (client_encryption_opts); + bson_value_destroy (&encrypted_field); + mongoc_client_encryption_encrypt_opts_destroy (encrypt_opts); + bson_value_destroy (&decrypted); + bson_value_destroy (&datakey_id); + + mongoc_cleanup (); + return exit_status; +} diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-helpers.c b/source/docs-libmongoc/includes/examples/client-side-encryption-helpers.c new file mode 100644 index 00000000..3e917c19 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-helpers.c @@ -0,0 +1,63 @@ +#include "client-side-encryption-helpers.h" + +uint8_t * +hex_to_bin (const char *hex, uint32_t *len) +{ + if (!hex) { + *len = 0; + return NULL; + } + const size_t hex_len = strlen (hex); + if (hex_len % 2 != 0) { + *len = 0; + return NULL; + } + + if (!bson_in_range_unsigned (uint32_t, hex_len / 2u)) { + return NULL; + } + + *len = (uint32_t) (hex_len / 2u); + uint8_t *const out = bson_malloc0 (*len); + + for (size_t i = 0u; i < hex_len; i += 2u) { + uint32_t hex_char; + + if (1 != sscanf (hex + i, "%2x", &hex_char)) { + bson_free (out); + *len = 0; + return NULL; + } + out[i / 2u] = (uint8_t) hex_char; + } + return out; +} + +bool +print_one_document (mongoc_collection_t *coll, bson_error_t *error) +{ + bool ret = false; + mongoc_cursor_t *cursor = NULL; + const bson_t *found; + bson_t *filter = NULL; + char *as_string = NULL; + + filter = bson_new (); + cursor = mongoc_collection_find_with_opts (coll, filter, NULL /* opts */, NULL /* read prefs */); + if (!mongoc_cursor_next (cursor, &found)) { + fprintf (stderr, "error: did not find inserted document\n"); + goto fail; + } + if (mongoc_cursor_error (cursor, error)) { + goto fail; + } + as_string = bson_as_canonical_extended_json (found, NULL); + printf ("%s", as_string); + + ret = true; +fail: + bson_destroy (filter); + mongoc_cursor_destroy (cursor); + bson_free (as_string); + return ret; +} diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-helpers.h b/source/docs-libmongoc/includes/examples/client-side-encryption-helpers.h new file mode 100644 index 00000000..6b02225d --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-helpers.h @@ -0,0 +1,16 @@ +#ifndef CLIENT_SIDE_ENCRYPTION_HELPERS +#define CLIENT_SIDE_ENCRYPTION_HELPERS + +#include + +/* Helper method to find a single document in the given collection and print it +to stdout */ +bool +print_one_document (mongoc_collection_t *coll, bson_error_t *error); + +/* hex_to_bin parses a hexadecimal string to an array of bytes. `NULL` is + * returned on error. `len` is set to the number of bytes written. */ +uint8_t * +hex_to_bin (const char *hex, uint32_t *len); + +#endif diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-schema-map.c b/source/docs-libmongoc/includes/examples/client-side-encryption-schema-map.c new file mode 100644 index 00000000..cdee3a6a --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-schema-map.c @@ -0,0 +1,256 @@ +#include +#include +#include + +#include "client-side-encryption-helpers.h" + +/* Helper method to create a new data key in the key vault, a schema to use that + * key, and writes the schema to a file for later use. */ +static bool +create_schema_file (bson_t *kms_providers, + const char *keyvault_db, + const char *keyvault_coll, + mongoc_client_t *keyvault_client, + bson_error_t *error) +{ + mongoc_client_encryption_t *client_encryption = NULL; + mongoc_client_encryption_opts_t *client_encryption_opts = NULL; + mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; + bson_value_t datakey_id = {0}; + char *keyaltnames[] = {"mongoc_encryption_example_1"}; + bson_t *schema = NULL; + char *schema_string = NULL; + size_t schema_string_len; + FILE *outfile = NULL; + bool ret = false; + + client_encryption_opts = mongoc_client_encryption_opts_new (); + mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); + mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, keyvault_db, keyvault_coll); + mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, keyvault_client); + + client_encryption = mongoc_client_encryption_new (client_encryption_opts, error); + if (!client_encryption) { + goto fail; + } + + /* Create a new data key and json schema for the encryptedField. + * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules + */ + datakey_opts = mongoc_client_encryption_datakey_opts_new (); + mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); + if (!mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, error)) { + goto fail; + } + + /* Create a schema describing that "encryptedField" is a string encrypted + * with the newly created data key using deterministic encryption. */ + schema = BCON_NEW ( + "properties", + "{", + "encryptedField", + "{", + "encrypt", + "{", + "keyId", + "[", + BCON_BIN (datakey_id.value.v_binary.subtype, datakey_id.value.v_binary.data, datakey_id.value.v_binary.data_len), + "]", + "bsonType", + "string", + "algorithm", + MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, + "}", + "}", + "}", + "bsonType", + "object"); + + /* Use canonical JSON so that other drivers and tools will be + * able to parse the MongoDB extended JSON file. */ + schema_string = bson_as_canonical_extended_json (schema, &schema_string_len); + outfile = fopen ("jsonSchema.json", "w"); + if (0 == fwrite (schema_string, sizeof (char), schema_string_len, outfile)) { + fprintf (stderr, "failed to write to file\n"); + goto fail; + } + + ret = true; +fail: + mongoc_client_encryption_destroy (client_encryption); + mongoc_client_encryption_datakey_opts_destroy (datakey_opts); + mongoc_client_encryption_opts_destroy (client_encryption_opts); + bson_free (schema_string); + bson_destroy (schema); + bson_value_destroy (&datakey_id); + if (outfile) { + fclose (outfile); + } + return ret; +} + +/* This example demonstrates how to use automatic encryption with a client-side + * schema map using the enterprise version of MongoDB */ +int +main (void) +{ +/* The collection used to store the encryption data keys. */ +#define KEYVAULT_DB "encryption" +#define KEYVAULT_COLL "__libmongocTestKeyVault" +/* The collection used to store the encrypted documents in this example. */ +#define ENCRYPTED_DB "test" +#define ENCRYPTED_COLL "coll" + + int exit_status = EXIT_FAILURE; + bool ret; + uint8_t *local_masterkey = NULL; + uint32_t local_masterkey_len; + bson_t *kms_providers = NULL; + bson_error_t error = {0}; + bson_t *index_keys = NULL; + bson_t *index_opts = NULL; + mongoc_index_model_t *index_model = NULL; + bson_json_reader_t *reader = NULL; + bson_t schema = BSON_INITIALIZER; + bson_t *schema_map = NULL; + + /* The MongoClient used to access the key vault (keyvault_namespace). */ + mongoc_client_t *keyvault_client = NULL; + mongoc_collection_t *keyvault_coll = NULL; + mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL; + mongoc_client_t *client = NULL; + mongoc_collection_t *coll = NULL; + bson_t *to_insert = NULL; + mongoc_client_t *unencrypted_client = NULL; + mongoc_collection_t *unencrypted_coll = NULL; + + mongoc_init (); + + /* Configure the master key. This must be the same master key that was used + * to create the encryption key. */ + local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); + if (!local_masterkey || local_masterkey_len != 96) { + fprintf (stderr, + "Specify LOCAL_MASTERKEY environment variable as a " + "secure random 96 byte hex value.\n"); + goto fail; + } + + kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); + + /* Set up the key vault for this example. */ + keyvault_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-keyvault"); + BSON_ASSERT (keyvault_client); + + keyvault_coll = mongoc_client_get_collection (keyvault_client, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_collection_drop (keyvault_coll, NULL); + + /* Create a unique index to ensure that two data keys cannot share the same + * keyAltName. This is recommended practice for the key vault. */ + index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); + index_opts = BCON_NEW ("unique", + BCON_BOOL (true), + "partialFilterExpression", + "{", + "keyAltNames", + "{", + "$exists", + BCON_BOOL (true), + "}", + "}"); + index_model = mongoc_index_model_new (index_keys, index_opts); + ret = mongoc_collection_create_indexes_with_opts ( + keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); + + if (!ret) { + goto fail; + } + + /* Create a new data key and a schema using it for encryption. Save the + * schema to the file jsonSchema.json */ + ret = create_schema_file (kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error); + + if (!ret) { + goto fail; + } + + /* Load the JSON Schema and construct the local schema_map option. */ + reader = bson_json_reader_new_from_file ("jsonSchema.json", &error); + if (!reader) { + goto fail; + } + + bson_json_reader_read (reader, &schema, &error); + + /* Construct the schema map, mapping the namespace of the collection to the + * schema describing encryption. */ + schema_map = BCON_NEW (ENCRYPTED_DB "." ENCRYPTED_COLL, BCON_DOCUMENT (&schema)); + + auto_encryption_opts = mongoc_auto_encryption_opts_new (); + mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts, keyvault_client); + mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts, kms_providers); + mongoc_auto_encryption_opts_set_schema_map (auto_encryption_opts, schema_map); + + client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); + BSON_ASSERT (client); + + /* Enable automatic encryption. It will determine that encryption is + * necessary from the schema map instead of relying on the server to provide + * a schema. */ + ret = mongoc_client_enable_auto_encryption (client, auto_encryption_opts, &error); + if (!ret) { + goto fail; + } + + coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); + + /* Clear old data */ + mongoc_collection_drop (coll, NULL); + + to_insert = BCON_NEW ("encryptedField", "123456789"); + ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); + if (!ret) { + goto fail; + } + printf ("decrypted document: "); + if (!print_one_document (coll, &error)) { + goto fail; + } + printf ("\n"); + + unencrypted_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-unencrypted"); + BSON_ASSERT (unencrypted_client); + + unencrypted_coll = mongoc_client_get_collection (unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL); + printf ("encrypted document: "); + if (!print_one_document (unencrypted_coll, &error)) { + goto fail; + } + printf ("\n"); + + exit_status = EXIT_SUCCESS; +fail: + if (error.code) { + fprintf (stderr, "error: %s\n", error.message); + } + + bson_free (local_masterkey); + bson_destroy (kms_providers); + mongoc_collection_destroy (keyvault_coll); + mongoc_index_model_destroy (index_model); + bson_destroy (index_opts); + bson_destroy (index_keys); + bson_json_reader_destroy (reader); + mongoc_auto_encryption_opts_destroy (auto_encryption_opts); + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + bson_destroy (to_insert); + mongoc_collection_destroy (unencrypted_coll); + mongoc_client_destroy (unencrypted_client); + mongoc_client_destroy (keyvault_client); + bson_destroy (&schema); + bson_destroy (schema_map); + mongoc_cleanup (); + return exit_status; +} diff --git a/source/docs-libmongoc/includes/examples/client-side-encryption-server-schema.c b/source/docs-libmongoc/includes/examples/client-side-encryption-server-schema.c new file mode 100644 index 00000000..0595a5c9 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/client-side-encryption-server-schema.c @@ -0,0 +1,245 @@ +#include +#include +#include + +#include "client-side-encryption-helpers.h" + +/* Helper method to create and return a JSON schema to use for encryption. +The caller will use the returned schema for server-side encryption validation. +*/ +static bson_t * +create_schema (bson_t *kms_providers, + const char *keyvault_db, + const char *keyvault_coll, + mongoc_client_t *keyvault_client, + bson_error_t *error) +{ + mongoc_client_encryption_t *client_encryption = NULL; + mongoc_client_encryption_opts_t *client_encryption_opts = NULL; + mongoc_client_encryption_datakey_opts_t *datakey_opts = NULL; + bson_value_t datakey_id = {0}; + char *keyaltnames[] = {"mongoc_encryption_example_2"}; + bson_t *schema = NULL; + + client_encryption_opts = mongoc_client_encryption_opts_new (); + mongoc_client_encryption_opts_set_kms_providers (client_encryption_opts, kms_providers); + mongoc_client_encryption_opts_set_keyvault_namespace (client_encryption_opts, keyvault_db, keyvault_coll); + mongoc_client_encryption_opts_set_keyvault_client (client_encryption_opts, keyvault_client); + + client_encryption = mongoc_client_encryption_new (client_encryption_opts, error); + if (!client_encryption) { + goto fail; + } + + /* Create a new data key and json schema for the encryptedField. + * https://dochub.mongodb.org/core/client-side-field-level-encryption-automatic-encryption-rules + */ + datakey_opts = mongoc_client_encryption_datakey_opts_new (); + mongoc_client_encryption_datakey_opts_set_keyaltnames (datakey_opts, keyaltnames, 1); + if (!mongoc_client_encryption_create_datakey (client_encryption, "local", datakey_opts, &datakey_id, error)) { + goto fail; + } + + /* Create a schema describing that "encryptedField" is a string encrypted + * with the newly created data key using deterministic encryption. */ + schema = BCON_NEW ( + "properties", + "{", + "encryptedField", + "{", + "encrypt", + "{", + "keyId", + "[", + BCON_BIN (datakey_id.value.v_binary.subtype, datakey_id.value.v_binary.data, datakey_id.value.v_binary.data_len), + "]", + "bsonType", + "string", + "algorithm", + MONGOC_AEAD_AES_256_CBC_HMAC_SHA_512_DETERMINISTIC, + "}", + "}", + "}", + "bsonType", + "object"); + +fail: + mongoc_client_encryption_destroy (client_encryption); + mongoc_client_encryption_datakey_opts_destroy (datakey_opts); + mongoc_client_encryption_opts_destroy (client_encryption_opts); + bson_value_destroy (&datakey_id); + return schema; +} + +/* This example demonstrates how to use automatic encryption with a server-side + * schema using the enterprise version of MongoDB */ +int +main (void) +{ +/* The collection used to store the encryption data keys. */ +#define KEYVAULT_DB "encryption" +#define KEYVAULT_COLL "__libmongocTestKeyVault" +/* The collection used to store the encrypted documents in this example. */ +#define ENCRYPTED_DB "test" +#define ENCRYPTED_COLL "coll" + + int exit_status = EXIT_FAILURE; + bool ret; + uint8_t *local_masterkey = NULL; + uint32_t local_masterkey_len; + bson_t *kms_providers = NULL; + bson_error_t error = {0}; + bson_t *index_keys = NULL; + bson_t *index_opts = NULL; + mongoc_index_model_t *index_model = NULL; + bson_json_reader_t *reader = NULL; + bson_t *schema = NULL; + + /* The MongoClient used to access the key vault (keyvault_namespace). */ + mongoc_client_t *keyvault_client = NULL; + mongoc_collection_t *keyvault_coll = NULL; + mongoc_auto_encryption_opts_t *auto_encryption_opts = NULL; + mongoc_client_t *client = NULL; + mongoc_collection_t *coll = NULL; + bson_t *to_insert = NULL; + mongoc_client_t *unencrypted_client = NULL; + mongoc_collection_t *unencrypted_coll = NULL; + bson_t *create_cmd = NULL; + bson_t *create_cmd_opts = NULL; + mongoc_write_concern_t *wc = NULL; + + mongoc_init (); + + /* Configure the master key. This must be the same master key that was used + * to create + * the encryption key. */ + local_masterkey = hex_to_bin (getenv ("LOCAL_MASTERKEY"), &local_masterkey_len); + if (!local_masterkey || local_masterkey_len != 96) { + fprintf (stderr, + "Specify LOCAL_MASTERKEY environment variable as a " + "secure random 96 byte hex value.\n"); + goto fail; + } + + kms_providers = BCON_NEW ("local", "{", "key", BCON_BIN (0, local_masterkey, local_masterkey_len), "}"); + + /* Set up the key vault for this example. */ + keyvault_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-keyvault"); + BSON_ASSERT (keyvault_client); + + keyvault_coll = mongoc_client_get_collection (keyvault_client, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_collection_drop (keyvault_coll, NULL); + + /* Create a unique index to ensure that two data keys cannot share the same + * keyAltName. This is recommended practice for the key vault. */ + index_keys = BCON_NEW ("keyAltNames", BCON_INT32 (1)); + index_opts = BCON_NEW ("unique", + BCON_BOOL (true), + "partialFilterExpression", + "{", + "keyAltNames", + "{", + "$exists", + BCON_BOOL (true), + "}", + "}"); + index_model = mongoc_index_model_new (index_keys, index_opts); + ret = mongoc_collection_create_indexes_with_opts ( + keyvault_coll, &index_model, 1, NULL /* opts */, NULL /* reply */, &error); + + if (!ret) { + goto fail; + } + + auto_encryption_opts = mongoc_auto_encryption_opts_new (); + mongoc_auto_encryption_opts_set_keyvault_client (auto_encryption_opts, keyvault_client); + mongoc_auto_encryption_opts_set_keyvault_namespace (auto_encryption_opts, KEYVAULT_DB, KEYVAULT_COLL); + mongoc_auto_encryption_opts_set_kms_providers (auto_encryption_opts, kms_providers); + schema = create_schema (kms_providers, KEYVAULT_DB, KEYVAULT_COLL, keyvault_client, &error); + + if (!schema) { + goto fail; + } + + client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption"); + BSON_ASSERT (client); + + ret = mongoc_client_enable_auto_encryption (client, auto_encryption_opts, &error); + if (!ret) { + goto fail; + } + + coll = mongoc_client_get_collection (client, ENCRYPTED_DB, ENCRYPTED_COLL); + + /* Clear old data */ + mongoc_collection_drop (coll, NULL); + + /* Create the collection with the encryption JSON Schema. */ + create_cmd = BCON_NEW ("create", ENCRYPTED_COLL, "validator", "{", "$jsonSchema", BCON_DOCUMENT (schema), "}"); + wc = mongoc_write_concern_new (); + mongoc_write_concern_set_wmajority (wc, 0); + create_cmd_opts = bson_new (); + mongoc_write_concern_append (wc, create_cmd_opts); + ret = mongoc_client_command_with_opts ( + client, ENCRYPTED_DB, create_cmd, NULL /* read prefs */, create_cmd_opts, NULL /* reply */, &error); + if (!ret) { + goto fail; + } + + to_insert = BCON_NEW ("encryptedField", "123456789"); + ret = mongoc_collection_insert_one (coll, to_insert, NULL /* opts */, NULL /* reply */, &error); + if (!ret) { + goto fail; + } + printf ("decrypted document: "); + if (!print_one_document (coll, &error)) { + goto fail; + } + printf ("\n"); + + unencrypted_client = mongoc_client_new ("mongodb://localhost/?appname=client-side-encryption-unencrypted"); + BSON_ASSERT (unencrypted_client); + + unencrypted_coll = mongoc_client_get_collection (unencrypted_client, ENCRYPTED_DB, ENCRYPTED_COLL); + printf ("encrypted document: "); + if (!print_one_document (unencrypted_coll, &error)) { + goto fail; + } + printf ("\n"); + + /* Expect a server-side error if inserting with the unencrypted collection. + */ + ret = mongoc_collection_insert_one (unencrypted_coll, to_insert, NULL /* opts */, NULL /* reply */, &error); + if (!ret) { + printf ("insert with unencrypted collection failed: %s\n", error.message); + memset (&error, 0, sizeof (error)); + } + + exit_status = EXIT_SUCCESS; +fail: + if (error.code) { + fprintf (stderr, "error: %s\n", error.message); + } + + bson_free (local_masterkey); + bson_destroy (kms_providers); + mongoc_collection_destroy (keyvault_coll); + mongoc_index_model_destroy (index_model); + bson_destroy (index_opts); + bson_destroy (index_keys); + bson_json_reader_destroy (reader); + mongoc_auto_encryption_opts_destroy (auto_encryption_opts); + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + bson_destroy (to_insert); + mongoc_collection_destroy (unencrypted_coll); + mongoc_client_destroy (unencrypted_client); + mongoc_client_destroy (keyvault_client); + bson_destroy (schema); + bson_destroy (create_cmd); + bson_destroy (create_cmd_opts); + mongoc_write_concern_destroy (wc); + + mongoc_cleanup (); + return exit_status; +} diff --git a/source/docs-libmongoc/includes/examples/cmake-deprecated/find_package/CMakeLists.txt b/source/docs-libmongoc/includes/examples/cmake-deprecated/find_package/CMakeLists.txt new file mode 100644 index 00000000..682d2d82 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake-deprecated/find_package/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright 2017 MongoDB Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Demonstrates how to use the CMake 'find_package' mechanism to locate +# and build against libmongoc. + +cmake_minimum_required (VERSION 2.8) + +if (APPLE) + cmake_policy (SET CMP0042 OLD) +endif () + +project (hello_mongoc LANGUAGES C) + +# NOTE: For this to work, the CMAKE_PREFIX_PATH variable must be set to point to +# the directory that was used as the argument to CMAKE_INSTALL_PREFIX when +# building libmongoc. +# -- sphinx-include-start -- +# Specify the minimum version you require. +find_package (libmongoc-1.0 1.7 REQUIRED) + +message (STATUS " mongoc found version \"${MONGOC_VERSION}\"") +message (STATUS " mongoc include path \"${MONGOC_INCLUDE_DIRS}\"") +message (STATUS " mongoc libraries \"${MONGOC_LIBRARIES}\"") + +# The "hello_mongoc.c" sample program is shared among four tests. +add_executable (hello_mongoc ../../hello_mongoc.c) +target_include_directories (hello_mongoc PRIVATE "${MONGOC_INCLUDE_DIRS}") +target_link_libraries (hello_mongoc PRIVATE "${MONGOC_LIBRARIES}") +target_compile_definitions (hello_mongoc PRIVATE "${MONGOC_DEFINITIONS}") diff --git a/source/docs-libmongoc/includes/examples/cmake-deprecated/find_package_static/CMakeLists.txt b/source/docs-libmongoc/includes/examples/cmake-deprecated/find_package_static/CMakeLists.txt new file mode 100644 index 00000000..a965225f --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake-deprecated/find_package_static/CMakeLists.txt @@ -0,0 +1,41 @@ +# Copyright 2017 MongoDB Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Demonstrates how to use the CMake 'find_package' mechanism to locate +# and build against libmongoc. + +cmake_minimum_required (VERSION 2.8) + +if (APPLE) + cmake_policy (SET CMP0042 OLD) +endif () + +project (hello_mongoc LANGUAGES C) + +# NOTE: For this to work, the CMAKE_PREFIX_PATH variable must be set to point to +# the directory that was used as the argument to CMAKE_INSTALL_PREFIX when +# building libmongoc. +# -- sphinx-include-start -- +# Specify the minimum version you require. +find_package (libmongoc-static-1.0 1.7 REQUIRED) + +message (STATUS " mongoc found version \"${MONGOC_STATIC_VERSION}\"") +message (STATUS " mongoc include path \"${MONGOC_STATIC_INCLUDE_DIRS}\"") +message (STATUS " mongoc libraries \"${MONGOC_STATIC_LIBRARIES}\"") + +# The "hello_mongoc.c" sample program is shared among four tests. +add_executable (hello_mongoc ../../hello_mongoc.c) +target_include_directories (hello_mongoc PRIVATE "${MONGOC_STATIC_INCLUDE_DIRS}") +target_link_libraries (hello_mongoc PRIVATE "${MONGOC_STATIC_LIBRARIES}") +target_compile_definitions (hello_mongoc PRIVATE "${MONGOC_STATIC_DEFINITIONS}") diff --git a/source/docs-libmongoc/includes/examples/cmake/find_package/CMakeLists.txt b/source/docs-libmongoc/includes/examples/cmake/find_package/CMakeLists.txt new file mode 100644 index 00000000..8e062ae5 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake/find_package/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2017 MongoDB Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Demonstrates how to use the CMake 'find_package' mechanism to locate +# and build against libmongoc. + +cmake_minimum_required (VERSION 3.0) + +if (APPLE) + cmake_policy (SET CMP0042 OLD) +endif () + +project (hello_mongoc LANGUAGES C) + +# NOTE: For this to work, the CMAKE_PREFIX_PATH variable must be set to point to +# the directory that was used as the argument to CMAKE_INSTALL_PREFIX when +# building libmongoc. +# -- sphinx-include-start -- +# Specify the minimum version you require. +find_package (mongoc-1.0 1.7 REQUIRED) + +# The "hello_mongoc.c" sample program is shared among four tests. +add_executable (hello_mongoc ../../hello_mongoc.c) +target_link_libraries (hello_mongoc PRIVATE mongo::mongoc_shared) diff --git a/source/docs-libmongoc/includes/examples/cmake/find_package_static/CMakeLists.txt b/source/docs-libmongoc/includes/examples/cmake/find_package_static/CMakeLists.txt new file mode 100644 index 00000000..f7e3e090 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake/find_package_static/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright 2017 MongoDB Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Demonstrates how to use the CMake 'find_package' mechanism to locate +# and build against libmongoc. + +cmake_minimum_required (VERSION 3.0) + +if (APPLE) + cmake_policy (SET CMP0042 OLD) +endif () + +project (hello_mongoc LANGUAGES C) + +# NOTE: For this to work, the CMAKE_PREFIX_PATH variable must be set to point to +# the directory that was used as the argument to CMAKE_INSTALL_PREFIX when +# building libmongoc. +# -- sphinx-include-start -- +# Specify the minimum version you require. +find_package (mongoc-1.0 1.7 REQUIRED) + +# The "hello_mongoc.c" sample program is shared among four tests. +add_executable (hello_mongoc ../../hello_mongoc.c) +target_link_libraries (hello_mongoc PRIVATE mongo::mongoc_static) diff --git a/source/docs-libmongoc/includes/examples/cmake/vcpkg/CMakeLists.txt b/source/docs-libmongoc/includes/examples/cmake/vcpkg/CMakeLists.txt new file mode 100644 index 00000000..271548a4 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake/vcpkg/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.15) +project(vcpkg-example-project) + +find_package(mongoc-1.0 CONFIG REQUIRED) +message(STATUS "Found libmongoc: ${mongoc-1.0_DIR}") + +enable_testing() + +add_executable(my-app app.c) +target_link_libraries(my-app PRIVATE mongo::mongoc_static) +add_test(my-app my-app) +set_property( + TEST my-app + PROPERTY PASS_REGULAR_EXPRESSION + "^Linked with libmongoc [1-9]+\\.[0-9]+\\.[0-9]+\r?\n$" +) diff --git a/source/docs-libmongoc/includes/examples/cmake/vcpkg/Makefile b/source/docs-libmongoc/includes/examples/cmake/vcpkg/Makefile new file mode 100644 index 00000000..483209f6 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake/vcpkg/Makefile @@ -0,0 +1,29 @@ +.SILENT: + +THIS_FILE := $(realpath $(lastword $(MAKEFILE_LIST))) +THIS_DIR := $(dir $(THIS_FILE)) + +VCPKG_ROOT ?= /opt/vcpkg + +.PHONY: test-classic +test-classic: + vcpkg install mongo-c-driver + rm -rf -- $(THIS_DIR)/_build + cmake \ + -S . \ + -B _build \ + -D CMAKE_PROJECT_INCLUDE=$(VCPKG_ROOT)/scripts/buildsystems/vcpkg.cmake + cmake --build _build --config=Debug + cmake --build _build --config=Debug --target test + +.PHONY: test-manifest-mode +test-manifest-mode: + test -f vcpkg.json \ + || (echo "Expects a vcpkg.json file in the project directory before running this target." 1>&2 \ + && false) + cmake \ + -S . \ + -B _build \ + -D CMAKE_PROJECT_INCLUDE=$(VCPKG_ROOT)/scripts/buildsystems/vcpkg.cmake + cmake --build _build --config=Debug + cmake --build _build --config=Debug --target test diff --git a/source/docs-libmongoc/includes/examples/cmake/vcpkg/app.c b/source/docs-libmongoc/includes/examples/cmake/vcpkg/app.c new file mode 100644 index 00000000..242bf9de --- /dev/null +++ b/source/docs-libmongoc/includes/examples/cmake/vcpkg/app.c @@ -0,0 +1,12 @@ +#include + +#include + +int +main (void) +{ + mongoc_init (); + fprintf (stdout, "Linked with libmongoc %s\n", mongoc_get_version ()); + mongoc_cleanup (); + return 0; +} diff --git a/source/docs-libmongoc/includes/examples/common_operations/common-operations.c b/source/docs-libmongoc/includes/examples/common_operations/common-operations.c new file mode 100644 index 00000000..319b0ec5 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/common_operations/common-operations.c @@ -0,0 +1,117 @@ +/* + * Copyright 2016 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + + +const char *COLLECTION_NAME = "things"; + +#include "../doc-common-insert.c" +#include "explain.c" + + +int +main (int argc, char *argv[]) +{ + mongoc_database_t *database = NULL; + mongoc_client_t *client = NULL; + mongoc_collection_t *collection = NULL; + mongoc_uri_t *uri = NULL; + bson_error_t error; + char *host_and_port; + int res = 0; + + if (argc < 2 || argc > 3) { + fprintf (stderr, + "usage: %s MONGOD-1-CONNECTION-STRING " + "[MONGOD-2-HOST-NAME:MONGOD-2-PORT]\n", + argv[0]); + fprintf (stderr, + "MONGOD-1-CONNECTION-STRING can be " + "of the following forms:\n"); + fprintf (stderr, "localhost\t\t\t\tlocal machine\n"); + fprintf (stderr, "localhost:27018\t\t\t\tlocal machine on port 27018\n"); + fprintf (stderr, + "mongodb://user:pass@localhost:27017\t" + "local machine on port 27017, and authenticate with username " + "user and password pass\n"); + return EXIT_FAILURE; + } + + mongoc_init (); + + if (strncmp (argv[1], "mongodb://", 10) == 0) { + host_and_port = bson_strdup (argv[1]); + } else { + host_and_port = bson_strdup_printf ("mongodb://%s", argv[1]); + } + + uri = mongoc_uri_new_with_error (host_and_port, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + host_and_port, + error.message); + res = EXIT_FAILURE; + goto cleanup; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + res = EXIT_FAILURE; + goto cleanup; + } + + mongoc_client_set_error_api (client, 2); + database = mongoc_client_get_database (client, "test"); + collection = mongoc_database_get_collection (database, COLLECTION_NAME); + + printf ("Inserting data\n"); + if (!insert_data (collection)) { + res = EXIT_FAILURE; + goto cleanup; + } + + printf ("explain\n"); + if (!explain (collection)) { + res = EXIT_FAILURE; + goto cleanup; + } + +cleanup: + if (collection) { + mongoc_collection_destroy (collection); + } + + if (database) { + mongoc_database_destroy (database); + } + + if (client) { + mongoc_client_destroy (client); + } + + if (uri) { + mongoc_uri_destroy (uri); + } + + bson_free (host_and_port); + mongoc_cleanup (); + return res; +} diff --git a/source/docs-libmongoc/includes/examples/common_operations/explain.c b/source/docs-libmongoc/includes/examples/common_operations/explain.c new file mode 100644 index 00000000..8c823c79 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/common_operations/explain.c @@ -0,0 +1,24 @@ +bool +explain (mongoc_collection_t *collection) +{ + bson_t *command; + bson_t reply; + bson_error_t error; + bool res; + + command = + BCON_NEW ("explain", "{", "find", BCON_UTF8 (COLLECTION_NAME), "filter", "{", "x", BCON_INT32 (1), "}", "}"); + res = mongoc_collection_command_simple (collection, command, NULL, &reply, &error); + if (!res) { + fprintf (stderr, "Error with explain: %s\n", error.message); + goto cleanup; + } + + /* Do something with the reply */ + print_res (&reply); + +cleanup: + bson_destroy (&reply); + bson_destroy (command); + return res; +} diff --git a/source/docs-libmongoc/includes/examples/compile-with-pkg-config-static.sh b/source/docs-libmongoc/includes/examples/compile-with-pkg-config-static.sh new file mode 100644 index 00000000..acc7fbdb --- /dev/null +++ b/source/docs-libmongoc/includes/examples/compile-with-pkg-config-static.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +# -- sphinx-include-start -- +gcc -o hello_mongoc hello_mongoc.c $(pkg-config --libs --cflags libmongoc-static-1.0) diff --git a/source/docs-libmongoc/includes/examples/compile-with-pkg-config.sh b/source/docs-libmongoc/includes/examples/compile-with-pkg-config.sh new file mode 100755 index 00000000..91e0a7eb --- /dev/null +++ b/source/docs-libmongoc/includes/examples/compile-with-pkg-config.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +# -- sphinx-include-start -- +gcc -o hello_mongoc hello_mongoc.c $(pkg-config --libs --cflags libmongoc-1.0) diff --git a/source/docs-libmongoc/includes/examples/doc-common-insert.c b/source/docs-libmongoc/includes/examples/doc-common-insert.c new file mode 100644 index 00000000..21edb4d5 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/doc-common-insert.c @@ -0,0 +1,47 @@ +/* Don't try to compile this file on its own. It's meant to be #included + by example code */ + +/* Insert some sample data */ +bool +insert_data (mongoc_collection_t *collection) +{ + mongoc_bulk_operation_t *bulk; + enum N { ndocs = 4 }; + bson_t *docs[ndocs]; + bson_error_t error; + int i = 0; + bool ret; + + bulk = mongoc_collection_create_bulk_operation_with_opts (collection, NULL); + + docs[0] = BCON_NEW ("x", BCON_DOUBLE (1.0), "tags", "[", "dog", "cat", "]"); + docs[1] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "cat", "]"); + docs[2] = BCON_NEW ("x", BCON_DOUBLE (2.0), "tags", "[", "mouse", "cat", "dog", "]"); + docs[3] = BCON_NEW ("x", BCON_DOUBLE (3.0), "tags", "[", "]"); + + for (i = 0; i < ndocs; i++) { + mongoc_bulk_operation_insert (bulk, docs[i]); + bson_destroy (docs[i]); + docs[i] = NULL; + } + + ret = mongoc_bulk_operation_execute (bulk, NULL, &error); + + if (!ret) { + fprintf (stderr, "Error inserting data: %s\n", error.message); + } + + mongoc_bulk_operation_destroy (bulk); + return ret; +} + +/* A helper which we'll use a lot later on */ +void +print_res (const bson_t *reply) +{ + char *str; + BSON_ASSERT (reply); + str = bson_as_canonical_extended_json (reply, NULL); + printf ("%s\n", str); + bson_free (str); +} diff --git a/source/docs-libmongoc/includes/examples/example-client.c b/source/docs-libmongoc/includes/examples/example-client.c new file mode 100644 index 00000000..5f3eb5f4 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-client.c @@ -0,0 +1,76 @@ +/* gcc example-client.c -o example-client $(pkg-config --cflags --libs + * libmongoc-1.0) */ + +/* ./example-client [CONNECTION_STRING [COLLECTION_NAME]] */ + +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client; + mongoc_collection_t *collection; + mongoc_cursor_t *cursor; + bson_error_t error; + const bson_t *doc; + const char *collection_name = "test"; + bson_t query; + char *str; + const char *uri_string = "mongodb://127.0.0.1/?appname=client-example"; + mongoc_uri_t *uri; + + mongoc_init (); + if (argc > 1) { + uri_string = argv[1]; + } + + if (argc > 2) { + collection_name = argv[2]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + + bson_init (&query); + collection = mongoc_client_get_collection (client, "test", collection_name); + cursor = mongoc_collection_find_with_opts (collection, + &query, + NULL, /* additional options */ + NULL); /* read prefs, NULL for default */ + + while (mongoc_cursor_next (cursor, &doc)) { + str = bson_as_canonical_extended_json (doc, NULL); + fprintf (stdout, "%s\n", str); + bson_free (str); + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "Cursor Failure: %s\n", error.message); + return EXIT_FAILURE; + } + + bson_destroy (&query); + mongoc_cursor_destroy (cursor); + mongoc_collection_destroy (collection); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-collection-command.c b/source/docs-libmongoc/includes/examples/example-collection-command.c new file mode 100644 index 00000000..50e171ff --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-collection-command.c @@ -0,0 +1,68 @@ +// BEGIN:mongoc_collection_command_simple +#include +#include +#include + +static void +do_ping (mongoc_collection_t *collection) +{ + bson_error_t error; + bson_t *cmd; + bson_t reply; + char *str; + + cmd = BCON_NEW ("ping", BCON_INT32 (1)); + + if (mongoc_collection_command_simple (collection, cmd, NULL, &reply, &error)) { + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("Got reply: %s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: %s\n", error.message); + } + + bson_destroy (&reply); + bson_destroy (cmd); +} +// END:mongoc_collection_command_simple + +int +main (int argc, char **argv) +{ + bson_error_t error; + char *uri_string; + mongoc_uri_t *uri; + mongoc_client_t *client; + mongoc_collection_t *coll; + + mongoc_init (); + + if (argc != 2) { + MONGOC_ERROR ("Error: expected URI argument.\n" + "Usage: %s \n" + "Example: %s mongodb://localhost:27017", + argv[0], + argv[0]); + return EXIT_FAILURE; + } + uri_string = argv[1]; + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + MONGOC_ERROR ("failed to parse URI: %s\nError: %s", uri_string, error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + MONGOC_ERROR ("failed to create client"); + return EXIT_FAILURE; + } + + coll = mongoc_client_get_collection (client, "db", "coll"); + do_ping (coll); + mongoc_collection_destroy (coll); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + mongoc_cleanup (); + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-collection-watch.c b/source/docs-libmongoc/includes/examples/example-collection-watch.c new file mode 100644 index 00000000..b03b01cc --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-collection-watch.c @@ -0,0 +1,77 @@ +#include + +int +main (void) +{ + bson_t empty = BSON_INITIALIZER; + const bson_t *doc; + bson_t *to_insert = BCON_NEW ("x", BCON_INT32 (1)); + const bson_t *err_doc; + bson_error_t error; + const char *uri_string; + mongoc_uri_t *uri; + mongoc_client_t *client; + mongoc_collection_t *coll; + mongoc_change_stream_t *stream; + mongoc_write_concern_t *wc = mongoc_write_concern_new (); + bson_t opts = BSON_INITIALIZER; + bool r; + + mongoc_init (); + + uri_string = "mongodb://" + "localhost:27017,localhost:27018,localhost:" + "27019/db?replicaSet=rs0"; + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + coll = mongoc_client_get_collection (client, "db", "coll"); + stream = mongoc_collection_watch (coll, &empty, NULL); + + mongoc_write_concern_set_wmajority (wc, 10000); + mongoc_write_concern_append (wc, &opts); + r = mongoc_collection_insert_one (coll, to_insert, &opts, NULL, &error); + if (!r) { + fprintf (stderr, "Error: %s\n", error.message); + return EXIT_FAILURE; + } + + while (mongoc_change_stream_next (stream, &doc)) { + char *as_json = bson_as_relaxed_extended_json (doc, NULL); + fprintf (stderr, "Got document: %s\n", as_json); + bson_free (as_json); + } + + if (mongoc_change_stream_error_document (stream, &error, &err_doc)) { + if (!bson_empty (err_doc)) { + fprintf (stderr, "Server Error: %s\n", bson_as_relaxed_extended_json (err_doc, NULL)); + } else { + fprintf (stderr, "Client Error: %s\n", error.message); + } + return EXIT_FAILURE; + } + + bson_destroy (to_insert); + mongoc_write_concern_destroy (wc); + bson_destroy (&opts); + mongoc_change_stream_destroy (stream); + mongoc_collection_destroy (coll); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-command-monitoring.c b/source/docs-libmongoc/includes/examples/example-command-monitoring.c new file mode 100644 index 00000000..5dc34ca7 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-command-monitoring.c @@ -0,0 +1,124 @@ +/* gcc example-command-monitoring.c -o example-command-monitoring \ + * $(pkg-config --cflags --libs libmongoc-1.0) */ + +/* ./example-command-monitoring [CONNECTION_STRING] */ + +#include +#include + + +typedef struct { + int started; + int succeeded; + int failed; +} stats_t; + + +void +command_started (const mongoc_apm_command_started_t *event) +{ + char *s; + + s = bson_as_relaxed_extended_json (mongoc_apm_command_started_get_command (event), NULL); + printf ("Command %s started on %s:\n%s\n\n", + mongoc_apm_command_started_get_command_name (event), + mongoc_apm_command_started_get_host (event)->host, + s); + + ((stats_t *) mongoc_apm_command_started_get_context (event))->started++; + + bson_free (s); +} + + +void +command_succeeded (const mongoc_apm_command_succeeded_t *event) +{ + char *s; + + s = bson_as_relaxed_extended_json (mongoc_apm_command_succeeded_get_reply (event), NULL); + printf ("Command %s succeeded:\n%s\n\n", mongoc_apm_command_succeeded_get_command_name (event), s); + + ((stats_t *) mongoc_apm_command_succeeded_get_context (event))->succeeded++; + + bson_free (s); +} + + +void +command_failed (const mongoc_apm_command_failed_t *event) +{ + bson_error_t error; + + mongoc_apm_command_failed_get_error (event, &error); + printf ("Command %s failed:\n\"%s\"\n\n", mongoc_apm_command_failed_get_command_name (event), error.message); + + ((stats_t *) mongoc_apm_command_failed_get_context (event))->failed++; +} + + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client; + mongoc_apm_callbacks_t *callbacks; + stats_t stats = {0}; + mongoc_collection_t *collection; + bson_error_t error; + const char *uri_string = "mongodb://127.0.0.1/?appname=cmd-monitoring-example"; + mongoc_uri_t *uri; + const char *collection_name = "test"; + bson_t *docs[2]; + + mongoc_init (); + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + callbacks = mongoc_apm_callbacks_new (); + mongoc_apm_set_command_started_cb (callbacks, command_started); + mongoc_apm_set_command_succeeded_cb (callbacks, command_succeeded); + mongoc_apm_set_command_failed_cb (callbacks, command_failed); + mongoc_client_set_apm_callbacks (client, callbacks, (void *) &stats /* context pointer */); + + collection = mongoc_client_get_collection (client, "test", collection_name); + mongoc_collection_drop (collection, NULL); + + docs[0] = BCON_NEW ("_id", BCON_INT32 (0)); + docs[1] = BCON_NEW ("_id", BCON_INT32 (1)); + mongoc_collection_insert_many (collection, (const bson_t **) docs, 2, NULL, NULL, NULL); + + /* duplicate key error on the second insert */ + mongoc_collection_insert_one (collection, docs[0], NULL, NULL, NULL); + + mongoc_collection_destroy (collection); + mongoc_apm_callbacks_destroy (callbacks); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + printf ("started: %d\nsucceeded: %d\nfailed: %d\n", stats.started, stats.succeeded, stats.failed); + + bson_destroy (docs[0]); + bson_destroy (docs[1]); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-command-with-opts.c b/source/docs-libmongoc/includes/examples/example-command-with-opts.c new file mode 100644 index 00000000..e1e6ab91 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-command-with-opts.c @@ -0,0 +1,138 @@ +/* + +Demonstrates how to prepare options for mongoc_client_read_command_with_opts and +mongoc_client_write_command_with_opts. First it calls "cloneCollectionAsCapped" +command with "writeConcern" option, then "distinct" command with "collation" and +"readConcern" options, + +Start a MongoDB 3.4 replica set with --enableMajorityReadConcern and insert two +documents: + +$ mongo +MongoDB Enterprise replset:PRIMARY> db.my_collection.insert({x: 1, y: "One"}) +WriteResult({ "nInserted" : 1 }) +MongoDB Enterprise replset:PRIMARY> db.my_collection.insert({x: 2, y: "Two"}) +WriteResult({ "nInserted" : 1 }) + +Build and run the example: + +gcc example-command-with-opts.c -o example-command-with-opts $(pkg-config +--cflags --libs libmongoc-1.0) +./example-command-with-opts [CONNECTION_STRING] +cloneCollectionAsCapped: { "ok" : 1 } +distinct: { "values" : [ 1, 2 ], "ok" : 1 } + +*/ + +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client; + const char *uri_string = "mongodb://127.0.0.1/?appname=client-example"; + mongoc_uri_t *uri; + bson_t *cmd; + bson_t *opts; + mongoc_write_concern_t *write_concern; + mongoc_read_prefs_t *read_prefs; + mongoc_read_concern_t *read_concern; + bson_t reply; + bson_error_t error; + char *json; + + mongoc_init (); + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + + cmd = BCON_NEW ("cloneCollectionAsCapped", + BCON_UTF8 ("my_collection"), + "toCollection", + BCON_UTF8 ("my_capped_collection"), + "size", + BCON_INT64 (1024 * 1024)); + + /* include write concern "majority" in command options */ + write_concern = mongoc_write_concern_new (); + mongoc_write_concern_set_wmajority (write_concern, 10000 /* wtimeoutMS */); + opts = bson_new (); + mongoc_write_concern_append (write_concern, opts); + + if (mongoc_client_write_command_with_opts (client, "test", cmd, opts, &reply, &error)) { + json = bson_as_canonical_extended_json (&reply, NULL); + printf ("cloneCollectionAsCapped: %s\n", json); + bson_free (json); + } else { + fprintf (stderr, "cloneCollectionAsCapped: %s\n", error.message); + } + + bson_free (cmd); + bson_free (opts); + + /* distinct values of "x" in "my_collection" where "y" sorts after "one" */ + cmd = BCON_NEW ("distinct", + BCON_UTF8 ("my_collection"), + "key", + BCON_UTF8 ("x"), + "query", + "{", + "y", + "{", + "$gt", + BCON_UTF8 ("one"), + "}", + "}"); + + read_prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); + + /* "One" normally sorts before "one"; make "One" sort after "one" */ + opts = BCON_NEW ("collation", "{", "locale", BCON_UTF8 ("en_US"), "caseFirst", BCON_UTF8 ("lower"), "}"); + + /* add a read concern to "opts" */ + read_concern = mongoc_read_concern_new (); + mongoc_read_concern_set_level (read_concern, MONGOC_READ_CONCERN_LEVEL_MAJORITY); + + mongoc_read_concern_append (read_concern, opts); + + if (mongoc_client_read_command_with_opts (client, "test", cmd, read_prefs, opts, &reply, &error)) { + json = bson_as_canonical_extended_json (&reply, NULL); + printf ("distinct: %s\n", json); + bson_free (json); + } else { + fprintf (stderr, "distinct: %s\n", error.message); + } + + bson_destroy (cmd); + bson_destroy (opts); + bson_destroy (&reply); + mongoc_read_prefs_destroy (read_prefs); + mongoc_read_concern_destroy (read_concern); + mongoc_write_concern_destroy (write_concern); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-gridfs-bucket.c b/source/docs-libmongoc/includes/examples/example-gridfs-bucket.c new file mode 100644 index 00000000..431943d0 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-gridfs-bucket.c @@ -0,0 +1,91 @@ +#include +#include + +#include + +int +main (int argc, char *argv[]) +{ + const char *uri_string = "mongodb://localhost:27017/?appname=new-gridfs-example"; + mongoc_client_t *client; + mongoc_database_t *db; + mongoc_stream_t *file_stream; + mongoc_gridfs_bucket_t *bucket; + mongoc_cursor_t *cursor; + bson_t filter; + bool res; + bson_value_t file_id; + bson_error_t error; + const bson_t *doc; + char *str; + mongoc_init (); + + if (argc != 3) { + fprintf (stderr, "usage: %s SOURCE_FILE_PATH FILE_COPY_PATH\n", argv[0]); + return EXIT_FAILURE; + } + + /* 1. Make a bucket. */ + client = mongoc_client_new (uri_string); + db = mongoc_client_get_database (client, "test"); + bucket = mongoc_gridfs_bucket_new (db, NULL, NULL, &error); + if (!bucket) { + printf ("Error creating gridfs bucket: %s\n", error.message); + return EXIT_FAILURE; + } + + /* 2. Insert a file. */ + file_stream = mongoc_stream_file_new_for_path (argv[1], O_RDONLY, 0); + res = mongoc_gridfs_bucket_upload_from_stream (bucket, "my-file", file_stream, NULL, &file_id, &error); + if (!res) { + printf ("Error uploading file: %s\n", error.message); + return EXIT_FAILURE; + } + + mongoc_stream_close (file_stream); + mongoc_stream_destroy (file_stream); + + /* 3. Download the file in GridFS to a local file. */ + file_stream = mongoc_stream_file_new_for_path (argv[2], O_CREAT | O_RDWR, 0); + if (!file_stream) { + perror ("Error opening file stream"); + return EXIT_FAILURE; + } + + res = mongoc_gridfs_bucket_download_to_stream (bucket, &file_id, file_stream, &error); + if (!res) { + printf ("Error downloading file to stream: %s\n", error.message); + return EXIT_FAILURE; + } + mongoc_stream_close (file_stream); + mongoc_stream_destroy (file_stream); + + /* 4. List what files are available in GridFS. */ + bson_init (&filter); + cursor = mongoc_gridfs_bucket_find (bucket, &filter, NULL); + + while (mongoc_cursor_next (cursor, &doc)) { + str = bson_as_canonical_extended_json (doc, NULL); + printf ("%s\n", str); + bson_free (str); + } + + /* 5. Delete the file that we added. */ + res = mongoc_gridfs_bucket_delete_by_id (bucket, &file_id, &error); + if (!res) { + printf ("Error deleting the file: %s\n", error.message); + return EXIT_FAILURE; + } + + /* 6. Cleanup. */ + mongoc_stream_close (file_stream); + mongoc_stream_destroy (file_stream); + mongoc_cursor_destroy (cursor); + bson_destroy (&filter); + mongoc_gridfs_bucket_destroy (bucket); + mongoc_database_destroy (db); + mongoc_client_destroy (client); + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-gridfs.c b/source/docs-libmongoc/includes/examples/example-gridfs.c new file mode 100644 index 00000000..4e7b43af --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-gridfs.c @@ -0,0 +1,154 @@ +#include +#include +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + mongoc_gridfs_t *gridfs; + mongoc_gridfs_file_t *file; + mongoc_gridfs_file_list_t *list; + mongoc_gridfs_file_opt_t opt = {0}; + mongoc_client_t *client; + const char *uri_string = "mongodb://127.0.0.1:27017/?appname=gridfs-example"; + mongoc_uri_t *uri; + mongoc_stream_t *stream; + bson_t filter; + bson_t opts; + bson_t child; + bson_error_t error; + ssize_t r; + char buf[4096]; + mongoc_iovec_t iov; + const char *filename; + const char *command; + bson_value_t id; + + if (argc < 2) { + fprintf (stderr, "usage - %s command ...\n", argv[0]); + return EXIT_FAILURE; + } + + mongoc_init (); + + iov.iov_base = (void *) buf; + iov.iov_len = sizeof buf; + + /* connect to localhost client */ + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + assert (client); + mongoc_client_set_error_api (client, 2); + + /* grab a gridfs handle in test prefixed by fs */ + gridfs = mongoc_client_get_gridfs (client, "test", "fs", &error); + assert (gridfs); + + command = argv[1]; + filename = argv[2]; + + if (strcmp (command, "read") == 0) { + if (argc != 3) { + fprintf (stderr, "usage - %s read filename\n", argv[0]); + return EXIT_FAILURE; + } + file = mongoc_gridfs_find_one_by_filename (gridfs, filename, &error); + assert (file); + + stream = mongoc_stream_gridfs_new (file); + assert (stream); + + for (;;) { + r = mongoc_stream_readv (stream, &iov, 1, -1, 0); + + assert (r >= 0); + + if (r == 0) { + break; + } + + if (fwrite (iov.iov_base, 1, r, stdout) != r) { + MONGOC_ERROR ("Failed to write to stdout. Exiting.\n"); + exit (1); + } + } + + mongoc_stream_destroy (stream); + mongoc_gridfs_file_destroy (file); + } else if (strcmp (command, "list") == 0) { + bson_init (&filter); + + bson_init (&opts); + bson_append_document_begin (&opts, "sort", -1, &child); + BSON_APPEND_INT32 (&child, "filename", 1); + bson_append_document_end (&opts, &child); + + list = mongoc_gridfs_find_with_opts (gridfs, &filter, &opts); + + bson_destroy (&filter); + bson_destroy (&opts); + + while ((file = mongoc_gridfs_file_list_next (list))) { + const char *name = mongoc_gridfs_file_get_filename (file); + printf ("%s\n", name ? name : "?"); + + mongoc_gridfs_file_destroy (file); + } + + mongoc_gridfs_file_list_destroy (list); + } else if (strcmp (command, "write") == 0) { + if (argc != 4) { + fprintf (stderr, "usage - %s write filename input_file\n", argv[0]); + return EXIT_FAILURE; + } + + stream = mongoc_stream_file_new_for_path (argv[3], O_RDONLY, 0); + assert (stream); + + opt.filename = filename; + + /* the driver generates a file_id for you */ + file = mongoc_gridfs_create_file_from_stream (gridfs, stream, &opt); + assert (file); + + id.value_type = BSON_TYPE_INT32; + id.value.v_int32 = 1; + + /* optional: the following method specifies a file_id of any + BSON type */ + if (!mongoc_gridfs_file_set_id (file, &id, &error)) { + fprintf (stderr, "%s\n", error.message); + return EXIT_FAILURE; + } + + if (!mongoc_gridfs_file_save (file)) { + mongoc_gridfs_file_error (file, &error); + fprintf (stderr, "Could not save: %s\n", error.message); + return EXIT_FAILURE; + } + + mongoc_gridfs_file_destroy (file); + } else { + fprintf (stderr, "Unknown command"); + return EXIT_FAILURE; + } + + mongoc_gridfs_destroy (gridfs); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-manage-collection-indexes.c b/source/docs-libmongoc/includes/examples/example-manage-collection-indexes.c new file mode 100644 index 00000000..d3879102 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-manage-collection-indexes.c @@ -0,0 +1,103 @@ +// example-manage-collection-indexes creates, lists and deletes an index from +// the `test.test` collection. + +#include +#include // abort + +#define HANDLE_ERROR(...) \ + if (1) { \ + fprintf (stderr, "Failure at %s:%d\n", __FILE__, __LINE__); \ + fprintf (stderr, __VA_ARGS__); \ + fprintf (stderr, "\n"); \ + goto fail; \ + } else \ + (void) 0 + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client = NULL; + const char *uri_string = "mongodb://127.0.0.1/?appname=create-indexes-example"; + mongoc_uri_t *uri = NULL; + mongoc_collection_t *coll = NULL; + bson_error_t error; + bool ok = false; + + mongoc_init (); + + if (argc > 2) { + HANDLE_ERROR ("Unexpected arguments. Expected usage: %s [CONNECTION_STRING]", argv[0]); + } + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + HANDLE_ERROR ("Failed to parse URI: %s", error.message); + } + client = mongoc_client_new_from_uri_with_error (uri, &error); + if (!client) { + HANDLE_ERROR ("Failed to create client: %s", error.message); + } + + coll = mongoc_client_get_collection (client, "test", "test"); + + { + // Create an index ... begin + // `keys` represents an ascending index on field `x`. + bson_t *keys = BCON_NEW ("x", BCON_INT32 (1)); + mongoc_index_model_t *im = mongoc_index_model_new (keys, NULL /* opts */); + if (mongoc_collection_create_indexes_with_opts (coll, &im, 1, NULL /* opts */, NULL /* reply */, &error)) { + printf ("Successfully created index\n"); + } else { + bson_destroy (keys); + HANDLE_ERROR ("Failed to create index: %s", error.message); + } + bson_destroy (keys); + // Create an index ... end + } + + { + // List indexes ... begin + mongoc_cursor_t *cursor = mongoc_collection_find_indexes_with_opts (coll, NULL /* opts */); + printf ("Listing indexes:\n"); + const bson_t *got; + while (mongoc_cursor_next (cursor, &got)) { + char *got_str = bson_as_canonical_extended_json (got, NULL); + printf (" %s\n", got_str); + bson_free (got_str); + } + if (mongoc_cursor_error (cursor, &error)) { + mongoc_cursor_destroy (cursor); + HANDLE_ERROR ("Failed to list indexes: %s", error.message); + } + mongoc_cursor_destroy (cursor); + // List indexes ... end + } + + { + // Drop an index ... begin + bson_t *keys = BCON_NEW ("x", BCON_INT32 (1)); + char *index_name = mongoc_collection_keys_to_index_string (keys); + if (mongoc_collection_drop_index_with_opts (coll, index_name, NULL /* opts */, &error)) { + printf ("Successfully dropped index\n"); + } else { + bson_free (index_name); + bson_destroy (keys); + HANDLE_ERROR ("Failed to drop index: %s", error.message); + } + bson_free (index_name); + bson_destroy (keys); + // Drop an index ... end + } + + ok = true; +fail: + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + mongoc_uri_destroy (uri); + mongoc_cleanup (); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/source/docs-libmongoc/includes/examples/example-manage-search-indexes.c b/source/docs-libmongoc/includes/examples/example-manage-search-indexes.c new file mode 100644 index 00000000..c16cc2da --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-manage-search-indexes.c @@ -0,0 +1,201 @@ +// example-manage-search-indexes creates, lists, updates, and deletes an Atlas +// search index from the `test.test` collection. +// Example is expected to be run against a MongoDB Atlas cluster. + +#include +#include // abort + +#define HANDLE_ERROR(...) \ + if (1) { \ + fprintf (stderr, __VA_ARGS__); \ + fprintf (stderr, "\n"); \ + goto fail; \ + } else \ + (void) 0 + +#define ASSERT(stmt) \ + if (!stmt) { \ + fprintf (stderr, "assertion failed on line: %d, statement: %s\n", __LINE__, #stmt); \ + abort (); \ + } else \ + (void) 0 + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client = NULL; + const char *uri_string = "mongodb://127.0.0.1/?appname=create-search-indexes-example"; + mongoc_uri_t *uri = NULL; + mongoc_collection_t *coll = NULL; + bson_error_t error; + bool ok = false; + + mongoc_init (); + + if (argc > 2) { + HANDLE_ERROR ("Unexpected arguments. Expected usage: %s [CONNECTION_STRING]", argv[0]); + } + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + HANDLE_ERROR ("Failed to parse URI: %s", error.message); + } + client = mongoc_client_new_from_uri_with_error (uri, &error); + if (!client) { + HANDLE_ERROR ("Failed to create client: %s", error.message); + } + + // Create a random collection name. + char collname[25]; + { + // There is a server-side limitation that prevents multiple search indexes + // from being created with the same name, definition and collection name. + // Atlas search index management operations are asynchronous. Dropping a + // collection may not result in the index being dropped immediately. Use a + // randomly generated collection name to avoid errors. + bson_oid_t oid; + bson_oid_init (&oid, NULL); + bson_oid_to_string (&oid, collname); + } + + // Create collection object. + { + // Create the collection server-side to avoid the server error: + // "Collection 'test.' does not exist." + mongoc_database_t *db = mongoc_client_get_database (client, "test"); + coll = mongoc_database_create_collection (db, collname, NULL /* options */, &error); + if (!coll) { + mongoc_database_destroy (db); + HANDLE_ERROR ("Failed to create collection: %s", error.message); + } + mongoc_database_destroy (db); + } + + // Check that $listSearchIndexes pipeline stage is supported. + // This is intended to check that a MongoDB Atlas cluster is used. + { + const char *pipeline_str = BSON_STR ({"pipeline" : [ {"$listSearchIndexes" : {}} ]}); + bson_t pipeline; + ASSERT (bson_init_from_json (&pipeline, pipeline_str, -1, &error)); + mongoc_cursor_t *cursor = + mongoc_collection_aggregate (coll, MONGOC_QUERY_NONE, &pipeline, NULL /* opts */, NULL /* read_prefs */); + const bson_t *got; + while (mongoc_cursor_next (cursor, &got)) + ; + if (mongoc_cursor_error (cursor, &error)) { + bson_destroy (&pipeline); + mongoc_cursor_destroy (cursor); + HANDLE_ERROR ("Failed to run $listSearchIndexes with error: %s\n" + "Does the URI point to a MongoDB Atlas cluster? %s", + error.message, + uri_string); + } + bson_destroy (&pipeline); + mongoc_cursor_destroy (cursor); + } + + { + // Create an Atlas Search Index ... begin + bson_t cmd; + // Create command. + { + char *cmd_str = bson_strdup_printf ( + BSON_STR ({ + "createSearchIndexes" : "%s", + "indexes" : [ {"definition" : {"mappings" : {"dynamic" : false}}, "name" : "test-index"} ] + }), + collname); + ASSERT (bson_init_from_json (&cmd, cmd_str, -1, &error)); + bson_free (cmd_str); + } + if (!mongoc_collection_command_simple (coll, &cmd, NULL /* read_prefs */, NULL /* reply */, &error)) { + bson_destroy (&cmd); + HANDLE_ERROR ("Failed to run createSearchIndexes: %s", error.message); + } + printf ("Created index: \"test-index\"\n"); + bson_destroy (&cmd); + // Create an Atlas Search Index ... end + } + + { + // List Atlas Search Indexes ... begin + const char *pipeline_str = BSON_STR ({"pipeline" : [ {"$listSearchIndexes" : {}} ]}); + bson_t pipeline; + ASSERT (bson_init_from_json (&pipeline, pipeline_str, -1, &error)); + mongoc_cursor_t *cursor = + mongoc_collection_aggregate (coll, MONGOC_QUERY_NONE, &pipeline, NULL /* opts */, NULL /* read_prefs */); + printf ("Listing indexes:\n"); + const bson_t *got; + while (mongoc_cursor_next (cursor, &got)) { + char *got_str = bson_as_canonical_extended_json (got, NULL); + printf (" %s\n", got_str); + bson_free (got_str); + } + if (mongoc_cursor_error (cursor, &error)) { + bson_destroy (&pipeline); + mongoc_cursor_destroy (cursor); + HANDLE_ERROR ("Failed to run $listSearchIndexes: %s", error.message); + } + bson_destroy (&pipeline); + mongoc_cursor_destroy (cursor); + // List Atlas Search Indexes ... end + } + + { + // Update an Atlas Search Index ... begin + bson_t cmd; + // Create command. + { + char *cmd_str = bson_strdup_printf ( + BSON_STR ( + {"updateSearchIndex" : "%s", "definition" : {"mappings" : {"dynamic" : true}}, "name" : "test-index"}), + collname); + ASSERT (bson_init_from_json (&cmd, cmd_str, -1, &error)); + bson_free (cmd_str); + } + if (!mongoc_collection_command_simple (coll, &cmd, NULL /* read_prefs */, NULL /* reply */, &error)) { + bson_destroy (&cmd); + HANDLE_ERROR ("Failed to run updateSearchIndex: %s", error.message); + } + printf ("Updated index: \"test-index\"\n"); + bson_destroy (&cmd); + // Update an Atlas Search Index ... end + } + + { + // Drop an Atlas Search Index ... begin + bson_t cmd; + // Create command. + { + char *cmd_str = bson_strdup_printf (BSON_STR ({"dropSearchIndex" : "%s", "name" : "test-index"}), collname); + ASSERT (bson_init_from_json (&cmd, cmd_str, -1, &error)); + bson_free (cmd_str); + } + if (!mongoc_collection_command_simple (coll, &cmd, NULL /* read_prefs */, NULL /* reply */, &error)) { + bson_destroy (&cmd); + HANDLE_ERROR ("Failed to run dropSearchIndex: %s", error.message); + } + printf ("Dropped index: \"test-index\"\n"); + bson_destroy (&cmd); + // Drop an Atlas Search Index ... end + } + + // Drop created collection. + { + if (!mongoc_collection_drop (coll, &error)) { + HANDLE_ERROR ("Failed to drop collection '%s': %s", collname, error.message); + } + } + + ok = true; +fail: + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + mongoc_uri_destroy (uri); + mongoc_cleanup (); + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/source/docs-libmongoc/includes/examples/example-pool.c b/source/docs-libmongoc/includes/examples/example-pool.c new file mode 100644 index 00000000..7271bbc8 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-pool.c @@ -0,0 +1,101 @@ +/* gcc example-pool.c -o example-pool $(pkg-config --cflags --libs + * libmongoc-1.0) */ + +/* ./example-pool [CONNECTION_STRING] */ + +#include +#include +#include + +static pthread_mutex_t mutex; +static bool in_shutdown = false; + +static void * +worker (void *data) +{ + mongoc_client_pool_t *pool = data; + mongoc_client_t *client; + bson_t ping = BSON_INITIALIZER; + bson_error_t error; + bool r; + + BSON_APPEND_INT32 (&ping, "ping", 1); + + while (true) { + client = mongoc_client_pool_pop (pool); + /* Do something with client. If you are writing an HTTP server, you + * probably only want to hold onto the client for the portion of the + * request performing database queries. + */ + r = mongoc_client_command_simple (client, "admin", &ping, NULL, NULL, &error); + + if (!r) { + fprintf (stderr, "%s\n", error.message); + } + + mongoc_client_pool_push (pool, client); + + pthread_mutex_lock (&mutex); + if (in_shutdown || !r) { + pthread_mutex_unlock (&mutex); + break; + } + + pthread_mutex_unlock (&mutex); + } + + bson_destroy (&ping); + return NULL; +} + +int +main (int argc, char *argv[]) +{ + const char *uri_string = "mongodb://127.0.0.1/?appname=pool-example"; + mongoc_uri_t *uri; + bson_error_t error; + mongoc_client_pool_t *pool; + pthread_t threads[10]; + unsigned i; + void *ret; + + pthread_mutex_init (&mutex, NULL); + mongoc_init (); + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + pool = mongoc_client_pool_new (uri); + mongoc_client_pool_set_error_api (pool, 2); + + for (i = 0; i < 10; i++) { + pthread_create (&threads[i], NULL, worker, pool); + } + + sleep (10); + pthread_mutex_lock (&mutex); + in_shutdown = true; + pthread_mutex_unlock (&mutex); + + for (i = 0; i < 10; i++) { + pthread_join (threads[i], &ret); + } + + mongoc_client_pool_destroy (pool); + mongoc_uri_destroy (uri); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-resume.c b/source/docs-libmongoc/includes/examples/example-resume.c new file mode 100644 index 00000000..72d00b87 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-resume.c @@ -0,0 +1,154 @@ +#include + +/* An example implementation of custom resume logic in a change stream. + * example-resume starts a client-wide change stream and persists the resume + * token in a file "resume-token.json". On restart, if "resume-token.json" + * exists, the change stream starts watching after the persisted resume token. + * + * This behavior allows a user to exit example-resume, and restart it later + * without missing any change events. + */ +#include + +static const char *RESUME_TOKEN_PATH = "resume-token.json"; + +static bool +_save_resume_token (const bson_t *doc) +{ + FILE *file_stream; + bson_iter_t iter; + bson_t resume_token_doc; + char *as_json = NULL; + size_t as_json_len; + ssize_t r, n_written; + const bson_value_t *resume_token; + + if (!bson_iter_init_find (&iter, doc, "_id")) { + fprintf (stderr, "reply does not contain operationTime."); + return false; + } + resume_token = bson_iter_value (&iter); + /* store the resume token in a document, { resumeAfter: } + * which we can later append easily. */ + file_stream = fopen (RESUME_TOKEN_PATH, "w+"); + if (!file_stream) { + fprintf (stderr, "failed to open %s for writing\n", RESUME_TOKEN_PATH); + return false; + } + bson_init (&resume_token_doc); + BSON_APPEND_VALUE (&resume_token_doc, "resumeAfter", resume_token); + as_json = bson_as_canonical_extended_json (&resume_token_doc, &as_json_len); + bson_destroy (&resume_token_doc); + n_written = 0; + while (n_written < as_json_len) { + r = fwrite ((void *) (as_json + n_written), sizeof (char), as_json_len - n_written, file_stream); + if (r == -1) { + fprintf (stderr, "failed to write to %s\n", RESUME_TOKEN_PATH); + bson_free (as_json); + fclose (file_stream); + return false; + } + n_written += r; + } + + bson_free (as_json); + fclose (file_stream); + return true; +} + +bool +_load_resume_token (bson_t *opts) +{ + bson_error_t error; + bson_json_reader_t *reader; + bson_t doc; + + /* if the file does not exist, skip. */ + if (-1 == access (RESUME_TOKEN_PATH, R_OK)) { + return true; + } + reader = bson_json_reader_new_from_file (RESUME_TOKEN_PATH, &error); + if (!reader) { + fprintf (stderr, "failed to open %s for reading: %s\n", RESUME_TOKEN_PATH, error.message); + return false; + } + + bson_init (&doc); + if (-1 == bson_json_reader_read (reader, &doc, &error)) { + fprintf (stderr, "failed to read doc from %s\n", RESUME_TOKEN_PATH); + bson_destroy (&doc); + bson_json_reader_destroy (reader); + return false; + } + + printf ("found cached resume token in %s, resuming change stream.\n", RESUME_TOKEN_PATH); + + bson_concat (opts, &doc); + bson_destroy (&doc); + bson_json_reader_destroy (reader); + return true; +} + +int +main (void) +{ + int exit_code = EXIT_FAILURE; + const char *uri_string; + mongoc_uri_t *uri = NULL; + bson_error_t error; + mongoc_client_t *client = NULL; + bson_t pipeline = BSON_INITIALIZER; + bson_t opts = BSON_INITIALIZER; + mongoc_change_stream_t *stream = NULL; + const bson_t *doc; + + const int max_time = 30; /* max amount of time, in seconds, that + mongoc_change_stream_next can block. */ + + mongoc_init (); + uri_string = "mongodb://localhost:27017/db?replicaSet=rs0"; + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + goto cleanup; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto cleanup; + } + + if (!_load_resume_token (&opts)) { + goto cleanup; + } + BSON_APPEND_INT64 (&opts, "maxAwaitTimeMS", max_time * 1000); + + printf ("listening for changes on the client (max %d seconds).\n", max_time); + stream = mongoc_client_watch (client, &pipeline, &opts); + + while (mongoc_change_stream_next (stream, &doc)) { + char *as_json; + + as_json = bson_as_canonical_extended_json (doc, NULL); + printf ("change received: %s\n", as_json); + bson_free (as_json); + if (!_save_resume_token (doc)) { + goto cleanup; + } + } + + exit_code = EXIT_SUCCESS; + +cleanup: + mongoc_uri_destroy (uri); + bson_destroy (&pipeline); + bson_destroy (&opts); + mongoc_change_stream_destroy (stream); + mongoc_client_destroy (client); + mongoc_cleanup (); + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/example-scram.c b/source/docs-libmongoc/includes/examples/example-scram.c new file mode 100644 index 00000000..237e5346 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-scram.c @@ -0,0 +1,118 @@ +/* gcc example.c -o example $(pkg-config --cflags --libs libmongoc-1.0) */ + +/* ./example-scram */ + +#include +#include +#include + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client = NULL; + mongoc_database_t *database = NULL; + mongoc_collection_t *collection = NULL; + mongoc_cursor_t *cursor = NULL; + bson_error_t error; + const char *uri_string = "mongodb://127.0.0.1/"; + mongoc_uri_t *uri = NULL; + const char *authuristr; + bson_t roles; + bson_t query; + const bson_t *doc; + int exit_code = EXIT_FAILURE; + + if (argc != 2) { + printf ("%s - [implicit|scram]\n", argv[0]); + return exit_code; + } + + if (strcmp (argv[1], "implicit") == 0) { + authuristr = "mongodb://user,=:pass@127.0.0.1/test?appname=scram-example"; + } else if (strcmp (argv[1], "scram") == 0) { + authuristr = "mongodb://user,=:pass@127.0.0.1/" + "test?appname=scram-example&authMechanism=SCRAM-SHA-1"; + } else { + printf ("%s - [implicit|scram]\n", argv[0]); + return exit_code; + } + + mongoc_init (); + + bson_init (&roles); + bson_init (&query); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + goto CLEANUP; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto CLEANUP; + } + + mongoc_client_set_error_api (client, 2); + + database = mongoc_client_get_database (client, "test"); + + BCON_APPEND (&roles, "0", "{", "role", "root", "db", "admin", "}"); + + mongoc_database_add_user (database, "user,=", "pass", &roles, NULL, &error); + + mongoc_database_destroy (database); + + mongoc_client_destroy (client); + + client = mongoc_client_new (authuristr); + + if (!client) { + fprintf (stderr, "failed to parse SCRAM uri\n"); + goto CLEANUP; + } + + mongoc_client_set_error_api (client, 2); + + collection = mongoc_client_get_collection (client, "test", "test"); + + cursor = mongoc_collection_find_with_opts (collection, &query, NULL, NULL); + + mongoc_cursor_next (cursor, &doc); + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "Auth error: %s\n", error.message); + goto CLEANUP; + } + + exit_code = EXIT_SUCCESS; + +CLEANUP: + + bson_destroy (&roles); + bson_destroy (&query); + + if (collection) { + mongoc_collection_destroy (collection); + } + + if (uri) { + mongoc_uri_destroy (uri); + } + + if (client) { + mongoc_client_destroy (client); + } + + if (cursor) { + mongoc_cursor_destroy (cursor); + } + + mongoc_cleanup (); + + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/example-sdam-monitoring.c b/source/docs-libmongoc/includes/examples/example-sdam-monitoring.c new file mode 100644 index 00000000..de617c87 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-sdam-monitoring.c @@ -0,0 +1,278 @@ +/* gcc example-sdam-monitoring.c -o example-sdam-monitoring \ + * $(pkg-config --cflags --libs libmongoc-1.0) */ + +/* ./example-sdam-monitoring [CONNECTION_STRING] */ + +#include +#include + + +typedef struct { + int server_changed_events; + int server_opening_events; + int server_closed_events; + int topology_changed_events; + int topology_opening_events; + int topology_closed_events; + int heartbeat_started_events; + int heartbeat_succeeded_events; + int heartbeat_failed_events; +} stats_t; + + +static void +server_changed (const mongoc_apm_server_changed_t *event) +{ + stats_t *context; + const mongoc_server_description_t *prev_sd, *new_sd; + + context = (stats_t *) mongoc_apm_server_changed_get_context (event); + context->server_changed_events++; + + prev_sd = mongoc_apm_server_changed_get_previous_description (event); + new_sd = mongoc_apm_server_changed_get_new_description (event); + + printf ("server changed: %s %s -> %s\n", + mongoc_apm_server_changed_get_host (event)->host_and_port, + mongoc_server_description_type (prev_sd), + mongoc_server_description_type (new_sd)); +} + + +static void +server_opening (const mongoc_apm_server_opening_t *event) +{ + stats_t *context; + + context = (stats_t *) mongoc_apm_server_opening_get_context (event); + context->server_opening_events++; + + printf ("server opening: %s\n", mongoc_apm_server_opening_get_host (event)->host_and_port); +} + + +static void +server_closed (const mongoc_apm_server_closed_t *event) +{ + stats_t *context; + + context = (stats_t *) mongoc_apm_server_closed_get_context (event); + context->server_closed_events++; + + printf ("server closed: %s\n", mongoc_apm_server_closed_get_host (event)->host_and_port); +} + + +static void +topology_changed (const mongoc_apm_topology_changed_t *event) +{ + stats_t *context; + const mongoc_topology_description_t *prev_td; + const mongoc_topology_description_t *new_td; + mongoc_server_description_t **prev_sds; + size_t n_prev_sds; + mongoc_server_description_t **new_sds; + size_t n_new_sds; + size_t i; + mongoc_read_prefs_t *prefs; + + context = (stats_t *) mongoc_apm_topology_changed_get_context (event); + context->topology_changed_events++; + + prev_td = mongoc_apm_topology_changed_get_previous_description (event); + prev_sds = mongoc_topology_description_get_servers (prev_td, &n_prev_sds); + new_td = mongoc_apm_topology_changed_get_new_description (event); + new_sds = mongoc_topology_description_get_servers (new_td, &n_new_sds); + + printf ("topology changed: %s -> %s\n", + mongoc_topology_description_type (prev_td), + mongoc_topology_description_type (new_td)); + + if (n_prev_sds) { + printf (" previous servers:\n"); + for (i = 0; i < n_prev_sds; i++) { + printf (" %s %s\n", + mongoc_server_description_type (prev_sds[i]), + mongoc_server_description_host (prev_sds[i])->host_and_port); + } + } + + if (n_new_sds) { + printf (" new servers:\n"); + for (i = 0; i < n_new_sds; i++) { + printf (" %s %s\n", + mongoc_server_description_type (new_sds[i]), + mongoc_server_description_host (new_sds[i])->host_and_port); + } + } + + prefs = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); + + /* it is safe, and unfortunately necessary, to cast away const here */ + if (mongoc_topology_description_has_readable_server ((mongoc_topology_description_t *) new_td, prefs)) { + printf (" secondary AVAILABLE\n"); + } else { + printf (" secondary UNAVAILABLE\n"); + } + + if (mongoc_topology_description_has_writable_server ((mongoc_topology_description_t *) new_td)) { + printf (" primary AVAILABLE\n"); + } else { + printf (" primary UNAVAILABLE\n"); + } + + mongoc_read_prefs_destroy (prefs); + mongoc_server_descriptions_destroy_all (prev_sds, n_prev_sds); + mongoc_server_descriptions_destroy_all (new_sds, n_new_sds); +} + + +static void +topology_opening (const mongoc_apm_topology_opening_t *event) +{ + stats_t *context; + + context = (stats_t *) mongoc_apm_topology_opening_get_context (event); + context->topology_opening_events++; + + printf ("topology opening\n"); +} + + +static void +topology_closed (const mongoc_apm_topology_closed_t *event) +{ + stats_t *context; + + context = (stats_t *) mongoc_apm_topology_closed_get_context (event); + context->topology_closed_events++; + + printf ("topology closed\n"); +} + + +static void +server_heartbeat_started (const mongoc_apm_server_heartbeat_started_t *event) +{ + stats_t *context; + + context = (stats_t *) mongoc_apm_server_heartbeat_started_get_context (event); + context->heartbeat_started_events++; + + printf ("%s heartbeat started\n", mongoc_apm_server_heartbeat_started_get_host (event)->host_and_port); +} + + +static void +server_heartbeat_succeeded (const mongoc_apm_server_heartbeat_succeeded_t *event) +{ + stats_t *context; + char *reply; + + context = (stats_t *) mongoc_apm_server_heartbeat_succeeded_get_context (event); + context->heartbeat_succeeded_events++; + + reply = bson_as_canonical_extended_json (mongoc_apm_server_heartbeat_succeeded_get_reply (event), NULL); + + printf ( + "%s heartbeat succeeded: %s\n", mongoc_apm_server_heartbeat_succeeded_get_host (event)->host_and_port, reply); + + bson_free (reply); +} + + +static void +server_heartbeat_failed (const mongoc_apm_server_heartbeat_failed_t *event) +{ + stats_t *context; + bson_error_t error; + + context = (stats_t *) mongoc_apm_server_heartbeat_failed_get_context (event); + context->heartbeat_failed_events++; + mongoc_apm_server_heartbeat_failed_get_error (event, &error); + + printf ( + "%s heartbeat failed: %s\n", mongoc_apm_server_heartbeat_failed_get_host (event)->host_and_port, error.message); +} + + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client; + mongoc_apm_callbacks_t *cbs; + stats_t stats = {0}; + const char *uri_string = "mongodb://127.0.0.1/?appname=sdam-monitoring-example"; + mongoc_uri_t *uri; + bson_t cmd = BSON_INITIALIZER; + bson_t reply; + bson_error_t error; + + mongoc_init (); + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + cbs = mongoc_apm_callbacks_new (); + mongoc_apm_set_server_changed_cb (cbs, server_changed); + mongoc_apm_set_server_opening_cb (cbs, server_opening); + mongoc_apm_set_server_closed_cb (cbs, server_closed); + mongoc_apm_set_topology_changed_cb (cbs, topology_changed); + mongoc_apm_set_topology_opening_cb (cbs, topology_opening); + mongoc_apm_set_topology_closed_cb (cbs, topology_closed); + mongoc_apm_set_server_heartbeat_started_cb (cbs, server_heartbeat_started); + mongoc_apm_set_server_heartbeat_succeeded_cb (cbs, server_heartbeat_succeeded); + mongoc_apm_set_server_heartbeat_failed_cb (cbs, server_heartbeat_failed); + mongoc_client_set_apm_callbacks (client, cbs, (void *) &stats /* context pointer */); + + /* the driver connects on demand to perform first operation */ + BSON_APPEND_INT32 (&cmd, "buildinfo", 1); + mongoc_client_command_simple (client, "admin", &cmd, NULL, &reply, &error); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + printf ("Events:\n" + " server changed: %d\n" + " server opening: %d\n" + " server closed: %d\n" + " topology changed: %d\n" + " topology opening: %d\n" + " topology closed: %d\n" + " heartbeat started: %d\n" + " heartbeat succeeded: %d\n" + " heartbeat failed: %d\n", + stats.server_changed_events, + stats.server_opening_events, + stats.server_closed_events, + stats.topology_changed_events, + stats.topology_opening_events, + stats.topology_closed_events, + stats.heartbeat_started_events, + stats.heartbeat_succeeded_events, + stats.heartbeat_failed_events); + + bson_destroy (&cmd); + bson_destroy (&reply); + mongoc_apm_callbacks_destroy (cbs); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-session.c b/source/docs-libmongoc/includes/examples/example-session.c new file mode 100644 index 00000000..589c9c51 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-session.c @@ -0,0 +1,143 @@ +/* gcc example-session.c -o example-session \ + * $(pkg-config --cflags --libs libmongoc-1.0) */ + +/* ./example-session [CONNECTION_STRING] */ + +#include +#include + + +int +main (int argc, char *argv[]) +{ + int exit_code = EXIT_FAILURE; + + mongoc_client_t *client = NULL; + const char *uri_string = "mongodb://127.0.0.1/?appname=session-example"; + mongoc_uri_t *uri = NULL; + mongoc_client_session_t *client_session = NULL; + mongoc_collection_t *collection = NULL; + bson_error_t error; + bson_t *selector = NULL; + bson_t *update = NULL; + bson_t *update_opts = NULL; + bson_t *find_opts = NULL; + mongoc_read_prefs_t *secondary = NULL; + mongoc_cursor_t *cursor = NULL; + const bson_t *doc; + char *str; + bool r; + + mongoc_init (); + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + goto done; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto done; + } + + mongoc_client_set_error_api (client, 2); + + /* pass NULL for options - by default the session is causally consistent */ + client_session = mongoc_client_start_session (client, NULL, &error); + if (!client_session) { + fprintf (stderr, "Failed to start session: %s\n", error.message); + goto done; + } + + collection = mongoc_client_get_collection (client, "test", "collection"); + selector = BCON_NEW ("_id", BCON_INT32 (1)); + update = BCON_NEW ("$inc", "{", "x", BCON_INT32 (1), "}"); + update_opts = bson_new (); + if (!mongoc_client_session_append (client_session, update_opts, &error)) { + fprintf (stderr, "Could not add session to opts: %s\n", error.message); + goto done; + } + + r = mongoc_collection_update_one (collection, selector, update, update_opts, NULL /* reply */, &error); + + if (!r) { + fprintf (stderr, "Update failed: %s\n", error.message); + goto done; + } + + bson_destroy (selector); + selector = BCON_NEW ("_id", BCON_INT32 (1)); + secondary = mongoc_read_prefs_new (MONGOC_READ_SECONDARY); + + find_opts = BCON_NEW ("maxTimeMS", BCON_INT32 (2000)); + if (!mongoc_client_session_append (client_session, find_opts, &error)) { + fprintf (stderr, "Could not add session to opts: %s\n", error.message); + goto done; + } + + /* read from secondary. since we're in a causally consistent session, the + * data is guaranteed to reflect the update we did on the primary. the query + * blocks waiting for the secondary to catch up, if necessary, or times out + * and fails after 2000 ms. + */ + cursor = mongoc_collection_find_with_opts (collection, selector, find_opts, secondary); + + while (mongoc_cursor_next (cursor, &doc)) { + str = bson_as_json (doc, NULL); + fprintf (stdout, "%s\n", str); + bson_free (str); + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "Cursor Failure: %s\n", error.message); + goto done; + } + + exit_code = EXIT_SUCCESS; + +done: + if (find_opts) { + bson_destroy (find_opts); + } + if (update) { + bson_destroy (update); + } + if (selector) { + bson_destroy (selector); + } + if (update_opts) { + bson_destroy (update_opts); + } + if (secondary) { + mongoc_read_prefs_destroy (secondary); + } + /* destroy cursor, collection, session before the client they came from */ + if (cursor) { + mongoc_cursor_destroy (cursor); + } + if (collection) { + mongoc_collection_destroy (collection); + } + if (client_session) { + mongoc_client_session_destroy (client_session); + } + if (uri) { + mongoc_uri_destroy (uri); + } + if (client) { + mongoc_client_destroy (client); + } + + mongoc_cleanup (); + + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/example-start-at-optime.c b/source/docs-libmongoc/includes/examples/example-start-at-optime.c new file mode 100644 index 00000000..0b7f4069 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-start-at-optime.c @@ -0,0 +1,94 @@ +/* An example of starting a change stream with startAtOperationTime. */ +#include + +int +main (void) +{ + int exit_code = EXIT_FAILURE; + const char *uri_string; + mongoc_uri_t *uri = NULL; + bson_error_t error; + mongoc_client_t *client = NULL; + mongoc_collection_t *coll = NULL; + bson_t pipeline = BSON_INITIALIZER; + bson_t opts = BSON_INITIALIZER; + mongoc_change_stream_t *stream = NULL; + bson_iter_t iter; + const bson_t *doc; + bson_value_t cached_operation_time = {0}; + int i; + bool r; + + mongoc_init (); + uri_string = "mongodb://localhost:27017/db?replicaSet=rs0"; + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + goto cleanup; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto cleanup; + } + + /* insert five documents. */ + coll = mongoc_client_get_collection (client, "db", "coll"); + for (i = 0; i < 5; i++) { + bson_t reply; + bson_t *insert_cmd = BCON_NEW ("insert", "coll", "documents", "[", "{", "x", BCON_INT64 (i), "}", "]"); + + r = mongoc_collection_write_command_with_opts (coll, insert_cmd, NULL, &reply, &error); + bson_destroy (insert_cmd); + if (!r) { + bson_destroy (&reply); + fprintf (stderr, "failed to insert: %s\n", error.message); + goto cleanup; + } + if (i == 0) { + /* cache the operation time in the first reply. */ + if (bson_iter_init_find (&iter, &reply, "operationTime")) { + bson_value_copy (bson_iter_value (&iter), &cached_operation_time); + } else { + fprintf (stderr, "reply does not contain operationTime."); + bson_destroy (&reply); + goto cleanup; + } + } + bson_destroy (&reply); + } + + /* start a change stream at the first returned operationTime. */ + BSON_APPEND_VALUE (&opts, "startAtOperationTime", &cached_operation_time); + stream = mongoc_collection_watch (coll, &pipeline, &opts); + + /* since the change stream started at the operation time of the first + * insert, the five inserts are returned. */ + printf ("listening for changes on db.coll:\n"); + while (mongoc_change_stream_next (stream, &doc)) { + char *as_json; + + as_json = bson_as_canonical_extended_json (doc, NULL); + printf ("change received: %s\n", as_json); + bson_free (as_json); + } + + exit_code = EXIT_SUCCESS; + +cleanup: + mongoc_uri_destroy (uri); + bson_destroy (&pipeline); + bson_destroy (&opts); + if (cached_operation_time.value_type) { + bson_value_destroy (&cached_operation_time); + } + mongoc_change_stream_destroy (stream); + mongoc_collection_destroy (coll); + mongoc_client_destroy (client); + mongoc_cleanup (); + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/example-transaction.c b/source/docs-libmongoc/includes/examples/example-transaction.c new file mode 100644 index 00000000..f7aa48bd --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-transaction.c @@ -0,0 +1,176 @@ +/* gcc example-transaction.c -o example-transaction \ + * $(pkg-config --cflags --libs libmongoc-1.0) */ + +/* ./example-transaction [CONNECTION_STRING] */ + +#include +#include + + +int +main (int argc, char *argv[]) +{ + int exit_code = EXIT_FAILURE; + + mongoc_client_t *client = NULL; + mongoc_database_t *database = NULL; + mongoc_collection_t *collection = NULL; + mongoc_client_session_t *session = NULL; + mongoc_session_opt_t *session_opts = NULL; + mongoc_transaction_opt_t *default_txn_opts = NULL; + mongoc_transaction_opt_t *txn_opts = NULL; + mongoc_read_concern_t *read_concern = NULL; + mongoc_write_concern_t *write_concern = NULL; + const char *uri_string = "mongodb://127.0.0.1/?appname=transaction-example"; + mongoc_uri_t *uri; + bson_error_t error; + bson_t *doc = NULL; + bson_t *insert_opts = NULL; + int32_t i; + int64_t start; + bson_t reply = BSON_INITIALIZER; + char *reply_json; + bool r; + + mongoc_init (); + + if (argc > 1) { + uri_string = argv[1]; + } + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + MONGOC_ERROR ("failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + goto done; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto done; + } + + mongoc_client_set_error_api (client, 2); + database = mongoc_client_get_database (client, "example-transaction"); + + /* inserting into a nonexistent collection normally creates it, but a + * collection can't be created in a transaction; create it now */ + collection = mongoc_database_create_collection (database, "collection", NULL, &error); + + if (!collection) { + /* code 48 is NamespaceExists, see error_codes.err in mongodb source */ + if (error.code == 48) { + collection = mongoc_database_get_collection (database, "collection"); + } else { + MONGOC_ERROR ("Failed to create collection: %s", error.message); + goto done; + } + } + + /* a transaction's read preferences, read concern, and write concern can be + * set on the client, on the default transaction options, or when starting + * the transaction. for the sake of this example, set read concern on the + * default transaction options. */ + default_txn_opts = mongoc_transaction_opts_new (); + read_concern = mongoc_read_concern_new (); + mongoc_read_concern_set_level (read_concern, "snapshot"); + mongoc_transaction_opts_set_read_concern (default_txn_opts, read_concern); + session_opts = mongoc_session_opts_new (); + mongoc_session_opts_set_default_transaction_opts (session_opts, default_txn_opts); + + session = mongoc_client_start_session (client, session_opts, &error); + if (!session) { + MONGOC_ERROR ("Failed to start session: %s", error.message); + goto done; + } + + /* in this example, set write concern when starting the transaction */ + txn_opts = mongoc_transaction_opts_new (); + write_concern = mongoc_write_concern_new (); + mongoc_write_concern_set_wmajority (write_concern, 1000 /* wtimeout */); + mongoc_transaction_opts_set_write_concern (txn_opts, write_concern); + + insert_opts = bson_new (); + if (!mongoc_client_session_append (session, insert_opts, &error)) { + MONGOC_ERROR ("Could not add session to opts: %s", error.message); + goto done; + } + +retry_transaction: + r = mongoc_client_session_start_transaction (session, txn_opts, &error); + if (!r) { + MONGOC_ERROR ("Failed to start transaction: %s", error.message); + goto done; + } + + /* insert two documents - on error, retry the whole transaction */ + for (i = 0; i < 2; i++) { + doc = BCON_NEW ("_id", BCON_INT32 (i)); + bson_destroy (&reply); + r = mongoc_collection_insert_one (collection, doc, insert_opts, &reply, &error); + + bson_destroy (doc); + + if (!r) { + MONGOC_ERROR ("Insert failed: %s", error.message); + mongoc_client_session_abort_transaction (session, NULL); + + /* a network error, primary failover, or other temporary error in a + * transaction includes {"errorLabels": ["TransientTransactionError"]}, + * meaning that trying the entire transaction again may succeed + */ + if (mongoc_error_has_label (&reply, "TransientTransactionError")) { + goto retry_transaction; + } + + goto done; + } + + reply_json = bson_as_json (&reply, NULL); + printf ("%s\n", reply_json); + bson_free (reply_json); + } + + /* in case of transient errors, retry for 5 seconds to commit transaction */ + start = bson_get_monotonic_time (); + while (bson_get_monotonic_time () - start < 5 * 1000 * 1000) { + bson_destroy (&reply); + r = mongoc_client_session_commit_transaction (session, &reply, &error); + if (r) { + /* success */ + break; + } else { + MONGOC_ERROR ("Warning: commit failed: %s", error.message); + if (mongoc_error_has_label (&reply, "TransientTransactionError")) { + goto retry_transaction; + } else if (mongoc_error_has_label (&reply, "UnknownTransactionCommitResult")) { + /* try again to commit */ + continue; + } + + /* unrecoverable error trying to commit */ + break; + } + } + + exit_code = EXIT_SUCCESS; + +done: + bson_destroy (&reply); + bson_destroy (insert_opts); + mongoc_write_concern_destroy (write_concern); + mongoc_read_concern_destroy (read_concern); + mongoc_transaction_opts_destroy (txn_opts); + mongoc_transaction_opts_destroy (default_txn_opts); + mongoc_client_session_destroy (session); + mongoc_collection_destroy (collection); + mongoc_database_destroy (database); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/example-update.c b/source/docs-libmongoc/includes/examples/example-update.c new file mode 100644 index 00000000..2443eee7 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-update.c @@ -0,0 +1,68 @@ +#include "mongoc/mongoc.h" + +int +main (void) +{ + bson_t *to_insert = BCON_NEW ("_id", BCON_INT32 (1)); + bson_t *selector = BCON_NEW ("_id", "{", "$gt", BCON_INT32 (0), "}"); + bson_t *update = BCON_NEW ("$set", "{", "x", BCON_INT32 (1), "}"); + const bson_t *next_doc; + char *to_str; + bson_error_t error = {0}; + mongoc_cursor_t *cursor; + mongoc_client_t *client; + mongoc_collection_t *coll; + const char *uri_string = "mongodb://localhost:27017/?appname=example-update"; + mongoc_uri_t *uri = mongoc_uri_new_with_error (uri_string, &error); + + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + coll = mongoc_client_get_collection (client, "db", "example_coll"); + + mongoc_client_set_error_api (client, 2); + /* insert a document */ + if (!mongoc_collection_insert_one (coll, to_insert, NULL, NULL, &error)) { + fprintf (stderr, "insert failed: %s\n", error.message); + return EXIT_FAILURE; + } + + if (!mongoc_collection_update_one (coll, selector, update, NULL, NULL, &error)) { + fprintf (stderr, "update failed: %s\n", error.message); + return EXIT_FAILURE; + } + + to_str = bson_as_relaxed_extended_json (to_insert, NULL); + printf ("inserted: %s\n", to_str); + bson_free (to_str); + + cursor = mongoc_collection_find_with_opts (coll, selector, NULL, NULL); + BSON_ASSERT (mongoc_cursor_next (cursor, &next_doc)); + printf ("after update, collection has the following document:\n"); + + to_str = bson_as_relaxed_extended_json (next_doc, NULL); + printf ("%s\n", to_str); + bson_free (to_str); + + BSON_ASSERT (mongoc_collection_drop (coll, NULL)); + + bson_destroy (to_insert); + bson_destroy (update); + bson_destroy (selector); + mongoc_collection_destroy (coll); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/example-with-transaction-cb.c b/source/docs-libmongoc/includes/examples/example-with-transaction-cb.c new file mode 100644 index 00000000..66f171d8 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/example-with-transaction-cb.c @@ -0,0 +1,180 @@ +/* gcc example-with-transaction-cb.c -o example-with-transaction-cb $(pkg-config + * --cflags --libs libmongoc-1.0) */ + +/* ./example-with-transaction-cb [CONNECTION_STRING] */ + +#include +#include +#include + +/* + * We pass this context object to mongoc_client_session_with_transaction() along + * with our callback function. The context object will be passed to our callback + * function when it runs, so we can access it. + */ +typedef struct { + mongoc_collection_t *collection; + bson_t *insert_opts; +} ctx_t; + +/* + * We pass this method as the callback to + * mongoc_client_session_with_transaction(). The insert that this method + * performs will happen inside of a new transaction. + */ +bool +create_and_insert_doc (mongoc_client_session_t *session, + void *ctx, + bson_t **reply, /* out param for our server reply */ + bson_error_t *error) +{ + /* + * mongoc_collection_insert_one requires an uninitialized, stack-allocated + * bson_t to receive the update result + */ + bson_t local_reply; + bson_t *doc = NULL; + ctx_t *data = NULL; + bool retval; + + /* + * Create a new bson document - { id: 1 } + */ + doc = BCON_NEW ("_id", BCON_INT32 (1)); + + printf ("Running the user-defined callback in a newly created transaction...\n"); + data = (ctx_t *) ctx; + retval = mongoc_collection_insert_one (data->collection, doc, data->insert_opts, &local_reply, error); + + /* + * To return to the mongoc_client_session_with_transaction() method, set + * *reply to a new copy of our local_reply before destroying it. + */ + *reply = bson_copy (&local_reply); + bson_destroy (&local_reply); + + bson_destroy (doc); + return retval; +} + +int +main (int argc, char *argv[]) +{ + int exit_code = EXIT_FAILURE; + + mongoc_uri_t *uri = NULL; + const char *uri_string = "mongodb://127.0.0.1/?appname=with-txn-cb-example"; + mongoc_client_t *client = NULL; + mongoc_database_t *database = NULL; + mongoc_collection_t *collection = NULL; + mongoc_client_session_t *session = NULL; + bson_t *insert_opts = NULL; + bson_t reply; + ctx_t ctx; + char *str; + bson_error_t error; + + /* + * Required to initialize libmongoc's internals + */ + mongoc_init (); + + /* + * Optionally get MongoDB URI from command line + */ + if (argc > 1) { + uri_string = argv[1]; + } + + /* + * Safely create a MongoDB URI object from the given string + */ + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + MONGOC_ERROR ("failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + goto done; + } + + /* + * Create a new client instance + */ + client = mongoc_client_new_from_uri (uri); + if (!client) { + goto done; + } + + mongoc_client_set_error_api (client, 2); + + /* + * Get a handle on the database "example-with-txn-cb" + */ + database = mongoc_client_get_database (client, "example-with-txn-cb"); + + /* + * Inserting into a nonexistent collection normally creates it, but a + * collection can't be created in a transaction; create it now + */ + collection = mongoc_database_create_collection (database, "collection", NULL, &error); + if (!collection) { + /* code 48 is NamespaceExists, see error_codes.err in mongodb source */ + if (error.code == 48) { + collection = mongoc_database_get_collection (database, "collection"); + } else { + MONGOC_ERROR ("Failed to create collection: %s", error.message); + goto done; + } + } + + /* + * Pass NULL for options - by default the session is causally consistent + */ + session = mongoc_client_start_session (client, NULL, &error); + if (!session) { + MONGOC_ERROR ("Failed to start session: %s", error.message); + goto done; + } + + /* + * Append a logical session id to command options + */ + insert_opts = bson_new (); + if (!mongoc_client_session_append (session, insert_opts, &error)) { + MONGOC_ERROR ("Could not add session to opts: %s", error.message); + goto done; + } + + ctx.collection = collection; + ctx.insert_opts = insert_opts; + + /* + * This method will start a new transaction on session, run our callback + * function, i.e., &create_and_insert_doc, passing &ctx as an argument and + * commit the transaction. + */ + if (!mongoc_client_session_with_transaction (session, &create_and_insert_doc, NULL, &ctx, &reply, &error)) { + MONGOC_ERROR ("Insert failed: %s", error.message); + goto done; + } + + str = bson_as_json (&reply, NULL); + printf ("%s\n", str); + + exit_code = EXIT_SUCCESS; + +done: + bson_free (str); + bson_destroy (&reply); + bson_destroy (insert_opts); + mongoc_client_session_destroy (session); + mongoc_collection_destroy (collection); + mongoc_database_destroy (database); + mongoc_client_destroy (client); + mongoc_uri_destroy (uri); + + mongoc_cleanup (); + + return exit_code; +} diff --git a/source/docs-libmongoc/includes/examples/find-and-modify.c b/source/docs-libmongoc/includes/examples/find-and-modify.c new file mode 100644 index 00000000..b2dbb02c --- /dev/null +++ b/source/docs-libmongoc/includes/examples/find-and-modify.c @@ -0,0 +1,76 @@ +#include +#include + + +int +main (void) +{ + mongoc_collection_t *collection; + mongoc_client_t *client; + const char *uri_string = "mongodb://127.0.0.1:27017/?appname=find-and-modify-example"; + mongoc_uri_t *uri; + bson_error_t error; + bson_t *query; + bson_t *update; + bson_t reply; + char *str; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + collection = mongoc_client_get_collection (client, "test", "test"); + + /* + * Build our query, {"cmpxchg": 1} + */ + query = BCON_NEW ("cmpxchg", BCON_INT32 (1)); + + /* + * Build our update. {"$set": {"cmpxchg": 2}} + */ + update = BCON_NEW ("$set", "{", "cmpxchg", BCON_INT32 (2), "}"); + + /* + * Submit the findAndModify. + */ + if (!mongoc_collection_find_and_modify (collection, query, NULL, update, NULL, false, false, true, &reply, &error)) { + fprintf (stderr, "find_and_modify() failure: %s\n", error.message); + return EXIT_FAILURE; + } + + /* + * Print the result as JSON. + */ + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + + /* + * Cleanup. + */ + bson_destroy (query); + bson_destroy (update); + bson_destroy (&reply); + mongoc_collection_destroy (collection); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/find_and_modify_with_opts/fam.c b/source/docs-libmongoc/includes/examples/find_and_modify_with_opts/fam.c new file mode 100644 index 00000000..3fd91b50 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/find_and_modify_with_opts/fam.c @@ -0,0 +1,364 @@ + +#include + +/* EXAMPLE_FAM_BYPASS_BEGIN */ +void +fam_bypass (mongoc_collection_t *collection) +{ + mongoc_find_and_modify_opts_t *opts; + bson_t reply; + bson_t *update; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + bool success; + + + /* Find Zlatan Ibrahimovic, the striker */ + BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); + BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); + BSON_APPEND_UTF8 (&query, "profession", "Football player"); + + /* Bump his age */ + update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}"); + + opts = mongoc_find_and_modify_opts_new (); + mongoc_find_and_modify_opts_set_update (opts, update); + /* He can still play, even though he is pretty old. */ + mongoc_find_and_modify_opts_set_bypass_document_validation (opts, true); + + success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); + + if (success) { + char *str; + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + } + + bson_destroy (&reply); + bson_destroy (update); + bson_destroy (&query); + mongoc_find_and_modify_opts_destroy (opts); +} +/* EXAMPLE_FAM_BYPASS_END */ + +/* EXAMPLE_FAM_FLAGS_BEGIN */ +void +fam_flags (mongoc_collection_t *collection) +{ + mongoc_find_and_modify_opts_t *opts; + bson_t reply; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + bson_t *update; + bool success; + + + /* Find Zlatan Ibrahimovic, the striker */ + BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); + BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); + BSON_APPEND_UTF8 (&query, "profession", "Football player"); + BSON_APPEND_INT32 (&query, "age", 34); + BSON_APPEND_INT32 (&query, "goals", (16 + 35 + 23 + 57 + 16 + 14 + 28 + 84) + (1 + 6 + 62)); + + /* Add his football position */ + update = BCON_NEW ("$set", "{", "position", BCON_UTF8 ("striker"), "}"); + + opts = mongoc_find_and_modify_opts_new (); + + mongoc_find_and_modify_opts_set_update (opts, update); + + /* Create the document if it didn't exist, and return the updated document */ + mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_UPSERT | MONGOC_FIND_AND_MODIFY_RETURN_NEW); + + success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); + + if (success) { + char *str; + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + } + + bson_destroy (&reply); + bson_destroy (update); + bson_destroy (&query); + mongoc_find_and_modify_opts_destroy (opts); +} +/* EXAMPLE_FAM_FLAGS_END */ + +/* EXAMPLE_FAM_UPDATE_BEGIN */ +void +fam_update (mongoc_collection_t *collection) +{ + mongoc_find_and_modify_opts_t *opts; + bson_t *update; + bson_t reply; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + bool success; + + + /* Find Zlatan Ibrahimovic */ + BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); + BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); + + /* Make him a book author */ + update = BCON_NEW ("$set", "{", "author", BCON_BOOL (true), "}"); + + opts = mongoc_find_and_modify_opts_new (); + /* Note that the document returned is the _previous_ version of the document + * To fetch the modified new version, use + * mongoc_find_and_modify_opts_set_flags (opts, + * MONGOC_FIND_AND_MODIFY_RETURN_NEW); + */ + mongoc_find_and_modify_opts_set_update (opts, update); + + success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); + + if (success) { + char *str; + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + } + + bson_destroy (&reply); + bson_destroy (update); + bson_destroy (&query); + mongoc_find_and_modify_opts_destroy (opts); +} +/* EXAMPLE_FAM_UPDATE_END */ + +/* EXAMPLE_FAM_FIELDS_BEGIN */ +void +fam_fields (mongoc_collection_t *collection) +{ + mongoc_find_and_modify_opts_t *opts; + bson_t fields = BSON_INITIALIZER; + bson_t *update; + bson_t reply; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + bool success; + + + /* Find Zlatan Ibrahimovic */ + BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); + BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); + + /* Return his goal tally */ + BSON_APPEND_INT32 (&fields, "goals", 1); + + /* Bump his goal tally */ + update = BCON_NEW ("$inc", "{", "goals", BCON_INT32 (1), "}"); + + opts = mongoc_find_and_modify_opts_new (); + mongoc_find_and_modify_opts_set_update (opts, update); + mongoc_find_and_modify_opts_set_fields (opts, &fields); + /* Return the new tally */ + mongoc_find_and_modify_opts_set_flags (opts, MONGOC_FIND_AND_MODIFY_RETURN_NEW); + + success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); + + if (success) { + char *str; + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + } + + bson_destroy (&reply); + bson_destroy (update); + bson_destroy (&fields); + bson_destroy (&query); + mongoc_find_and_modify_opts_destroy (opts); +} +/* EXAMPLE_FAM_FIELDS_END */ + +/* EXAMPLE_FAM_OPTS_BEGIN */ +void +fam_opts (mongoc_collection_t *collection) +{ + mongoc_find_and_modify_opts_t *opts; + bson_t reply; + bson_t *update; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + mongoc_write_concern_t *wc; + bson_t extra = BSON_INITIALIZER; + bool success; + + + /* Find Zlatan Ibrahimovic, the striker */ + BSON_APPEND_UTF8 (&query, "firstname", "Zlatan"); + BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); + BSON_APPEND_UTF8 (&query, "profession", "Football player"); + + /* Bump his age */ + update = BCON_NEW ("$inc", "{", "age", BCON_INT32 (1), "}"); + + opts = mongoc_find_and_modify_opts_new (); + mongoc_find_and_modify_opts_set_update (opts, update); + + /* Abort if the operation takes too long. */ + mongoc_find_and_modify_opts_set_max_time_ms (opts, 100); + + /* Set write concern w: 2 */ + wc = mongoc_write_concern_new (); + mongoc_write_concern_set_w (wc, 2); + mongoc_write_concern_append (wc, &extra); + + /* Some future findAndModify option the driver doesn't support conveniently + */ + BSON_APPEND_INT32 (&extra, "futureOption", 42); + mongoc_find_and_modify_opts_append (opts, &extra); + + success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); + + if (success) { + char *str; + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + } + + bson_destroy (&reply); + bson_destroy (&extra); + bson_destroy (update); + bson_destroy (&query); + mongoc_write_concern_destroy (wc); + mongoc_find_and_modify_opts_destroy (opts); +} +/* EXAMPLE_FAM_OPTS_END */ + +/* EXAMPLE_FAM_SORT_BEGIN */ +void +fam_sort (mongoc_collection_t *collection) +{ + mongoc_find_and_modify_opts_t *opts; + bson_t *update; + bson_t sort = BSON_INITIALIZER; + bson_t reply; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + bool success; + + + /* Find all users with the lastname Ibrahimovic */ + BSON_APPEND_UTF8 (&query, "lastname", "Ibrahimovic"); + + /* Sort by age (descending) */ + BSON_APPEND_INT32 (&sort, "age", -1); + + /* Bump his goal tally */ + update = BCON_NEW ("$set", "{", "oldest", BCON_BOOL (true), "}"); + + opts = mongoc_find_and_modify_opts_new (); + mongoc_find_and_modify_opts_set_update (opts, update); + mongoc_find_and_modify_opts_set_sort (opts, &sort); + + success = mongoc_collection_find_and_modify_with_opts (collection, &query, opts, &reply, &error); + + if (success) { + char *str; + + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + } + + bson_destroy (&reply); + bson_destroy (update); + bson_destroy (&sort); + bson_destroy (&query); + mongoc_find_and_modify_opts_destroy (opts); +} +/* EXAMPLE_FAM_SORT_END */ + +/* EXAMPLE_FAM_MAIN_BEGIN */ +int +main (void) +{ + mongoc_collection_t *collection; + mongoc_database_t *database; + mongoc_client_t *client; + const char *uri_string = "mongodb://localhost:27017/admin?appname=find-and-modify-opts-example"; + mongoc_uri_t *uri; + bson_error_t error; + bson_t *options; + + mongoc_init (); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + database = mongoc_client_get_database (client, "databaseName"); + + options = BCON_NEW ("validator", + "{", + "age", + "{", + "$lte", + BCON_INT32 (34), + "}", + "}", + "validationAction", + BCON_UTF8 ("error"), + "validationLevel", + BCON_UTF8 ("moderate")); + + collection = mongoc_database_create_collection (database, "collectionName", options, &error); + if (!collection) { + fprintf (stderr, "Got error: \"%s\" on line %d\n", error.message, __LINE__); + return EXIT_FAILURE; + } + + fam_flags (collection); + fam_bypass (collection); + fam_update (collection); + fam_fields (collection); + fam_opts (collection); + fam_sort (collection); + + mongoc_collection_drop (collection, NULL); + bson_destroy (options); + mongoc_uri_destroy (uri); + mongoc_database_destroy (database); + mongoc_collection_destroy (collection); + mongoc_client_destroy (client); + + mongoc_cleanup (); + return EXIT_SUCCESS; +} +/* EXAMPLE_FAM_MAIN_END */ diff --git a/source/docs-libmongoc/includes/examples/hello_mongoc.c b/source/docs-libmongoc/includes/examples/hello_mongoc.c new file mode 100644 index 00000000..f4ad8fae --- /dev/null +++ b/source/docs-libmongoc/includes/examples/hello_mongoc.c @@ -0,0 +1,115 @@ +/* + * Copyright 2017 MongoDB Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* -- sphinx-include-start -- */ +#include + +int +main (int argc, char *argv[]) +{ + const char *uri_string = "mongodb://localhost:27017"; + mongoc_uri_t *uri; + mongoc_client_t *client; + mongoc_database_t *database; + mongoc_collection_t *collection; + bson_t *command, reply, *insert; + bson_error_t error; + char *str; + bool retval; + + /* + * Required to initialize libmongoc's internals + */ + mongoc_init (); + + /* + * Optionally get MongoDB URI from command line + */ + if (argc > 1) { + uri_string = argv[1]; + } + + /* + * Safely create a MongoDB URI object from the given string + */ + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + /* + * Create a new client instance + */ + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + /* + * Register the application name so we can track it in the profile logs + * on the server. This can also be done from the URI (see other examples). + */ + mongoc_client_set_appname (client, "connect-example"); + + /* + * Get a handle on the database "db_name" and collection "coll_name" + */ + database = mongoc_client_get_database (client, "db_name"); + collection = mongoc_client_get_collection (client, "db_name", "coll_name"); + + /* + * Do work. This example pings the database, prints the result as JSON and + * performs an insert + */ + command = BCON_NEW ("ping", BCON_INT32 (1)); + + retval = mongoc_client_command_simple (client, "admin", command, NULL, &reply, &error); + + if (!retval) { + fprintf (stderr, "%s\n", error.message); + return EXIT_FAILURE; + } + + str = bson_as_json (&reply, NULL); + printf ("%s\n", str); + + insert = BCON_NEW ("hello", BCON_UTF8 ("world")); + + if (!mongoc_collection_insert_one (collection, insert, NULL, NULL, &error)) { + fprintf (stderr, "%s\n", error.message); + } + + bson_destroy (insert); + bson_destroy (&reply); + bson_destroy (command); + bson_free (str); + + /* + * Release our handles and clean up libmongoc + */ + mongoc_collection_destroy (collection); + mongoc_database_destroy (database); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + mongoc_cleanup (); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/mongoc-dump.c b/source/docs-libmongoc/includes/examples/mongoc-dump.c new file mode 100644 index 00000000..2323cde9 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/mongoc-dump.c @@ -0,0 +1,251 @@ +/* + * Copyright 2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include +#include + + +static bool +mongoc_dump_mkdir_p (const char *path, int mode) +{ + int r; + +#ifdef _WIN32 + r = _mkdir (path); +#else + r = mkdir (path, mode); +#endif + + return (r == 0 || errno == EEXIST); +} + + +static int +mongoc_dump_collection (mongoc_client_t *client, const char *database, const char *collection) +{ + mongoc_collection_t *col; + mongoc_cursor_t *cursor; + const bson_t *doc; + bson_error_t error; + bson_t query = BSON_INITIALIZER; + FILE *stream; + char *path; + int ret = EXIT_SUCCESS; + + path = bson_strdup_printf ("dump/%s/%s.bson", database, collection); +#ifdef _WIN32 + _unlink (path); +#else + unlink (path); +#endif + + stream = fopen (path, "w"); + if (!stream) { + fprintf (stderr, "Failed to open \"%s\", aborting.\n", path); + exit (EXIT_FAILURE); + } + + col = mongoc_client_get_collection (client, database, collection); + cursor = mongoc_collection_find_with_opts (col, &query, NULL, NULL); + + while (mongoc_cursor_next (cursor, &doc)) { + if (BSON_UNLIKELY (doc->len != fwrite (bson_get_data (doc), 1, doc->len, stream))) { + fprintf (stderr, "Failed to write %u bytes to %s\n", doc->len, path); + ret = EXIT_FAILURE; + goto cleanup; + } + } + + if (mongoc_cursor_error (cursor, &error)) { + fprintf (stderr, "ERROR: %s\n", error.message); + ret = EXIT_FAILURE; + } + +cleanup: + bson_free (path); + fclose (stream); + mongoc_cursor_destroy (cursor); + mongoc_collection_destroy (col); + + return ret; +} + + +static int +mongoc_dump_database (mongoc_client_t *client, const char *database, const char *collection) +{ + mongoc_database_t *db; + bson_error_t error; + char *path; + char **str; + int ret = EXIT_SUCCESS; + int i; + + BSON_ASSERT_PARAM (client); + BSON_ASSERT (database); + + path = bson_strdup_printf ("dump/%s", database); + if (!mongoc_dump_mkdir_p (path, 0750)) { + fprintf (stderr, "failed to create directory \"%s\"", path); + bson_free (path); + return EXIT_FAILURE; + } + + bson_free (path); + + if (collection) { + return mongoc_dump_collection (client, database, collection); + } + + db = mongoc_client_get_database (client, database); + str = mongoc_database_get_collection_names_with_opts (db, NULL, &error); + for (i = 0; str[i]; i++) { + if (EXIT_SUCCESS != mongoc_dump_collection (client, database, str[i])) { + ret = EXIT_FAILURE; + goto cleanup; + } + } + +cleanup: + mongoc_database_destroy (db); + bson_strfreev (str); + + return ret; +} + + +static int +mongoc_dump (mongoc_client_t *client, const char *database, const char *collection) +{ + bson_error_t error; + char **str; + int i; + + BSON_ASSERT_PARAM (client); + + if (!mongoc_dump_mkdir_p ("dump", 0750)) { + perror ("Failed to create directory \"dump\""); + return EXIT_FAILURE; + } + + if (database) { + return mongoc_dump_database (client, database, collection); + } + + if (!(str = mongoc_client_get_database_names_with_opts (client, NULL, &error))) { + fprintf (stderr, "Failed to fetch database names: %s\n", error.message); + return EXIT_FAILURE; + } + + for (i = 0; str[i]; i++) { + if (EXIT_SUCCESS != mongoc_dump_database (client, str[i], NULL)) { + bson_strfreev (str); + return EXIT_FAILURE; + } + } + + bson_strfreev (str); + + return EXIT_SUCCESS; +} + + +static void +usage (FILE *stream) +{ + fprintf (stream, + "Usage: mongoc-dump [OPTIONS]\n" + "\n" + "Options:\n" + "\n" + " -h HOST Optional hostname to connect to [127.0.0.1].\n" + " -p PORT Optional port to connect to [27017].\n" + " -d DBNAME Optional database name to dump.\n" + " -c COLNAME Optional collection name to dump.\n" + " --ssl Use SSL when connecting to server.\n" + "\n"); +} + + +int +main (int argc, char *argv[]) +{ + mongoc_client_t *client; + const char *collection = NULL; + const char *database = NULL; + const char *host = "127.0.0.1"; + uint16_t port = 27017; + bool ssl = false; + char *uri_string; + mongoc_uri_t *uri; + bson_error_t error; + int ret; + int i; + + mongoc_init (); + + for (i = 1; i < argc; i++) { + if (0 == strcmp (argv[i], "-c") && ((i + 1) < argc)) { + collection = argv[++i]; + } else if (0 == strcmp (argv[i], "-d") && ((i + 1) < argc)) { + database = argv[++i]; + } else if (0 == strcmp (argv[i], "--help")) { + usage (stdout); + return EXIT_SUCCESS; + } else if (0 == strcmp (argv[i], "-h") && ((i + 1) < argc)) { + host = argv[++i]; + } else if (0 == strcmp (argv[i], "--ssl")) { + ssl = true; + } else if (0 == strcmp (argv[i], "-p") && ((i + 1) < argc)) { + port = atoi (argv[++i]); + if (!port) { + fprintf (stderr, "Invalid port \"%s\"", argv[i]); + return EXIT_FAILURE; + } + } else { + fprintf (stderr, "Unknown argument \"%s\"\n", argv[i]); + return EXIT_FAILURE; + } + } + + uri_string = bson_strdup_printf ( + "mongodb://%s:%hu/%s?appname=dump-example&ssl=%s", host, port, database ? database : "", ssl ? "true" : "false"); + + uri = mongoc_uri_new_with_error (uri_string, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + uri_string, + error.message); + return EXIT_FAILURE; + } + + if (!(client = mongoc_client_new_from_uri (uri))) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + + ret = mongoc_dump (client, database, collection); + + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + return ret; +} diff --git a/source/docs-libmongoc/includes/examples/mongoc-ping.c b/source/docs-libmongoc/includes/examples/mongoc-ping.c new file mode 100644 index 00000000..f4539e5f --- /dev/null +++ b/source/docs-libmongoc/includes/examples/mongoc-ping.c @@ -0,0 +1,89 @@ +/* + * Copyright 2013-2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include +#include + + +int +main (int argc, char *argv[]) +{ + mongoc_database_t *database; + mongoc_client_t *client; + bson_t reply; + uint16_t port; + bson_error_t error; + bson_t ping; + char *host_and_port; + mongoc_uri_t *uri; + char *str; + bool r; + + if (argc < 2 || argc > 3) { + fprintf (stderr, "usage: %s HOSTNAME [PORT]\n", argv[0]); + return EXIT_FAILURE; + } + + mongoc_init (); + + port = (argc == 3) ? atoi (argv[2]) : 27017; + + if (!strncmp (argv[1], "mongodb://", 10) || !strncmp (argv[1], "mongodb+srv://", 14)) { + host_and_port = bson_strdup (argv[1]); + } else { + host_and_port = bson_strdup_printf ("mongodb://%s:%hu", argv[1], port); + } + + uri = mongoc_uri_new_with_error (host_and_port, &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + host_and_port, + error.message); + return EXIT_FAILURE; + } + bson_free (host_and_port); + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + + bson_init (&ping); + bson_append_int32 (&ping, "ping", 4, 1); + database = mongoc_client_get_database (client, "test"); + r = mongoc_database_command_with_opts (database, &ping, NULL, NULL, &reply, &error); + + if (r) { + str = bson_as_canonical_extended_json (&reply, NULL); + fprintf (stdout, "%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Ping failure: %s\n", error.message); + } + + bson_destroy (&ping); + bson_destroy (&reply); + mongoc_database_destroy (database); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + return r ? 0 : 3; +} diff --git a/source/docs-libmongoc/includes/examples/mongoc-tail.c b/source/docs-libmongoc/includes/examples/mongoc-tail.c new file mode 100644 index 00000000..40f2f6c4 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/mongoc-tail.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include + +#ifdef _WIN32 +#define sleep(_n) Sleep ((_n) * 1000) +#endif + + +static void +print_bson (const bson_t *b) +{ + char *str; + + str = bson_as_canonical_extended_json (b, NULL); + fprintf (stdout, "%s\n", str); + bson_free (str); +} + + +static mongoc_cursor_t * +query_collection (mongoc_collection_t *collection, uint32_t last_time) +{ + mongoc_cursor_t *cursor; + bson_t query; + bson_t gt; + bson_t opts; + + BSON_ASSERT (collection); + + bson_init (&query); + BSON_APPEND_DOCUMENT_BEGIN (&query, "ts", >); + BSON_APPEND_TIMESTAMP (>, "$gt", last_time, 0); + bson_append_document_end (&query, >); + + bson_init (&opts); + BSON_APPEND_BOOL (&opts, "tailable", true); + BSON_APPEND_BOOL (&opts, "awaitData", true); + + cursor = mongoc_collection_find_with_opts (collection, &query, &opts, NULL); + + bson_destroy (&query); + bson_destroy (&opts); + + return cursor; +} + + +static void +tail_collection (mongoc_collection_t *collection) +{ + mongoc_cursor_t *cursor; + uint32_t last_time; + const bson_t *doc; + bson_error_t error; + bson_iter_t iter; + + BSON_ASSERT (collection); + + last_time = (uint32_t) time (NULL); + + while (true) { + cursor = query_collection (collection, last_time); + while (!mongoc_cursor_error (cursor, &error) && mongoc_cursor_more (cursor)) { + if (mongoc_cursor_next (cursor, &doc)) { + if (bson_iter_init_find (&iter, doc, "ts") && BSON_ITER_HOLDS_TIMESTAMP (&iter)) { + bson_iter_timestamp (&iter, &last_time, NULL); + } + print_bson (doc); + } + } + if (mongoc_cursor_error (cursor, &error)) { + if (error.domain == MONGOC_ERROR_SERVER) { + fprintf (stderr, "%s\n", error.message); + exit (1); + } + } + + mongoc_cursor_destroy (cursor); + sleep (1); + } +} + + +int +main (int argc, char *argv[]) +{ + mongoc_collection_t *collection; + mongoc_client_t *client; + mongoc_uri_t *uri; + bson_error_t error; + + if (argc != 2) { + fprintf (stderr, "usage: %s MONGO_URI\n", argv[0]); + return EXIT_FAILURE; + } + + mongoc_init (); + + uri = mongoc_uri_new_with_error (argv[1], &error); + if (!uri) { + fprintf (stderr, + "failed to parse URI: %s\n" + "error message: %s\n", + argv[1], + error.message); + return EXIT_FAILURE; + } + + client = mongoc_client_new_from_uri (uri); + if (!client) { + return EXIT_FAILURE; + } + + mongoc_client_set_error_api (client, 2); + + collection = mongoc_client_get_collection (client, "local", "oplog.rs"); + + tail_collection (collection); + + mongoc_collection_destroy (collection); + mongoc_uri_destroy (uri); + mongoc_client_destroy (client); + + return EXIT_SUCCESS; +} diff --git a/source/docs-libmongoc/includes/examples/parse_handshake_cfg.py b/source/docs-libmongoc/includes/examples/parse_handshake_cfg.py new file mode 100644 index 00000000..3712e54d --- /dev/null +++ b/source/docs-libmongoc/includes/examples/parse_handshake_cfg.py @@ -0,0 +1,62 @@ +import sys + +# `MD_FLAGS` maps the flag to its bit position. +# The bit positions must match those defined in src/mongoc/mongoc-handshake-private.h +MD_FLAGS = { + "MONGOC_MD_FLAG_ENABLE_CRYPTO": 0, + "MONGOC_MD_FLAG_ENABLE_CRYPTO_CNG": 1, + "MONGOC_MD_FLAG_ENABLE_CRYPTO_COMMON_CRYPTO": 2, + "MONGOC_MD_FLAG_ENABLE_CRYPTO_LIBCRYPTO": 3, + "MONGOC_MD_FLAG_ENABLE_CRYPTO_SYSTEM_PROFILE": 4, + "MONGOC_MD_FLAG_ENABLE_SASL": 5, + "MONGOC_MD_FLAG_ENABLE_SSL": 6, + "MONGOC_MD_FLAG_ENABLE_SSL_OPENSSL": 7, + "MONGOC_MD_FLAG_ENABLE_SSL_SECURE_CHANNEL": 8, + "MONGOC_MD_FLAG_ENABLE_SSL_SECURE_TRANSPORT": 9, + "MONGOC_MD_FLAG_EXPERIMENTAL_FEATURES": 10, + "MONGOC_MD_FLAG_HAVE_SASL_CLIENT_DONE": 11, + "MONGOC_MD_FLAG_HAVE_WEAK_SYMBOLS": 12, + "MONGOC_MD_FLAG_NO_AUTOMATIC_GLOBALS": 13, + "MONGOC_MD_FLAG_ENABLE_SSL_LIBRESSL": 14, + "MONGOC_MD_FLAG_ENABLE_SASL_CYRUS": 15, + "MONGOC_MD_FLAG_ENABLE_SASL_SSPI": 16, + "MONGOC_MD_FLAG_HAVE_SOCKLEN": 17, + "MONGOC_MD_FLAG_ENABLE_COMPRESSION": 18, + "MONGOC_MD_FLAG_ENABLE_COMPRESSION_SNAPPY": 19, + "MONGOC_MD_FLAG_ENABLE_COMPRESSION_ZLIB": 20, + "MONGOC_MD_FLAG_ENABLE_SASL_GSSAPI": 21, + "MONGOC_MD_FLAG_ENABLE_RES_NSEARCH": 22, + "MONGOC_MD_FLAG_ENABLE_RES_NDESTROY": 23, + "MONGOC_MD_FLAG_ENABLE_RES_NCLOSE": 24, + "MONGOC_MD_FLAG_ENABLE_RES_SEARCH": 25, + "MONGOC_MD_FLAG_ENABLE_DNSAPI": 26, + "MONGOC_MD_FLAG_ENABLE_RDTSCP": 27, + "MONGOC_MD_FLAG_HAVE_SCHED_GETCPU": 28, + "MONGOC_MD_FLAG_ENABLE_SHM_COUNTERS": 29, + "MONGOC_MD_FLAG_TRACE": 30, + # `MONGOC_MD_FLAG_ENABLE_ICU` was accidentally removed in libmongoc 1.25.0-1.25.3. + # If parsing a config-bitfield produced by libmongoc 1.25.0-1.25.3, use the version of `parse_handshake_cfg.py` from the git tag 1.25.0. + "MONGOC_MD_FLAG_ENABLE_ICU": 31, + "MONGOC_MD_FLAG_ENABLE_CLIENT_SIDE_ENCRYPTION": 32, + "MONGOC_MD_FLAG_ENABLE_MONGODB_AWS_AUTH": 33, + "MONGOC_MD_FLAG_ENABLE_SRV": 34, +} + +def main(): + flag_to_number = {s: 2 ** i for s,i in MD_FLAGS.items()} + + if len(sys.argv) < 2: + print ("Usage: python {0} config-bitfield".format(sys.argv[0])) + print ("Example: python parse_handshake_cfg.py 0x3e65") + return + + config_bitfield_string = sys.argv[1] + config_bitfield_num = int(config_bitfield_string, 0) + print ("Decimal value: {}".format(config_bitfield_num)) + + for flag, num in flag_to_number.items(): + v = "true" if config_bitfield_num & num else "false" + print ("{:<50}: {}".format(flag, v)) + +if __name__ == "__main__": + main() diff --git a/source/docs-libmongoc/includes/examples/tutorial/appending.c b/source/docs-libmongoc/includes/examples/tutorial/appending.c new file mode 100644 index 00000000..eb16a6b1 --- /dev/null +++ b/source/docs-libmongoc/includes/examples/tutorial/appending.c @@ -0,0 +1,83 @@ +#include + +int +main (void) +{ + struct tm born = {0}; + struct tm died = {0}; + const char *lang_names[] = {"MATH-MATIC", "FLOW-MATIC", "COBOL"}; + const char *schools[] = {"Vassar", "Yale"}; + const char *degrees[] = {"BA", "PhD"}; + uint32_t i; + bson_t *document; + bson_t child; + bson_array_builder_t *bab; + char *str; + + document = bson_new (); + + /* + * Append { "born" : ISODate("1906-12-09") } to the document. + * Passing -1 for the length argument tells libbson to calculate the + * string length. + */ + born.tm_year = 6; /* years are 1900-based */ + born.tm_mon = 11; /* months are 0-based */ + born.tm_mday = 9; + bson_append_date_time (document, "born", -1, mktime (&born) * 1000); + + /* + * Append { "died" : ISODate("1992-01-01") } to the document. + */ + died.tm_year = 92; + died.tm_mon = 0; + died.tm_mday = 1; + + /* + * For convenience, this macro passes length -1 by default. + */ + BSON_APPEND_DATE_TIME (document, "died", mktime (&died) * 1000); + + /* + * Append a subdocument. + */ + BSON_APPEND_DOCUMENT_BEGIN (document, "name", &child); + BSON_APPEND_UTF8 (&child, "first", "Grace"); + BSON_APPEND_UTF8 (&child, "last", "Hopper"); + bson_append_document_end (document, &child); + + /* + * Append array of strings. Generate keys "0", "1", "2". + */ + BSON_APPEND_ARRAY_BUILDER_BEGIN (document, "languages", &bab); + for (i = 0; i < sizeof lang_names / sizeof (char *); ++i) { + bson_array_builder_append_utf8 (bab, lang_names[i], -1); + } + bson_append_array_builder_end (document, bab); + + /* + * Array of subdocuments: + * degrees: [ { degree: "BA", school: "Vassar" }, ... ] + */ + BSON_APPEND_ARRAY_BUILDER_BEGIN (document, "degrees", &bab); + for (i = 0; i < sizeof degrees / sizeof (char *); ++i) { + bson_array_builder_append_document_begin (bab, &child); + BSON_APPEND_UTF8 (&child, "degree", degrees[i]); + BSON_APPEND_UTF8 (&child, "school", schools[i]); + bson_array_builder_append_document_end (bab, &child); + } + bson_append_array_builder_end (document, bab); + + /* + * Print the document as a JSON string. + */ + str = bson_as_canonical_extended_json (document, NULL); + printf ("%s\n", str); + bson_free (str); + + /* + * Clean up allocated bson documents. + */ + bson_destroy (document); + return 0; +} diff --git a/source/docs-libmongoc/includes/examples/tutorial/executing.c b/source/docs-libmongoc/includes/examples/tutorial/executing.c new file mode 100644 index 00000000..164a25ef --- /dev/null +++ b/source/docs-libmongoc/includes/examples/tutorial/executing.c @@ -0,0 +1,33 @@ +#include +#include +#include + +int +main (void) +{ + mongoc_client_t *client; + bson_error_t error; + bson_t *command; + bson_t reply; + char *str; + + mongoc_init (); + + client = mongoc_client_new ("mongodb://localhost:27017/?appname=executing-example"); + + command = BCON_NEW ("ping", BCON_INT32 (1)); + if (mongoc_client_command_simple (client, "mydb", command, NULL, &reply, &error)) { + str = bson_as_canonical_extended_json (&reply, NULL); + printf ("%s\n", str); + bson_free (str); + } else { + fprintf (stderr, "Failed to run command: %s\n", error.message); + } + + bson_destroy (command); + bson_destroy (&reply); + mongoc_client_destroy (client); + mongoc_cleanup (); + + return 0; +}