Skip to content

Commit

Permalink
feat postgresql: clarify docs on timezones and move the pages to .md …
Browse files Browse the repository at this point in the history
…files

Tests: протестировано CI
commit_hash:8b0380809bed21954a7a1cefe7d6b1dacab9ca06
  • Loading branch information
apolukhin committed Oct 11, 2024
1 parent 63d8907 commit abeec6f
Show file tree
Hide file tree
Showing 11 changed files with 338 additions and 232 deletions.
1 change: 1 addition & 0 deletions .mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -3299,6 +3299,7 @@
"scripts/docs/en/userver/os_signals.md":"taxi/uservices/userver/scripts/docs/en/userver/os_signals.md",
"scripts/docs/en/userver/periodics.md":"taxi/uservices/userver/scripts/docs/en/userver/periodics.md",
"scripts/docs/en/userver/pg_connlimit_mode_auto.md":"taxi/uservices/userver/scripts/docs/en/userver/pg_connlimit_mode_auto.md",
"scripts/docs/en/userver/pg_types.md":"taxi/uservices/userver/scripts/docs/en/userver/pg_types.md",
"scripts/docs/en/userver/pg_user_types.md":"taxi/uservices/userver/scripts/docs/en/userver/pg_user_types.md",
"scripts/docs/en/userver/profile_context_switches.md":"taxi/uservices/userver/scripts/docs/en/userver/profile_context_switches.md",
"scripts/docs/en/userver/publications.md":"taxi/uservices/userver/scripts/docs/en/userver/publications.md",
Expand Down
61 changes: 8 additions & 53 deletions postgresql/include/userver/storages/postgres/io/chrono.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ using ClockType = std::chrono::system_clock;
using TimePoint = ClockType::time_point;
using IntervalType = std::chrono::microseconds;

/// @brief Corresponds to TIMESTAMP WITH TIME ZONE (value in absolute time (no
/// TZ offset)). Time zones are applied automatically.
/// @brief Corresponds to TIMESTAMP WITH TIME ZONE database type.
///
/// @warning It's important that no conversion to TIMESTAMP WITHOUT TIME ZONE is
/// performed on the DB side, see @ref pg_timestamp
/// @warning Make sure that no unwanted
/// `TIMESTAMP` <> `TIMESTAMP WITHOUT TIME ZONE` conversions are performed on
/// the DB side, see @ref pg_timestamp.
///
/// @see @ref Now
struct TimePointTz final
Expand All @@ -52,11 +52,11 @@ logging::LogHelper& operator<<(logging::LogHelper&, TimePointTz);
/// @brief gtest logging support for TimePointTz.
std::ostream& operator<<(std::ostream&, TimePointTz);

/// @brief Corresponds to TIMESTAMP WITHOUT TIME ZONE (value in absolute time
/// (no TZ offset)).
/// @brief Corresponds to TIMESTAMP WITHOUT TIME ZONE database type.
///
/// @warning It's important that no conversion to TIMESTAMP WITH TIME ZONE is
/// performed on the DB side, see @ref pg_timestamp
/// @warning Make sure that no unwanted
/// `TIMESTAMP` <> `TIMESTAMP WITHOUT TIME ZONE` conversions are performed on
/// the DB side, see @ref pg_timestamp.
///
/// @see @ref NowWithoutTz
struct TimePointWithoutTz final
Expand Down Expand Up @@ -98,51 +98,6 @@ inline constexpr TimePoint kTimestampPositiveInfinity = TimePoint::max();
/// https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-SPECIAL-TABLE
inline constexpr TimePoint kTimestampNegativeInfinity = TimePoint::min();

/**
* @page pg_timestamp uPg timestamp support
*
* The driver provides mapping from C++ std::chrono::time_point template type to
* Postgres timestamp (without time zone) data type.
*
* To read/write timestamp with time zone Postgres data type a TimePointTz
* helper type is provided.
*
* Postgres internal timestamp resolution is microseconds.
*
* **Example:**
*
* @code
* namespace pg = storages::postgres;
*
* pg::Transaction trx = ...;
*
* auto now = std::chrono::system_clock::now();
* // Send as TIMESTAMP WITH TIME ZONE
* res = trx.Execute("select $1", pg::TimePointTz{now});
* // Send as TIMESTAMP WITHOUT TIME ZONE
* auto res = trx.Execute("select $1", pg::TimePointWithoutTz{now});
* // For reading, there is no difference between these time types
* res[0].To(now);
* @endcode
*
* ## How not to get skewed times in the database
*
* Postgres has two types corresponding to absolute time
* (a.k.a. global time; Unix time; NOT local time):
* * `TIMESTAMP WITH TIME ZONE`
* * `TIMESTAMP`
*
* An unfortunate design decision on the Postgres side is that it allows
* implicit conversion between them, and it applies an offset to the time point
* when doing so, depending on the timezone of the Postgres database.
*
* Because of this you MUST ensure that you always use the correct type:
* * storages::postgres::TimePointTz for `TIMESTAMP WITH TIME ZONE`;
* * storages::postgres::TimePointWithoutTz for `TIMESTAMP`.
*
* Otherwise, you'll get skewed times in database!
*/

namespace io {

namespace detail {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ struct IntegralBinaryParser : BufferParserBase<T> {
this->value = IntegralBySizeParser<8>::ParseBuffer(buf);
break;
default:
throw InvalidInputBufferSize{buf.length, "for an integral value type"};
throw InvalidInputBufferSize{
buf.length,
"for an integral value type (expecting size 2, 4, or 8). Not an "
"integer was returned from query."};
}
}
};
Expand Down
170 changes: 3 additions & 167 deletions postgresql/include/userver/storages/postgres/io/supported_types.hpp
Original file line number Diff line number Diff line change
@@ -1,172 +1,8 @@
#pragma once

// clang-format off
/// @page pg_types uPg: Supported data types
///
/// uPg provides data type support with a system of buffer parsers and
/// formatters.
/// Please refer to @ref pg_io for more information about the system.
///
/// @see @ref userver_postgres_parse_and_format
///
/// @par Fundamental PostgreSQL types
///
/// The fundamental PostgreSQL types support is provided by the driver. The
/// table below shows supported Postgres types and their mapping to C++ types
/// provided by the driver. Column "Default" marks the Postgres type to which
/// a C++ type is mapped when used as a parameter. Where the C++ type is N/A
/// it means that the PosgreSQL data type is not supported. When there is a
/// C++ type in parenthesis, it is a data type that will be supported later
/// and the C++ type is planned counterpart.
/// PG type | C++ type | Default |
/// ----------------- | --------------------------------------- | ------- |
/// smallint | std::int16_t | + |
/// integer | std::int32_t | + |
/// bigint | std::int64_t | + |
/// smallserial | std::int16_t | |
/// serial | std::int32_t | |
/// bigserial | std::int64_t | |
/// boolean | bool | + |
/// real | float | + |
/// double precision | double | + |
/// numeric(p) | decimal64::Decimal | + |
/// decimal(p) | decimal64::Decimal | + |
/// money | N/A | |
/// text | std::string | + |
/// char(n) | std::string | |
/// varchar(n) | std::string | |
/// "char" | char | + |
/// timestamp | std::chrono::system_clock::time_point | + |
/// timestamptz | storages::postgres::TimePointTz | + |
/// date | utils::datetime::Date | + |
/// time | utils::datetime::TimeOfDay | + |
/// timetz | N/A | |
/// interval | std::chrono::microseconds | |
/// bytea | container of one-byte type | |
/// bit(n) | utils::Flags | |
/// ^ | std::bitset<N> | |
/// ^ | std::array<bool, N> | |
/// bit varying(n) | utils::Flags | |
/// ^ | std::bitset<N> | |
/// ^ | std::array<bool, N> | |
/// uuid | boost::uuids::uuid | + |
/// json | formats::json::Value | |
/// jsonb | formats::json::Value | + |
/// int4range | storages::postgres::IntegerRange | |
/// ^ | storages::postgres::BoundedIntegerRange | |
/// int8range | storages::postgres::BigintRange | |
/// ^ | storages::postgres::BoundedBigintRange | |
/// inet | utils::ip::AddressV4 | |
/// ^ | utils::ip::AddressV6 | |
/// cidr | utils::ip::NetworkV4 | |
/// ^ | utils::ip::NetworkV6 | |
/// macaddr | utils::Macaddr | |
/// macaddr8 | utils::Macaddr8 | |
/// numrange | N/A | |
/// tsrange | N/A | |
/// tstzrange | N/A | |
/// daterange | N/A | |
///
/// @warning The library doesn't provide support for C++ unsigned integral
/// types intentionally as PostgreSQL doesn't provide unsigned types and
/// using the types with the database is error-prone.
///
/// For more information on timestamps and working with time zones please see
/// @ref pg_timestamp
///
/// @anchor pg_arrays
/// @par Arrays
///
/// The driver supports PostgreSQL arrays provided that the element type is
/// supported by the driver, including user types.
///
/// Array parser will throw storages::postgres::DimensionMismatch if the
/// dimensions of C++ container do not match that of the buffer received from
/// the server.
///
/// Array formatter will throw storages::postgres::InvalidDimensions if
/// containers on same level of depth have different sizes.
///
/// @par User-defined PostgreSQL types
///
/// The driver provides support for user-defined PostgreSQL types:
/// - domains
/// - enumerations
/// - composite types
/// - custom ranges
///
/// For more information please see
/// @ref scripts/docs/en/userver/pg_user_types.md.
///
/// @par C++ strong typedefs
///
/// The driver provides support for C++ strong typedef idiom. For more
/// information see @ref pg_strong_typedef
///
/// @par PostgreSQL ranges
///
/// PostgreSQL range type support is provided by `storages::postgres::Range`
/// template.
///
/// @par Geometry types
///
/// For geometry types the driver provides parsing/formatting from/to
/// on-the-wire representation. The types provided do not define any calculus.
///
/// @anchor pg_bytea
/// @par PostgreSQL bytea support
///
/// The driver allows reading and writing raw binary data from/to PostgreSQL
/// `bytea` type.
///
/// Reading and writing to PostgreSQL is implemented for `std::string`,
/// `std::string_view` and `std::vector` of `char` or `unsigned char`.
///
/// @warning When reading to `std::string_view` the value MUST NOT be used after
/// the PostgreSQL result set is destroyed.
///
///
///
///
/// Bytea() is a helper function for reading and writing binary data from/to a database.
///
/// Example usage of Bytea():
/// @snippet postgresql/src/storages/postgres/tests/bytea_pgtest.cpp bytea_simple
/// @snippet postgresql/src/storages/postgres/tests/bytea_pgtest.cpp bytea_string
/// @snippet postgresql/src/storages/postgres/tests/bytea_pgtest.cpp bytea_vector
///
///
///
///
///
/// @par Network types
///
/// The driver offers data types to store IPv4, IPv6, and MAC addresses, as
/// well as network specifications (CIDR).
///
/// @par Bit string types
///
/// The driver supports PostgreSQL `bit` and `bit varying` types.
///
/// Parsing and formatting is implemented for integral values
/// (e.g. `uint32_t`, `uint64_t`), `utils::Flags`, `std::array<bool, N>`
/// and `std::bitset<N>`.
///
/// Example of using the bit types from tests:
/// @snippet storages/postgres/tests/bitstring_pgtest.cpp Bit string sample
///
/// @par PostgreSQL types not covered above
///
/// The types not covered above or marked as N/A in the table of fundamental
/// types will be eventually supported later, on request from the driver's
/// users.
///
/// ----------
///
/// @htmlonly <div class="bottom-nav"> @endhtmlonly
/// ⇦ @ref pg_process_results | @ref pg_user_row_types ⇨
/// @htmlonly </div> @endhtmlonly
// clang-format on
/// @file userver/storages/postgres/io/supported_types.hpp
/// @brief Includes parsers and formatters for all supported data types;
/// prefer using the type specific include to avoid compilation time slowdown.

//@{
/** @name Traits etc */
Expand Down
4 changes: 2 additions & 2 deletions postgresql/include/userver/storages/postgres/postgres.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
/// - @ref pg_transactions
/// - @ref pg_run_queries
/// - @ref pg_process_results
/// - @ref pg_types
/// - @ref pg_user_types
/// - @ref scripts/docs/en/userver/pg_types.md
/// - @ref scripts/docs/en/userver/pg_user_types.md
/// - @ref pg_errors
/// - @ref pg_topology
///
Expand Down
7 changes: 4 additions & 3 deletions postgresql/include/userver/storages/postgres/result_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ namespace storages::postgres {
/// @par Extracting field's data to variables
///
/// A Field object provides an interface to convert underlying buffer to a
/// C++ variable of supported type. Please see @ref pg_types for more
/// information on supported types.
/// C++ variable of supported type. Please see
/// @ref scripts/docs/en/userver/pg_types.md for more information on supported
/// types.
///
/// Functions Field::As and Field::To can throw an exception if the field
/// value is `null`. Their Field::Coalesce counterparts instead set the result
Expand Down Expand Up @@ -181,7 +182,7 @@ namespace storages::postgres {
/// ----------
///
/// @htmlonly <div class="bottom-nav"> @endhtmlonly
/// ⇦ @ref pg_run_queries | @ref pg_types ⇨
/// ⇦ @ref pg_run_queries | @ref scripts/docs/en/userver/pg_types.md
/// @htmlonly </div> @endhtmlonly

struct FieldDescription {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ namespace storages::postgres {
/// - non-aggregate class with some augmentation.
///
/// Data members of the tuple or the classes must be supported by the driver.
/// For more information on supported data types please see @ref pg_types
/// For more information on supported data types please see
/// @ref scripts/docs/en/userver/pg_types.md.
///
/// @par std::tuple.
///
Expand Down Expand Up @@ -143,7 +144,7 @@ namespace storages::postgres {
/// ----------
///
/// @htmlonly <div class="bottom-nav"> @endhtmlonly
/// ⇦ @ref pg_types | @ref pg_errors ⇨
/// ⇦ @ref scripts/docs/en/userver/pg_types.md | @ref pg_errors ⇨
/// @htmlonly </div> @endhtmlonly

template <typename T, typename ExtractionTag>
Expand Down
Loading

0 comments on commit abeec6f

Please sign in to comment.